2012-09-20 12 views
7

Ist es möglich, ein Verfahren zu schreiben, die eine string nimmt und hat es in etwa so aussehen,C++ verwendet string nach << als Parameter

void method(string str) 
void printStringStream(StringStream& ss) 
{ 
    method(ss.str()); 
} 

und kann wie diese

stringstream var; 
printStringStream(var << "Text" << intVar << "More text"<<floatvar); 

genannt werden Ich sah den < Operator nach oben und es sieht aus wie es ein ostream& Objekt zurückgibt, aber ich lese wahrscheinlich this falsch oder einfach nicht richtig implementieren.

Wirklich alles, was ich will, ist eine saubere Möglichkeit, Sachen zusammen als eine Kette zu verketten und es an eine Funktion zu übergeben. Das sauberste Ding, das ich finden konnte, war ein Stringstream-Objekt, aber das lässt noch viel zu wünschen übrig.

Hinweise:

kann ich nicht viel von c++11 Antworten verwenden, weil ich auf Visual Studio 2010 ausgeführt wird (gegen meinen Willen, aber immer noch)

Ich habe Zugang zu Boost so geht Nüsse damit.

Ich wäre nicht gegen eine benutzerdefinierte Methode, solange es diese Unordnung aufräumt.

Edit:

Mit @Mooing mit @PiotrNycz Syntax Ente Antwort gemischt ich mein Ziel geschriebenen Code wie dies erreicht,

try{ 

    //code 

}catch(exception e) 
{ 
    printStringStream(stringstream() << "An exception has occurred.\n" 
          <<" Error: " << e.message 
          <<"\n If this persists please contact "<< contactInfo 
          <<"\n Sorry for the inconvenience"); 
} 

Das so sauber ist und gut lesbar, wie ich gehofft hätte zum.

Hoffentlich hilft dies anderen anderen beim Schreiben von Nachrichten.

+2

Visual Studio 11 verfügt über die gesamte C++ 11-Bibliothek und einige der Sprachfunktionen. _Welches_ Visual Studio sind Sie beschränkt? Abgesehen von der Großschreibung sieht der Code für mein Auge gut aus. sollte gut funktionieren. –

+0

Hast du das versucht? Wenn ja, was ist passiert? Wenn nicht - warum? –

+0

Warum füllst du den Stream nicht zuerst und gibst ihn als Argument weiter? –

Antwort

8

Ah, nahm mich eine Minute. Da operator<< ist eine freie Funktion für alle ostream Typen überladen, gibt es keine std::stringstream, gibt es eine std::ostream wie Sie sagen.

void printStringStream(std::ostream& ss) 

nun klar, allgemeine ostream s haben keine .str() Mitglied, aber sie tun eine magische Art und Weise haben einen ganzen Stream in einen anderen zu kopieren:

std::cout << ss.rdbuf(); 

Hier ist ein Link auf die vollständiger Code zeigt, dass es kompiliert und läuft gut http://ideone.com/DgL5V

EDIT

Wenn Sie wirklich eine Zeichenfolge in der Funktion benötigen, kann ich ein paar Lösungen denken:

Erstens haben die Streaming-seperat:

stringstream var; 
var << "Text" << intVar << "More text"<<floatvar; 
printStringStream(var); 

Zweitens: Kopieren Sie den Stream in einen String (mögliche Performance-Problem)

void printStringStream(ostream& t) 
{ 
    std::stringstream ss; 
    ss << t.rdbuf(); 
    method(ss.str()); 
} 

Drittens: machen die andere Funktion einen Strom nehmen zu

+0

Und hier experimentierte ich mit 'copy' anstelle von' rdbuf'. – chris

+0

Also ich weiß, das war nicht wirklich klar, weil ich mein Problem für das Beispiel vereinfache, aber ich brauche eine Zeichenfolge auf der Innenseite dieser Methode, um es an eine andere Funktion zu übergeben, die so aussieht. 'void method (string str)' Wie mache ich 'rdbuf()' zu etwas, das damit arbeitet? – Dan

+0

Das ist Präfekt! Meine 'Methode' verwendet tatsächlich einen anderen' stringstream', um einen Zeitstempel und einige andere Informationen für die Protokollierung zu verketten, so dass ich sie mit einer überladen kann, die einen 'streambuf * 'anstelle einer' Zeichenkette' nimmt und meine Probleme vorüber sind. Als ein Noob habe ich nicht bemerkt, dass ich '' '' es konnte. Vielen Dank! – Dan

3

Zum leichteren Schreiben von Objekten, die in einen Stream eingefügt werden können, überlasten alle diese Klassen operator<< auf ostream&. (Operatorüberladung kann von Unterklassen verwendet werden, wenn keine engere Übereinstimmung vorhanden ist.) Diese operator<< Überladungen geben alle ostream& zurück.

Was Sie tun können, ist die Funktion nehmen Sie eine ostream& und dynamic_cast<> es zu stringstream&. Wenn der falsche Typ übergeben wird, wird bad_cast geworfen.

void printStringStream(ostream& os) { 
    stringstream &ss = dynamic_cast<stringstream&>(os); 
    cout << ss.str(); 
} 

Hinweis: static_cast<> verwendet werden kann, es wird schneller sein, aber nicht so Beweis Fehler in dem Fall übergeben Sie etwas, das kein stringstream ist.

2

Da Sie wissen, dass Sie ein stringstream haben, werfen einfach den Rückgabewert:

stringstream var; 
printStringStream(static_cast<stringstream&>(var << whatever)); 
3

Machen Sie Ihren Wrapper über Std :: Stringstream. In dieser neuen Klasse können Sie festlegen, was operator << Sie brauchen:

class SSB { 
public: 
    operator std::stringstream&() { return ss; } 

    template <class T> 
    SSB& operator << (const T& v) { ss << v; return *this; } 
    template <class T> 
    SSB& operator << (const T* v) { ss << v; return *this; } 
    SSB& operator << (std::ostream& (*v)(std::ostream&)) { ss << v; return *this; } 
    // Be aware - I am not sure I cover all <<'s  
private: 
    std::stringstream ss; 
}; 

void print(std::stringstream& ss) 
{ 
    std::cout << ss.str() << std::endl; 
} 

int main() { 
    SSB ssb; 
    print (ssb << "Hello" << " world in " << 2012 << std::endl); 
    print (SSB() << "Hello" << " world in " << 2012 << std::endl); 
} 
+0

+1, um mir zu zeigen, dass ich diese ganze Zeit 'stringstream() << stuff 'hätte machen können, was das auf 1 Zeile verdichtet. – Dan

+0

Das ist perfekt! Genau das, was ich gesucht habe, so dass ich alle Objekte einfach mit der '' '' -Notation ausdrucken konnte und einen Print() -Funktionswrapper durchlaufen musste, bevor ich nach 'cout' ging. – gbmhunter

0

einfach auf die Mischung hinzufügen: Persönlich würde ich einen Strom erzeugen, die ruft, was Funktion, die ich auf Zerstörung aufrufen müssen:

#include <sstream> 
#include <iostream> 

void someFunction(std::string const& value) 
{ 
    std::cout << "someFunction(" << value << ")\n"; 
} 

void method(std::string const& value) 
{ 
    std::cout << "method(" << value << ")\n"; 
} 

class FunctionStream 
    : private virtual std::stringbuf 
    , public std::ostream 
{ 
public: 
    FunctionStream() 
     : std::ostream(this) 
     , d_function(&method) 
    { 
    } 
    FunctionStream(void (*function)(std::string const&)) 
    : std::ostream(this) 
    , d_function(function) 
    { 
    } 
    ~FunctionStream() 
    { 
     this->d_function(this->str()); 
    } 
private: 
    void (*d_function)(std::string const&); 
}; 

int main(int ac, char* av[]) 
{ 
    FunctionStream() << "Hello, world: " << ac; 
    FunctionStream(&someFunction) << "Goodbye, world: " << ac; 
} 

Es ist erwähnenswert, dass das erste Objekt, das an das temporäre Objekt gesendet wird, aus einer bestimmten Menge von Typen bestehen muss, nämlich der Klasse std::ostream: Normalerweise nimmt der Schichtoperator ein std::ostream& als erstes Argument, aber ein temporäres kann nicht sein an diesen Typ gebunden. Es gibt jedoch eine Reihe von Mitgliedsoperatoren, die als Mitglied nicht an eine Referenz gebunden sein müssen! Wenn Sie zuerst einen benutzerdefinierten Typ verwenden möchten, müssen Sie ein Referenztempo extrahieren, das mit einem der Elementeingabeoperatoren durchgeführt werden kann.

+0

Ich glaube, ich verstehe fast, was hier passiert. Könnten Sie einige Beispieleingaben hinzufügen und ausgeben, damit ich das, was Sie hier gemacht haben, einsperren kann? – Dan

+0

Ich denke, es ist etwas wie 'Methode (Hallo, Welt:: ##) someFunction (Auf Wiedersehen, Welt: ##)' wo '##' ist die Anzahl der Argumente. Ist das in Ordnung? – Dan

+0

Ja: Die jeweilige Funktion wird mit String formatiert aufgerufen. Der Hauptpunkt ist, dass es nur eine spezielle Entität gibt (das 'FunctionStream'-Objekt) und keine Umwandlung oder irgendetwas benötigt wird. –

Verwandte Themen