What is the output of this C++ program?
#include <stdio.h>
#include <iostream>
#include <iomanip>
using namespace std;
main()
{
printf("%05d\n", -3);
cout << setw(5) << setfill('0') << -3 << endl;
}
It turns out that it is:
-0003
000-3
To get the numbers where you'd like them to be, you do it this way:
printf("%05d\n", -3);
cout << setw(5) << setfill('0') << internal -3 << endl;
Compare with C to see why C++ iostream is not really that much used. Also, setfill and internal are persistently changing the state of the stream, contributing fancy and interesting side effects:
cout << setw(5) << setfill('0') << internal << -3 << endl;
cout << setw(10) << "ciao" << endl;
this prints:
-0003
000000ciao
and I didn't see any sort of
RAII save and
restore of the stream state, nor a particularly obvious way to reset the stream
to factory settings. Suppose that the function foo
throws an exception here:
try {
cout << setfill('=');
cout << setw(10) << foo() << endl;
cout << setfill(' ');
} catch (MyException& e) {
// Catch this hypotetical exception
cerr << setw(3) << e.errCode() << ": " << e.msg() << endl;
}
Then the state of the stream never gets reset, and the error code ends up being padded with equals instead of the default space. What would the alternative be, reset the stream state after each function call in the code? Or am I missing something?
Update: here are some suggested, but still not optimal, ways of dealing with it:
From Simon Richter:
std::cout << (std::stringstream() << "foo" << std::setw(8) << "bar").rdbuf() << std::endl;
From Peter De Wachter:
fstream tmp;
tmp.copyfmt(cout);
cout << setw(5) << setfill('0') << internal << -3 << endl;
cout.copyfmt(tmp);
cout << setw(10) << "ciao" << endl;
This is a possible RAII class to save the stream state (based on Peter De Watcher's approach), but I suspect that creating a fstream for every block that uses iomanip operators is rather heavyweight:
struct SaveIOState
{
fstream tmp;
ostream& s;
SaveIOState(ostream& s) : s(s)
{
tmp.copyfmt(s);
}
~SaveIOState()
{
s.copyfmt(tmp);
}
};
And this is a lightweight version, again thanks to Sylvain Sauvage:
class SaveIOState
{
ios_base& s;
ios_base::fmtflags f;
public:
SaveIOState(ios_base& s) : s(s), f(s.flags())
{}
~SaveIOState()
{
s.flags(f);
}
};