"回滚"或撤消任何适用于流的操纵器,而不知道机器人是什么

Joh*_*ing 35 c++

如果我将任意数量的操纵器应用于流,是否有办法以通用方式撤消这些操纵器的应用程序?

例如,请考虑以下事项:

#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
    cout << "Hello" << hex << 42 << "\n";
    // now i want to "roll-back" cout to whatever state it was in
    // before the code above, *without* having to know 
    // what modifiers I added to it

    // ... MAGIC HAPPENS! ...

    cout << "This should not be in hex: " << 42 << "\n";
}
Run Code Online (Sandbox Code Playgroud)

假设我想添加代码MAGIC HAPPENS,将流操纵器的状态恢复到我之前的状态cout << hex.我不知道我添加了什么操纵器.我怎么能做到这一点?

换句话说,我希望能够写出这样的东西(psudocode/fantasy code):

std::something old_state = cout.current_manip_state();
cout << hex;
cout.restore_manip_state(old_state);
Run Code Online (Sandbox Code Playgroud)

这可能吗?

编辑:

如果你很好奇,我有兴趣在operator<<()我为复杂类型编写的自定义中这样做.类型是一种区分联合,不同的值类型将有不同的manips应用于流.

EDIT2:

限制:我不能使用Boost或任何其他第三方库.解决方案必须采用标准C++.

Mar*_*ork 58

是.

您可以保存状态并将其恢复:

#include <iostream>
#include <iomanip>

using namespace std;

int main()
{

    std::ios  state(NULL);
    state.copyfmt(std::cout);

    cout << "Hello" << hex << 42 << "\n";
    // now i want to "roll-back" cout to whatever state it was in
    // before the code above, *without* having to know what modifiers I added to it

  // ... MAGIC HAPPENS! ...

    std::cout.copyfmt(state);
    cout << "This should not be in hex: " << 42 << "\n";
}
Run Code Online (Sandbox Code Playgroud)

如果要返回默认状态,甚至不需要保存状态,可以从临时对象中提取状态.

std::cout.copyfmt(std::ios(NULL));
Run Code Online (Sandbox Code Playgroud)

  • @Zereges:因为这段代码是在2010年`nulllptr`存在之前编写的. (2认同)

CB *_*ley 16

标准操纵器都操纵流的格式标志,精度和宽度设置.无论如何,宽度设置由大多数格式化的输出操作重置.这些都可以像这样检索:

std::ios_base::fmtflags saveflags = std::cout.flags();
std::streamsize prec = std::cout.precision();
std::streamsize width = std::cout.width();
Run Code Online (Sandbox Code Playgroud)

并恢复:

std::cout.flags( saveflags );
std::cout.precision( prec );
std::cout.width( width );
Run Code Online (Sandbox Code Playgroud)

把它变成RAII课是读者的练习......

  • +1提及RAII (5认同)

Nav*_*een 13

提升IO状态保护程序可能会有所帮助.

http://www.boost.org/doc/libs/1_40_0/libs/io/doc/ios_state.html


fre*_*low 13

保存和恢复状态不是例外安全的.我建议把所有东西都变成一个stringstream,最后你把它放在真正的流上(它根本没有改变它的标志).

#include <iostream>
#include <iomanip>
#include <sstream>

int main()
{
    std::ostringstream out;
    out << "Hello" << std::hex << 42 << "\n";
    std::cout << out.str();

    // no magic necessary!

    std::cout << "This should not be in hex: " << 42 << "\n";
}
Run Code Online (Sandbox Code Playgroud)

当然,性能稍差.完美的解决方案取决于您的具体需求.

  • +1好建议.唉这个代码每秒可能被调用500万次,所以我宁愿不构造一个新的流:) (2认同)

Ore*_*n S 6

我知道这是一个老问题,但对于后代来说:

您还可以自己编写一个简单的状态保护程序(它肯定会帮助您避免状态发生变化)。只需使用 @loki 建议的解决方案,并从对象的构造函数/析构函数(简称:RAII)中运行它,如下所示:

class stateSaver
{
  public:
    stateSaver(ostream& os): stream_(os), state_(nullptr) { state_.copyfmt(os); }
    ~stateSaver() { stream_.copyfmt(state_); }
  private:
    std::ios state_;
    ostream& stream_;
};
Run Code Online (Sandbox Code Playgroud)

然后,您将像这样使用它:

void myFunc() {
    stateSaver state(cout);
    cout << hex << 42 << endl; // will be in hex
}

int main() {
    cout << 42 << endl; // will be in dec
    myFunc();
    cout << 42 << endl; // will also be in dec
}
Run Code Online (Sandbox Code Playgroud)