如果我将任意数量的操纵器应用于流,是否有办法以通用方式撤消这些操纵器的应用程序?
例如,请考虑以下事项:
#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应用于流.
限制:我不能使用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)
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课是读者的练习......
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)
当然,性能稍差.完美的解决方案取决于您的具体需求.
我知道这是一个老问题,但对于后代来说:
您还可以自己编写一个简单的状态保护程序(它肯定会帮助您避免状态发生变化)。只需使用 @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)