2016-07-05 9 views
1

Der folgende Code funktioniert einwandfrei und gibt 50 wie erwartet aus. Was ich jedoch nicht verstehe, ist, warum das gleiche Programm nicht mit ein paar leichten Änderungen an diesem Code geschrieben werden kann. Die beiden Linien des vorgeschlagenen Code sind Bad markiert Code 1 und 2. Wenn diese für den aktuellen Arbeitscode links von ihnen ersetzt werden (dh in addStuff und main), erhalte ich folgende Fehlermeldung:Problem beim Kombinieren von Vorlagen und Überladen der Klassenfunktion

error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream}' and 'MyClass')| 

Die So habe ich erwartet, dass es funktioniert: Wenn addStuff(x,y) in der (schlechten) cout Zeile von main() aufgerufen wird, wertet es zuerst x+y aus, deren Verhalten durch die operator+ MyClass überladene Memberfunktion definiert ist. Dies sollte nur ein MyClass-Objekt zurückgeben, das dann keine Probleme hat, getVar aufzurufen.

Was fehlt mir hier?

#include <iostream> 
using namespace std; 

class MyClass 
{ 
public: 
    MyClass(){} 
    MyClass(int a) : priV(a){} 
    MyClass operator+(MyClass otherMC) 
    { 
     MyClass newMC; 
     newMC.priV = this->priV + otherMC.priV; 
     return newMC; 
    } 
    int getVar(){return priV;} 
    void setVar(int v){priV=v;} 
private: 
    int priV; 
}; 

template <class gen> 
gen addStuff(gen x, gen y) 
{ 
    return x+y;   //Bad code 1: return (x+y).getVar(); 
} 

int main() 
{ 
    MyClass x(20), y(30); 
    cout << addStuff(x,y).getVar() << endl; //Bad code 2: cout << addStuff(x,y) << endl; 
} 
+0

fehlerhafter Code 1: falscher Typ wird zurückgegeben. bad code 2: implementiere den ostream << für den Typ, den du behandeln willst, oder benutze getVar() wie du explizit in einen Typ konvertiert hast, den ostream bereits behandelt. –

Antwort

2

Ihre Interpretation dessen, was in Zeile 1 passieren sollte, return (x+y).getVar(); korrekt ist .Der überladene operator+ wird für die Argumente x und y aufgerufen, und getVar() wird für das Ergebnis operator+ aufgerufen. Wenn x und y vom Typ MyClass sind, gibt der Operator + Aufruf ein Objekt vom Typ MyClass zurück, so dass der Aufruf an getVar() funktioniert.

getVar() gibt jedoch einen int zurück. Ihre Funktion addStuff wird angegeben, um gen zurückzugeben. Dies ist derselbe Vorlagenparameter, der mit den Argumenten x und y übereinstimmt. Dies bedeutet, dass, wenn x und y MyClass sind, die Funktion addStuff MyClass zurückgeben muss.

Wenn Sie also addStuff(x,y) in Ihre cout-Anweisung eingeben, wird der Rückgabetyp addStuff als MyClass bezeichnet. Das ist, was Ihren Compiler dazu bringt, den Fehler zu erzeugen, dass "es keinen Operator gibt < < für den Typ MyClass."

Wenn Sie addStuff wollen das Ergebnis der getVar() zurückzukehren, sollten Sie erklären es int zurückzukehren, nicht gen.

1

Sie haben addStuff so zu modifizieren, dass es sich um eine int zurückgibt, nicht die Template-Parameter gen (die MyClass sein wird):

template <class gen> 
int addStuff (gen x, gen y) 
{ 
    return (x + y).getVar(); 
} 

Wenn Sie nicht gen in int ändern, dann die Funktion wird gut funktionieren, da der Konstruktor MyClass(int a) explizit aufgerufen wird und das Ergebnis ein Objekt vom Typ MyClass sein wird.

Und natürlich wird der Compiler sagen, dass Sie nicht 'cout' ein Objekt des Typs MyClass. So

Ich schlage vor, Sie den Konstruktor mit explicit markieren: auch Ihren Code kompilieren nicht, weil es keinen Default-Konstruktor ist, so fügen Sie ein, oder einfach markieren Sie den Parameter mit einem Standardwert:

explicit MyClass (int a = 0) : priV (a) {} 

EDIT: wenn Sie nicht wollen, den Rückgabetyp der Funktion ändern, wenn Sie den Typ des Elements zu ändern, Sie decltype verwenden können, wird der Code allgemeinere zu machen:

template <class gen> 
decltype (auto) addStuff (gen x, gen y) //Or decltype (declval<gen>().getVar()) 
{ 
    return (x + y).getVar(); 
} 
+0

Kann nicht 'auto' hier verwendet werden? –

+0

Sie meinen decltype (auto)? Ja, das wird funktionieren. –

+0

Vielleicht ... Ich habe nur "Auto" Rückgabetypen für einfachere Funktionen bisher verwendet, daher die Unsicherheit. –

1

Problem ist in addStuff Funktion, es gibt MyClass -Objekt, aus Int-Variable erstellt. Sie müssen diese Funktion ändern, um mit "fehlerhaftem Code" zu arbeiten

template <class gen> 
int addStuff(gen x, gen y) 
{ 
    return (x+y).getVar(); 
} 

Oder schreiben Sie einen Ostream-Operator für MyClass. Dafür benötigen Sie getVar Methode, umfassen einen Freund Erklärung ändern und es

int getVar() const { return priV; } 
friend std::ostream& operator<< (std::ostream &out, const MyClass& m); 
std::ostream& operator<< (std::ostream& out, const MyClass& m) { 
    out << m.getVar(); 
    return out; 
} 

Auf diese Weise müssen Sie nicht implementieren addStuff Funktion ändern.

Randnotiz, Ihren Code nicht für mich kompilieren, weil es keinen Default-Konstruktor in MyClass war, hatte Konstruktor zu ändern wie diese

MyClass(int a = 0) : priV(a) {} 
Verwandte Themen