2015-06-03 16 views
5

Ich habe versucht, einige Operator Überladungen (* und +) für eine Klasse, die in Smart-Zeigern verpackt ist.Operator Überladung der Klasse in Smartpointern

Wenn ich versuche, es mit normaler Überladung zu überlasten, fragt es offensichtlich nach den intelligenten Zeigertypen.

bearbeiten, so:

std::unique_ptr<Polynomial<T>> operator+(const std::unique_ptr<Polynomial<T>>& right); 

template<class T>std::unique_ptr<Polynomial<T>> Polynomial<T>::operator+(const std::unique_ptr<Polynomial<T>>& right) { 
    //Do stuff 
} 

Und der Fehler:

Error from trying to use the + operator

So wie Sie die normalen Betreiber Überlastung gehen über, wenn die Klasse in einem Intelligenter Zeiger eingekapselt ist?

+1

„Wenn ich versuche, es zu überlasten normale Überlastung verwendet, fragt sich offensichtlich für die Smart-Pointer-Typen.“ - Was? – Shoe

+0

Warum sind diese Klassen in Smartpointern verpackt? Warum können Sie sie nicht als Werttypen verwenden? –

Antwort

11

Nicht.

Führen Sie diese Operationen an den pointees, nicht auf den Zeiger:

*p = *p + *p 

Es wäre für die Benutzer des Codes sehr verwirrend sein, wenn plötzlich Zeiger ganz andere und unerwartete Semantik hatte.

Es wäre auch für Sie verwirrend.

2

So how do you go about overloading the normal operators when the class is encapsulated in a smartpointer?

sie einfach erklären wie Sie es normalerweise:

template<typename T> 
Polynomial<T> operator*(Polynomial<T> lhs, Polynomial<T> rhs) { ... } 

template<typename T> 
Polynomial<T> operator+(Polynomial<T> lhs, Polynomial<T> rhs) { ... } 

und dann so etwas wie gegeben:

auto p = std::make_unique<Polynomial<int>>(); 
auto q = std::make_unique<Polynomial<int>>(); 

rufen Sie einfach:

auto x = (*p) * (*q); 
auto y = (*q) + (*p); 

Live demo


Der Fehler, den Sie zur Verfügung gestellt:

enter image description here

auf die Tatsache zurückzuführen ist, dass Ihr Betreiber Überlastung:

std::unique_ptr<Polynomial<T>> operator+(const std::unique_ptr<Polynomial<T>>& right); 

ist eine Überlastung der einstelligeoperator+ für Ausdrücke wie +x.

Und die andere:

template<class T> 
std::unique_ptr<Polynomial<T>> Polynomial<T>::operator+(const std::unique_ptr<Polynomial<T>>& right) { 
    //Do stuff 
} 

ist Überlastung operator+ für Operanden vom Typ Polynomial<T> und std::unique_ptr<Polynomial<T>>.

daher zwei unique_ptr<Polynomial<T>> gegeben, nämlich x und y, den folgenden Ausdruck:

x + y 

keine Überladungsauflösung für operator+ finden.

Ich rate auch stark von der Überlastung von Betreibern für Standard-Bibliothekstypen.

2

Für eine direkte Antwort auf Ihre Frage, stimme ich @LightnessRacesinOrbit: Just nicht. Aber der Grund, eine andere Antwort zu schreiben, ist, dass die Frage, die Sie stellen, ein bisschen wie ein XY-problem für mich klingt.

Sie haben eine Klasse Polynomial<T>, aber Sie erwarten, dass der Benutzer es in einem intelligenten Zeiger umschließt? Dies ist fischig, da ein vernünftiges Design nur erwarten würde, dass der Benutzer direkt mit Polynomial arbeitet und somit normale Operatoren bereitstellt, die direkt an diesem Typ arbeiten.

Machen Sie einen Schritt zurück und überlegen Sie, warum Sie denken, dass ein intelligenter Zeiger verwendet wird/benötigt/hilfreich ist. Oft geschieht dies aus vermeintlichen Effizienzgründen, oder? Aber das bedeutet nur, dass Sie überdenken sollten, wie Sie selbst implementiert Polynomial. Sehen Sie sich folgendes an:

  • Hat Polynomial move-constructor und -assignment? Wenn nicht, implementieren Sie es.
  • Was ist mit den gespeicherten Daten? Vielleicht sollte der interne Speicher von einem intelligenten Zeiger verwaltet werden. Zusammen mit move-semantics kann dies zu sehr effizienten Operationen führen.
  • Für die Überlastung des Bedieners implementieren Sie a+=b;, verwenden Sie eine Bibliothek, um für Sie generiert zu haben. Überprüfen Sie Boost.Operators oder meine df.operators, letzteres ist auch move-aware.

Mit der richtigen Implementierung der Drang std::unique_ptr<Polynomial<T>> sollte gehen verwenden weg :)

+0

'Vorlage Freund Polynomoperator + (Lhs && lhs, Rhs && rhs) {Polynomial ret = std :: vorwärts (lhs); ret + = std :: vorwärts (rechts); Rückkehr ret; } - Warum brauchst du dafür eine Bibliothek? Ich nehme an, Sie könnten Kommutativität voraussetzen und in diesem Fall für das erste "ret" bedingt links oder rechts verwenden? Und SFINAE Tests, nehme ich an. Und einige arbeiten, um eine widersprüchliche "Operator +" Ambiguität zu vermeiden. – Yakk

+0

@Yakk Manche Leute sind mit meiner Herangehensweise nicht einverstanden, aber mit Überladungen für Provisorien können Sie weiter optimieren, indem Sie in einigen Fällen eine rvalue-Referenz anstelle eines neuen Objekts zurückgeben. "Move-aware" bedeutet für mich mehr als Ihre Implementierung. Speziell für Klassen, in denen zusätzliche Provisorien erhebliche Kosten verursachen und "Polynomial " genau so aussieht wie einer dieser Fälle. –

+1

Geben Sie nie einen Rvalue-Verweis zurück (außerhalb von Cast-Ausdrücken): Dies bedeutet, dass die Referenz-Lebensdauerverlängerung nicht funktioniert. Etwas so einfaches wie 'für (Koeff x: a + b)' wird nicht funktionieren! Und was gut ist das! – Yakk

Verwandte Themen