开发者

How to make the format flags non-binding in C++? [duplicate]

开发者 https://www.devze.com 2023-04-04 20:13 出处:网络
This question already has answers here: 开发者_开发百科Closed 11 years ago. Possible Duplicate: “Roll-Back” or Undo Any Manipulators Applied To A Stream Without Knowing What The Ma
This question already has answers here: 开发者_开发百科 Closed 11 years ago.

Possible Duplicate:

“Roll-Back” or Undo Any Manipulators Applied To A Stream Without Knowing What The Manipulators Were

Consider the following code

int temp=256;
cout<<temp<<endl;
cout<<hex<<temp<<endl;
cout<<temp<<endl;

The output is "256","100" and "100" respectively. Is it possible to make the 'hex' flag non-binding?

I do not wish to write 'dec' explicitly.


Not for the standard manipulators. But in practice, you probably shouldn't be using the standard manipulators (other than perhaps as an example); they correspond to physical markup, and in an application, you want to use logical markup. You want to write something like

cout << temperature << roomTemperature;

, where temperature is an application specific manipulator, defining (globally) how temperatures are supposed to be output. That way, if the specification changes, and requires a different format for temperatures, you only have to change it in one place. Debugging output is somewhat of an exception here, but even there, it's much easier to write something like:

cout << HexFmt( 4 ) << var;

than

cout << hex << setfill( '0' ) << setw( 4 ) << var;

(And you will probably use somthing like HexFmt often enough to justify having it in your toolbox.)

Manipulators which you write yourself can be made to restore the previous state, at least at the end of the full expression. All of my manipulators derive from the following class:

StateSavingManip.hh:

class StateSavingManip : boost::noncopyable
{
    mutable std::ios*   myStream;
    mutable std::ios::fmtflags
                        mySavedFlags;
    mutable int         mySavedPrec;
    mutable char        mySavedFill;

private:
    virtual void        setState( std::ios& stream ) const = 0;

protected:
    StateSavingManip();

public:
    StateSavingManip( StateSavingManip const& other );
    virtual             ~StateSavingManip();
    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;
}

StateSavingManip.cc:

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()
    :   myStream( NULL )
{
}

StateSavingManip::StateSavingManip(
    StateSavingManip const&
                        other )
{
    assert( other.myStream == NULL );
}

StateSavingManip::~StateSavingManip()
{
    if ( myStream != NULL ) {
        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 == NULL ) {
        backptr      = const_cast< StateSavingManip* >( this );
        myStream     = &stream;
        mySavedFlags = stream.flags();
        mySavedPrec  = stream.precision();
        mySavedFill  = stream.fill();
    }
    setState( stream );
}

Which allows something simple like:

class HexFmt : public StateSavingManip
{
    int                 myWidth;
protected:
    virtual void        setState( std::ios& targetStream ) const
    {
        targetStream.flags( std::ios::hex | std::ios::uppercase );
        targetStream.width( myWidth );
        targetStream.fill( '0' );
    }
public:
    explicit            HexFmt( int width )
        : myWidth( width )
    {
    }
};


Use the Boost I/O Streams-State Saver Library:

int temp=256;
cout<<temp<<endl;
{
    boost::io::ios_flags_saver saveflags(cout);
    cout<<hex<<temp<<endl;
}
cout<<temp<<endl;


No. No, it's not. hex sticks.

0

精彩评论

暂无评论...
验证码 换一张
取 消