stringstream verketten



  • Hallo,

    void print_string ( stringstream& ss )
    {
    	cout << ss.str();
    }
    
    int main ( int arg, char* argv[] )
    {
    
    	stringstream ss; 
    	print_string( ss << "hello" << " u " << 2 << endl );
    	return 0;
    }
    

    Obiges bedingt die Ausgabe:

    print_string': Konvertierung des Parameters 1 von 'std::basic_ostream<_Elem,_Traits>' in 'std::stringstream &' nicht möglich

    So geht es zwar:

    ss << "hello" << " u " << 2 << endl;
    	print_string(ss);
    

    aber kann man das irgendwie drehen, das es mit einer Zeile funzt?



  • Natürlich geht das 😉 Aber eigentlich ist so etwas nicht schön...

    #include <sstream>
    #include <iostream>
    
    void print_string ( std::stringstream& ss )
    {
        std::cout << ss.str();
    }
    
    int main ( int arg, char* argv[] )
    {
    
        std::stringstream ss;
    	print_string( (ss << "hello" << " u " << 2 << std::endl, ss) );
    
        return 0;
    }
    


  • So würde es gehen:

    void print_string ( std::basic_ios< char >& ss )
    {
        cout << ss.rdbuf();
    }
    

    ... aber das print_string() ist ziemlich sinnlos.

    Warum nicht gleich:

    cout << "hello" << " u " << 2 << endl;
    

    ?



  • BBBB schrieb:

    Natürlich geht das 😉 Aber eigentlich ist so etwas nicht schön...

    wieso nicht?

    Werner_logoff schrieb:

    So würde es gehen:

    void print_string ( std::basic_ios< char >& ss )
    {
        cout << ss.rdbuf();
    }
    

    ... aber das print_string() ist ziemlich sinnlos.

    Warum nicht gleich:

    cout << "hello" << " u " << 2 << endl;
    

    ?

    weil es im projekt nur eine 'zentrale printfunktion' gibt, die je nach system ausgaben macht. an diese zentrale funktion soll ein fertiges objekt übergeben werden.



  • verkett0r schrieb:

    weil es im projekt nur eine 'zentrale printfunktion' gibt, die je nach system ausgaben macht. an diese zentrale funktion soll ein fertiges objekt übergeben werden.

    .. dann bietet es sich eher an, ein eigenes ostream-Objekt zur Verfügung zu stellen (oder auch std::clog dazu zu benutzen), und dieses Objekt je nach Anforderung auf den gewünschten streambuf umzuschalten.



  • Werner_logoff schrieb:

    verkett0r schrieb:

    weil es im projekt nur eine 'zentrale printfunktion' gibt, die je nach system ausgaben macht. an diese zentrale funktion soll ein fertiges objekt übergeben werden.

    .. dann bietet es sich eher an, ein eigenes ostream-Objekt zur Verfügung zu stellen (oder auch std::clog dazu zu benutzen), und dieses Objekt je nach Anforderung auf den gewünschten streambuf umzuschalten.

    Bin zwar kein totaler Anfänger, aber dafür reichen meine Kenntnisse leider nicht aus, hast du mal nen Link oder nen Ansatz?



  • das kann so aussehen - alles nach cout:

    #include <iostream>
    using namespace std;
    
    int main ( int arg, char* argv[] )
    {
        streambuf* old_one = clog.rdbuf( cout.rdbuf() );
    
        // --   Programm
        clog << "hello" << " u " << 2 << endl;
    
        // --   vorm beenden streambuf wieder herstellen
        clog.rdbuf( old_one );
        return 0;
    }
    

    oder in eine Datei

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int main ( int arg, char* argv[] )
    {
        ofstream logfile("logfile.txt");
        streambuf* old_one = clog.rdbuf( logfile.rdbuf() );
    
        // --   Programm
        clog << "hello" << " u " << 2 << endl;
    
        // --   vorm beenden streambuf wieder herstellen
        clog.rdbuf( old_one );
        return 0;
    }
    

    oder nirgendwo hin

    #include <iostream>
    #include <streambuf>
    using namespace std;
    
    struct Nirvana : std::streambuf
    {
        Nirvana() {}
    };
    
    int main ( int arg, char* argv[] )
    {
        Nirvana nirvana; // nirgendwo hin
        streambuf* old_one = clog.rdbuf( &nirvana );
    
        // --   Programm
        clog << "hello" << " u " << 2 << endl;
    
        // --   vorm beenden streambuf wieder herstellen
        clog.rdbuf( old_one );
        return 0;
    }
    

    Sonst siehe auch, wie das Umschalten des streambuf mit RAII funktioniert.



  • Vielen Dank!
    Die erste Lösung passt mir am besten in den Kram, dazu hätte ich noch eine Frage. Die Funktion make_message konvertiert in einen String:

    static string message_buffer;
    void make_message ( basic_ios <char>& ss ) 
    { 
    	stringstream aa; 
    	aa <<  ss.rdbuf();
    	message_buffer = aa.str();
    	ss.clear();
    }
    

    Jetzt bin ich einem Rätsel auf der Spur:

    stringstream ss; 
    	make_message ( ss << "That's" << 2 << " deep for me." << endl  );
    	cout << message_buffer;
    	cout << ss.rdbuf();
    	cout << message_buffer;
    

    Obiges bewirkt eine einmalige Ausgabe! 😮
    Kömmentiere ich allderdings die Zeile cout << ss.rdbuf();
    aus, dann wird wie erwartet zweimal ausgegeben! 😕
    Die Zeile cout << ss.rdbuf(); scheint die Variable message_buffer zu löschen! Das ist doch nicht normal?!



  • verkett0r schrieb:

    Vielen Dank!
    Die erste Lösung passt mir am besten in den Kram,

    warum eigentlich?

    verkett0r schrieb:

    dazu hätte ich noch eine Frage. Die Funktion make_message konvertiert in einen String:

    static string message_buffer;
    void make_message ( basic_ios <char>& ss ) 
    { 
    	stringstream aa; 
    	aa <<  ss.rdbuf();
    	message_buffer = aa.str();
    	ss.clear();
    }
    

    bei Aufruf der make_message-Funktion werden alle Zeichen in den string von 'ss' geschrieben. In Zeile 5 werden die Zeichen in den string von 'aa' kopiert. Anschließend wird in Zeile 6 der Inhalt von 'aa' in die string message_buffer kopiert. Ist irgendwie ziemlich umständlich - oder?

    verkett0r schrieb:

    Jetzt bin ich einem Rätsel auf der Spur:

    stringstream ss; 
    	make_message ( ss << "That's" << 2 << " deep for me." << endl  );
    	cout << message_buffer;
    	cout << ss.rdbuf();
    	cout << message_buffer;
    

    Obiges bewirkt eine einmalige Ausgabe! 😮
    Kömmentiere ich allderdings die Zeile cout << ss.rdbuf();
    aus, dann wird wie erwartet zweimal ausgegeben! 😕
    Die Zeile cout << ss.rdbuf(); scheint die Variable message_buffer zu löschen! Das ist doch nicht normal?!

    Doch - um genauer zu sein, das ist C++-Standard. 🕶
    mit 'make_message' landet die Ausgabe nach zwei weiteren Kopien (s.o.) in der Variablen 'message_buffer'. Der wird anschließend ausgegeben. Dann wird der Rest aus 'ss' auf cout ausgegeben. Da ist der Lesezeiger intern aber schon auf EOF positioniert, da der Inhalt von 'ss' bereits innerhalb von make_message ausgegeben wurde; damit wird dann der Status von cout auf 'fail' gesetzt, und die nächste Ausgabe wird erst nach einem cout.clear() wieder möglich.

    Gruß
    Werner



  • Werner Salomon schrieb:

    verkett0r schrieb:

    Vielen Dank!
    Die erste Lösung passt mir am besten in den Kram,

    warum eigentlich?

    Ich muss mich dann nicht um dieses streambuf Zeugs kümmern.

    Werner Salomon schrieb:

    bei Aufruf der make_message-Funktion werden alle Zeichen in den string von 'ss' geschrieben. In Zeile 5 werden die Zeichen in den string von 'aa' kopiert. Anschließend wird in Zeile 6 der Inhalt von 'aa' in die string message_buffer kopiert. Ist irgendwie ziemlich umständlich - oder?

    Ja, sieht umständlich aus. Wäre schön wenn es irgendwie direkt ginge.

    Optimal wäre so etwas in der Art:

    static string message;
    string& make_message ( /* ??? */ )
    {
    	// Assemble stuff ...
    	return message;
    }
    string s = make_message ( "Hallo ", 1.2, " Echo", " Wurst." );
    

    🙂


Anmelden zum Antworten