Template Frage
-
David_pb schrieb:
So:
template <class Bla, class T> const Vector3<Bla> operator*(const T& scalar, const Vector3<Bla>& rhs) { return Vector3<Bla>(rhs.x * scalar, rhs.y * scalar, rhs.z * scalar); }Ich hab es auch so gelöst, aber WARUM geht denn mein Code oben nicht? v*=2 geht doch auch.
-
Operator* wird mittels eines Funktionstemplates implementiert, während Konstruktor und op*= gewöhnliche Funktionen sind.
Um das korrekte T für zu ermitteln wird nun folglich für jedes Argument Templateargumentdeduktion durchgeführt (soweit möglich).
beim Aufruf
v * 2wird so deduziert
Überladung T aus 1. Argument T aus 2. Argument 1. operator*(const T&, const Vector3<T>&) Vector3<float> n/a 2. operator*(const Vector3<T>&, const T&) float intBei der ersten Überladung schlägt die Deduktion beim 2. Argument fehl, bei der 2. Überladung stimmen die deduzierten Templateparameter nicht überein (die Fehlermeldungen des Compilers lassen hier eigentlich nichts zu wünschen übrig).
Beabsichtigt wird hier eigentlich, dass der Templateparameter aus dem Typ des übergebenen Vectors ermittelt wird, während das 2. Argument nicht mit diesem T exakt überein stimmen muss, es genügt Konvertierbarkeit.
Das geht mit einem kleinen Trick
template <typename T> struct identity { typedef T type; }; ... template <class T> const Vector3<T> operator*(const typename identity<T>::type&, const Vector3<T>&); template <class T> const Vector3<T> operator*(const Vector3<T>&, const identity<T>::type&);indentity<T>::type ist kein deduzierbarer Kontext - demzufolge wird für das entsprechende Argument keine Templateargumentdeduktion versucht, im Gegenzug sind Konvertierungen möglich.
Nebenbei: identity wird sich auch in der Standardbibliothek (<utility> des nächsten Standards befinden), gegenwärtig gibt es das u.a. auch noch in boost.mpl.
-
Danke für die Erklärung.
Ich hab den Code jetzt einfach so ungeschrieben wie bei David_pb (also statt nur einem Typargument T hab ich jetzt 2: T fürn Vektor und U für den Skalar.
Ist doch auch ok, oder? (das mit dem unity Dings ist mir zu frickelig. Und boost werde ich auf keinen Fall benutzen (ebenfalls wegen Overdesign/Frickelfaktor)
-
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.
-
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.
-
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?
-
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.