2010-03-12 10 views
13

die folgende Funktion vor:temporäre string Drehen() in einzelne Anweisung c_str

void f(const char* str); 

Angenommen, ich möchte eine Zeichenfolge generieren string verwenden und es an diese Funktion übergeben. Wenn ich es in einer Erklärung tun will, könnte ich versuchen:

f((std::ostringstream() << "Value: " << 5).str().c_str()); // error 

Dies gibt eine Fehlermeldung: ‚str()‘ ist kein Mitglied von ‚basic_ostream‘ ist. OK, also Operator < < gibt ostream statt ostringstream zurück - wie wäre es, es in einen ostringstream zurückzuwerfen?

1) Ist das sicher?

f(static_cast<std::ostringstream&>(std::ostringstream() << "Value: " << 5).str().c_str()); // incorrect output 

Jetzt mit diesem, stellt sich heraus, für den Bediener < < ("Wert:") nennen, ist es tatsächlich Ostream Bedienungs < < (void *) und Drucken eines Hex-Adresse ruft. Das ist falsch, ich will den Text.

2) Warum ruft der Operator < < auf dem temporären std :: ostringstream() den Ostream-Operator auf? Sicherlich hat das Temporäre eine Art "ostringstream" nicht "ostream"?

Ich kann die temporäre zu erzwingen, um den richtigen Operator Anruf auch zu erzwingen!

f(static_cast<std::ostringstream&>(static_cast<std::ostringstream&>(std::ostringstream()) << "Value: " << 5).str().c_str()); 

Dies scheint zu arbeiten und übergibt "Wert: 5" bis f().

3) Verlasse ich mich jetzt auf undefiniertes Verhalten? Die Modelle sehen ungewöhnlich aus.


Ich bin mir bewusst, die beste Alternative so etwas wie diese:

std::ostringstream ss; 
ss << "Value: " << 5; 
f(ss.str().c_str()); 

... aber ich bin daran interessiert, das Verhalten in einer Linie zu tun. Angenommen, jemand wollte ein (zweifelhaftes) Makro erstellen:

Würde dies wie erwartet funktionieren?

+0

Mögliche Duplikat [string, string und char \ * Umwandlung Verwirrung] (http://stackoverflow.com/questions/1374468/stringstream-string-and-char-conversion-confusion). – jww

Antwort

14

Sie können den temporären Stream nicht in std::ostringstream& umwandeln. Es ist schlecht gebildet (der Compiler muss Ihnen sagen, dass es falsch ist). Das Folgende kann es jedoch tun:

f(static_cast<std::ostringstream&>(
    std::ostringstream().seekp(0) << "Value: " << 5).str().c_str()); 

Das ist natürlich hässlich. Aber es zeigt, wie es funktionieren kann. ist eine Mitgliedsfunktion, die eine std::ostream& zurückgibt.Würde wahrscheinlich besser, diese im Allgemeinen, dass

template<typename T> 
struct lval { T t; T &getlval() { return t; } }; 

f(static_cast<std::ostringstream&>(
    lval<std::ostringstream>().getlval() << "Value: " << 5).str().c_str()); 

Der Grund zu schreiben, ohne etwas zu den void* nimmt, weil ist, dass operator<< Mitglied-Funktion ist. Die operator<<, die eine char const* dauert, ist nicht.

+0

Ihr Snippet mit suchep (0) gibt eine leere Zeichenfolge für mich zurück - aber die lval-Vorlage scheint korrekt zu funktionieren. Das hängt dann vollständig von definiertem Verhalten ab und wäre tragbar? – AshleysBrain

+0

@Ashley, sicher ist alles definiert. –

+0

Könnte lval einen Konvertierungsoperator zu T & haben und den Funktionsaufruf vermeiden? (oder vielleicht nimmt der Compiler diesen Operator nicht automatisch auf ...) – Macke

3

Ein temporäres kann nicht als nicht-konstanter Verweis auf eine Funktion übergeben werden, deshalb findet es nicht den richtigen Streaming-Operator und verwendet stattdessen das Argument void * (es ist eine Member-Funktion und ruft sie auf a auf temporär ist OK).

Was kommt um die Einschränkungen durch Casting zu bekommen, ich habe das Gefühl, dass es in der Tat UB ist, aber ich kann nicht sicher sagen. Jemand anderes wird sicherlich den Standard zitieren.

+0

Ich übergebe nicht den temporären ostringstream zu f() - ich übergebe nur das Ergebnis von c_str(), das ist const (wenn es darauf ankommt). Abgesehen davon, was bedeutet das, dass es das Argument void * auswählt? Was ist anders daran, dass es ausgewählt werden kann, aber nicht das Argument const char *? – AshleysBrain

+2

Sie versuchen, einen vorübergehenden ostringstream an ostream & operator << (ostream &, char const *) zu übergeben, und das schlägt fehl (ohne die Besetzung, die Sie gemacht haben, um es zu beheben). ostream & ostream :: operator << (void const *) kann ausgewählt werden, da es sich um eine Memberfunktion handelt und das Aufrufen von Memberfunktionen von Provisorien erlaubt ist. – Tronic

0

Wenn Sie Aussagen wie one_lined können Sie schreiben:

// void f(const char* str); 
f(static_cast<ostringstream*>(&(ostringstream() << "Value: " << 5))->str()); 

Allerdings sollten Sie leichter bevorzugen Code zu erhalten, wie:

template <typename V> 
    string NumberValue(V val) 
    { 
    ostringstream ss; 
    ss << "Value: " << val; 
    return ss.str(); 
    } 
f(NumberValue(5)); 
+0

Der One-Liner, den Sie vorgeschlagen haben, ist falsch und würde nicht in allen Fällen funktionieren. – missingfaktor

0

ich etwas, das ein bisschen wie dies für die Protokollierung verwenden.

#include <sstream> 

using namespace std; 

const char *log_text(ostringstream &os, ostream &theSame) 
{ 
    static string ret; // Static so it persists after the call 
    ret = os.str(); 
    os.str(""); // Truncate so I can re-use the stream 
    return ret.c_str(); 
} 


int main(int argc, char **argv) 
{ 
    ostringstream ss; 
    cout << log_text(ss, ss << "My first message") << endl; 
    cout << log_text(ss, ss << "Another message") << endl; 
} 

Ausgang:

Meine erste Nachricht

Eine weitere Nachricht

+1

Warum in 'const char *' konvertieren, wenn Sie 'std :: string' in einen Stream einfügen können? – quantum

1

Dies kann getan werden, eine C++ 11 Lambda-Funktion.

#include <iostream> 
#include <sstream> 

void f(const char * str) 
{ 
    std::cout << str << std::endl; 
} 

std::string str(void (*populate)(std::ostream &)) 
{ 
    std::ostringstream stream; 
    populate(stream); 
    return stream.str(); 
} 

int main(int argc, char * * args) 
{ 
    f(str([](std::ostream & ss){ ss << "Value: " << 5; }).c_str()); 
    return 0; 
} 

// g++ -std=c++11 main.cpp -o main 
// ./main 
// Value: 5