Werte 'klug' einlesen



  • Hi,

    ich arbeite selten mit istreams und bin daher nicht sicher auf diesem Gebiet.

    Ich möchte Tupel einlesen. Diese Tupel haben stets das Format "(a, b)", wobei a und b Gleitkommazahlen sind. Das Tupel wird intern als 'x_y_pair' repräsentiert (ich weiß, 'std::pair' täte es auch).

    Ist folgender Code zum Einlesen in Ordnung, wenn man davon ausgeht, dass zwischen allen Tokens Leerzeichen vorkommen dürfen? Übersehe ich etwas?

    std::istream& operator >> (std::istream& in, x_y_pair& v)
    {
        char c;
    
        if (not (in >> c) or c != '(') return fail(in);
        if (not (in >> v.x)) return in;
        if (not (in >> c) or c != ',') return fail(in);
        if (not (in >> v.y)) return in;
        if (not (in >> c) or c != ')') return fail(in);
        return in;
    }
    


  • Ich würde die Daten nicht sofort in dein pair reinschreiben, sondern erstmal in eine lokale Variable, die ganz am Ende nach v kopiert wird. Auf diese Weise bleibt deine Variable in einem gültigen Zustand, wenn mittendrin etwas schiefgegangen ist.



  • CStoll schrieb:

    Ich würde die Daten nicht sofort in dein pair reinschreiben, sondern erstmal in eine lokale Variable, die ganz am Ende nach v kopiert wird. Auf diese Weise bleibt deine Variable in einem gültigen Zustand, wenn mittendrin etwas schiefgegangen ist.

    Na, wenn das alles ist ... Danke. 🙂 Wird gemacht.



  • Hallo Konrad,

    Konrad Rudolph schrieb:

    Das Tupel wird intern als 'x_y_pair' repräsentiert (ich weiß, 'std::pair' täte es auch).

    Eine eigene Klasse oder Struktur ist die saubere Lösung, wenn Du so eine Eingabefunktion schreibst.

    Konrad Rudolph schrieb:

    Ist folgender Code zum Einlesen in Ordnung, wenn man davon ausgeht, dass zwischen allen Tokens Leerzeichen vorkommen dürfen?

    Um die Leerzeichen brauchst Du Dir keine Sorgen machen. Die formatierten Eingaben des istream sind dafür gemacht. Da darf auch ein tab '\t' oder newline '\n' zwischen den Token stehen.

    man könnte es vielleicht noch ein wenig verändern ...

    template< char C > struct Char {};
    template< char C >
    std::istream& operator>>( std::istream& in, const Char< C > )
    {
        char c;
        if( in >> c && c != C )
            in.setstate( std::ios_base::failbit );
        return in;
    }
    
    std::istream& operator>>( std::istream& in, x_y_pair& v )
    {
        x_y_pair tmp;
        if(     in >> Char<'('>()
            &&  in >> tmp.x
            &&  in >> Char<','>()
            &&  in >> tmp.y
            &&  in >> Char<')'>() )
            v = tmp;
        return in;
    }
    

    aber das ist letztlich Geschmackssache.

    Gruß
    Werner



  • Hallo Werner,

    Werner Salomon schrieb:

    Konrad Rudolph schrieb:

    Das Tupel wird intern als 'x_y_pair' repräsentiert (ich weiß, 'std::pair' täte es auch).

    Eine eigene Klasse oder Struktur ist die saubere Lösung, wenn Du so eine Eingabefunktion schreibst.

    Schon klar, ich meinte eigentlich, dass die Struktur von 'std::pair' erben sollte, denn sie "ist-ein" 'std::pair'.

    man könnte es vielleicht noch ein wenig verändern ...

    Die Änderungen sind gut, gehen aber ziemlich in Richtung Parser-Framework, was ich in C++ sowieso schmerzlich vermisse. Ich wünschte mir, C++ hätte da sowas komfortables wie Haskell. Klar, man könnte Spirit verwenden aber das ist für sowas kleines dann doch hoffnungsloses Overkill, vor allem, wenn man an die Codegröße denkt. Ich hätte gerne ein Lightweight-Parserframework. 🙂


Anmelden zum Antworten