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 des Foo -Templates mit verschiedenen Argumenten für T ) 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...


Anmelden zum Antworten