8

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?

andrea
  • 1,326
  • 7
  • 31
  • 60

3 Answers3

9

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.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • sorry I did not get it, I understood I have to do something like: int prec=file.precision(); but it does not work. I don't understand how to get the original precision – andrea Feb 08 '12 at 16:36
  • just another thing... it will also reset file.setf(ios::fixed, ios::floafield);? – andrea Feb 08 '12 at 16:45
  • @andrea `file.precision()` should return an `int`, which can later be passed to `file.precision( newValue )`. On the other hand, nothing you do with the precision will have any effect on the flags; you need to do the same thing with them. And make sure that you restore both in case of an exception. – James Kanze Feb 08 '12 at 17:16
  • The type is `std::streamsize`. It may be an integer, but write `std::streamsize` because that's what it is. – Lightness Races in Orbit Feb 08 '12 at 18:08
  • @andrea: It most certainly _does_ "work"; I have showed you how. – Lightness Races in Orbit Feb 08 '12 at 18:09
4

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.

WhatIsHeDoing
  • 541
  • 1
  • 6
  • 20
James Kanze
  • 150,581
  • 18
  • 184
  • 329
1

One solution:

std::streamsize oldPres = file.precision(2);
file.setf(ios::fixed, ios::floafield);
… code continues …
file.precision(oldPres);
file.unsetf(std::ios::fixed);
Werner
  • 2,537
  • 1
  • 26
  • 38