Welche iomanip-Manipulatoren sind „klebrig“?

Lesezeit: 9 Minuten

Welche iomanip Manipulatoren sind „klebrig
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.

  • Eine Arbeitsrunde finden Sie hier: stackoverflow.com/a/37495361/984471

    – Manohar Reddy Poreddy

    28. Mai 2016 um 5:04 Uhr

1646913611 329 Welche iomanip Manipulatoren sind „klebrig
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

  • Schöner Spickzettel. Fügen Sie einen Verweis hinzu, woher die Informationen stammen, und es wäre eine perfekte Antwort.

    – Markieren Sie Lösegeld

    7. Oktober 2009 um 18:07 Uhr

  • Ich kann jedoch überprüfen, dass setfill() tatsächlich “sticky” ist, obwohl es ein Objekt zurückgibt. Daher denke ich, dass diese Antwort nicht richtig ist.

    – Johannes K

    7. Oktober 2009 um 19:03 Uhr

  • Objekte, die einen Stream zurückgeben Muss klebrig sein, während diejenigen, die ein Objekt zurückgeben, klebrig sein können, aber es ist nicht erforderlich. Ich werde die Antwort mit Johns Info aktualisieren.

    – Martin York

    7. Oktober 2009 um 20:42 Uhr

  • Ich bin mir nicht sicher, ob ich deine Argumentation verstehe. Alle Manipulatoren, die Parameter annehmen, werden als freie Funktionen implementiert, die ein nicht spezifiziertes Objekt zurückgeben, das auf einen Stream wirkt, wenn dieses Objekt in den Stream eingefügt wird, da dies die einzige (?) Möglichkeit ist, die Einfüge-Syntax mit Parametern beizubehalten. So oder so, das Passende operator<< denn der Manipulator sorgt dafür, dass der Zustand des Stroms auf eine bestimmte Weise verändert wird. Keines der Formulare richtet irgendeine Art von staatlicher Wache ein. Es ist nur das Verhalten des nächsten formatierten Einfügungsvorgangs, der bestimmt, welcher Teil des Zustands zurückgesetzt wird, wenn überhaupt.

    – CB Bailey

    7. Oktober 2009 um 21:26 Uhr

  • Exakt! und der einzige Grund dafür setw scheint sich anders zu verhalten liegt daran, dass es explizit Anforderungen an formatierte Ausgabeoperationen gibt .width(0) der Ausgangsstrom.

    – CB Bailey

    8. Oktober 2009 um 10:48 Uhr

Welche iomanip Manipulatoren sind „klebrig
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 charsigniert 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';

1646913612 662 Welche iomanip Manipulatoren sind „klebrig
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

  • Nun, die meisten von ihnen setzen nur Flags, also sind diese “klebrig”. setw() scheint die einzige zu sein, die nur eine Einfügung betrifft. Genauere Informationen finden Sie jeweils unter cplusplus.com/reference/iostream/manipulators

    – David Braun

    7. Oktober 2009 um 16:31 Uhr

  • Brunnen std::hex ist auch nicht klebrig und natürlich std::flush oder std::setiosflags kleben auch nicht. Also so einfach ist das glaube ich nicht.

    – sbi

    7. Oktober 2009 um 16:42 Uhr

  • Beim Testen von hex und setiosflags() scheinen beide klebrig zu sein (beide setzen einfach Flags, die für diesen Stream bestehen bleiben, bis Sie sie ändern).

    – David Braun

    7. Oktober 2009 um 16:51 Uhr

  • Ja, die Webseite, die behauptete std::hex nicht klebrig zu sein war falsch – das habe ich auch gerade herausgefunden. Stream-Flags können sich jedoch auch ändern, wenn Sie keine einfügen std::setiosflags wieder, so dass man dies als nicht klebrig sehen könnte. Ebenfalls, std::ws klebt auch nicht. So dass es ist nicht das leicht.

    – sbi

    7. Oktober 2009 um 16:54 Uhr

  • Sie haben sich viel Mühe gegeben, Ihre Antwort zu verbessern. +1

    – sbi

    9. Oktober 2009 um 15:10 Uhr

987830cookie-checkWelche iomanip-Manipulatoren sind „klebrig“?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy