Template, Objekt/Pointer unterscheiden..



  • tpl schrieb:

    Die folgende Klasse wird unterschiedlich, mit ItemHandle<x> oder mit
    ItemHandle<x*> instanziert, was auch so bleiben soll. Allerdings habe
    ich dadurch das Problem, daß der Konstruktor einmal element.bbox()
    und einmal element->bbox() aufrufen müßte. Gibt es eine Möglichkeit
    zu unterscheiden, ob da ein Pointer oder eine Klasse hereinkommt?

    template<class T_Item>
    class ItemHandle  
    {
    public:
    	ItemHandle(const T_Item& element_);
    private:
    	Bbox itemBB;	
    };
    
    template<class T_Item>
    ItemHandle<T_Item>::ItemHandle(const T_Item& element_) : itemBB(element.bbox())
    {
    }
    }
    

    ..danke!

    template <typename T>
    struct is_pointer_type
    {
        enum { value = false };
    };
    
    template <typename T>
    struct is_pointer_type<T*>
    {
        enum { value = true };
    };
    
    template <typename T>
    bool is_pointer(const T&)
    {
        return is_pointer_type<T>::value;
    }
    

    Dann anwenden :xmas1:

    http://ideone.com/ESMtM#view_edit_box

    Geprüft (atschibätsch PI).



  • Hacker schrieb:

    template <typename T>
    struct is_pointer_type
    {
        enum { value = false };
    };
    
    template <typename T>
    struct is_pointer_type<T*>
    {
        enum { value = true };
    };
    
    template <typename T>
    bool is_pointer(const T&)
    {
        return is_pointer_type<T>::value;
    }
    

    Dann anwenden :xmas1:

    http://ideone.com/ESMtM#view_edit_box

    Geprüft (atschibätsch PI).

    Geil! Das sollte die Lösung sein, ich werds gleich probieren. Ich kann mich
    jetzt auch erinnern, daß ich davon mal gelesen habe, und zwar in Alexandrescu's
    Modern C++ Design.

    Danke fürn Hinweis!



  • Hm, das war jetzt doch nicht die Lösung, denn is_pointer() generiert einen
    Wert, aber was ich brauche, ist eine Unterscheidung zur Compile-Zeit, denn

    if(is_pointer(a)) a->bbox();
      else a.bbox();
    

    compiliert natürlich nicht. Wie könnte man denn die vorgeschlagene
    Spezialisierung syntaktisch umsetzen? Ich habe Beispiel gefunden, wo
    man für einen festen Typ spezialisiert, aber wie denn, wenn der Typ
    ein Template-Parameter ist wie in diesem Fall?



  • Bei einzelnen Funktionen mit Überladung:

    template <typename T>
    void do_stuff(T* obj)
    {
        // Zeigervariante
    }
    
    template <typename T>
    void do_stuff(T& obj)
    {
        // Referenzvariante
    }
    

    Bei Klassen mithilfe einer Spzialisierung:

    template <typename T>
    struct foo { ... };
    
    template <typename T>
    struct foo<T*> { ... };
    

    Ich kann mir nicht vorstellen, dass Hackers Ding da irgendwie ne Hilfe ist. Zumal es das Ding sowieso schon unter std::is_pointer in <type_traits> gibt.

    Edit: Und in deinem Fall würde ich einfach einen zweiten Ctor basteln, der einen const T* nimmt.

    Edit 2: Achso, ich seh schon das Problem. Ist schon etwas spät 🤡
    Ich würde wohl zwei Ctoren schreiben, die so aussehen:

    ItemHandle(typename std::remove_pointer<T>::type* ptr);
    ItemHandle(typename std::remove_pointer<T>::type& ref);
    

  • Mod

    template <typename T> struct pointersensitiv
    {
      pointersensitiv(T a) {a.foo();}
    };
    
    template<typename T> struct pointersensitiv<T*>
    {
      pointersensitiv(T* a) {a->foo();}
    };
    
    #include<iostream>
    struct nur_zum_test
    {
      void foo() {std::cout << "Foo!\n";}
    };
    
    int main()
    {
      nur_zum_test bar;
      pointersensitiv<nur_zum_test> objekt(bar);
      pointersensitiv<nur_zum_test*> pointer(&bar);
    }
    

  • Mod

    template <typename T>
    T&& deref(T&& v) { return std::forward<T>(v); }
    
    template <typename T>
    T& deref(T* v) { return *v; }
    

    und dann einfach überall, wo a.foo() oder a->foo() auftauchen würde:

    deref(a).foo()
    

    schreiben.



  • @SeppJ
    Buääääääh, Konstruktoren als Funktionen misbrauchen ist mir ein Gräul 🤡



  • camper schrieb:

    template <typename T>
    T&& deref(T&& v) { return std::forward<T>(v); }
    
    template <typename T>
    T& deref(T* v) { return *v; }
    

    und dann einfach überall, wo a.foo() oder a->foo() auftauchen würde:

    deref(a).foo()
    

    schreiben.

    Danke, das war die Lösung. 👍 👍 👍 Die erste Funktion mußte ich aber anpassen:

    template <typename T>
    T& deref(T& v) { return v; }
    
    template <typename T>
    T& deref(T* v) { return *v; }
    

    was sollte denn das T&& deref(T&& v) bedeuten?



  • campers Lösung hat sowohl LValues als auch RValues geschluckt. Deine nimmt nur LValues. Stichwörter: Perfect Forwarding, Reference Collapsing.



  • 314159265358979 schrieb:

    Stichwörter: Perfect Forwarding, Reference Collapsing.

    Und vor allem Anderen Stichwort C++11 und Rvalue-Referenzen. Wenn du das anpassen musstest, kann dein Compiler das wohl noch nicht.



  • pumuckl schrieb:

    314159265358979 schrieb:

    Stichwörter: Perfect Forwarding, Reference Collapsing.

    Und vor allem Anderen Stichwort C++11 und Rvalue-Referenzen. Wenn du das anpassen musstest, kann dein Compiler das wohl noch nicht.

    Ah, gcc version 4.5.2, und die Software soll am Ende auch noch auf VS 2008
    compilieren. Daher habe ich es mit C++11 gar nicht eilig 🙂

    Danke allen für die Hinweise, das Problem ist nun gut gelöst.



  • Beim GCC brauchst du nur beim kompilieren -std=c++0x angeben.


  • Mod

    hustbaer schrieb:

    @SeppJ
    Buääääääh, Konstruktoren als Funktionen misbrauchen ist mir ein Gräul 🤡

    Mir auch. Der Threadersteller hat aber ausdrücklich danach gefragt. Wenn du schnell gewesen wärst, hättest du vor dem edit noch eine Version mit normalen Funktoren gesehen.



  • 314159265358979 schrieb:

    Beim GCC brauchst du nur beim kompilieren -std=c++0x angeben.

    Oder, wie bei mir (wie schon bei unserer Spielwiese festgestellt):
    -std=gnu++0x



  • Zuletzt bearbeitet von Hacker am 16:01:35 17.12.2011, insgesamt 1-mal bearbeitet

    Um uns das mitzuteilen musstest du den Thread nochmals ausgegraben?



  • h4xx02 schrieb:

    Zuletzt bearbeitet von Hacker am 16:01:35 17.12.2011, insgesamt 1-mal bearbeitet

    Um uns das mitzuteilen musstest du den Thread nochmals ausgegraben?

    1. Falsches Deutsch,
    2. Ja. Denn bei mir z.B. klappt das anders nicht, und wenn dich der Thread nervt dann ignorier ihn verdammt nochmal. Dadurch das du (und eig. ich auch) ihn weiter befüllen bleibt er ausgegraben. :xmas1: 😉


Anmelden zum Antworten