Spezilisierung von onstruktor Templates?
-
pumuckl schrieb:
Konstruktor templates
Sowas nennt man auch gerne "Typumwandlungskonstruktor"

-
inp schrieb:
...Seltsam
Wieso schluckt das mein gcc nicht ?
Ihm gefällt das hier nicht:Dingsda::Dingsda<char>Fragt sich anscheinend wieso Dingsda kein Klassentemplate ist, obwohl dann das <..> ja hinterm ersten Dingsda sein müsste ...
Aber Comeau meckert nicht, dann ist ja alles gut

-
KasF schrieb:
Th schrieb:
Besser ist es du nimmst überhaupt keine templates und überlädst die Konstruktoren direkt. Um dieimplizite Typkonvertierung zu unterbinden, gibt es das Schlüsselwort 'explicit':
class Dingsda { public: explicit Dingsda(float rhs); explicit Dingsda(Dingsda const& rhs); };Das würde leider bei einem Aufruf wie:
Dingsda dings(6);nicht helfen, da der Compiler sowas draus macht:
Dingsda dings( /*Dingsda(float)->*/Dingsda(6)/*Dingsda(copy)*/ );das seh ich anders
class Dingsda { public: explicit Dingsda(float rhs); explicit Dingsda(Dingsda const& rhs); }; ... Dingsda dings(6);da der ctor float definiert ist wird nur dieser ctor aufgerufen
davor wird int zu float gecastet.explizit wird eigentlich verwendet um soetwas zu verhindern
class Dingsda3; class Dingsda2; class Dingsda { float m_f; public: explicit Dingsda(float) : m_f(0) { } /* explicit */ Dingsda(Dingsda const& other) : m_f(other.m_f) { } /* explicit */ Dingsda(Dingsda3 const&) {}; }; class Dingsda2 { float m_f; public: Dingsda2() : m_f(1.0f) { }; operator Dingsda() { return Dingsda(m_f); //expliziter aufruf Dingsda::Dingsda(float) } }; class Dingsda3 { public: Dingsda3(int) {}; }; int main(int, char**) { Dingsda d(Dingsda2); // error : wenn Dingsda::Dingsda(Dingsda const&) als explizit definiert // ansonsten : explizit Dingsda2::Dingsda2(), implizit static_cast<Dingsda>(exlizit kreirtes dingsda2), impliziter Dingsda(Dingsda const&) aufruf Dingsda d2 = 1; // error : wenn Dingsda::Dingsda(Dingsda3 const&) als explizit definiert // ansonsten : geht nicht über Dingsda::Dingsda(float) da als explizit definiert // sondern implizit Dingsda3::Dingsda3(int), implizit Dingsda::Dingsda(Dingsda3 const&) return 0; }
-
KasF schrieb:
inp schrieb:
...Seltsam
Wieso schluckt das mein gcc nicht ?
Ihm gefällt das hier nicht:Dingsda::Dingsda<char>Fragt sich anscheinend wieso Dingsda kein Klassentemplate ist, obwohl dann das <..> ja hinterm ersten Dingsda sein müsste ...
Aber Comeau meckert nicht, dann ist ja alles gut

hmmh, hast recht (vs2005 auch)
die syntax kommt mir richtig vor
ich hab hab <char> weggetan damit der compiler den typen automatisch rausfindet.
so lässts sich kompilieren.template<> Dingsda::Dingsda(char const&) { }
-
inp schrieb:
KasF schrieb:
Th schrieb:
Besser ist es du nimmst überhaupt keine templates und überlädst die Konstruktoren direkt. Um dieimplizite Typkonvertierung zu unterbinden, gibt es das Schlüsselwort 'explicit':
class Dingsda { public: explicit Dingsda(float rhs); explicit Dingsda(Dingsda const& rhs); };Das würde leider bei einem Aufruf wie:
Dingsda dings(6);nicht helfen, da der Compiler sowas draus macht:
Dingsda dings( /*Dingsda(float)->*/Dingsda(6)/*Dingsda(copy)*/ );das seh ich anders
class Dingsda { public: explicit Dingsda(float rhs); explicit Dingsda(Dingsda const& rhs); }; ... Dingsda dings(6);da der ctor float definiert ist wird nur dieser ctor aufgerufen
davor wird int zu float gecastet.Hrmpf, hast natürlich vollkommen Recht. In letzter Zeit schreibe ich immer viel Unsinn. Sollte besser mal meine Post's genauer lesen

Mir ist auch natürlich klar was es mit explicit auf sich hat.Trotzdem hilft hier die Lösung von Th nicht, um die Konvertierung von int to float zu verhindern ...
-
das stimmt
alternativ kann man den "int" konstruktor private definieren, somit gibts ihn für einen typen (und keine impliziten spielchen werden probiert) da er im private bereich ist kann man ihn nicht ausführen.
so:
class Dingsda { public: Dingsda(float) {}; private: Dingsda(int) {}; //speziell für einen typen konstruktion abdrehen Dingsda(Dingsda const&) {}; // template<typename T> beinhaltet copy construktor nicht, wenn nicht vorhanden wird er generiert !!!! template<typename T> Dingsda(T const&) {}; //für alle typen konstrkution abdrehen, ausnahme die public definierten nicht "template basierten" konstrkutoren }; int main(int, char**) { Dingsda d(1), //error , private Dingsda(int) d2 = 2; //error , private Dingsda(int) Dingsda d(1.0), //error , private template<typename T> Dingsda(T) d2 = 2.0; //error , private template<typename T> Dingsda(T) Dingsda f(1.0f), //ok f2 = 2.0f; //ok Dingsda c = f; //error , private Dingsda(Dingsda const&) c2 = f2; //error , private Dingsda(Dingsda const&) return 0; }die regeln hierfür, soweit ich mich erinnern kann
- schauen ob konstruktor auf direktem wege gefunden wird
- schauen ob konstruktor durch templates gefunden wird (ausgenommen copykonstruktor mit eigenem typen)
- schauen ob konstruktor auf indirektem wege gefunden wird (durch implizites herumgecaste (aber nicht 10000mal hintereinander, sondern maximal 1mal))
-
Die Konstruktion mit bestimmten Argumenten zu verhindern ist ja kein schweres Ding.
Ich hatte es eher so verstanden, dass pumuckl für bestimmte Typen, bestimmte Konstruktoren aufrufen will, aber dennoch grundlegende Konvertierung wie int to float verhindern wollte ...Dazu fällt mir aber auch keine andere Methode ein, wie die mit Templates von dir.
-
inp schrieb:
Dingsda f(1.0f), //ok f2 = 2.0f; //oknicht ganz. Für f2 brauchen wir einen Copy-Konstruktor - auch dann, wenn dieser ausgelassen wird. Im Übrigen ist es zweckmäßig, diese privaten Konstruktoren nicht zu definieren, um auch dann, wenn wir es mit friends oder Funktionen der Klasse zu tun haben, wenigstens einen Linkerfehler zu erhalten.
Ein andere Methode bedient sich SFINAE um unerwünschte Spezialisierungen zu unterdrücken bzw. erwünschte zuzulassen (geht auch ohne boost - aber so ist es einfacher)
#include "boost/utility.hpp" #include "boost/mpl/vector.hpp" #include <boost/mpl/contains.hpp> namespace mpl = boost::mpl; class Dingsda // : boost::noncopyable { public: template<typename T> Dingsda(const T& t, typename boost::disable_if< typename mpl::contains< mpl::vector< int, char, void*, float, double // Für alle Typen außer den aufgezählten >, T >::type >::type* = 0) {} template<typename T> Dingsda(const T& t, typename boost::enable_if< typename mpl::contains< mpl::vector< float // Für alle aufgezählten Typen >, T >::type >::type* = 0) {} private: Dingsda(Dingsda&); void operator=(Dingsda&); }; int main(int, char**) { Dingsda d(1), //error, kann nicht in Dingsda& konvertieren d2 = 2; //error, kann nicht in Dingsda& konvertieren Dingsda e(1.0), //error, kann nicht in Dingsda& konvertieren e2 = 2.0; //error, kann nicht in Dingsda& konvertieren Dingsda f(1.0f), //ok f2 = 2.0f; //fehler, kann rvalue nicht an referenz binden Dingsda c = f; //error , private Dingsda(Dingsta&) return 0; }
-
camper schrieb:
inp schrieb:
Dingsda f(1.0f), //ok f2 = 2.0f; //oknicht ganz. Für f2 brauchen wir einen Copy-Konstruktor - auch dann, wenn dieser ausgelassen wird. Im Übrigen ist es zweckmäßig, diese privaten Konstruktoren nicht zu definieren, um auch dann, wenn wir es mit friends oder Funktionen der Klasse zu tun haben, wenigstens einen Linkerfehler zu erhalten.
Ein andere Methode bedient sich SFINAE um unerwünschte Spezialisierungen zu unterdrücken bzw. erwünschte zuzulassen (geht auch ohne boost - aber so ist es einfacher)
#include "boost/utility.hpp" #include "boost/mpl/vector.hpp" #include <boost/mpl/contains.hpp> namespace mpl = boost::mpl; class Dingsda // : boost::noncopyable { public: template<typename T> Dingsda(const T& t, typename boost::disable_if< typename mpl::contains< mpl::vector< int, char, void*, float, double // Für alle Typen außer den aufgezählten >, T >::type >::type* = 0) {} template<typename T> Dingsda(const T& t, typename boost::enable_if< typename mpl::contains< mpl::vector< float // Für alle aufgezählten Typen >, T >::type >::type* = 0) {} private: Dingsda(Dingsda&); void operator=(Dingsda&); }; int main(int, char**) { Dingsda d(1), //error, kann nicht in Dingsda& konvertieren d2 = 2; //error, kann nicht in Dingsda& konvertieren Dingsda e(1.0), //error, kann nicht in Dingsda& konvertieren e2 = 2.0; //error, kann nicht in Dingsda& konvertieren Dingsda f(1.0f), //ok f2 = 2.0f; //fehler, kann rvalue nicht an referenz binden Dingsda c = f; //error , private Dingsda(Dingsta&) return 0; }yup

wollt die schweren geschütze nicht ausfahren
mit template meta kann man sich aber auch unnötig viel spielen

edit:
das mit undefiniertem body leuchtet ein, ty für tip.
-
Naja, das mit boost erscheint mir bissl overkill. Wenn ich (neben dem Copy-Ctor) das Konstruktor template wie oben von mir geschrieben deklariere, aber abgesehen von den drei oder vier Spezialisierungen für die Typen die ich zulassen will keine allgemeine Definition liefere, wird er mir auf jeden Fall schon zur Compilezeit Linkerfehler geben, falls ich das mit nem falschen Typ versuche oder?