The usual solution in C++ is to defined manipulators which state
what your trying to format, rather than to hack physical values
directly at the point of output. (One possible exception is the
width, where std::setw
may be useful directly.) Thus, for
example, when actually outputting something, you won't specify
zero padding, or fixed, with 2 decimals, but something like:
std::cout << temperature(2) << theTemporature;
where temperature
would be something like:
class temperature
{
int myMinWidth;
public:
temperature( int minWidth )
: myMinWidth( minWidth )
{
}
friend std::ostream& operator<<( std::ostream& dest, temperature const& manip )
{
dest.setf( std::ios_base::fixed, std::ios_base::floatfield );
dest.precision( 2 );
dest.width( myMinWidth );
return dest;
}
};
For the list of format modifications available, see the
specification of std::ios_base
, and the fields of
std::ios_base::fmtflags
.
If you're doing a lot of output, you might want to modify this
to restore the original format flags at the end of the full
expression. (All of the format information except the width is
sticky, so forcing fixed format here leaves you with fixed
format for the rest of the program, which isn't necessarily what
you want.) I use the following as base class for all of my
manipulators:
class StateSavingManip
{
public:
void operator()( std::ios& stream ) const;
protected:
StateSavingManip() : myStream( nullptr ) {}
~StateSavingManip();
private:
virtual void setState( std::ios& stream ) const = 0;
private:
mutable std::ios* myStream;
mutable std::ios::fmtflags mySavedFlags;
mutable int mySavedPrec;
mutable char mySavedFill;
};
implementation:
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()
{
if ( myStream != nullptr ) {
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 == nullptr ) {
backptr = const_cast< StateSavingManip* >( this ) ;
myStream = &stream ;
mySavedFlags = stream.flags() ;
mySavedPrec = stream.precision() ;
mySavedFill = stream.fill() ;
}
setState( stream ) ;
}
Note the use of the pword
field to ensure that only the first
temporary manipulator restores the format; the destructors will
be called in the reverse order of construction, but the order of
construction will typically not be specified if you have more
than one such manipulator in an expression.
Finally: not everything is possible using this technique: if you
want to systematically append a degree sign to the temperature,
there's no way of doing so. In this case, you need to define
a class Temperature, and overload the <<
operator for it; this
allows everything imaginable (much more than you could ever
achieve with printf
style formatting).