Bei Template-Klassen Operatoren überladen - geht das?
-
Hallo,
kann man bei Template-Klassen Operatoren überladen? Und wenn ja, wie?
Ich habe leider noch nichts dazu gefunden.
Danke.
-
Das geht wie mit normalen Klassen.
-
Hier mal ein Beispiel. Da wird (hoffentlich) klar, dass das Überladen von Operatoren im Hinbilck auf Verständlichkeit des Codes, wohl überlegt zu geschehen hat.
EDIT: Beispiel minimiert.
#include <iostream> using std::cout; using std::endl; /** * Class to demonstrate some of the stuff that you can do with operator overloading and templates */ template <typename T> class Fun { public: Fun( void ) : i(0) { } Fun& operator () ( void ) { cout << i << " "; cout.flush(); return *this; } Fun& operator[](Fun& f) { (*this)(); return *this; } Fun& operator ++( void ) { ++i; (*this)(); return *this; } Fun operator ++( int ) { Fun temp = *this; ++(*this); return temp; } private: T i; }; /* * Here comes the demonstration code */ int main(int argc, char* argv[]) { Fun<double> f; // fun with parantheses, ()Spam like in Lisp ((f())())(); cout << endl; // Fun with prefix and infix, close to Brainf*** ++++++++++++f++++++++++++++; cout << endl; // fun with indexing, no, its not an multidimensional array f[f][f][f][f][f][f]; cout << endl; // fun with all of the above, can you deduct the result without running the program? ((++(f())()[f]++)()[f])(); return 0; }
-
stefan-tiger schrieb:
kann man bei Template-Klassen Operatoren überladen?
Ja, kann man. Das ist auch nichts besonderes von der Syntax her. Es fällt mir da aber ein Punkt ein, der erwähnenswert ist. Beispiel:
class foo { double re, im; public: double real() const {return re;} double imag() const {return re;} foo(double r=0, double i=0) : re(r), im(i) {} // <-- Konvertierungskonstruktor }; inline foo operator+(foo a, foo b) { return foo( a.real()+b.real(),a.imag()+b.imag() ); } int main() { foo x = 1; foo y = 2 + x; // <-- funktioniert }
Die Zeile in der main funktioniert, weil operator+ mit einer impliziten Konvertierung der 2 nach foo(2,0) benutzt werden kann. Wenn man das jetzt templatisiert....
template<typename T> class foo { T re, im; public: T real() const {return re;} T imag() const {return re;} foo(T r=0, T i=0) : re(r), im(i) {} // <-- Konvertierungskonstruktor }; template<typename T> inline foo<T> operator+(foo<T> a, foo<T> b) { return foo<T>( a.real()+b.real(),a.imag()+b.imag() ); } int main() { foo<double> x = 1; foo<double> y = 2 + x; // <-- funktioniert NICHT MEHR }
lässt sich das nicht mehr kompilieren, weil operator+ nun ein Funktionstemplate ist und T nicht mehr deduziert werden kann. Eine automatische Konvertierung kommt hier nicht in Frage. Helfen können einem dabei inline friend Funktionen:
template<typename T> class foo { T re, im; public: T real() const {return re;} T imag() const {return re;} foo(T r=0, T i=0) : re(r), im(i) {} // <-- Konvertierungskonstruktor friend foo operator+(foo a, foo b) { return foo( a.re+b.re,a.im+b.im ); } }; int main() { foo<double> x = 1; foo<double> y = 2 + x; // <-- Funktioniert wieder! }
Mit "inline friends" in einem Klassentemplate kann man also "normale" freie Funktionen definieren, wo keine Template Argument Deduction stattfinden muss. Diese Funktionen sind über ADL sichtbar.
kk
-
Danke für eure Antworten.
Kann man es so hinschreiben, dass man die Implementierung der Operatoren nicht in die Klasse schreiben muss?
-
Noch eine Frage:
Angenommen Foo ist eine Template-Klasse die eine überladenen Zuweiseungsoperator (operator
hat, wie kann man es erreichen, dass dann folgendes funktioniert:
template<class T> class Foo { public: T data; operator =... {} } ... Foo<int> a; Foo<short> b; a=42; // 42 soll in data von a gespeichert werden b=a; // data soll von a nach b kopiert werden. in data von b steht nun 42 ...
Sprichm, wie muss der Überladene Operator dann aussehen?
-
stefan-tiger schrieb:
Angenommen Foo ist eine Template-Klasse die eine überladenen Zuweiseungsoperator (operator
hat, wie kann man es erreichen, dass dann folgendes funktioniert
Du bietest einen
operator=
an, der auch andere Typen (konkret sind das Instanziierungen desFoo
-Templates mit verschiedenen Argumenten fürT
) unterstützt.template <typename T> class Foo { public: template <typename U> Foo& operator= (const Foo<U>& origin); };
Und vergiss den dazugehörigen Template-Konstruktor mit
const Foo<U>&
als Parameter nicht.Übrigens sind im Allgemeinen zusätzlich ein normaler Kopier-Zuweisungsoperator sowie Kopierkonstruktor notwendig, da Funktionstemplates nie als solche gelten. Hier sollten jedoch die vom Compiler generierten Funktionen ausreichen.
-
stefan-tiger schrieb:
Noch eine Frage:
Angenommen Foo ist eine Template-Klasse die eine überladenen Zuweiseungsoperator (operator
hat, wie kann man es erreichen, dass dann folgendes funktioniert:
template<class T> class Foo { public: T data; operator =... {} } ... Foo<int> a; Foo<short> b; a=42; // 42 soll in data von a gespeichert werden b=a; // data soll von a nach b kopiert werden. in data von b steht nun 42 ...
Sprichm, wie muss der Überladene Operator dann aussehen?
Na das eine Mal mit nem int-Datentyp, das andere mal mit der Klasse.
stefan-tiger schrieb:
Danke für eure Antworten.
Kann man es so hinschreiben, dass man die Implementierung der Operatoren nicht in die Klasse schreiben muss?
Also wenn du :: meinst...