[C++] überladene Operatoren funktionieren nicht in Reihe

Design Patterns, Erklärungen zu Algorithmen, Optimierung, Softwarearchitektur
Forumsregeln
Wenn das Problem mit einer Programmiersprache direkt zusammenhängt, bitte HIER posten.
Antworten
Benutzeravatar
Brainsmith
Establishment
Beiträge: 109
Registriert: 04.09.2009, 13:52
Echter Name: Fabbo

[C++] überladene Operatoren funktionieren nicht in Reihe

Beitrag von Brainsmith »

Hallo, ich habe für meine Vektorklassen diverse Operatoren überladen. Ich kann sie auch benutzen, solange ich immer nur einen Operator nach dem anderen benutze.

Jetzt will ich einen Vektor linear interpolieren und eigentlich ist das ja nicht schwer.
hier mal ein Auszug:

Code: Alles auswählen

//{(2DVECTOR STRUCT)
struct rVector2D {
//2D Vector with x,y as Parameters
    float x,y;
    rVector2D(): x(0), y(0) {};
    rVector2D(const rVector2D& xbRefTo2DVector) : x(xbRefTo2DVector.x), y(xbRefTo2DVector.y) {};
    rVector2D(float bx, float by) : x(bx), y(by) {};




};
//}

//{(INLINE 2D OPERATORS OUTSIDE)
inline rVector2D operator + (rVector2D& xbNum1, rVector2D& xbNum2) {
    rVector2D ReturnVector(xbNum1.x+xbNum2.x, xbNum1.y+xbNum2.y);
    return ReturnVector;
};

inline rVector2D operator - (rVector2D& xbNum1, rVector2D& xbNum2) {
    rVector2D ReturnVector(xbNum1.x-xbNum2.x, xbNum1.y-xbNum2.y);
    return ReturnVector;
};

inline rVector2D operator * (rVector2D& xbNum1, float xbSkalar) {
    rVector2D ReturnVector(xbNum1.x*xbSkalar, xbNum1.y*xbSkalar);
    return ReturnVector;
};

inline rVector2D operator * (float xbSkalar, rVector2D& xbNum1) {
    rVector2D ReturnVector(xbNum1.x*xbSkalar, xbNum1.y*xbSkalar);
    return ReturnVector;
};

Einzeln funktioniert alles bestens. Wenn ich jetzt aber einen Vektor linear interpolieren will, brauch ich natürlich mehr als einen Rechenschritt.
Hier mein Code:

Code: Alles auswählen

inline rVector2D VectorInterpolate(rVector2D& xbVec1, rVector2D& xbVec2, float bFloatFac) {
    rVector2D ReturnVector(xbVec1+ bFloatFac *(xbVec2-xVec1));
    return ReturnVector;
};
Der sagt dann:
error: no match for 'operator+' in 'operator*(float, rVector2D&)(((rVector2D&)(+xbVec1))) + xbVec2'|

Was habe ich falsch gemacht? Wär schön wenn mir jemand helfen könnte.
Benutzeravatar
Schrompf
Moderator
Beiträge: 4929
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: [C++] überladene Operatoren funktionieren nicht in Reihe

Beitrag von Schrompf »

Deine Operatoren müssen unbedingt const Referenzen nehmen. Zum Einen natürlich deswegen, weil sie die übergebenen Werte nicht verändern dürfen, sondern einen neuen Vektor mit dem Ergebnis zurückgeben. Und zum Anderen, weil der Compiler den Operator dann auch anwenden kann, wenn einer oder beide der Operatoren Zwischenergebnisse aus anderen Operationen sind.

Hier zum Beispiel:

Code: Alles auswählen

Vector v = a + faktor * b
würde zuerst die Skalare Multiplikation aufgerufen werden, also Skalar "faktor" mal Vektor "b". Das Ergebnis ist ein temporäres, anonymes Objekt. Und davon kannst Du keine Referenz bilden. Eine const Reference aber schon.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Aramis
Moderator
Beiträge: 1458
Registriert: 25.02.2009, 19:50
Echter Name: Alexander Gessler
Wohnort: 2016
Kontaktdaten:

Re: [C++] überladene Operatoren funktionieren nicht in Reihe

Beitrag von Aramis »

Code: Alles auswählen

//{(INLINE 2D OPERATORS OUTSIDE)
inline rVector2D operator + (rVector2D& xbNum1, rVector2D& xbNum2) {
rVector2D ReturnVector(xbNum1.x+xbNum2.x, xbNum1.y+xbNum2.y);
return ReturnVector;
};
Das solltest du auch eher vermeiden. Nur Compiler mit Unterstützung für NRVO (Named Return Value Optimization) können das optimieren. Andernfalls werden deine Vektoren mehrfach kopiert, was sich eher negativ in der Performance niederschlägt (und auch weitere Optimierungen durch den Compiler behindern dürfte).

Code: Alles auswählen

//{(INLINE 2D OPERATORS OUTSIDE)
inline rVector2D operator + (const rVector2D& xbNum1, const rVector2D& xbNum2) {
   return rVector2D(xbNum1.x+xbNum2.x, xbNum1.y+xbNum2.y);
};
Benutzeravatar
Krishty
Establishment
Beiträge: 8293
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] überladene Operatoren funktionieren nicht in Reihe

Beitrag von Krishty »

Déjà vu.

boost empfiehlt die NRVO-Version (wegen breiterem Support auch bei alten / lasch optimierenden Compilern). Ich persönlich bevorzuge die von Aramis vorgeschlagene Version (Unnamed Local) und benutze NRVO nur, wenn sich der Rückgabewert nicht in einem K’tor-Aufruf berechnen lässt. Haben die Operatoren keine Side-Effects, wird heutzutage auf den meisten Compilern eh alles gleich gut optimiert … Geschmacksfrage also.

Gruß, Ky
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Brainsmith
Establishment
Beiträge: 109
Registriert: 04.09.2009, 13:52
Echter Name: Fabbo

Re: [C++] überladene Operatoren funktionieren nicht in Reihe

Beitrag von Brainsmith »

Also liegt das Problem daran, dass meine Eingaben Referenzen sind und keine const Referenzen?
In dem Fall würde ich nämlich einfach umsteigen. Die Komfortabilität wäre ja unglaublich viel größer
Aramis hat geschrieben:Das solltest du auch eher vermeiden. Nur Compiler mit Unterstützung für NRVO (Named Return Value Optimization) können das optimieren. Andernfalls werden deine Vektoren mehrfach kopiert, was sich eher negativ in der Performance niederschlägt (und auch weitere Optimierungen durch den Compiler behindern dürfte).
Ich benutze den GCC. Ich dachte, der hätte diesen Support für NRVO. Hätte ich gewusst, dass es keinen Unterschied macht, wär ich auch gar nicht auf die Idee gekommen NRVO zu benutzen. Aber bei Boost stand das halt da.. Hab mir gedacht, dass der schon weiß, wovon der schreibt. ^^ Bin nämlich recht frisch in der C++-Schiene


@Krishty

Ja, du hast recht. So ein ähnliches Thema hatten wir schonmal. Allerdings war das Augenmerk darauf gerichtet, herauszufinden, welche Methode am schnellsten wäre. Hier gehts nur darum, wie ich diesen lästigen Fehler behebe. ^^



Edit: Leck mich am Baum.. Da wär ich nie von alleine drauf gekommen.. einfach const Referenzen nehmen... okay, da muss ich wohl meine Basics überarbeiten. ^^
Danke für den Tipp. Bin quasi schon fast enttäuscht, dass es so leicht zu lösen war.. :D Aber besser so, als irgendein fatalerer Fehler
Benutzeravatar
Lord Delvin
Establishment
Beiträge: 595
Registriert: 05.07.2003, 11:17

Re: [C++] überladene Operatoren funktionieren nicht in Reihe

Beitrag von Lord Delvin »

Ich hab mit folgender Faustregel eigentlich ganz gute Erfahrungen gemacht:
Entweder es ist <= 8 byte, dann kannst du es so übergeben, wenn dus nicht nach außen hin ändern willst. Wenn dus in diesem Fall ändern willst, dann ist es ein &.
Sonst ist es ein const &, wenn dus nicht ändern willst und ein * wenn du was ändern willst.

Natürlich ist es sehr vereinfacht, in der Praxis wird man wohl noch öfter * verwenden, z.B. wenn man Arrays hat oder sowas, da is mit & meist nicht viel zu machen.

Btw.: Operatoren für const und nicht const zu überladen kann deinen Code schneller machen, falls du das nicht const irgendwo brauchst. Sonst willst du eigentlich so viel const wie möglich hinschreiben, da du dann schnelleren Code bekommst und dir weniger selbst in den Fuß schießst.
Gruß
XML/JSON/EMF in schnell: OGSS
Keine Lust mehr auf C++? Versuche Tyr: Get & Get started
Benutzeravatar
Krishty
Establishment
Beiträge: 8293
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] überladene Operatoren funktionieren nicht in Reihe

Beitrag von Krishty »

Lord Delvin hat geschrieben:Ich hab mit folgender Faustregel eigentlich ganz gute Erfahrungen gemacht:
Entweder es ist <= 8 byte, dann kannst du es so übergeben, wenn dus nicht nach außen hin ändern willst. Wenn dus in diesem Fall ändern willst, dann ist es ein &.
Sonst ist es ein const &, wenn dus nicht ändern willst und ein * wenn du was ändern willst.

Natürlich ist es sehr vereinfacht […]
Über die richtige Übergabemethode kann man wirklich ganze Bücher schreiben … es geht ja damit weiter, dass Objekte <= 8 Bytes auch komplexe Copy-C’tors haben können oder, wie ich es in Brainsmiths Fall vermute, Objekte von 128 Bytes in den SSE-Registern (also by-Value) übergeben werden sollen. Ich habe irgendwann mal Templates geschrieben, die mir die ideale Übergabemethode automatisiert bestimmten – die Syntax war aber teils nur noch widerlich …

Gerade bei solchen Dingen wie einer Mathebibliothek, wo man hunderte Funktionen ändern müsste, falls sich die Übergabemethode als falsch heraus stellt, kann es nützlich sein, auf das gute alte typedef zurück zu greifen:

Code: Alles auswählen

class Vector {
    …
    typedef Vector const & InParamType;
    typedef Vector & InOutParamType;

    Vector operator + (InParamType Summand) const {
        return Vector(*this) += Summand;
    }

};
Sollte sich Pass-by-Value später als schneller als Pass-by-Reference herausstellen, brauchst du InParamType nur in Vector ändern und alle Funktionen übernehmen es sofort.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Brainsmith
Establishment
Beiträge: 109
Registriert: 04.09.2009, 13:52
Echter Name: Fabbo

Re: [C++] überladene Operatoren funktionieren nicht in Reihe

Beitrag von Brainsmith »

Ich möchte diesen Platz nochmal nutzen, um eine weitere Frage zu stellen. Ich kann mir nicht helfen.

ich will eine Translationsmatrix haben. Soweit so gut:
hier der Code:

Code: Alles auswählen

inline rMatrix4D MatrixGetTranslated(const rVector3D& xbVec){

    return rMatrix4D (
1.0f,0.0f,0.0f,0.0f,
0.0f,1.0f,0.0f,0.0f,
0.0f,0.0f,1.0f,0.0f,
xbVec.x,xbVec.y,xbVec.z,1.0f);
};
//ich multipliziere die Vektoren von links als Zeilenvektor..

Wenn ich jetzt aber so eine Matrix erstellen will, wo ich jetzt in die umgekehrte Richtung translieren will, meckert der immer.

Code: Alles auswählen

MatrixGetTranslated(-xbVec);
Da sagt der mir immer, dass er keinen Operator für -xbVec finden kann.

Meine Frage also:
welche Operator muss ich überladen, dass ich schreiben kann:

Code: Alles auswählen

MatrixGetTranslated(-xbVec);
Bin für jede Hilfe dankbar.. hab schon alles erdenkliche probiert, bin aber irgendwie auf kein Ergebnis gekommen.
Benutzeravatar
Aramis
Moderator
Beiträge: 1458
Registriert: 25.02.2009, 19:50
Echter Name: Alexander Gessler
Wohnort: 2016
Kontaktdaten:

Re: [C++] überladene Operatoren funktionieren nicht in Reihe

Beitrag von Aramis »

Den unären operator-.

Code: Alles auswählen

T operator-(const T& s) {
  ...
}
Benutzeravatar
Brainsmith
Establishment
Beiträge: 109
Registriert: 04.09.2009, 13:52
Echter Name: Fabbo

Re: [C++] überladene Operatoren funktionieren nicht in Reihe

Beitrag von Brainsmith »

Wer lesen kann, ist klar im Vorteil.. ich hatte den schonmal implementiert. hab aber nen Fehler bekommen und direkt gedacht, es läge am operator.. naja..
hatte einfach nur nen Vektor genommen, den ich gar nicht deklariert hatte.. :oops:

Danke für die fixe Hilfe.. ^^
Antworten