假设我有这样的代码:
void printHex(std::ostream& x){
x<<std::hex<<123;
}
..
int main(){
std::cout<<100; // prints 100 base 10
printHex(std::cout); //prints 123 in hex
std::cout<<73; //problem! prints 73 in hex..
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,在从函数返回后,是否有任何方法可以将cout的状态"恢复"到原来的状态?(有点像std :: boolalpha和std :: noboolalpha ..)?
谢谢.
Ste*_*all 82
您需要#include <iostream>
或#include <ios>
在需要时:
std::ios_base::fmtflags f( cout.flags() );
//Your code here...
cout.flags( f );
Run Code Online (Sandbox Code Playgroud)
您可以将这些放在函数的开头和结尾,或者查看关于如何在RAII中使用它的答案.
Chr*_*ung 60
该升压IO流状态节电器似乎正是你需要的.:-)
基于代码段的示例:
void printHex(std::ostream& x) {
boost::io::ios_flags_saver ifs(x);
x << std::hex << 123;
}
Run Code Online (Sandbox Code Playgroud)
rr-*_*rr- 40
请注意,此处提供的答案不会恢复完整状态std::cout
.例如,std::setfill
即使在打电话后也会"坚持" .flags()
.更好的解决方案是使用.copyfmt
:
std::ios oldState(nullptr);
oldState.copyfmt(std::cout);
std::cout
<< std::hex
<< std::setw(8)
<< std::setfill('0')
<< 0xDECEA5ED
<< std::endl;
std::cout.copyfmt(oldState);
std::cout
<< std::setw(15)
<< std::left
<< "case closed"
<< std::endl;
Run Code Online (Sandbox Code Playgroud)
将打印:
case closed
Run Code Online (Sandbox Code Playgroud)
而不是:
case closed0000
Run Code Online (Sandbox Code Playgroud)
qbe*_*220 21
我使用此答案中的示例代码创建了一个RAII类.如果你有一个在iostream上设置标志的函数有多个返回路径,那么这个技术的最大优势就来了.无论使用哪个返回路径,都将始终调用析构函数,并始终重置标志.函数返回时,没有机会忘记恢复标志.
class IosFlagSaver {
public:
explicit IosFlagSaver(std::ostream& _ios):
ios(_ios),
f(_ios.flags()) {
}
~IosFlagSaver() {
ios.flags(f);
}
IosFlagSaver(const IosFlagSaver &rhs) = delete;
IosFlagSaver& operator= (const IosFlagSaver& rhs) = delete;
private:
std::ostream& ios;
std::ios::fmtflags f;
};
Run Code Online (Sandbox Code Playgroud)
然后,只要您想保存当前标志状态,就可以通过创建IosFlagSaver的本地实例来使用它.当此实例超出范围时,将恢复标志状态.
void f(int i) {
IosFlagSaver iosfs(std::cout);
std::cout << i << " " << std::hex << i << " ";
if (i < 100) {
std::cout << std::endl;
return;
}
std::cout << std::oct << i << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
通过一些修改使输出更具可读性:
void printHex(std::ostream& x) {
ios::fmtflags f(x.flags());
x << std::hex << 123 << "\n";
x.flags(f);
}
int main() {
std::cout << 100 << "\n"; // prints 100 base 10
printHex(std::cout); // prints 123 in hex
std::cout << 73 << "\n"; // problem! prints 73 in hex..
}
Run Code Online (Sandbox Code Playgroud)
std::format
在大多数情况下,C++20将是保存恢复的更好选择
一旦你可以使用它,你就可以简单地编写十六进制:
#include <format>
#include <string>
int main() {
std::cout << std::format("{x} {#x} {}\n", 16, 17, 18);
}
Run Code Online (Sandbox Code Playgroud)
预期输出:
10 0x11 18
Run Code Online (Sandbox Code Playgroud)
因此,这将完全克服修改std::cout
状态的疯狂。
更多信息请访问:C++ cout hex values?
您可以在stdout缓冲区周围创建另一个包装器:
#include <iostream>
#include <iomanip>
int main() {
int x = 76;
std::ostream hexcout (std::cout.rdbuf());
hexcout << std::hex;
std::cout << x << "\n"; // still "76"
hexcout << x << "\n"; // "4c"
}
Run Code Online (Sandbox Code Playgroud)
在函数中:
void print(std::ostream& os) {
std::ostream copy (os.rdbuf());
copy << std::hex;
copy << 123;
}
Run Code Online (Sandbox Code Playgroud)
当然,如果性能是一个问题,那会贵一点,因为它会复制整个ios
对象(而不是缓冲区),其中包括您要付费但不太可能使用的某些内容,例如语言环境。
否则,我觉得如果您要使用.flags()
它,则最好保持一致并使用它.setf()
,而不要使用<<
语法(纯粹的样式问题)。
void print(std::ostream& os) {
std::ios::fmtflags os_flags (os.flags());
os.setf(std::ios::hex);
os << 123;
os.flags(os_flags);
}
Run Code Online (Sandbox Code Playgroud)
正如其他人所说,您可以将上述内容(和.precision()
和.fill()
,但通常不包括与语言环境和单词相关的东西,这些东西通常不会被修改且较重)放在一个类中,以方便使用并使其异常安全;构造函数应该接受std::ios&
。
归档时间: |
|
查看次数: |
33662 次 |
最近记录: |