"Roll-Back" or Undo Any Manipulators Applied to a Stream Without Knowing What the Manipulators Were

Roll-Back or Undo Any Manipulators Applied To A Stream Without Knowing What The Manipulators Were

Yes.

You can save the state and restore it:

#include <iostream>
#include <iomanip>

using namespace std;

int main()
{

std::ios state(NULL);
state.copyfmt(std::cout);

cout << "Hello" << hex << 42 << "\n";
// now i want to "roll-back" cout to whatever state it was in
// before the code above, *without* having to know what modifiers I added to it

// ... MAGIC HAPPENS! ...

std::cout.copyfmt(state);
cout << "This should not be in hex: " << 42 << "\n";
}

If you want to get back to the default state you don't even need to save the state you can extract it from a temporary object.

std::cout.copyfmt(std::ios(NULL));

How to make the format flags non-binding in C++?

Not for the standard manipulators. But in practice, you probably
shouldn't be using the standard manipulators (other than perhaps as an
example); they correspond to physical markup, and in an application, you
want to use logical markup. You want to write something like

cout << temperature << roomTemperature;

, where temperature is an application specific manipulator, defining
(globally) how temperatures are supposed to be output. That way, if the
specification changes, and requires a different format for temperatures,
you only have to change it in one place. Debugging output is somewhat
of an exception here, but even there, it's much easier to write
something like:

cout << HexFmt( 4 ) << var;

than

cout << hex << setfill( '0' ) << setw( 4 ) << var;

(And you will probably use somthing like HexFmt often enough to
justify having it in your toolbox.)

Manipulators which you write yourself can be made to restore the
previous state, at least at the end of the full expression. All of my
manipulators derive from the following class:

StateSavingManip.hh:

class StateSavingManip : boost::noncopyable
{
mutable std::ios* myStream;
mutable std::ios::fmtflags
mySavedFlags;
mutable int mySavedPrec;
mutable char mySavedFill;

private:
virtual void setState( std::ios& stream ) const = 0;

protected:
StateSavingManip();

public:
StateSavingManip( StateSavingManip const& other );
virtual ~StateSavingManip();
void operator()( std::ios& stream ) const;
};

inline std::ostream&
operator<<(
std::ostream& out,
StateSavingManip const&
manip )
{
manip( out );
return out;
}

inline std::istream&
operator>>(
std::istream& in,
StateSavingManip const&
manip )
{
manip( in );
return in;
}

StateSavingManip.cc:

namespace {

int getXAlloc();
int ourXAlloc = getXAlloc() + 1;

int
getXAlloc()
{
if ( ourXAlloc == 0 ) {
ourXAlloc = std::ios::xalloc() + 1;
assert( ourXAlloc != 0 );
}
return ourXAlloc - 1;
}
}

StateSavingManip::StateSavingManip()
: myStream( NULL )
{
}

StateSavingManip::StateSavingManip(
StateSavingManip const&
other )
{
assert( other.myStream == NULL );
}

StateSavingManip::~StateSavingManip()
{
if ( myStream != NULL ) {
myStream->flags( mySavedFlags );
myStream->precision( mySavedPrec );
myStream->fill( mySavedFill );
myStream->pword( getXAlloc() ) = NULL;
}
}

void
StateSavingManip::operator()(
std::ios& stream ) const
{
void*& backptr = stream.pword( getXAlloc() );
if ( backptr == NULL ) {
backptr = const_cast< StateSavingManip* >( this );
myStream = &stream;
mySavedFlags = stream.flags();
mySavedPrec = stream.precision();
mySavedFill = stream.fill();
}
setState( stream );
}

Which allows something simple like:

class HexFmt : public StateSavingManip
{
int myWidth;
protected:
virtual void setState( std::ios& targetStream ) const
{
targetStream.flags( std::ios::hex | std::ios::uppercase );
targetStream.width( myWidth );
targetStream.fill( '0' );
}
public:
explicit HexFmt( int width )
: myWidth( width )
{
}
};

Restore the state of std::cout after manipulating it

you need to #include <iostream> or #include <ios> then when required:

std::ios_base::fmtflags f( cout.flags() );

//Your code here...

cout.flags( f );

You can put these at the beginning and end of your function, or check out this answer on how to use this with RAII.

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

Dealing with iostream manipulators and ANSI console color codes

What is the type returned by getCode? If it isn't
std::string or char const*, all you need to do is write
a << for it which ignores the formatting data you don't want
to affect it. If it's one of C++'s string types, then you
should probably wrap the call in a special object, with an <<
for that object type, e.g.:

class ColorCode
{
ColorType myColor;
public:
ColorCode(ColorType color) : myColor( color ) {}
friend std::ostream& operator<<( std::ostream& dest, ColorCode const& cc )
{
std::string escapeSequence = getCode( myColor );
for ( char ch : escapeSequence ) {
dest.put( ch );
}
return dest;
}
};

How to clear width when outputting from a stream, after using std::setw?

Remember that the input operator >> stops reading at whitespace.

Use e.g. std::getline to get the remainder of the string:

std::stringstream ss("123ABCDEF1And then the rest of the string");
ss >> std::setw(3) >> nId
>> std::setw(6) >> sLabel
>> std::setw(1) >> bFlag;
std::getline(ss, sLeftovers);

How to remove redundancy in formatted ofstream

std::fixed, std::setprecision, and std::right are all "permanent". They set persistent flags on the stream object.

The only one that you need to put every time is setw, which (as I understand) does not set a flag on the stream object, just adds a certain amount of whitespace by altering the stream itself. But it leaves the stream alone.

This is similar to endl, which operates on the stream but leaves the actual stream object alone.

This answer by @LokiAstari on a similar question details which specifiers are, as they put it, "sticky" (and why).

EDIT: Cleared up distinctions between the stream object and the actual stream

Set back default floating point print precision in C++

You can get the precision before you change it, with std::ios_base::precision and then use that to change it back later.

You can see this in action with:

#include <ios>
#include <iostream>
#include <iomanip>

int main (void) {
double d = 3.141592653589;
std::streamsize ss = std::cout.precision();
std::cout << "Initial precision = " << ss << '\n';

std::cout << "Value = " << d << '\n';

std::cout.precision (10);
std::cout << "Longer value = " << d << '\n';

std::cout.precision (ss);
std::cout << "Original value = " << d << '\n';

std::cout << "Longer and original value = "
<< std::setprecision(10) << d << ' '
<< std::setprecision(ss) << d << '\n';

std::cout << "Original value = " << d << '\n';

return 0;
}

which outputs:

Initial precision = 6
Value = 3.14159
Longer value = 3.141592654
Original value = 3.14159
Longer and original value = 3.141592654 3.14159
Original value = 3.14159

The code above shows two ways of setting the precision, first by calling std::cout.precision (N) and second by using a stream manipulator std::setprecision(N).


But you need to keep in mind that the precision is for outputting values via streams, it does not directly affect comparisons of the values themselves with code like:

if (val1== val2) ...

In other words, even though the output may be 3.14159, the value itself is still the full 3.141592653590 (subject to normal floating point limitations, of course).

If you want to do that, you'll need to check if it's close enough rather than equal, with code such as:

if ((fabs (val1 - val2) < 0.0001) ...


Related Topics



Leave a reply



Submit