falscher operator aufruf



  • CStoll schrieb:

    Aber genau dieser Cast scheint das Problem zu sein, weil jetzt außer deinem op- auch der eingebaute op- für Zeiger in Frage kommt für diesen Ausdruck 😉 Wie gesagt, lass mal testweise diesen Operator weg.

    Aber der Cast DARF kein Problem sein, denn es ist standardisierte Regel, daß den passenden Typen priorität vor den implizit umzuwandelnden Typen eingeräumt wird. Selbst der eklige und antike MSVC 6.0 hier in der Firma macht das korrekt.
    Ich schätze mal, daß nach wie vor entweder im Rückgabewert von operator- oder im Copy-Konstroktor ein Bock ist, und der Typ eben nicht passt ( vielleicht das kleine t vom Template-Type mit dem großen T der Klasse vertauscht o.ä.). Die Tatsache, daß es plötzlich gar keinen passenden Konstruktor mehr gibt, wenn man den Konvertierungskonstruktor mit den drei Float-Argumenten als explicit deklariert, ist ein weiteres Indiz dafür.



  • das problem ist ich kann den cast-operator nicht einfach weglassen, weil ich dann tausend anderen stellen fehlermeldungen bekomme, die eben genau diesen verwenden.



  • 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:

    1. Verwendung deines op- (vorher Upcast von var1 und var2 in einen T<float,3>&) und des Ctor's 'T2(const T<..>&)'
    2. 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).


  • Mod

    CStoll schrieb:

    So, wie ich das verstehe, hat der Compiler zwei Möglichkeiten, den Ausdruck "T2 var3 = var1 - var2;" zu deuten:

    1. Verwendung deines op- (vorher Upcast von var1 und var2 in einen T<float,3>&) und des Ctor's 'T2(const T<..>&)'
    2. 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.


  • Mod

    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 😃


  • Mod

    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.


  • Mod

    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


  • Mod

    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.


  • Mod

    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.


Anmelden zum Antworten