Problem mit Templates



  • Hey Leute,

    ich versuche gerade ca folgendes (Vorsicht, die Funktion zur Überladung des "+" ist ist nicht kompilierbar und soll meine Gedankengänge etwas verdeutlichen)

    template <typename T>
    class A {
    
    public:
    	T x;
    	A(int init) : x(init) {}
    };
    
    template <typename T, typename U, typename Z>
    A<typeid(tmp).name> operator+(A<T> lhs, A<U> rhs) {
    	auto tmp = lhs.x + rhs.x;
    	return A<typeid(tmp).name>(tmp);
    }
    
    int main()
    {
    	A<int> a(1);
    	A<float> b(2.1f);
    
    	std::cout << (a+b).x << std::endl;
    
            return 0;
    }
    

    Das Problem ist folgendes, ich möchte, falls ich wie Beispielsweise in der Main-Funktion ein A<int> und ein A<float> addiere, final ein A<float> erhalte.

    Weiß einer von euch wie man das elegant realisieren kann, dass dies allgemein für alle Standardtypen die sich implizit ineinander casten lassen funktioniert?

    Gruß 🙂



  • Nur so ne Idee, nicht getestet:

    template <typename U, typename V>
    auto operator +(A<U> lhs, A<V> rhs) -> A<decltype(lhs.x + rhs.x)>
    {
      return lhs.x + rhs.x;
    }
    


  • Wenn das von dot nicht geht, kannst du die andere C++11-Lösung probieren:

    template <typename T, typename U,
              typename Z = decltype(std::declval<T>()+std::declval<U>())>
    A<Z> operator+(A<T> lhs, A<U> rhs) {
      return A<Z>(lhs.x + rhs.x);
    }
    

    Wenn du kein C++11 hast, geht es auch, aber dann wirds wüst.



  • Vielen Dank für eure Hilfen 🙂

    Leider bekomme ich für die Version von "einfachmalso " den Fehler, dass + für die Operanden nicht definiert sein soll 😞
    Weiß zufällig einer warum?

    Die andere Version von "dot" kompiliert zwar, aber gibt eine "3" aus anstatt "3.1."
    Was genau macht "-> A<decltype(lhs.x + rhs.x)>" ?

    Gruß 🙂



  • MatheStein schrieb:

    Was genau macht "-> A<decltype(lhs.x + rhs.x)>" ?

    Es setzt den Rückgabetyp der Funktion auf den Typ des Ausdrucks lhs.x + rhs.x, bei int und float sollte das float sein.
    Das gibt bei mir wie erwartet 8.3 aus:

    template <typename T>
    struct A
    {
    	T x;
    	A(T x)
    		: x(x)
    	{}
    };
    
    template <typename T, typename U>
    auto operator + (const A<T>& lhs, const A<U>& rhs) -> A<decltype(lhs.x + rhs.x)>
    {
    	return A<decltype(lhs.x + rhs.x)>(lhs.x + rhs.x);
    }
    
    int main()
    {
    	A<int> a1(5);
    	A<float> a2(3.3f);
    	std::cout << (a1 + a2).x << '\n';
    }
    


  • Was wäre denn der Unterschied zu

    template <typename U, typename V>
    A<decltype(lhs.x + rhs.x)> operator +(A<U> lhs, A<V> rhs) ->
    {
      return lhs.x + rhs.x;
    }
    

    Gruß 🙂



  • Siehe mein Edit.
    Der Unterschied ist, dass es nicht kompiliert, weil lhs und rhs da noch gar nicht bekannt sind.



  • MatheStein schrieb:

    Die andere Version von "dot" kompiliert zwar, aber gibt eine "3" aus anstatt "3.1."

    Wie sieht der Code dazu aus?

    MatheStein schrieb:

    Was genau macht "-> A<decltype(lhs.x + rhs.x)>" ?

    decltype() liefert den Typ eines Ausdrucks.
    A<decltype(lhs.x + rhs.x)> entspricht also A< Was auch immer lhs.x + rhs.x produziert > .
    Die Syntax mit auto und dem -> gefolgt von einem Typ ist eine alternative Möglichkeit den Rückgabetyp einer Funktion zu deklarieren. Vorteil dabei ist, dass hinter der Parameterliste die Parameter lhs und rhs bekannt sind und ich daher über decltype() dem Compiler sagen kann, dass er den passenden Typ doch bitte selbst rausfinden soll.



  • Danke für deine Antwort 🙂

    Wie nennt man das Konzept mit dem Pfeil, bzw was muss man dafür googlen?

    Gruß 🙂





  • Jap. Man spricht dabei von einem "trailing-return-type".



  • Danke 🙂


Anmelden zum Antworten