Template Frage



  • Das hier sollte auch gehen:

    template<typename T>
    class Vector3
    {
      ...
      friend Vector3<T> operator*(Vector3<T> const& v, T scalar)
      {return ...}
    
      friend Vector3<T> operator*(T scalar, Vector3<T> const& v)
      {return ...}
      ...
    };
    


  • @Sebastian Pizer: Ne, geht nicht. Gibt bei mir die selbe Fehlermeldung.



  • Komisch, bei mir gehts....
    template.h

    #include <iostream>
    
    template <typename T>
    class Vector
    {
        T m_x, m_y;
        public:
            Vector(const T& x, const T& y)
             : m_x(x), m_y(y)
            {}
            const T& get_x() const
            {
                return m_x;
            }
            const T& get_y() const
            {
                return m_y;
            }
    
            friend Vector<T> operator*(const Vector<T>& vec, T val)
            {
                return Vector<T>(vec.get_x() * val, vec.get_y() * val);
            }
    
            friend Vector<T> operator*(T val, const Vector<T>& vec)
            {
                return Vector<T>(vec.get_x() * val, vec.get_y() * val);
            }
    };
    
    template< typename T >
    std::ostream& operator<<(std::ostream& str, const Vector<T>& vec)
    {
        str << vec.get_x() << ", " << vec.get_y();
        return str;
    }
    

    main.cpp

    #include "template.h"
    #include <iostream>
    using namespace std;
    
    int main()
    {
        Vector<float> vec(2,3);
        float val = 2.3;
        Vector<float> vec2 = vec * 2.3;
        cout << vec2 << endl;
    }
    


  • Wie gesagt, bei mir nicht.

    Vec3 vec;
    (vec * 2.3);
    

    liefert:

    error C2784: 'const Vector3<T> operator *(T,const Vector3<T> &)' : could not deduce template argument for 'const Vector3<T> &' from 'double'

    error C2782: 'Vector3<T> operator *(const Vector3<T> &,T)' : template parameter 'T' is ambiguous

    Du definierst operator* in der Klasse. Ist das dann eine freie Funktion oder eine inline Memberfunktion?



  • @gregorowitsch mach mal aus der 2.3 eine 2 ->funktioniert nicht. Genau das war das Problem des Threadstarters.

    //edit oder gehts doch? Ist ja kein Funktionstemplate mehr...gelten dann Konvertierungsregeln?



  • 2.3 ist kein float sondern (zu mindest bei mir) ein double. Die ursprüngliche Version hat mit 2.3 auch nicht geklapt, erst ein 2.3f funktionierte.


  • Mod

    otze schrieb:

    @gregorowitsch mach mal aus der 2.3 eine 2 ->funktioniert nicht. Genau das war das Problem des Threadstarters.

    //edit oder gehts doch? Ist ja kein Funktionstemplate mehr...gelten dann Konvertierungsregeln?

    Bist du wirklich otze? O_^



  • Leuchtet mir null ein, wieso es bei T gehen soll, aber bei const T& nicht.


  • Mod

    templateritter schrieb:

    Leuchtet mir null ein, wieso es bei T gehen soll, aber bei const T& nicht.

    Sollte es auch nicht.
    Andererseits ist auch klar, dass du den Vorschlag gar nicht umgesetzt hast, denn Funktionstemplates tauchen dort nicht auf. Da sich deine Fehlermeldung aber auf Typdeduktion bezieht, muss ein Template im Spiel sein.
    "Geht nicht" ist keine brauchbare Fehlerbeschreibung, folglich wirst du regelmäßig auch keine brauchbaren Antworten bekommen können. Und den meisten hier dürfte ohnehin die Zeit zu kostbar sein, die nötigt ist, ins Blaue hinein auf alle denkbaren Ursachen einzugehen.

    Der Name in einer friend-Deklaration wird immer im umschließenden Namensraum gesucht. Da die Funktionsid hier unqualifiziert ist, kann es sich nur um eine freie Funktion handeln, was in diesem Fall übrigens auch an der Länge der Parameterliste erkennbar ist. Die Funktion ist außerdem inline - so wie jede andere Funktion, die innerhalb einer Klassendefinition definiert wird.



  • camper schrieb:

    "Geht nicht" ist keine brauchbare Fehlerbeschreibung

    Wie oft soll ich denn noch die gleiche Fehlermeldung posten?

    camper schrieb:

    Der Name in einer friend-Deklaration wird immer im umschließenden Namensraum gesucht. Da die Funktionsid hier unqualifiziert ist, kann es sich nur um eine freie Funktion handeln, was in diesem Fall übrigens auch an der Länge der Parameterliste erkennbar ist. Die Funktion ist außerdem inline - so wie jede andere Funktion, die innerhalb einer Klassendefinition definiert wird.

    Unqualifizierte Funktionsid... wtf. Ist auch net sehr hilfreich, wenn du einem ANFÄNGER mit solchen "Erklärungen" daherkommst. Mir wären simple Sätze lieber.

    Also ist in diesem Beispiel:

    class Foo {
    
    friend void bar() { }
    };
    

    bar eine freie Funktion, die einfach mit bar() aufgerufen werden kann? Irgendwie ist das doch ein Widerspruch. Alles was ich im Rumpf einer Klasse definiere, gehört zum Scope der Klasse. Und friend heißt doch: Dieses aussenstehende Ding darf jetzt auf alle Interna der Klasse zugreifen. Wenn ich jetzt eine Funktion mit friend deklariere und IN der Klasse definiere... ist das dann die Kurzsyntax um eine freie Funktion zu definieren?

    Zu meiner unbeantworteten Frage:

    template <class T, class U>
    const Vector3<T> operator*(U scalar, const Vector3<T>& rhs) {
    	return Vector3<T>(rhs.x * scalar, rhs.y * scalar, rhs.z * scalar);
    }
    

    Ist diese Lösung ok?


  • Mod

    templateritter schrieb:

    camper schrieb:

    "Geht nicht" ist keine brauchbare Fehlerbeschreibung

    Wie oft soll ich denn noch die gleiche Fehlermeldung posten?

    gar nicht. Den Code, der zu der Fehlermeldung gehört, aber bitte wenigstens einmal.

    templateritter schrieb:

    camper schrieb:

    Der Name in einer friend-Deklaration wird immer im umschließenden Namensraum gesucht. Da die Funktionsid hier unqualifiziert ist, kann es sich nur um eine freie Funktion handeln, was in diesem Fall übrigens auch an der Länge der Parameterliste erkennbar ist. Die Funktion ist außerdem inline - so wie jede andere Funktion, die innerhalb einer Klassendefinition definiert wird.

    Unqualifizierte Funktionsid... wtf. Ist auch net sehr hilfreich, wenn du einem ANFÄNGER mit solchen "Erklärungen" daherkommst. Mir wären simple Sätze lieber.

    Das ist in Ordnung, allerdings erfordert es meinerseits einige Überwindung, überhaupt etwas zu schreiben. Als schreibe ich lieber so, dass du zum Verständins drei (oder meinetwegen auch 10) mal lesen musst, statt der dreifachen Menge. Viel wichtiger ist mir Korrektheit, vermeidbare Ungenauigkeiten führen nur zu weiteren Missverständnissen.
    Natürlich gibt es jede Menge Mitglieder mit größerer Geduld und didaktischem Verständnis, es kommt nur darauf an, dass du deren Interesse weckst.

    templateritter schrieb:

    Also ist in diesem Beispiel:

    class Foo {
    
    friend void bar() { }
    };
    

    bar eine freie Funktion, die einfach mit bar() aufgerufen werden kann?

    Ja. 😉

    templateritter schrieb:

    Irgendwie ist das doch ein Widerspruch. Alles was ich im Rumpf einer Klasse definiere, gehört zum Scope der Klasse. Und friend heißt doch: Dieses aussenstehende Ding darf jetzt auf alle Interna der Klasse zugreifen.

    Eine friend-Deklaration bezieht sich immer auf etwas, dass nicht Member der Klasse ist, in der die Deklaration steht.

    templateritter schrieb:

    Wenn ich jetzt eine Funktion mit friend deklariere und IN der Klasse definiere... ist das dann die Kurzsyntax um eine freie Funktion zu definieren?

    Es ist auf jedenfall kürzer, als die Deklaration außerhalb der Klasse zu wiederholen. Im Falle von gregorowitschs Lösung ist es sogar die einzige Möglichkeit:
    Die einzelne friend-Definition innerhalb des Templates definiert ja eine Vielzahl von Funktionen (für jedes mögliche Templateargument des Klassentemplates), die wir außerhalb der Klasse alle einzeln deklarieren müssten.

    templateritter schrieb:

    Zu meiner unbeantworteten Frage:

    template <class T, class U>
    const Vector3<T> operator*(U scalar, const Vector3<T>& rhs) {
    	return Vector3<T>(rhs.x * scalar, rhs.y * scalar, rhs.z * scalar);
    }
    

    Ist diese Lösung ok?

    funktioniert sie?

    😉 Aufruf ist zunächst nur innerhalb der Klasse und ihrer Memberfunktionen möglich, weil der Bezeichner foo nicht in den umligenden Namensraum injiziert wird, und die Funktion dort schlicht nicht gefunden werden kann. Dazu müsste sie außerhalb der Klasse noch einmal deklariert werden. Bei den Operatoren haben wir das Problem nicht, da diese Funktionen Parameter haben und daher per ADNL gefunden werden können. Als Anfänger musst du dich damit aber wahrscheinlich erst einmal nicht auseinander setzen.

    Definitionen:
    Id (=Bezeichner):
    - der Name eines Objektes, eines Typs, einer Funktion oder eines Templates; oder
    - ein Operatorbezeichner, oder
    - der der Bezeichner für eine Konvertireungsfunktion
    (hoffe, dass ich nichts vergessen habe, ist aber eigentlich recht klar).
    unqualifiziert: Eine Id, die den Scopeoperator :: nicht bemüht.
    qualifiziert: Alles, was den Scopeoperator enthält.


Anmelden zum Antworten