andrea
andrea

Reputation: 1358

ofstream reset precision

I'm using c++ to manipulate txt files. I need to write some numbers with a certain precision so I'm doing:

    ofstrem file;
    file.open(filename, ios::app);
    file.precision(6);
    file.setf(ios::fixed, ios::floafield);
    //writing number on the file.....

now I need to write other stuff, so I need to reset precision. how can I do it?

Upvotes: 8

Views: 13504

Answers (3)

James Kanze
James Kanze

Reputation: 153899

There are two possible solutions. If you're handling a large block of output which uses the same formatting parameters, you can use something like this:

class IOSave
{
    std::ios&           myStream;
    std::ios::fmtflags  myFlags;
    std::streamsize     myPrecision;
    char                myFill;
public:
    IOSave( std::ios& userStream )
        : myStream( userStream )
        , myFlags( userStream.flags() )
        , myPrecision( userStream.precision() )
        , myFill( userStream.fill() )
    {
    }
    ~IOSave()
    {
        myStream.flags( myFlags );
        myStream.precision( myPrecision );
        myStream.fill( myFill );
    }
};

Just define an instance of it at the top of the block doing the output.

Most of the time, however, I'll be defining my own manipulator, which derives from something like:

class StateSavingManipulator
{
    mutable std::ios*          myStream;
    mutable std::ios::fmtflags mySavedFlags;
    mutable int                mySavedPrec;
    mutable char               mySavedFill;

    virtual void               setState( std::ios& stream ) const = 0 ;
protected:
    StateSavingManipulator();
public:
    virtual                   ~StateSavingManipulator();
    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 ;
}

The implementation is a bit tricky, since you have to take into account that if several manipulators are used in the same expression, the compiler can construct them (and thus destruct them) in any order it pleases. So:

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

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

StateSavingManipulator::StateSavingManipulator()
    : myStream( NULL )
{
}

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

void StateSavingManipulator::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 ) ;
}

The derived manipulator then does whatever it has to in its implementation of setState. Given this, you can write things like:

std::cout << FFmt( 6, 2 ) << someValue << std::endl;

without having to worry about saving and restoring the formatting state.

Upvotes: 4

Werner
Werner

Reputation: 2557

One solution:

std::streamsize oldPres = file.precision(2);
file.setf(ios::fixed, ios::floafield);
… code continues …
file.precision(oldPres);
file.unsetf(std::ios::fixed);

Upvotes: 1

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385098

Retrieve the stream's original precision value first with precision(), store it, change it, do your insertions, then change it back to the stored value.

int main() {
   std::stringstream ss;
   ss << 1.12345 << " ";

   std::streamsize p = ss.precision();

   ss.precision(2);
   ss << 1.12345 << " ";

   ss.precision(p);
   ss << 1.12345;

   cout << ss.str();  // 1.12345 1.1 1.12345
}

Live demo.

Upvotes: 9

Related Questions