2014-11-06 5 views
10

Angenommen, ich habe eine Funktion, die einen ostream & Parameter o nimmt und in diesen Ostream schreibt. Eine operator << Implementierung wäre ein gutes Beispiel.Soll ich einen temporären Ostream mit dem streambuf eines anderen Benutzers erstellen?

ostream& operator << (ostream& o, const MyThing& t) 
{ 
    // ... interesting code here ... 
    return o; 
} 

Innerhalb der Funktion möchte ich möglicherweise Formatierungsoptionen für den Stream angeben. Beispielsweise möchte ich, dass eine Zahl als Hex gedruckt wird, egal wie die o konfiguriert ist, wenn sie an die Funktion übergeben wird.

Zweitens möchte ich in der Lage sein, Annahmen über die aktuellen Formatierungsflags zu machen. Zum Beispiel wäre es schön, davon ausgehen zu können, dass Zahlen als Dezimalzahlen formatiert sind, wenn ich nichts anderes wünsche.

Schließlich, bis die Funktion beendet Ich möchte die Formatierungsoptionen auf o die gleichen wie sie vor dem Aufruf der Funktion waren, so dass sie für den Aufrufer unverändert angezeigt werden. Das ist einfach eine Frage der Höflichkeit gegenüber dem Anrufer.

Bisher habe ich dies erreicht, indem eine lokale ostringstream innerhalb der Funktion zu schaffen, tun alle meine Arbeit an, dass (einschließlich Formatierungsoptionen einstellen) und die .str()-o am Ende der Funktion sendet. Die StackOverflow-Frage here legt nahe, dass Menschen, die klüger sind als ich, denselben Ansatz verfolgen. Es stört mich jedoch, dass ich so viele Daten in ostringstreams aufbewahre, die vielleicht früher an den Ausgang gesendet werden könnten (die Strings können ziemlich groß werden).

Ich habe zwei Fragen:

1) Ist es legal, idiomatisch, gute Form, usw. einen temporären (Stack basierte) Ostream um o.rdbuf() zu erstellen und an diesem Ostream meine Arbeit tun? Meine eigenen Tests und die Seite unter cppreference.com scheint darauf hinzudeuten, dass ich es kann.

ostream& operator << (ostream& o_, const MyThing& t) 
{ 
    ostream o (o_.rdbuf()); 
    // write stuff to "o", 
    // setting formatting options as I go. 
    return o_; // Formatting on the parameter ostream o_ unchanged. 
} 

2) Gibt es einen anderen, besseren Weg, den ich nicht berücksichtigt habe?

Antwort

0

Die Einstellungen können in einem Objekt namens fmtflags-Objekt gespeichert werden, das in einer Klasse namens ios definiert ist, die in iostream enthalten ist. Sie können eines der Objekte deklarieren, aber Sie müssen es mit dem Scope-Resolution-Operator deklarieren.

Die folgende Erklärung wird in den variablen old_settings bestimmte Aspekte des Formats Zustand speichern:

ios::fmtflags old_settings = cout.flags(); 

Dann nachdem ich die Ausgabe mit der neuen Einstellung, die Sie mit der gleichen Funktion durch den Aufruf der alten Einstellung wiederherstellen die alten Einstellungen als Argument:

cout.flags(old_settings); 

Weitere Einstellungen können mit Elementfunktionen abgerufen und wiederhergestellt werden. Beispiel:

int old_precision = cout.precision(); 

speichert die aktuelle Präzisionsspezifikation.Dann

cout.precision(old_precision); 

wird die Präzision auf den ursprünglichen Wert wiederherzustellen

+0

Diese Anrufe am besten in den Konstruktor und Destruktor platziert werden würde irgendein stapelbasiertes Objekt. Ich gehe davon aus, dass die Boost-Klassen das tun. – peterpi

1

Das ist keine schlechte Lösung; es ist sicherlich legal. Ich glaube nicht es ist zu häufig, so ist es wahrscheinlich eine gute Idee zu kommentieren, wie , warum Sie es tun.

Die häufigste Lösung, die ich hier gesehen habe, ist ein Zustand Schoner-Klasse zu erstellen, die alle des Staates Sie müssen sparen (in der Regel flags(), precision() und fill()) im Konstruktor, und es wieder in der Destruktor, und dann zwangsweise alle gewünschten Optionen festlegen. (Es kann möglich sein copyfmt dafür zu verwenden, obwohl diese auch Kopien Dinge wie die Ausnahme Maske, die Sie wahrscheinlich nicht wollen, zu spielen.)

Verwandte Themen