2013-02-12 14 views
5

Ich schreibe gerade einen Wrapper für eine std::stringstream und ich möchte alle operator<< Anrufe über meine Klasse an die std::stringstream weiterleiten. Dies funktioniert jetzt gut (Danke an diese Frage: wrapper class for STL stream: forward operator<< calls), aber es gibt immer noch ein Problem damit.C++ Wrapper-Klasse für Iostream, verwenden Sie Stream-Modifizierer wie std :: endl mit Operator <<

Sagen wir, ich habe den folgenden Code:

class StreamWrapper { 
private: 
    std::stringstream buffer; 
public: 
    template<typename T> 
    void write(T &t); 

    template<typename T> 
    friend StreamWrapper& operator<<(StreamWrapper& o, T const& t); 

    // other stuff ... 
}; 


template<typename T> 
StreamWrapper& operator<<(StreamWrapper& o, T const& t) { 
    o.write(t); 
    return o; 
} 

template<typename T> 
void StreamWrapper::write(T& t) { 
    // other stuff ... 

    buffer << t; 

    // other stuff ... 
} 

Wenn ich das jetzt tun:

StreamWrapper wrapper; 
wrapper << "text" << 15 << "stuff"; 

Dies funktioniert gut. Aber wenn ich die Stream-Modifikatoren wie std::endl verwenden möchte, die eine Funktion gemäß http://www.cplusplus.com/reference/ios/endl ist, kompiliere ich einfach nicht.

StreamWrapper wrapper; 
wrapper << "text" << 15 << "stuff" << std::endl; 

Warum? Wie kann ich die Stream-Modifikatoren auch weiterleiten?

+0

Was ist der Compiler-Fehler? –

+0

Es gibt Überladungen von 'operator <<', die eine Funktion annehmen, und rufen Sie dann diese Funktion im Stream auf: http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt http: //en.cppreference .com/w/cpp/io/manip – BoBTFish

Antwort

3

Siehe this answer.

werden Sie

wollen
typedef std::ostream& (*STRFUNC)(std::ostream&); 

StreamWrapper& operator<<(STRFUNC func) // as a member, othewise you need the additional StreamWrappe& argument first 
{ 
    this->write(func); 
    return *this; 
} 
+0

@Mogria warum die Bearbeitung? Die 'STRFUNC'-Objekte sind Funktionen (Zeiger), so dass sie direkt im 'ostream' aufgerufen werden können. – rubenvb

+0

weil es meine Schreibmethode durchlaufen muss, wegen der anderen Sachen darin. – MarcDefiant

2

Sie scheinen ein bisschen mehr Arbeit zu tun. Ich benutze normalerweise:

class StreamWrapper 
{ 
    // ... 
public: 
    template <typename T> 
    StreamWrapper& operator<<(T const& obj) 
    { 
     // ... 
    } 
}; 

Mit einem modernen Compiler, diese sollte Arbeit für alle konkreten Typen. Das Problem besteht darin, dass Manipulatoren Template-Funktionen sind, , so dass der Compiler keine Vorlage Argument Typ Abzug ausführen kann. Die Lösung ist nicht-Template Überlastungen für die Typen der Manipulatoren zu bieten:

StreamWrapper& operator<<(std::ostream& (*pf)(std::ostream&)) 
{ 
    // For manipulators... 
} 

StreamWrapper& operator<<(std::basic_ios<char>& (*pf)(std::basic_ios<char>&) 
{ 
    // For manipulators... 
} 

Typ Abzug für die Manipulatoren scheitern, aber der Compiler werden diese für die Funktion der Überladungsauflösung aufzunehmen.

(Beachten Sie, dass Sie noch mehr vielleicht brauchen, für Dinge wie std::setw(int).)

+0

Löst das perfekte Weiterleitungs-Idiom das Problem, wenn Sie r-Wert Referenzunterstützung haben? –

+0

@Tim glaube ich nicht. Ich sehe nicht aus, wie es etwas verändern würde. Laut Scott Meyer (dem ich definitiv vertraue) können Vorlagennamen nicht perfekt weitergeleitet werden (und ich sehe nicht, wie man sie in einem Compiler implementieren könnte), und die Manipulatoren sind alle Vorlagennamen. –

+0

Wenn er das sagte, dann vertraue ich auch darauf. Ich hatte nur in meiner Erinnerung seine wiederholten Aussagen, dass universelle Referenzen "an alles binden". –