Ich hatte kürzlich ein Problem beim Erstellen eines stringstream
, da ich fälschlicherweise angenommen habe, dass std::setw()
dies den Stringstream bei jeder Einfügung beeinflussen würde, bis ich ihn explizit geändert habe. Es wird jedoch nach dem Einfügen immer deaktiviert.
// With timestruct with value of 'Oct 7 9:04 AM'
std::stringstream ss;
ss.fill('0'); ss.setf(ios::right, ios::adjustfield);
ss << setw(2) << timestruct.tm_mday;
ss << timestruct.tm_hour;
ss << timestruct.tm_min;
std::string filingTime = ss.str(); // BAD: '0794'
Ich habe also eine Reihe von Fragen:
- Warum ist
setw()
das so? - Sind andere Manipulatoren so?
- Gibt es einen Unterschied im Verhalten zwischen
std::ios_base::width()
undstd::setw()
? - Gibt es schließlich eine Online-Referenz, die dieses Verhalten klar dokumentiert? Meine Herstellerdokumentation (MS Visual Studio 2005) scheint dies nicht klar zu zeigen.
Antworten:
Wichtige Hinweise aus den Kommentaren unten:
Von Martin:
Von Charles:
Das Folgende ist die Diskussion, die zu der obigen Schlussfolgerung führt:
Wenn Sie sich den Code ansehen, geben die folgenden Manipulatoren eher ein Objekt als einen Stream zurück:
Dies ist eine übliche Technik, um eine Operation nur auf das nächste Objekt anzuwenden, das auf den Stream angewendet wird. Leider schließt dies nicht aus, dass sie klebrig sind. Tests zeigen, dass alle außer
setw
klebrig sind.Alle anderen Manipulatoren geben ein Stream-Objekt zurück. Daher müssen alle Statusinformationen, die sie ändern, im Stream-Objekt aufgezeichnet werden und sind somit permanent (bis ein anderer Manipulator den Status ändert). Daher müssen die folgenden Manipulatoren Sticky- Manipulatoren sein.
Diese Manipulatoren führen tatsächlich eine Operation für den Stream selbst und nicht für das Stream-Objekt aus (obwohl der Stream technisch gesehen Teil des Status der Stream-Objekte ist). Ich glaube jedoch nicht, dass sie einen anderen Teil des Status der Stream-Objekte beeinflussen.
Die Schlussfolgerung ist, dass setw der einzige Manipulator in meiner Version zu sein scheint, der nicht klebrig ist.
Für Charles ein einfacher Trick, um nur das nächste Element in der Kette zu beeinflussen:
Hier ist ein Beispiel, wie ein Objekt verwendet werden kann, um den Status vorübergehend zu ändern und ihn dann mithilfe eines Objekts zurückzusetzen:
quelle
operator<<
für den Manipulator geeignete Wert sicher, dass der Status des Streams auf eine bestimmte Weise geändert wird. Keines der beiden Formulare richtet einen staatlichen Wachposten ein. Nur das Verhalten der nächsten formatierten Einfügeoperation bestimmt, welcher Teil des Status gegebenenfalls zurückgesetzt wird.setw
der sich anders zu verhalten scheint, ist, dass es Anforderungen an formatierte Ausgabeoperationen gibt, um.width(0)
den Ausgabestream explizit anzuzeigen.Der Grund,
width
der nicht "klebrig" zu sein scheint, ist, dass bestimmte Vorgänge garantiert.width(0)
einen Ausgabestream aufrufen . Jene sind:21.3.7.9 [lib.string.io]:
22.2.2.2.2 [lib.facet.num.put.virtuals]: Alle
do_put
Überladungen für dienum_put
Vorlage. Diese werden bei Überlastungenoperator<<
mit einembasic_ostream
und einem eingebauten numerischen Typ verwendet.22.2.6.2.2 [lib.locale.money.put.virtuals]: Alle
do_put
Überladungen für diemoney_put
Vorlage.27.6.2.5.4 [lib.ostream.inserters.character]: Überladungen von
operator<<
abasic_ostream
und eins des char-Typs der basic_ostream-Instanziierung oderchar
, signiertchar
oderunsigned char
oder Zeiger auf Arrays dieser char-Typen.Um ehrlich zu sein, bin ich mir der Gründe dafür nicht sicher, aber keine anderen Zustände von
ostream
sollten durch formatierte Ausgabefunktionen zurückgesetzt werden. Natürlich können Dinge wiebadbit
und eingestelltfailbit
werden, wenn ein Fehler in der Ausgabeoperation auftritt, aber das sollte erwartet werden.Der einzige Grund, den ich mir für das Zurücksetzen der Breite vorstellen kann, ist, dass es möglicherweise überraschend ist, wenn beim Versuch, einige begrenzte Felder auszugeben, Ihre Trennzeichen aufgefüllt wurden.
Z.B
Um dies zu "korrigieren", müsste man:
Bei einer Rücksetzbreite kann die gewünschte Ausgabe mit der kürzeren erzeugt werden:
quelle
setw()
wirkt sich nur auf die nächste Einfügung aus. Sosetw()
verhält es sich einfach . Das Verhalten vonsetw()
ist das gleiche wieios_base::width()
. Ich habe meinesetw()
Informationen von cplusplus.com erhalten .Eine vollständige Liste der Manipulatoren finden Sie hier . Von diesem Link aus sollten alle Stream-Flags gesetzt sein, bis sie von einem anderen Manipulator geändert werden. Eine Anmerkung über das
left
,right
undinternal
Manipulatoren: Sie sind wie die anderen Flaggen und sie bestehen bleiben , bis sie geändert. Sie wirken sich jedoch nur aus, wenn die Breite des Streams festgelegt ist und die Breite für jede Zeile festgelegt werden muss. So zum Beispielwürde dir geben
aber
würde dir geben
Die Eingabe- und Ausgabemanipulatoren sind nicht klebrig und treten nur einmal dort auf, wo sie verwendet werden. Die parametrisierten Manipulatoren sind jeweils unterschiedlich. Hier eine kurze Beschreibung der einzelnen:
setiosflags
Mit dieser Option können Sie Flags manuell setzen, von denen eine Liste hier als Quelle verwendet werden kann.resetiosflags
verhält sich ähnlich wie,setiosflags
außer dass die angegebenen Flags deaktiviert werden.setbase
Legt die Basis der in den Stream eingefügten Ganzzahlen fest (also wäre 17 in Basis 16 "11" und in Basis 2 "10001").setfill
Legt das Füllzeichen fest, das beisetw
Verwendung in den Stream eingefügt werden soll.setprecision
Legt die Dezimalgenauigkeit fest, die beim Einfügen von Gleitkommawerten verwendet werden soll.setw
macht nur beim nächsten Einfügen die angegebene Breite, indem es mit dem in angegebenen Feld fülltsetfill
quelle
std::hex
wird auch nicht klebrig und, natürlich,std::flush
oderstd::setiosflags
nicht klebrig ist entweder. Ich denke also nicht, dass es so einfach ist.std::hex
, nicht klebrig zu sein, war falsch - ich habe das auch gerade herausgefunden. Stream-Flags können sich jedoch ändern, selbst wenn Sie keinestd::setiosflags
erneut einfügen , sodass dies als nicht klebrig angesehen werden kann. Auchstd::ws
ist nicht klebrig. So ist es ist nicht , dass einfach.