149 votes

Quels manipulateurs iomanip sont "collants" ?

J'ai récemment eu un problème pour créer un stringstream en raison du fait que j'ai supposé à tort std::setw() affecterait le stringstream à chaque insertion, jusqu'à ce que je le change explicitement. Cependant, il est toujours désactivé après l'insertion.

// 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'

J'ai donc un certain nombre de questions :

  • Pourquoi est-ce que setw() de cette façon ?
  • Y a-t-il d'autres manipulateurs de cette façon ?
  • Y a-t-il une différence de comportement entre std::ios_base::width() y std::setw() ?
  • Enfin, existe-t-il une référence en ligne qui documente clairement ce comportement ? La documentation de mon fournisseur (MS Visual Studio 2005) ne semble pas le montrer clairement.

0 votes

Un tour de travail est ici : stackoverflow.com/a/37495361/984471

96voto

Loki Astari Points 116129

Remarques importantes tirées des commentaires ci-dessous :

Par Martin :

@Chareles : Alors par cette exigence, tous les manipulateurs sont collants. Sauf setw qui semble être réinitialisé après utilisation.

Par Charles :

Exactement ! et la seule raison pour laquelle setw semble se comporter différemment est qu'il y a des exigences sur les opérations de sortie formatée pour explicitement .width(0) le flux de sortie.

Voici la discussion qui a mené à la conclusion ci-dessus :


En regardant le code, les manipulateurs suivants retournent un objet plutôt qu'un flux :

setiosflags
resetiosflags
setbase
setfill
setprecision
setw

Il s'agit d'une technique courante pour appliquer une opération uniquement au prochain objet qui est appliqué au flux. Malheureusement, cela ne les empêche pas d'être collants. Les tests indiquent que tous les objets, à l'exception de setw sont collants.

setiosflags:  Sticky
resetiosflags:Sticky
setbase:      Sticky
setfill:      Sticky
setprecision: Sticky

Tous les autres manipulateurs renvoient un objet stream. Ainsi, toute information d'état qu'ils modifient doit être enregistrée dans l'objet stream et est donc permanente (jusqu'à ce qu'un autre manipulateur modifie l'état). Ainsi, les manipulateurs suivants doivent être Sticky manipulateurs.

[no]boolalpha
[no]showbase
[no]showpoint
[no]showpos
[no]skipws
[no]unitbuf
[no]uppercase

dec/ hex/ oct

fixed/ scientific

internal/ left/ right

Ces manipulateurs effectuent en fait une opération sur le flux lui-même plutôt que sur l'objet flux (bien que techniquement le flux fasse partie de l'état de l'objet flux). Mais je ne pense pas qu'ils affectent une autre partie de l'état de l'objet stream.

ws/ endl/ ends/ flush

La conclusion est que setw semble être le seul manipulateur de ma version qui ne soit pas collant.

Pour Charles, une astuce simple pour n'affecter que l'élément suivant de la chaîne :
Voici un exemple de la façon dont un objet peut être utilisé pour changer temporairement l'état puis le rétablir par l'utilisation d'un objet :

#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

0 votes

Un bon aide-mémoire. Ajoutez une référence à l'origine de l'information, et la réponse sera parfaite.

1 votes

Cependant, je peux vérifier que setfill() est en fait "collant" bien qu'il renvoie un objet. Je pense donc que cette réponse n'est pas correcte.

0 votes

Ce snippet montre que setprecision est "collant", c'est le fait que .width(0) est appelé soit directement, soit indirectement par toutes les fonctions de sortie formatées qui font que setw semble non collant. int main() { std::ostringstream a; std::cout << a.precision() << ' ' << a.width() << '\n'; a << std::setprecision(7) << std::setw(7); std::cout << a.precision() << ' ' << a.width() << '\n'; a << 5.6; std::cout << a.precision() << ' ' << a.width() << '\n'; return 0; }

31voto

Charles Bailey Points 244082

La raison pour laquelle width ne semble pas être "collante" est que certaines opérations sont garanties d'appeler .width(0) sur un flux de sortie. Ce sont :

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] : Tous do_put surcharges pour le num_put modèle. Ils sont utilisés par les surcharges de operator<< en prenant un basic_ostream et un type numérique intégré.

22.2.6.2.2 [lib.locale.money.put.virtuals] : Tous do_put surcharges pour le money_put modèle.

27.6.2.5.4 [lib.ostream.inserters.character] : Les surcharges de operator<< en prenant un basic_ostream et l'un des types suivants : char de l'instanciation basic_ostream ou char signé char o unsigned char ou des pointeurs vers des tableaux de ces types de caractères.

Pour être honnête, je ne suis pas sûr de la raison de ce choix, mais aucun autre état d'un pays de l'Union européenne n'a été créé. ostream doit être remis à zéro par les fonctions de sortie formatées. Bien sûr, des choses comme badbit y failbit peut être défini s'il y a un échec dans l'opération de sortie, mais cela devrait être attendu.

La seule raison qui me vient à l'esprit pour réinitialiser la largeur est qu'il pourrait être surprenant que, lorsque vous essayez de sortir des champs délimités, vos délimiteurs soient remplis.

Par exemple

std::cout << std::setw(6) << 4.5 << '|' << 3.6 << '\n';

"   4.5     |   3.6      \n"

Pour "corriger" cela, il faudrait :

std::cout << std::setw(6) << 4.5 << std::setw(0) << '|' << std::setw(6) << 3.6 << std::setw(0) << '\n';

alors qu'avec une largeur de remise à zéro, la sortie souhaitée peut être générée avec le plus court :

std::cout << std::setw(6) << 4.5 << '|' << std::setw(6) << 3.6 << '\n';

6voto

David Brown Points 7090

setw() n'affecte que la prochaine insertion. C'est juste la façon dont setw() se comporte. Le comportement de setw() est la même chose que ios_base::width() . J'ai eu mon setw() des informations provenant de cplusplus.com .

Vous pouvez trouver une liste complète de manipulateurs aquí . À partir de ce lien, tous les drapeaux de flux doivent rester activés jusqu'à ce qu'ils soient modifiés par un autre manipulateur. Une remarque concernant le left , right y internal manipulateurs : Ils sont comme les autres drapeaux et faire persistent jusqu'à ce qu'ils soient modifiés. Cependant, ils n'ont un effet que lorsque la largeur du flux est définie, et la largeur doit être définie à chaque ligne. Ainsi, par exemple

cout.width(6);
cout << right << "a" << endl;
cout.width(6);
cout << "b" << endl;
cout.width(6);
cout << "c" << endl;

vous donnerait

>     a
>     b
>     c

mais

cout.width(6);
cout << right << "a" << endl;
cout << "b" << endl;
cout << "c" << endl;

vous donnerait

>     a
>b
>c

Les manipulateurs d'entrée et de sortie ne sont pas collants et n'apparaissent qu'une seule fois là où ils sont utilisés. Les manipulateurs paramétrés sont tous différents, voici une brève description de chacun :

setiosflags vous permet de définir manuellement des drapeaux, dont la liste se trouve à l'adresse suivante aquí donc il est collant.

resetiosflags se comporte de la même manière que setiosflags sauf qu'il annule les drapeaux spécifiés.

setbase définit la base des entiers insérés dans le flux (ainsi 17 en base 16 serait "11", et en base 2 serait "10001").

setfill définit le caractère de remplissage à insérer dans le flux lorsque setw est utilisé.

setprecision définit la précision décimale à utiliser lors de l'insertion de valeurs à virgule flottante.

setw ne rend que l'insertion suivante de la largeur spécifiée en la remplissant avec le caractère spécifié en setfill

0 votes

Eh bien, la plupart d'entre eux sont juste des drapeaux de réglage, donc ceux-là sont "collants". setw() semble être le seul qui affecte une seule insertion. Vous pouvez trouver plus de détails sur chacune d'entre elles à l'adresse suivante cplusplus.com/reference/iostream/manipulateurs

0 votes

Bien std::hex n'est pas non plus collant et, évidemment, std::flush o std::setiosflags ne sont pas non plus collants. Donc je ne pense pas que ce soit si simple.

0 votes

Je viens de tester hex et setiosflags(), ils semblent tous deux être collants (ils définissent simplement des drapeaux qui persistent pour ce flux jusqu'à ce que vous les changiez).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X