Stream: mehrere Zahlen



  • Hi,

    #include <iostream>
    #include <sstream>
    #include <string>
    
    using namespace std;
    
    struct Subtest
    {
    	int x;
    
    	friend ostream& operator<<(ostream& os, const Subtest& subtest)
    	{
    		return os << subtest.x;
    	}
    
    	friend istream& operator>>(istream& is, Subtest& subtest)
    	{
    		return is >> subtest.x;
    	}
    };
    
    struct Test
    {
    	int a;
    	Subtest b;
    
    	friend ostream& operator<<(ostream& os, const Test& test)
    	{
    		return os << test.a << test.b;
    	}
    
    	friend istream& operator>>(istream& is, Test& test)
    	{
    		return is >> test.a >> test.b;
    	}
    };
    
    int main()
    {
    	Test x;
    	x.a = 100;
    	x.b.x = 200;
    
    	cout << x;
    
    	Test y;
    	{
    		stringstream ss;
    		ss << x;
    
    		ss >> y;
    	}
    
    	cout << '\n' << y;
    
    	int z;
    	cin >> z;
    }
    

    Dieses sehr simple Beispiel gibt mir in Zeile 2 100200-12347891 aus. Klar ist, dass er also 100200 als eine Zahl interpretiert. Die offensichtliche Lösung ist ein Leerzeichen zwischen die Zahlen zu stecken. Bisher habe ich in Serializer-Lösungen über Streams so etwas aber nicht gesehen. Ist es legitim das so zu machen oder gibt es bessere Varianten?

    Ich frage deshalb, weil dieses Problem ja nicht so einfach zu lösen ist, wenn man ein beliebiges Element, etwa über Templates, serialisieren möchte.



  • Stream im Binärmodus öffnen und Typen fester Breite reinschieben?

    // edit:

    #include <iostream>
    #include <fstream>
    #include <cstdint>
    
    class foo_t {
    
    	friend std::ostream& operator<<( std::ostream &os, foo_t const &foo );
    
    	friend std::ofstream& operator<<( std::ofstream &os, foo_t const &foo );
    	friend std::ifstream& operator>>( std::ifstream &is, foo_t &foo );
    
    	private:
    		int32_t bar;
    
    	public:
    		foo_t( ) : bar( 0 ) {}
    		foo_t( int bar ) : bar( bar ) {}
    };
    
    std::ostream& operator<<( std::ostream &os, foo_t const &foo )
    {
    	os << foo.bar;
    	return os;
    }
    
    std::ofstream& operator<<( std::ofstream &os, foo_t const &foo )
    {
    	os.write( reinterpret_cast< char const* >( &foo.bar ), sizeof( foo.bar ) );
    	return os;
    }
    
    std::ifstream& operator>>( std::ifstream &is, foo_t &foo )
    {
    	is.read( reinterpret_cast< char * >( &foo.bar ), sizeof( foo.bar ) );
    	return is;
    }
    
    int main()
    {
    	{
    		foo_t a( 43 );
    		foo_t b( 98 );
    
    		std::ofstream file( "data.dat", std::ios_base::binary | std::ios_base::trunc );
    		file << a;
    		file << b;
    	}
    
    	{
    		foo_t a;
    		foo_t b;
    
    		std::ifstream file( "data.dat", std::ios_base::binary );
    		file >> a;
    		file >> b;
    
    		std::cout << "a = " << a << "\nb = " << b << '\n';
    	}
    }
    


  • Okay, das wäre eine Lösung. Aber dann sind die operatoren<</>> für cout und cin z.B. nicht mehr zu gebrauchen. Zudem ist dann alles voller reinterpret_casts. Das gibt mir irgendwie das Gefühl, dass die Lösung nicht besonders elegant ist, aber vielleicht gibt es auch keine andere.



  • Eisflamme schrieb:

    Okay, das wäre eine Lösung. Aber dann sind die operatoren<</>> für cout und cin z.B. nicht mehr zu gebrauchen.

    Warum nicht?

    Eisflamme schrieb:

    Zudem ist dann alles voller reinterpret_casts.

    Wenn's angebracht ist, ist am reinterpret_cast nichts schlimmes.

    Eisflamme schrieb:

    Das gibt mir irgendwie das Gefühl, dass die Lösung nicht besonders elegant ist, aber vielleicht gibt es auch keine andere.

    Sonst gingen im Textformat noch Delimiter, feste Breite oder variable Breite mit Angabe der Länge. Letztere beide mMn. bescheiden.

    Vielleicht hat jemand noch einen anderen Vorschlag?



  • es geht um das einlesen von zahlen und ihr macht da so ein affentheater draus 🙄



  • Swordfisch:
    Weil der mir die Zahlen binär ausgibt und ich bei der cin-Eingabe auch nicht spontan auf das Zeichen für 100 oder 200 komme. Ich will die aber eigentlich ganz gerne sehen. 😉 Ja, die von Dir erwähnten Alternativen gefallen mir auch weniger gut. Ein ' ' hinzuzufügen empfinde ich gerade jedoch noch etwas weniger unelegant.

    kasper:
    Na und? Wie würdest Du es denn lösen?



  • Eisflamme schrieb:

    kasper:
    Na und? Wie würdest Du es denn lösen?

    na und weiter nichts, ist einfach nur low level sinnig. 😃
    fscanf.



  • Ne, will C++ nutzen. Außerdem ist das auch nicht besser als die obige Lösung.



  • Eisflamme schrieb:

    Ne, will C++ nutzen. Außerdem ist das auch nicht besser als die obige Lösung.

    wenn du schlankeren code und einfachere lesbarkeit nicht als besser ansiehst dann kann ich dir auch nicht weiter helfen.
    weiterhin viel spaß beim verkomplizieren der angelegenheit.
    - und tschüs -



  • Eisflamme schrieb:

    Weil der mir die Zahlen binär ausgibt und ich bei der cin-Eingabe auch nicht spontan auf das Zeichen für 100 oder 200 komme. Ich will die aber eigentlich ganz gerne sehen. 😉

    Nur die Varianten für ifstream und ofstream schreiben byteweise.



  • Swordfish:
    Stimmt, da habe ich nicht genau genug geschaut, dann ist das okay. So vieleiInterpret_castsblähen den Code halt ziemlich auf. Wie löst ein Werner z.B. dieses Problem?



  • Eisflamme schrieb:

    Wie löst ein Werner z.B. dieses Problem?

    Hallo Eisflamme,

    ganz einfach mit einem Leerzeichen zwischen den Zahlen. Ich sehe da auch gar kein Problem; oder habe ich hier was überlesen?

    struct Test
    {
        int a;
        Subtest b;
    
        friend ostream& operator<<(ostream& os, const Test& test)
        {
            return os << test.a << " " << test.b; // Leerzeichen als Trenner
        } 
        // usw.
    

    Eisflamme schrieb:

    Die offensichtliche Lösung ist ein Leerzeichen zwischen die Zahlen zu stecken. Bisher habe ich in Serializer-Lösungen über Streams so etwas aber nicht gesehen.

    ich schon, warum auch nicht

    Gruß
    Werner



  • Okay, cool, so sieht meine aktuelle Lösung auch aus. 🙂 Ich muss dann nur aufpassen, wenn beim Serialisieren plötzlich Strings auftauchen, die Leerzeichen enthalten dürfen. Dann muss std::noskipws her, damit er bei \0 trennt, richtig? Und später für den Stream noch brav ios::skipws zurücksetzen, falls es vorher drin war.



  • Hallo nochmal,

    ich frage gleich nochmal hier nach. Jetzt würde ich gerne Strings in den Stream schicken, die aber mit Leerzeichen getrennt sein können sollen. Findet ihr meine folgende Lösung in Ordnung?

    ofstream: ofs << string << '\0';
    ifstream: getline(ifs, string, '\0');


Anmelden zum Antworten