falscher operator aufruf
-
also T2 hat jetzt folgende Konstruktoren
explicit T2(float x = 0, float y = 0, float z = 0); T2(const T<float, 3>& src); T2(const T2& src);dennoch findet er bei der anweisung
T2 var1, var2; //... T2 var3 = var1 - var2;keinen passenden Konstruktor
-
Ehrlich gesagt gehen mir da die Erklärungen aus. Ich habe es mit der von Dir geposteten Templatisierung und Vererbung auf verschiedenen Compilern getestet, und bei mir wird immer der Operator und der Copy-Konstruktor aufgerufen. Bei camper scheint es auch zu laufen.
Das von Dir beschriebene Verhalten erreiche ich nur, wenn ich den Copy-Konstruktor auskommentiere oder einen anderen Rückgabewert für operator- angebe.
-
FreakyBKA schrieb:
das problem ist ich kann den cast-operator nicht einfach weglassen, weil ich dann tausend anderen stellen fehlermeldungen bekomme, die eben genau diesen verwenden.
Beschränk dich bitte erstmal auf das aktuelle Problem - um die "tausend anderen Stellen" kannst du dich später kümmern
(oder auf Deutsch - reduzier' dein Programm/Problem auf das Wesentliche)So, wie ich das verstehe, hat der Compiler zwei Möglichkeiten, den Ausdruck "T2 var3 = var1 - var2;" zu deuten:
- Verwendung deines op- (vorher Upcast von var1 und var2 in einen T<float,3>&) und des Ctor's 'T2(const T<..>&)'
- Verwendung des eingebauten op- für Zeiger (vorher Umwandlung mit deinem operator t*) und des Ctor's 'T2(float,float,float);'
Nach meinem Verständnis ist Variante 1 "besser", aber offenbar ist dein Compiler anderer Meinung. Also würde ich gerne wissen was herauskommt, wenn du Variante 2 komplett unmöglich machst, indem du die Typumwandlung T/T2 -> float* entfernst. (möglicherweise hast du einen Fehler eingebaut, der Variante 1 unmöglich macht)
PS: Worin besteht eigentlich der konzeptionelle Unterschied von T2 und T<float,3> - abgesehen von dem Ctor, der drei float-Werte übernehmen kann? Und was spricht dagegen, einen einfachen T<float,3> direkt zu verwenden?
-
CStoll schrieb:
Nach meinem Verständnis ist Variante 1 "besser", aber offenbar ist dein Compiler anderer Meinung. Also würde ich gerne wissen was herauskommt, wenn du Variante 2 komplett unmöglich machst, indem du die Typumwandlung T/T2 -> float* entfernst. (möglicherweise hast du einen Fehler eingebaut, der Variante 1 unmöglich macht)
Das hat er im Prinzip schon gezeigt (indem er den 3xfloat-Konstruktor explicit deklariert hat). Den Cast zu entfernen ist nicht notwendig. Danach gabs einen Fehler da kein passender Konstruktor mehr exisierte.
Meiner Meinung nach kann das nur bedeuten, daß entweder der tatsächlich omplementierte Copy-Kunstruktor nicht dem entspricht, was er hier gepostet hat, oder aber der operator- gibt einen falschen Typen zurück.
-
Was mich stutzig macht, ist aber die Aussage von oben, daß das selbe mit einem global definierten op- funktioniert hat. Also tippe ich mal auf ein Scope-Problem (oder der Klassen-Operator wird nicht gewählt, weil der erste Operand kein T<> ist, sondern ein T2).
-
CStoll schrieb:
So, wie ich das verstehe, hat der Compiler zwei Möglichkeiten, den Ausdruck "T2 var3 = var1 - var2;" zu deuten:
- Verwendung deines op- (vorher Upcast von var1 und var2 in einen T<float,3>&) und des Ctor's 'T2(const T<..>&)'
- Verwendung des eingebauten op- für Zeiger (vorher Umwandlung mit deinem operator t*) und des Ctor's 'T2(float,float,float);'
Und so ist es eigentlich nicht. Welcher operator- benutzt wird, hängt ausschließlich von den Parametern ab, nicht davon, ob wir mit dem Funktionsergebnis weiterkommen. Ob also ein passender Konstruktor in T2 existiert, ist dafür völlig irrelevant. Um den eingebauten operator aufrufen zu können, sind hier für beide Parameter selbstdefinierte Konvertierungssequenzen notwendig, während es für den überladenen Operator genügt, je eine derived-to-base-Konvertierung vorzunehmen. Unser Operator ist keine Templatefunktion, also wird diese Konvertierung auch nicht unterdrückt. Dann kann das Ganze nur noch scheitern, wenn diese derived-to-base-Konvertierung wegen Zugriffsbeschränkung oder Mehrdeutigkeit nicht möglich ist - beides offenbar auch nicht der Fall. Ich glaube daher immer noch, dass der Fehler durch die Vereinfachung des Originals verschwunden ist. wie sieht es denn mit
var1.operator-(var2);im Original aus?
-
also ich könnte anbieten beide klassen komplett hier drin zu posten, dann wirds aber sehr unübersichtlich, weil viele codezeilen.
-
FreakyBKA schrieb:
also ich könnte anbieten beide klassen komplett hier drin zu posten, dann wirds aber sehr unübersichtlich, weil viele codezeilen.
Im Zweifel ist das die sicher Variante.
-
ursprünglich die Klasse T
template <class t, unsigned int n, unsigned int m> class cmatrix { private: t _elements[n * m]; public: cmatrix(); cmatrix(const cmatrix<t, n, m>& src); void copy(const cmatrix<t, n, m>& src); void load_identity(); void load_null(); void load_natural(); void load_random(); void set_element(unsigned int i, unsigned int j, const t& e); const t& get_element(unsigned int i, unsigned int j = 0) const; void set_col(unsigned int j, const cmatrix<t, n, 1>& col); void set_row(unsigned int i, const cmatrix<t, 1, m>& row); cmatrix<t, n, 1> get_col(unsigned int j) const; cmatrix<t, 1, m> get_row(unsigned int i) const; void swap_row(unsigned int i1, unsigned int i2); void swap_col(unsigned int j1, unsigned int j2); cmatrix<t, m, n> transpose() const; cmatrix<t, m, n> pseudo_inverse() const; void print() const; //Operatoren void operator = (const cmatrix<t, n, m>& src); cmatrix<t, n, m>& operator ++ (); cmatrix<t, n, m>& operator -- (); t& operator () (unsigned int i, unsigned int j = 0); const t& operator () (unsigned int i, unsigned int j = 0) const; cmatrix<t, n, m> operator () (const cmatrix<unsigned int, n, 1>& p) const; operator const t* () const; //Vergleichsoperationen bool operator == (const cmatrix<t, n, m>& r) const; bool operator != (const cmatrix<t, n, m>& r) const; //Negation cmatrix<t, n, m> operator - (); //Matrix-Matrix-Operationen cmatrix<t, n, m>& operator += (const cmatrix<t, n, m>& r); cmatrix<t, n, m>& operator -= (const cmatrix<t, n, m>& r); cmatrix<t, n, m>& operator *= (const cmatrix<t, m, m>& r); cmatrix<t, n, m> operator + (const cmatrix<t, n, m>& r) const; cmatrix<t, n, m> operator - (const cmatrix<t, n, m>& r) const; //Matrix-Skalar-Operationen cmatrix<t, n, m>& operator *= (const t& r); cmatrix<t, n, m>& operator /= (const t& r); cmatrix<t, n, m> operator * (const t& r) const; cmatrix<t, n, m> operator / (const t& r) const; }; //Ausgabeoperation template <class t, unsigned int n, unsigned int m> ostream& operator << (ostream& os, const cmatrix<t, n, m>& src); //Matrix-Matrix-Operationen template <class t, unsigned int n, unsigned int m, unsigned int p> cmatrix<t, n, p> operator * (const cmatrix<t, n, m>& l, const cmatrix<t, m, p>& r); //Matrix-Skalar-Operationen template <class t, unsigned int n, unsigned int m> cmatrix<t, n, m> operator * (const t& l, const cmatrix<t, n, m>& r); //Skalarprodukt template <class t, unsigned int n> t operator * (const cmatrix<t, n, 1>& l, const cmatrix<t, n, 1>& r);ursprünglich die Klasse T2
class cvertex : virtual public cmatrix<float, 4, 1> { public: cvertex(float x = 0, float y = 0, float z = 0, float v = 0); cvertex(const cmatrix<float, 4, 1>& src); cvertex(const cvertex& src); void set(float x = 0, float y = 0, float z = 0, float v = 0); void set_point(); void set_vector(); void set_affine(); void set_positive(); float x() const; float y() const; float z() const; float abs2() const; float abs() const; void normalize(); void draw(float red = 1, float green = 1, float blue = 1, float alpha = 1) const; void set_dot() const; void print() const; void operator = (const cmatrix<float, 4, 1>& src); void operator = (const cvertex& src); cvertex operator - () const; cvertex& operator ^= (const cvertex& r); }; ostream& operator << (ostream& os, const cvertex& src); cvertex operator ^ (const cvertex& l, const cvertex& r); float volume(const cvertex& a, const cvertex& b, const cvertex& c); float abs(const cvertex& vertex); float abs2(const cvertex& vertex);bitte nicht schlagen

-
wußte doch, dass du was unterschlagen hast

cvertex operator - () const;Stichwort Verdeckung.
-
aber das ist doch nur ein negations-operator und kein subtraktions-operator, der eine hat 2 und der andere nur einen parameter.
-
FreakyBKA schrieb:
aber das ist doch nur ein negations-operator und kein subtraktions-operator, der eine hat 2 und der andere nur einen parameter.
Ob unärer oder binärer Operator ist eine Frage der Grammatik und hat keinen Einfluß auf das Namelookup. Der Name beider Funktionen ist jeweils operator- und nur danach wird erst einmal geschaut. Die Frage nach der passenden Überladung ist erst der zweite Schritt - wir müssen ja erst einmal eine Menage an Kandidaten haben, bevor wir eine Überladung auflösen können. Abhilfe könnte z.B. eine using-Deklaration bringen:
using cmatrix<float, 4, 1>::operator-;oder du machst gleich eine freie Funktion daraus.
-
aber der operator passt doch überhaupt nicht auf die anweisung
cvertex var3 = var1 - var2;ich meine mit diesem negations-operator kann er doch nichts anfangen
-
FreakyBKA schrieb:
aber der operator passt doch überhaupt nicht auf die anweisung
cvertex var3 = var1 - var2;ich meine mit diesem negations-operator kann er doch nichts anfangen
richtig, deshalb nimmt er ja auch den eingebauten Operator für Zeiger. Das Problem ist, dass er die eigentlich gewollte Überladung nicht findet, weil der Namensraum der Basisklasse gar nicht erst durchsucht wird.
-
den negations-operator von cmatrix<float, 4, 1> soll er ja eben nicht verwenden, weil der komplett negiert, was ich bei cvertex nicht haben will, der soll nämlich nur die erste 3 werte negieren und den 4. unberührt lassen
-
und was genau muss jetzt ändern damit das so funktioniert wie ich das möchte?
-
Eigentlich wird nur der unäre Operator der Basisklasse verdeckt. Beim binären Operator handelt es sich tatsächlich um eine Überladung, da beide Funktionen sich in ihrer Signatur unterscheiden.
-
struct A { void f(int,int); }; struct B : A { void f(int); }; void foo() { B b; b.f(1,1); }gleiche Konstellation. Natürlich kann die Überladung in B nicht genutzt werden, weil die Parameteranzahl nicht stimmt. Trotzdem wird die Basisklasse nicht durchsucht, denn die bloße Suche nach dem Namen f ist bereits erfolgreich gewesen. Nur sind eben alle gefunden Überladungen in B unbrauchbar und der Compiler quittiert es mit einem Fehler. In deinem Falle gibt es dann aber noch die Alternative des eingebauten Operators, deswegen bekommst du nichts zu sehen.
-
Tja, wieder was gelernt.
Mal ne andere Frage: Wieso deklarierst Du du Deine Vererbung da als virtual? Das macht doch nur bei Mehrfachvererbung Sinn, oder?
-
na ich wusste nicht genau ob sich das überträgt, wenn ich später vllt mal ne klasse habe die von cmatrix und cvertex erbt. also
class T1 {}; class T2 : public T1 {}; class T3 : public T2, public T1 {};da wusste ich jetzt nicht ob es ausreicht bei T3 einfach virtual davor zu schreiben ober ob das bei T2 schon hin muss, und da hab ich es sicherheitshalber schon bei T2 gemacht.
mal abgesehen davon weiß ich auch gar nicht genau welche klasse da priorität hat, da ja doch einige operatoren/methoden 'gleich' sind.