
John K
Ich hatte kürzlich ein Problem beim Erstellen einer stringstream
aufgrund der Tatsache, dass ich falsch angenommen habe std::setw()
würde den Stringstream für jede Einfügung beeinflussen, bis ich es explizit geändert habe. Es ist 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'
Also, ich habe eine Reihe von Fragen:
- Warum ist
setw()
Hier entlang?
- Sind andere Manipulatoren so?
- Gibt es einen Unterschied im Verhalten zwischen
std::ios_base::width()
und std::setw()
?
- Gibt es schließlich eine Online-Referenz, die dieses Verhalten eindeutig dokumentiert? Meine Herstellerdokumentation (MS Visual Studio 2005) scheint dies nicht klar zu zeigen.

Martin York
Wichtige Hinweise aus den Kommentaren unten:
Von Martin:
@Chareles: Dann sind durch diese Anforderung alle Manipulatoren klebrig. Außer setw, das nach der Verwendung zurückgesetzt zu werden scheint.
Von Karl:
Exakt! und der einzige Grund, warum sich setw anders zu verhalten scheint, ist, dass es Anforderungen an formatierte Ausgabeoperationen gibt, den Ausgabestrom explizit mit .width(0) zu versehen.
Das Folgende ist die Diskussion, die zu der obigen Schlussfolgerung geführt hat:
Wenn Sie sich den Code ansehen, geben die folgenden Manipulatoren eher ein Objekt als einen Stream zurück:
setiosflags
resetiosflags
setbase
setfill
setprecision
setw
Dies ist eine gängige 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
sind klebrig.
setiosflags: Sticky
resetiosflags:Sticky
setbase: Sticky
setfill: Sticky
setprecision: Sticky
Alle anderen Manipulatoren geben ein Stream-Objekt zurück. Daher müssen alle Zustandsinformationen, die sie ändern, im Stream-Objekt aufgezeichnet werden und sind somit dauerhaft (bis ein anderer Manipulator den Zustand ändert). Also müssen die folgenden Manipulatoren sein Klebrig Manipulatoren.
[no]boolalpha
[no]showbase
[no]showpoint
[no]showpos
[no]skipws
[no]unitbuf
[no]uppercase
dec/ hex/ oct
fixed/ scientific
internal/ left/ right
Diese Manipulatoren führen tatsächlich eine Operation am Stream selbst und nicht am Stream-Objekt aus (obwohl der Stream technisch gesehen Teil des Status des Stream-Objekts ist). Aber ich glaube nicht, dass sie irgendeinen anderen Teil des Zustands von Stream-Objekten beeinflussen.
ws/ endl/ ends/ flush
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 Zustand vorübergehend zu ändern und ihn dann durch die Verwendung eines Objekts zurückzusetzen:
#include <iostream>
#include <iomanip>
// Private object constructed by the format object PutSquareBracket
struct SquareBracktAroundNextItem
{
SquareBracktAroundNextItem(std::ostream& str)
:m_str(str)
{}
std::ostream& m_str;
};
// New Format Object
struct PutSquareBracket
{};
// Format object passed to stream.
// All it does is return an object that can maintain state away from the
// stream object (so that it is not STICKY)
SquareBracktAroundNextItem operator<<(std::ostream& str,PutSquareBracket const& data)
{
return SquareBracktAroundNextItem(str);
}
// The Non Sticky formatting.
// Here we temporariy set formating to fixed with a precision of 10.
// After the next value is printed we return the stream to the original state
// Then return the stream for normal processing.
template<typename T>
std::ostream& operator<<(SquareBracktAroundNextItem const& bracket,T const& data)
{
std::ios_base::fmtflags flags = bracket.m_str.flags();
std::streamsize currentPrecision = bracket.m_str.precision();
bracket.m_str << '[' << std::fixed << std::setprecision(10) << data << std::setprecision(currentPrecision) << ']';
bracket.m_str.flags(flags);
return bracket.m_str;
}
int main()
{
std::cout << 5.34 << "\n" // Before
<< PutSquareBracket() << 5.34 << "\n" // Temp change settings.
<< 5.34 << "\n"; // After
}
> ./a.out
5.34
[5.3400000000]
5.34

CB Bailey
Der Grund dass width
nicht ‘klebrig’ zu sein scheint, ist, dass bestimmte Operationen garantiert aufgerufen werden .width(0)
auf einem Ausgangsstrom. Jene sind:
21.3.7.9 [lib.string.io]:
template<class charT, class traits, class Allocator>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& os,
const basic_string<charT,traits,Allocator>& str);
22.2.2.2.2 [lib.facet.num.put.virtuals]: Alle do_put
Überladungen für die num_put
Vorlage. Diese werden von Überladungen von verwendet operator<<
ein Nehmen basic_ostream
und ein eingebauter numerischer Typ.
22.2.6.2.2 [lib.locale.money.put.virtuals]: Alle do_put
Überladungen für die money_put
Vorlage.
27.6.2.5.4 [lib.ostream.inserters.character]: Überlastungen von operator<<
ein Nehmen basic_ostream
und einer vom char-Typ der basic_ostream-Instanziierung oder char
signiert char
oder unsigned char
oder Zeiger auf Arrays dieser Zeichentypen.
Um ehrlich zu sein, bin ich mir der Begründung dafür nicht sicher, aber keine anderen Zustände von an ostream
sollten durch formatierte Ausgabefunktionen zurückgesetzt werden. Natürlich Dinge wie badbit
und failbit
kann gesetzt werden, wenn bei der Ausgabeoperation ein Fehler auftritt, aber das sollte erwartet werden.
Der einzige Grund, der mir für das Zurücksetzen der Breite einfällt, ist, dass es überraschend sein könnte, wenn beim Versuch, einige getrennte Felder auszugeben, Ihre Trennzeichen aufgefüllt wurden.
Z.B
std::cout << std::setw(6) << 4.5 << '|' << 3.6 << '\n';
" 4.5 | 3.6 \n"
Um dies zu “korrigieren”, würde Folgendes dauern:
std::cout << std::setw(6) << 4.5 << std::setw(0) << '|' << std::setw(6) << 3.6 << std::setw(0) << '\n';
wohingegen bei einer Rückstellbreite mit der kürzeren die gewünschte Leistung erzeugt werden kann:
std::cout << std::setw(6) << 4.5 << '|' << std::setw(6) << 3.6 << '\n';

David Braun
setw()
wirkt sich nur auf das nächste Einfügen aus. Das ist halt so setw()
verhält. Das Verhalten von setw()
ist das gleiche wie ios_base::width()
. Ich habe meine setw()
Information von cplusplus.com.
Hier finden Sie eine vollständige Liste der Manipulatoren Hier. Von diesem Link aus sollten alle Stream-Flags gesetzt sein, bis sie von einem anderen Manipulator geändert werden. Eine Anmerkung zu den left
, right
und internal
Manipulatoren: Sie sind wie die anderen Flaggen und tun bleiben bestehen, bis sie geändert werden. Sie wirken sich jedoch nur dann aus, wenn die Breite des Streams festgelegt ist, und die Breite muss für jede Zeile festgelegt werden. Also zum Beispiel
cout.width(6);
cout << right << "a" << endl;
cout.width(6);
cout << "b" << endl;
cout.width(6);
cout << "c" << endl;
würde dir geben
> a
> b
> c
aber
cout.width(6);
cout << right << "a" << endl;
cout << "b" << endl;
cout << "c" << endl;
würde dir geben
> a
>b
>c
Die Eingabe- und Ausgabemanipulatoren sind nicht klebrig und treten nur einmal dort auf, wo sie verwendet werden. Die parametrisierten Manipulatoren sind jeweils unterschiedlich, hier ist eine kurze Beschreibung von jedem:
setiosflags
ermöglicht das manuelle Setzen von Flags, von denen eine Liste gefunden werden kann Hieres ist also klebrig.
resetiosflags
verhält sich ähnlich wie setiosflags
außer es setzt die angegebenen Flags zurück.
setbase
legt die Basis der in den Stream eingefügten Ganzzahlen fest (also wäre 17 zur Basis 16 „11“ und zur Basis 2 „10001“).
setfill
legt das Füllzeichen fest, das in den Stream eingefügt werden soll, wenn setw
wird genutzt.
setprecision
legt die Dezimalgenauigkeit fest, die beim Einfügen von Fließkommawerten verwendet werden soll.
setw
macht erst beim nächsten Einfügen die angegebene Breite durch Füllen mit dem in angegebenen Zeichen setfill
9878300cookie-checkWelche iomanip-Manipulatoren sind „klebrig“?yes
Eine Arbeitsrunde finden Sie hier: stackoverflow.com/a/37495361/984471
– Manohar Reddy Poreddy
28. Mai 2016 um 5:04 Uhr