Generic C++ stream inserter and extractor

Hier können Artikel, Tutorials, Bücherrezensionen, Dokumente aller Art, Texturen, Sprites, Sounds, Musik und Modelle zur Verfügung gestellt bzw. verlinkt werden.
Forumsregeln
Möglichst sinnvolle Präfixe oder die Themensymbole nutzen.
Antworten
Benutzeravatar
Biolunar
Establishment
Beiträge: 154
Registriert: 27.06.2005, 17:42
Alter Benutzername: dLoB

Generic C++ stream inserter and extractor

Beitrag von Biolunar »

Vielen dürfte die Überladung der Operatoren << und >> geläufig sein mit denen man die standard C++ Streams für user-defined types (UDT) verwendet werden können, aber mit den Schwierigkeiten, die bei der Implementierung auftauchen können, kennen sich nur die wenigsten aus. Diese Operatoren werde ich im folgenden als inserter (operator <<) und extractor (operator >>) bezeichnen.


Ein gravierender Punkt, der mich an meinem bisherigen Code gestört hat, ist das Fehlverhalten bei Exceptions. Im C++ standard ist es vorgeschrieben, dass die IOStreams von sich aus keine Exceptions werfen, außer man legt dieses Verhalten explizit mit der Elementfunktion std::basic_ios::exceptions() fest. So kann es vorkommen, das bei UDTs in den inserter/extractor-Operatoren Exceptions geworfen werden, ohne dass der Benutzer der Streams dieses Verhalten gebilligt hat. Ich sehe selten ein catch(...) in den überladenen Operatoren.

Ein weiterer Punkt ist, dass irgendwie Niemand (Ich auch nicht :D) die std::basic_istream::sentry bzw. std::basic_ostream::sentry Objekte in dem inserter/extractor erstellt, was bei größeren Schreib- und Lesevorgängen zu Performanceeinbußen führen kann.

Eher nebensächlich (aber auch falsch!) ist die Tatsache, dass nach jedem Schreiben die Länge (std::ios_base::width()) auf 0 gesetzt werden sollte, sie es aber in den meisten Fällen nicht wird.

Ich habe daraufhin zwei generische Funktionen geschrieben, die genau diese Misstände vermeiden sollen. Die Funktionsweise und die Anwendung sind sehr simpel, haben dennoch den nachteil, dass man für jeden inserter/extractor eine weitere "print"-Funktion erstellen muss.
Nehmen wir folgenden Code mit dem UDT "vector" und der Funktion "print":

Code: Alles auswählen

struct vector
{
    int x, y;
};

#include <ostream>

template <typename char_t, typename traits_t>
void print(std::basic_ostream<char_t, traits_t>& os, vector const& vec)
{
    os << "( " << vec.x << " | " << vec.y << " )";
}
Jetzt kann auch schon die Überladung des Operators beginnen:

Code: Alles auswählen

#include "generic_inserter.hpp"

template <typename char_t, typename traits_t>
std::basic_ostream<char_t, traits_t>& operator<< (std::basic_ostream<char_t, traits_t>& os, vector const& vec)
{
    return generic_inserter(print, os, vec);
}
Das wars schon. Für den Extraktor existiert eine ähnliche Funktion generic_extractor() in generic_extractor.hpp

Die Ausgabe- bzw. Eingabefunktionen müssen folgende Signatur haben:
void <name>(std::basic_ostream&, UDT const&); // Für Ausgabe
void <name>(std::basic_istream&, UDT&); // Für Eingabe
Also fast wie die überladenen Operatoren auch, nur ist der Rückgabewert redundant also void.
Das war eigentlich auch schon alles, was zu sagen ist.


Nachdem ich das Buch "Standard C++ IOStreams and Locales" von Angelika Langer und Klaus Kreft gelesen habe, musste ich feststellen, dass es meine Idee schon gab :< Aber durch das Buch hab ich ein paar Fehler von mir entdeckt und behoben.

Update:
Header durchkommentiert und die Boost Software Lizenz hinzugefügt.
Die Header sind im Anhang als Tarball verfügbar.

Update:
Ab sofort kann man den Code über Github erreichen oder besser man klont das Repo per git clone git://github.com/Biolunar/generic_stream.git
Zuletzt geändert von Biolunar am 09.09.2010, 16:53, insgesamt 4-mal geändert.
Benutzeravatar
donelik
Beiträge: 56
Registriert: 28.11.2006, 17:49
Benutzertext: Will releasen!
Kontaktdaten:

Re: Generic C++ stream inserter and extractor

Beitrag von donelik »

Vielen Dank! Sowas habe ich gesucht! :)
Ach hör' auf ...
Benutzeravatar
Aramis
Moderator
Beiträge: 1458
Registriert: 25.02.2009, 19:50
Echter Name: Alexander Gessler
Wohnort: 2016
Kontaktdaten:

Re: Generic C++ stream inserter and extractor

Beitrag von Aramis »

Ich könnte den Stream-Inserter aktuell für Assimp brauchen - wie sieht es damit lizenztechnisch aus? Bei aller Perfektion vermisse ich oben an deinen wunderschönen Headern noch eine entsprechende Angabe :-)
Benutzeravatar
Biolunar
Establishment
Beiträge: 154
Registriert: 27.06.2005, 17:42
Alter Benutzername: dLoB

Re: Generic C++ stream inserter and extractor

Beitrag von Biolunar »

Lizenztext habe is den Headern hinzugefügt und den Code einmal durchkommentiert.
Ich habe mich für die Boost Software License entschieden, ich denke das ist für Jedermann optimal :)

Die aktualisierten Header stehen im ersten Post zur Verfügung!
Benutzeravatar
Aramis
Moderator
Beiträge: 1458
Registriert: 25.02.2009, 19:50
Echter Name: Alexander Gessler
Wohnort: 2016
Kontaktdaten:

Re: Generic C++ stream inserter and extractor

Beitrag von Aramis »

Danke dir! BSL ist perfekt :-)
Antworten