2016-07-10 19 views
1

Ich habe eine Klasse, die sich sehr ähnlich verhält (die C++ 11-Version von) std::ostream, auf die ich viele verschiedene (nicht verwandte) Typen streamen kann.Überlädt systematisch für r-Wert-Referenzen ein gutes Muster?

class mystream{...some implementation...};

Die typische Funktion ist

mystream& operator<<(mystream& ms, type1 const& t1){...}

mystream& operator<<(mystream& ms, type2 const& t2){...}

usw.

jedoch zu definieren (wie bei 11 ++ Stream C) Ich möchte streamen-auf-bau. Zum Beispiel:

mystream{} << t1;

Um in der Lage sein, dies zu tun, überlasten ich auf l-Wert Referenzen für jeden Typ:

mystream& operator<<(mystream&& ms, type1 const& t1){ 
    return ms << t1; // this calls the l-value version 
} 

Der Code ist nicht kompliziert, aber es wiederholt sich, weil Ich muss es für alle Beteiligten tun. Aufgrund der Art dieser Klasse ist es sinnvoll, auf Referenzen und l-Wert-Referenzen zu verwenden.

Die Frage ist, ob dies der richtige Ansatz ist? Sollte ich für jeden Typ zwei Funktionen schreiben? Ist das ein gutes Muster?

Sekundäre Frage: Natürlich könnte ich einige Template-Magie tun, um l-Wert-Referenzen zu akzeptieren, wenn geeignet, aber wieder weiß ich nicht, ob dies der empfohlene Pfad ist.

Ternäre Frage: Sollte die Funktion mystream& (wie oben) oder mystream&& zurückgeben.


Dies ist der Beispielcode:

class A{}; 
class B{}; 

class mystream{}; 

mystream& operator<<(mystream& ms, A const& a){return ms;} // (1) 
mystream& operator<<(mystream& ms, B const& b){return ms;} // (2) 

mystream& operator<<(mystream&& ms, A const& a){return ms; /*ms << a;*/} // (3) 
mystream& operator<<(mystream&& ms, B const& b){return ms; /*ms << a;*/} // (4) 

int main(){ 

    mystream ms; 
    ms << A{}; 
    ms << B{}; 

    mystream{} << A{}; // ok only if line (3) is defined 
    mystream{} << B{}; // ok only if line (4) is defined 

} 

Wenn ich Linie Kommentar (3) ist die Fehlermeldung

fatal error: invalid operands to binary expression ('mystream' and 'A') 
     mystream{} << A{}; // ok only if line (3) is defined 
     ~~~~~~~~~~^~~~ 
././random.hpp:146:11: note: candidate function not viable: expects an l-value for 1st argument 
mystream& operator<<(mystream& ms, A const& a){return ms;} // (1) 

Wenn ich Linie Kommentar (1) das Gegenteil geschieht

fatal error: invalid operands to binary expression ('mystream' and 'A') 
     ms << A{}; 
     ~~^~~~ 
././random.hpp:149:11: note: candidate function not viable: no known conversion from 'mystream' to 'mystream &&' for 1st argument 
mystream& operator<<(mystream&& ms, A const& a){return ms; /*ms << a;*/} // (3) 

Antwort

2

C++ definiert eine einzelne Funktion Vorlage, die eine Ostream rvalue Referenz nimmt:

template< class CharT, class Traits, class T > 
basic_ostream< CharT, Traits >& operator<<(basic_ostream<CharT,Traits>&& os, 
              const T& value); 

Es ruft ein entsprechender Ausgabe-Operator. Dementsprechend sollten Sie nur definieren

template <typename X> 
mystream& operator<< (mystream&& ms, const X& x) 
{ 
    ms << x; 
    return ms; 
} 
+0

Ist das auch für konkrete 'std :: o? Stream'-Klassen? (wie 'std :: ofstream'). Wie auch immer, ich denke 'ms << x;' in Ihrem Code wird die l-Wert-Referenz für die konkrete Klasse aufrufen. Das funktioniert auch nicht, weil dieser Anruf nicht funktioniert. 'mystream ms {}; ms << t1; '. – alfC

+0

Es gibt immer die Basisklassenreferenz zurück. Wenn Sie Kompilierungsfehler erhalten, zeigen Sie bitte den vollständigen Code und die vollständigen Fehlermeldungen an. –

+0

Ja, aber beruht auf einer l-Wert-Version der Funktion in der abgeleiteten konkreten Klasse.Meine Frage bezieht sich nicht auf Vererbung oder Basisklassen. Ich fügte den Beispielcode hinzu, um zu zeigen, warum anscheinend die zwei Versionen benötigt werden. – alfC