klassentemplate in klassentemplate
-
hallo
ich versuche gerade einen code im stil von dem hier zum laufen zu bekommen (minimalbeispiel):
template<class T> struct foo { template<class U> struct bar { int val; bar(int n) : val(n) {} }; }; template<class T, class U> foo<T>::bar<U> operator+ (int lhs, foo<T>::bar<U> rhs) { rhs.val += lhs; return rhs; } #include <iostream> int main() { foo<char>::bar<int> tester(5); std::cout << (2 + tester).val; }
ausgabe:
Compilation error time: 0 memory: 3428 signal:0 prog.cpp:12:44: error: ‘foo<T>::bar’ is not a type foo<T>::bar<U> operator+ (int lhs, foo<T>::bar<U> rhs) ^ prog.cpp:12:47: error: expected ‘,’ or ‘...’ before ‘<’ token foo<T>::bar<U> operator+ (int lhs, foo<T>::bar<U> rhs) ^ prog.cpp:12:54: error: ‘foo<T>::bar<U> operator+(int, int)’ must have an argument of class or enumerated type foo<T>::bar<U> operator+ (int lhs, foo<T>::bar<U> rhs) ^ prog.cpp: In function ‘int main()’: prog.cpp:21:18: error: no match for ‘operator+’ (operand types are ‘int’ and ‘foo<char>::bar<int>’) std::cout << (2 + tester).val; ^
dass bar kein typ sondern ein template ist ist mir auch bewusst, soll der compiler halt bis zur template-argumentenliste weiterlesen...
was kann ich da machen damit das funktioniert?
-
template<class T> template<class U> typename foo<T>::template bar<U> operator+ (int lhs, typename foo<T>::template bar<U> rhs) { ...
-
sowas ähnliches hab ich auch schon versucht, jedoch kommt vom compiler dann immer
prog.cpp:13:34: error: too many template-parameter-lists typename foo<T>::template bar<U> operator+ (int lhs, typename foo<T>::template bar<U> rhs) ^
-
ah sorry,
template<class T, class U> typename foo<T>::template bar<U> operator+ (int lhs, typename foo<T>::template bar<U> rhs)
nat. nur eine Templateparameterliste. Wir wollen ja kein Membertemplate definieren. Funktionieren wird das trotzdem nicht, weil T so nicht deduziert werden kann.
-
Wenn du eine Template-Klasse hast, Operatoren immer als friend deklarieren, nie als Template
template<class T> struct foo { template<class U> struct bar { int val; bar(int n) : val(n) {} friend bar operator+ (int lhs, bar rhs) { rhs.val += lhs; return rhs; } }; };
Grund dazu ist, dass nur so implizite Konvertierungen greifen (weil die friend-Funktion bei der Instanzierung der Klasse generiert wird). Du hättest auch schreiben können
friend bar operator+ (bar lhs, bar rhs) { rhs.val += lhs.val; return rhs; }
und du könntest trotzdem "5 + tester" berechnen, weil 5 in bar konvertiert werden kann.
-
Wenn du eine Template-Klasse hast, Operatoren immer als friend deklarieren, nie als Template
Das ist Unsinn. Die Regel muss ganz anders formuliert werden:
Überlädt man einen binären Operator für eine Klasse, so bietet es sich manchmal an, diesen als non-member zu überladen, damit implizite Konvertierungen greifen.
-
Arcoth schrieb:
Wenn du eine Template-Klasse hast, Operatoren immer als friend deklarieren, nie als Template
Das ist Unsinn. Die Regel muss ganz anders formuliert werden:
Überlädt man einen binären Operator für eine Klasse, so bietet es sich manchmal an, diesen als non-member zu überladen, damit implizite Konvertierungen greifen.Bring mal ein Beispiel, wann das gewünscht ist und es einen impliziten Konstruktor braucht.
-
Moment, hab' ich deinen Tipp falsch interpretiert?
Ich dachte, du beziehst dich auf das Member-Sein, nicht auf das Deklarieren außerhalb, denn direkt danach hast du ja genau den Grund genanntAllerdings ist mein ursprünglicher Einwand weiterhin richtig; es sei Unsinn, u.a. da man nie alles standardmäßig als
friend
deklariert, auch wenn man dann ein wenig Tipparbeit spart. Das ist eine Sünde. Man darf nicht einfach um Tipparbeit zu sparen die Kapselung lockern.
-
camper schrieb:
Funktionieren wird das trotzdem nicht, weil T so nicht deduziert werden kann.
Ja, ich verstehe im Übrigen nicht, warum das ein non-deduced context ist:
§14.8.2.5/5 schrieb:
— The nested-name-specifier of a type that was specified using a qualified-id.
Könntest du mir das erklären?
-
[in Klassentemplates:] Operatoren immer als friend deklarieren
sollte ziemlich klar sein, ich kann mir nicht vorstellen, wie man da etwas falsch interpretieren könnte.
Arcoth schrieb:
Allerdings ist mein ursprünglicher Einwand weiterhin richtig; es sei Unsinn, u.a. da man nie alles standardmäßig als
friend
deklariert, auch wenn man dann ein wenig Tipparbeit spart. Das ist eine Sünde. Man darf nicht einfach um Tipparbeit zu sparen die Kapselung lockern.Es wird nirgendwo Kapselung gelockert. Vielleicht formal gesehen lokal in den 2 Zeilen des Operators, aber das ist nicht schlimm. Das hat auch nichts mit Kapselung zu tun.
Und nebenbei bemerkt gibt es (normalerweise, auch hier) keine Alternative. Das hat nichts mit Tipparbeit zu tun.
-
Arcoth schrieb:
camper schrieb:
Funktionieren wird das trotzdem nicht, weil T so nicht deduziert werden kann.
Ja, ich verstehe im Übrigen nicht, warum das ein non-deduced context ist:
§14.8.2.5/5 schrieb:
— The nested-name-specifier of a type that was specified using a qualified-id.
Könntest du mir das erklären?
weil es im Allgemeinen nicht möglich ist
template <typename T> struct strange { using type = T*; }; template <typename T> struct strange<T*> { using type = T; }; template <typename T> void foo(typename strange<T>::type); ... int* x; foo(x); // T=int oder T = int** ?
-
Vielleicht formal gesehen lokal in den 2 Zeilen des Operators, aber das ist nicht schlimm.
Doch.
Und nebenbei bemerkt gibt es (normalerweise, auch hier) keine Alternative.
Leider sind injected-class-names nicht in inneren Klassen verfügbar...
sollte ziemlich klar sein, ich kann mir nicht vorstellen, wie man da etwas falsch interpretieren könnte.
Folglich ist deine Begründung dann irgendwie unpassend:
Wenn du eine Template-Klasse hast, Operatoren immer als friend deklarieren, nie als Template [...]
Grund dazu ist, dass nur so implizite Konvertierungen greifenweil es im Allgemeinen nicht möglich ist
Das ist mir auch klar. Aber da, wo es nicht möglich ist, könnte man es ill-formed machen, und wo nicht, da nicht. Ist die Entität, auf die die qualified-id sich bezieht, ein UDT innerhalb jener Klasse, ist es eindeutig.