I created a Vector
class in C++ and it works great for my problems. I am now cleaning it up, and I ran into the following piece of code:
std::ostream& operator<<(std::ostream &output, const Vector &v){
output<<"["
<<std::setiosflags(std::ios::right | std::ios::scientific)
<<std::setw(23)
<<std::setprecision(16)
<<v._x<<", "
<<std::setiosflags(std::ios::right | std::ios::scientific)
<<std::setw(23)
<<std::setprecision(16)
<<v._y<<", "
<<std::setiosflags(std::ios::right | std::ios::scientific)
<<std::setw(23)
<<std::setprecision(16)
<<v._z<<"]";
return output;
}
The code allows to print a vector as std::cout<<v<<std::endl;
. Each number has 23 spaces, of which 16 are the decimals. The text is right-aligned so that it will print:
1.123456123456e+01
-1.123456123456e+01
Instead of
1.123456123456e+01
-1.123456123456e+01
The code seems awfully repetitive. How can you "store" the format (all the setiosflags
, setw
and setprecision
statements) such that you can say something like "print the characters in a standard way, but the numbers with this given format".
Thank you!
Edit
As per Rob Adams' comment, I changed my ugly code (which, as pointed out by others, would mess up the precision for the "next guy") to a more succinct (and correct):
std::ostream& operator<<(std::ostream &output, const Vector &v){
std::ios_base::fmtflags f = output.flags(std::ios::right | std::ios::scientific);
std::streamsize p = output.precision(16);
output<<"["
<<std::setw(23)<<v._x<<", "
<<std::setw(23)<<v._y<<", "
<<std::setw(23)<<v._z
<<"]";
output.flags(f);
output.precision(p);
return output;
}
Everything but the setw() actually do that already. They are "sticky".
Your real problem is what happens to the next output after this one...
Only
std::setw()
is temporary. The other two calls,setiosflags
, andsetprecision
have a permanent effect.So, you could change your code to :
But now you've borked the flags and precision for the next guy. Try this instead:
Finally, if you absolutely have to get rid of the duplication of the constant
23
, you could do something like this (but I wouldn't recommend it):See also this other question, where they decided that you can't make width permanent.
Generally, you don't use the standard manipulators directly. In this case, for example, you might define a manipulator fromVector, and use that:
That way, if you want to change the width and precision of elements in the vector, you only have to do it in one place.
In this case, where the manipulator has no arguments, all that's needed is a simple function:
Of course, this will have changed most of the formatting for any later user. In general, it would be better practice to use a temporary class object which saves the state, and restores it in the destructor. I usually derive my manipulators from something like:
header: class StateSavingManip { public: StateSavingManip( StateSavingManip const& other ) ;
source: int getXAlloc() ; int ourXAlloc = getXAlloc() + 1 ;
If you do this, you'll have to add parentheses after the manipulator, e.g.:
(I'm sure that some clever soul will figure out a way of avoiding them, but they've never bothered me, so I haven't bothered.)