Which Iomanip Manipulators Are 'Sticky'

Which iomanip manipulators are 'sticky'?

Important notes from the comments below:

By Martin:

@Chareles: Then by this requirement all manipulators are sticky. Except setw which seems to be reset after use.

By Charles:

Exactly! and the only reason that setw appears to behave differently is because there are requirements on formatted output operations to explicitly .width(0) the output stream.

The following is the discussion that lead to the above conclusion:


Looking at the code the following manipulators return an object rather than a stream:

setiosflags
resetiosflags
setbase
setfill
setprecision
setw

This is a common technique to apply an operation to only the next object that is applied to the stream. Unfortunately this does not preclude them from being sticky. Tests indicate that all of them except setw are sticky.

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

All the other manipulators return a stream object. Thus any state information they change must be recorded in the stream object and is thus permanent (until another manipulator changes the state). Thus the following manipulators must be Sticky manipulators.

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

dec/ hex/ oct

fixed/ scientific

internal/ left/ right

These manipulators actually perform an operation on the stream itself rather than the stream object (Though technically the stream is part of the stream objects state). But I do not believe they affect any other part of the stream objects state.

ws/ endl/ ends/ flush

The conclusion is that setw seems to be the only manipulator on my version that is not sticky.

For Charles a simple trick to affect only the next item in the chain:

Here is an Example how an object can be used to temporaily change the state then put it back by the use of an object:

#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

Is There an Official Resource for Sticky Manipulators

Not "official", but cppreference.com says, in std::setw

The width property of the stream will be reset to zero (meaning "unspecified") if any of the following functions are called:

  • Input

    1. operator>>(basic_istream&, basic_string&)

    2. operator>>(basic_istream&, char*)

  • Output

    1. Overloads 1-7 of basic_ostream::operator<<() (at Stage 3 of num_put::put()) (1-7 are the integer, boolean, and pointer overloads)

    2. operator<<(basic_ostream&, char) and operator<<(basic_ostream&, char*)

    3. operator<<(basic_ostream&, basic_string&)

    4. std::put_money (inside money_put::put())

    5. std::quoted (when used with an output stream)

As the edit history in cppreference says, this list was compiled by grepping the standard draft for "width"

All other manipulators are "sticky", as in, the stream state changes they perform persist until explicitly changed again.

How can I make my function sticky for overloaded iostream extraction operators

The width is handled specially: all of the built-in operators will reset the width after outputting an object. The fact that you don't see a corresponding call to width(0) in the code or the debugger doesn't mean it isn't there! It may be inlined and not hit a breakpoint, for exampke. With respect to the code you'd need to look, e.g., in the implementation of std::num_put<...>: the actual output operator doesn't include the code but the do_put() functions do.

To reset other formatting flags you'd need to hook into some operation called after each output operation. There isn't much opportunity, though: the streams din't support generic customization after each object. Below are things which can be done but I would recomment leaving formatting flags sticky. It is arguably a mistake to make the width special:

  • The numeric formatting is done via the do_put() virtual functions in std::num_put<cT>. These functiins can be overridden and, e.g., do the normal formatting by delegating to the base class implementation, followed by something else.

    The key problem with this approach in your setting is that it does not work with non-numeric output. For example, outputting strings wouldn't reset anything.

  • It is possible to set the formatting flag std::unitbuf causing a flush after each [correctly written] output operator. The flush is translated into a call of pubsync() and eventually sync() on the streams std::basic_streambuf<cT>. The sync() function can be overridden. That is, the approach would be installing a custom stream buffer and the flag std::ios_base::unitbuf when setting up sone flags which sends output to the original stream and on call to sync() resets flags.

    Aside from being a bit contrived it has the problem that you can't distinguish a genuine flush from the automatic flush (the primary purpose of srd::ios_base::unitbuf is to get std::cerr flushed). Also, the reset happens on the first std::ostream::sentry being destroyed. For composite values that is most likely after the first portion being formatted.

  • The colour formatter uses a temporary object anyway. The dstructor of this object could be used to reset some fornatting flags. The output operator would set the necessary stream information on the corresponding object when it get "formatted" (probably using a mutable member). Of course, this means that setting the format and output need to be done from the same statement. Also, all output on the same statement receives the same format.

I'm not aware of any other approach to deal with formatting after some output. None of the approaches works particular well. I'd rather use a guard-like approach to set/unset flags than trying to be clever.

iomanip / fixed width persistence

Unfortunately you've wandered into one of the areas of the standard that's a little archaic and seemingly without any overarching design goals.

This is undoubtedly historic as the iostreams library AFAIAA, was not originally part of the STL which is what became the standard library.

It's worth reading the notes on all std::ios_base members and the associated manipulators.

For example:

http://en.cppreference.com/w/cpp/io/ios_base/width

Some I/O functions call width(0) before returning, see std::setw (this results in this field having effect on the next I/O function only, and not on any subsequent I/O)

The exact effects this modifier has on the input and output vary between the individual I/O functions and are described at each operator<< and operator>> overload page individually.

Anticipating:

But that's just <insert expletive>!!!

A: yup.

CPP Setfill() repeats itself in second and other steps of for loop

std::setfill is a "sticky" manipulator: it will change the state of the ostream until it is reverted.

If you revert it after you print your first number, you will get the expected output:

for (i; i < 10; i++) {
for (j = 1; j < 10; j++)
cout << setw(3) << i*j << setfill(' ');
cout << endl << setw(3) << setfill('x');
}

live example on wandbox.org

Having trouble with iomanip, columns not lining up the way I expect

It doesn't work as you think. std::setw sets the width of the field only for the next insertion (i.e., it is not "sticky").

Try something like this instead:

#include <iostream>
#include <iomanip>

using namespace std;

int main() {

cout << "Student Grade Summary\n";
cout << "---------------------\n\n";
cout << "BIOLOGY CLASS\n\n";

cout << left << setw(42) << "Student" // left is a sticky manipulator
<< setw(8) << "Final" << setw(6) << "Final"
<< "Letter" << "\n";
cout << setw(42) << "Name"
<< setw(8) << "Exam" << setw(6) << "Avg"
<< "Grade" << "\n";
cout << setw(62) << setfill('-') << "";
cout << setfill(' ') << "\n";
cout << setw(42) << "bill joeyyyyyyy"
<< setw(8) << "89" << setw(6) << "21.00"
<< "43" << "\n";
cout << setw(42) << "Bob James"
<< setw(8) << "89" << setw(6) << "21.00"
<< "43" << "\n";
}

Also related: What's the deal with setw()?

C++ setiosflags function manipulator - undetermined indentation

std::ios::left tells to add fill characters to the right, i.e. it adds few characters to first string, so "Mathieu\n" "becomes" "Mathieu\n ". There is new line character at the end ('\n'), so added spaces are moved to next line (Gauthier). So it's not indentation of second line, those are trailing characters from first.



Related Topics



Leave a reply



Submit