015
10.11.2004, 17:40 Uhr
virtual
Sexiest Bit alive (Operator)
|
Die Frienddeklaration ist gleichzeitig Definition. Das war die entscheidende Antwort:
Zitat: |
Johannes Hampel" <johannes@hipphampel.de> schrieb im Newsbeitrag news:cmr4a6$t13$1@online.de...
>> Hallo, >> >> gegeben sei folgendes Nonsense Template: >> >> template<typename T> >> class integer { >> T i; >> public: >> integer(T i_) :i(i_) { } >> >> friend integer<T> operator + <>(const integer<T>&, const integer<T>& >> }; >> >> template<typename T> >> integer<T> operator + (const integer<T>& a, const integer<T>& b) { >> return integer<T>(a.i+b.i); >> } >> >> int main() { >> integer<long> a(100); >> >> a = ::operator +<long>(4, a); // Geht >> a = 4 + a; // Geht nicht! >> } >> >> >> Wie zu sehen, funktioniert letzte Zeile nicht, die ja eigentlich die >> Motivation war, den Operator als non-member zu definieren. >> Nur weiss ich eben nicht, *warum* das nicht geht, denn bei normalen >> Klassen geht das ja schon. >> Geht es nicht, weil ich eineN Fehler Mache (wahrscheinlich), mein >> Kompiler einen Fehler macht oder der Standard es einfach nicht zulaesst >> (und wenn er es nicht zulaesst: warum laesst er es nicht zu?)
Bei Deinem Code gibt es 2 Fehler:
a) die friend - Deklaration bezieht sich auf eine nicht deklarierte template-Funktion
Du müßtest vorher eine forward-declaration dieser Funktion machen, damit die friend-Deklaration gültig wird.
b) Die interessante Zeile a = 4 + a;
Der Compiler kann den Typ T hier nicht ableiten, da er nur ein int vorgesetzt kriegt.
Dein Problem hat mich animiert, den Standard nachzulesen, und nach einiger Zeit bin ich in 14.8.2.4/2 fündig geworden:
".... Type deduction is done independently for each P/A pair, and the deduced template arguments values are then combined. If type deduction cannot be done for any P/A pair .... template argument deduction fails."
Ich hoffe das ist die richtige Stelle.
Demnach probiert der Compiler, aus 4 (Typ int) das T aus integer<T> abzuleiten, was fehlschlägt, und somit ist die Zeile ungültig.
Bei a = ::operator +<long>(4, a); umgehst Du die Ableitung des template arguments, somit funktioniert das.
Die IMHO einfachste Lösung besteht darin, die friend-Deklaration in der Klasse gleich auch als Definition zu nutzen:
template<typename T> class integer { T i; public: integer(T i_) :i(i_) { } friend integer operator +(const integer& a, const integer& b) {return integer(a.i+b.i);} };
Dann funktioniert die betreffende Zeile, da mit dieser friend-Definition gleichzeitig eine Überladung von operator+ mit dem jeweiligen Instanzierungstyp bereitgestellt wird, und template argument deduction wegfällt und nur mehr die Überladungsregeln zum Zug kommen (da wird dann der implizite Konvertierungskonstruktor von integer aufgerufen).
Falls der Funktionsrumpf relativ lang ist (für eine inline-Definition in der Klasse) kannst Du einfach eine einfache Hilfsfunktion aufrufen.
Thomas
-- de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod@bud.prima.de FAQ: www.voyager.prima.de/cpp/ mailto:voyager+send-faq@bud.prima.de
|
-- Gruß, virtual Quote of the Month Ich eß' nur was ein Gesicht hat (Creme 21) Dieser Post wurde am 10.11.2004 um 17:40 Uhr von virtual editiert. |