有没有一种好的方法来组合流操作符?

7
如果我想在流中输出一个宽度为固定的4位十六进制数,我需要像这样做:
cout << "0x" << hex << setw(4) << setfill('0') << 0xABC;

看起来有点冗长。使用宏可以帮助:

#define HEX(n) "0x" << hex << setw(n) << setfill('0')

cout << HEX(4) << 0xABC;

有没有更好的方法来组合这些操纵器?

boost有一个输出格式库:请参见https://dev59.com/knVD5IYBdhLWcg3wAWoO#119194 - Martin York
3个回答

19
尽可能避免使用宏!它们隐藏代码,使得调试变得困难,不尊重作用域等。您可以像KenE提供的那样使用简单的函数。如果您想变得花哨和灵活,那么可以编写自己的操纵器:
#include <iostream>
#include <iomanip>
using namespace std;

ostream& hex4(ostream& out)
{
    return out << "0x" << hex << setw(4) << setfill('0');
}

int main()
{
    cout << hex4 << 123 << endl;
}

这使得它更加通用。以上函数能够使用的原因是因为operator<<已经像这样被重载:ostream& operator<<(ostream&, ostream& (*funtion_ptr)(ostream&))。例如,endl和其他一些操纵符也是这样实现的。

如果您想在运行时允许指定小数位数,我们可以使用一个类:

#include <iostream>
#include <iomanip>
using namespace std;

struct formatted_hex
{
    unsigned int n;
    explicit formatted_hex(unsigned int in): n(in) {}
};

ostream& operator<<(ostream& out, const formatted_hex& fh)
{
    return out << "0x" << hex << setw(fh.n) << setfill('0');
}

int main()
{
    cout << formatted_hex(4) << 123 << endl;
}

然而,如果大小可以在编译时确定,最好使用函数模板[感谢Jon Purdy提供的建议]:

template <unsigned int N>
ostream& formatted_hex(ostream& out)
{
    return out << "0x" << hex << setw(N) << setfill('0');
}

int main()
{
    cout << formatted_hex<4> << 123 << endl;
}

3
+1 我更喜欢使用操纵器而不是自由函数,因为它似乎更能传达意图。为了使其完全通用,将其编写为模板“hex<N>”。 - Jon Purdy
我相信你在第一个例子中输入的内容不起作用。你需要写成 hex4(cout) << 123 << endl; - rlbond
@rlbond 代码可以运行,但如果有疑问请随意尝试。这是操纵符语法(endl本身是一个函数,它通过引用接受ostream参数)。它能够工作的原因是因为operator<<已经像这样重载:ostream& operator<<(ostream&, ostream& (*funtion_ptr)(ostream&))。因此,我们可以使用任何接受ostream引用并返回ostream引用的函数的地址与插入operator<< - stinky472
哇,我学到了新东西!谢谢!我认为你应该把那个解释加到你的答案里 :) - rlbond
@rlbond 不用谢! :-) 我已经把它添加到答案中了;感谢您的建议! - stinky472
显示剩余2条评论

4
为什么要使用宏,不能使用函数代替?
void write4dhex(ostream& strm, int n)
{
    strm << "0x" << hex << setw(4) << setfill('0') << n;
}

1
在C++20中,您将能够使用std::format使其更简洁:
std::cout << std::format("0x{:04x}", 0xABC);  

输出:

0x0abc

你可以轻松地通过将其存储在常量中来重复使用格式字符串。
同时,您可以使用 {fmt}库std::format基于该库。{fmt}还提供了print函数,使这一过程更加简便和高效(godbolt)。
fmt::print("0x{:04x}", 0xABC); 

免责声明: 我是 {fmt} 和 C++20 std::format 的作者。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接