【问题标题】:How to make the format flags non-binding in C++? [duplicate]如何在 C++ 中使格式标志不绑定? [复制]
【发布时间】:2011-09-15 08:44:59
【问题描述】:

可能重复:
“Roll-Back” or Undo Any Manipulators Applied To A Stream Without Knowing What The Manipulators Were

考虑下面的代码

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

输出分别为“256”、“100”和“100”。 是否可以使“十六进制”标志不具有约束力?

我不想明确写出 'dec'。

【问题讨论】:

  • @MSalters:只是那种。这个希望隐式完成以节省打字;那个人想要很多 的事情要做,并不真正关心节省打字。的确,这个问题的解决方案相当复杂。我的意思是,这个问题的答案不适合这个问题,所以它真的可以重复吗?事实上,我希望我现在可以收回我的密切投票。
  • @Tomalak:Naveen 的答案(Boost state saver)可能与你能得到的一样接近。此外,这里有一个隐含的假设,即他想要恢复旧状态,但如果旧状态是 oct 怎么办?必须保存该状态才能恢复它。
  • @MSalters:正确答案是“不”,这些答案都没有说不。这些问题是不同的。
  • @Tomalak:如果你投票重新开放,我发现它经常跟着一堆我也投票重新开放。我可以看到这可能不是我以前的问题的重复。只有 Ronin420 可以肯定地告诉我们。
  • 说实话,我自己不知道这个问题的范围有多大。虽然我想到的问题与链接中的问题不同,很可能是由于我缺乏 C++ 知识,但它已经得到了回答。让它保持关闭状态很好。

标签: c++ hex


【解决方案1】:

不适用于标准机械手。但在实践中,你可能 不应该使用标准的操纵器(除了可能作为 例子);它们对应于物理标记,在应用程序中,您 想使用逻辑标记。你想写类似的东西

cout << temperature << roomTemperature;

,其中温度是特定于应用程序的操纵器,定义 (全球)温度应该如何输出。这样,如果 规格发生变化,并且需要不同的温度格式, 你只需要在一个地方改变它。调试输出有点 这里有一个例外,但即使在那里,写起来也容易得多 类似:

cout << HexFmt( 4 ) << var;

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

(而且你可能会经常使用像HexFmt 这样的东西来 证明把它放在你的工具箱里是合理的。)

你自己写的操纵器可以用来恢复 先前的状态,至少在完整表达式的末尾。我的所有 操纵器派生自以下类:

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 );
}

这允许一些简单的事情,例如:

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 )
    {
    }
};

【讨论】:

  • +1:James,您能否详细说明为什么在生产代码中不建议使用标准操纵器?
  • @John Dibling 我以为我有。操纵器实现标记;它们的作用很像 HTML 中的标签。标准操纵器实现物理标记。而一般来说,你想要的是逻辑标记:你不想在每次输出时都指定精度,你想指定输出的逻辑角色,并在一个地方指定该逻辑角色的精度(并且只有一个地方)在您的代码中。
【解决方案2】:

使用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;

【讨论】:

  • 当然,但是如果他不想明确写dec,那么我确定他不想这样做!
  • 好吧,它使hex 不具有约束力并且没有明确的dec,所以我说它符合规范。此外,我喜欢这个小库,我在每个场合都宣传它;)
  • 它符合问题的措辞,但不符合精神,我会说 ;)
  • 不需要 {}:boost::io::ios_flags_saver(cout), cout&lt;&lt;hex&lt;&lt;temp&lt;&lt;endl;。未命名的临时在完整表达式的末尾被销毁。基本上,该前缀表示“使格式标志仅对该表达式不具有约束力”
  • @MSalters:哦,这样更好。现在这实际上可能被认为接近这个问题的答案(尽管我仍然认为问题的精神是 OP 希望改变hex 的工作方式以避免dec,而不是增加他的代码的复杂性) .
【解决方案3】:

没有。不,这不对。 hex 棍子。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-01
    • 2020-12-12
    • 1970-01-01
    • 2021-08-22
    • 2016-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多