enable_if



  • Ich bin gerade ziemlich verwirrt. Warum kompiliert das nicht und wie repariert man es? Ideone.

    struct Test{
    	template<class T>
    	Test(T &t) : Test<T, typename std::is_const<T>::type>(t){}
    
    	template<class T, std::true_type> //error
    	Test(T &t){ "t ist const!"; }
    
    	template<class T, std::false_type>
    	Test(T &t){ "t ist nicht const!"; }
    };
    	//Zeile 5:
    	//error: ‘struct std::integral_constant<bool, true>’ is not a valid type for a template non-type parameter
    	//bzw.
    	//'std::true_type' : illegal type for non-type template parameter
    


  • template-parameter müssen entweder templates, typen oder integrale werte sein. klassen-instanzen von nicht-integralen typen sind nicht erlaubt.



  • Irgendwie sehe ich die Klasseninstanz nicht. std::true_type ist meiner Meinung nach ein Typ, aber der Rest der Welt scheint zu meinen, dass std::true_type ein Objekt ist. 😕



  • nwp3 schrieb:

    Irgendwie sehe ich die Klasseninstanz nicht. std::true_type ist meiner Meinung nach ein Typ, aber der Rest der Welt scheint zu meinen, dass std::true_type ein Objekt ist. 😕

    uups, verlesen. ja, du hast recht. true_type ist ein typ:
    http://www.cplusplus.com/reference/type_traits/true_type/
    http://en.cppreference.com/w/cpp/types/integral_constant

    und indem du template<typ> schreibst, forderst du eine instanz des types als template-argument an, was (mit true_type) nicht erlaubt ist.

    nachtrag: ich glaube, man kann sowieso die template-argumente bei konstruktor-templates nicht explizit angeben. oder hat sich das mit c++11 geändert?



  • nwp3 schrieb:

    Irgendwie sehe ich die Klasseninstanz nicht. std::true_type ist meiner Meinung nach ein Typ

    Typen sind aber nicht erlaubt (ausser integrale, vielleicht wurde das in C++11 etwas gelockert). Wenn du Typen in der Template-Parameterliste auflistest, erwartet das Template bei der Instanziierung ein Objekt.

    Typparameter hingegen (mit typename deklarierte Templateparameter) erwarten einen Typ als Argument.

    Dein Code enthält keine Templatespezialisierung, da du den Basisfall nicht deklarierst (Funktionstemplate mit 2 Parametern). Würde ich aber gar nicht erst versuchen, schon gar nicht bei Konstruktoren. Nimm stattdessen Überladung; das ist ein übliches Idiom für Tag-Dispatching.

    template <typename T>
    Test(T& t, std::true_type) {...}
    
    template<typename T>
    Test(T& t, std::false_type) {...}
    


  • Nexus schrieb:

    In deinem Fall, nimm Überladung

    Danke, irgendwie bin ich da nicht drauf gekommen.

    struct Test{
    	template<class T>
    	Test(T &t) : Test(t, std::is_const<T>::value){}
    
    	template<class T>
    	Test(T &t, std::true_type){ "t ist const!"; }
    
    	template<class T>
    	Test(T &t, std::false_type){ "t ist nicht const!"; }
    };
    


  • Gibt es einen Grund dafür dass du hier nicht einfach ein mal T& und einmal const T& nimmst?



  • cooky451 schrieb:

    Gibt es einen Grund dafür dass du hier nicht einfach ein mal T& und einmal const T& nimmst?

    Der Grund ist, dass ich ein weiteres Template mit dem übergebenen Typ T instanziiere und dieses T dann const ist, was mir Sachen kaputt macht.
    Ich versuche Vererbung zu verstecken in diesem Stil: Inheritance Is The Base Class of Evil.
    Und wenn ich ein const-Objekt übergebe funktioniert es nicht weil T const ist.
    Hier ein Beispiel, dass das Problem zeigt. In der Fehlermeldung sieht man was er aus dem T gemacht hat.



  • Du meinst so? https://ideone.com/ksNs96
    make_unique gibt's btw nicht weil die das (ja, das ist ernst gemeint) "übersehen" haben. Wie auch immer, ab C++14 ist es da, und VS hat es z.B. auch schon implementiert.



  • Cool danke, funktioniert.
    Das mit dem unique_ptr wusste ich eigentlich. Irgendwie passt er nur nicht in mein Weltbild, dass VS bei neuen C++-Features dem gcc voraus sein könnte und da habe ich es verdrängt.
    Irgendwann sollte ich dir mal eine Riesenpackung Kekse spendieren.


Anmelden zum Antworten