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 << " )";
}
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);
}
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