#include<algorithm>
#include<iostream>
using namespace std;
int main()
{
cout << (uint8_t)123 << endl;
}
这将输出
{
,因为 {
的 ASCII 是 123。
但我想得到
123
。我发现 cout << (int)123 << endl;
可以做到这一点,但我不愿意每次都将 uint_8
转换为 int
。我可以配置 cout
来实现此目的吗?
我绝对不会容忍我即将提出的解决方案。 我还怀疑标准可能不允许它,但到目前为止我还无法证明这一点。 如果有人可以给我提供一个参考,表明这是不允许的,那么我会删除这个答案。 不管怎样,到目前为止我的测试表明,简单地在全局范围内重载运算符似乎是可行的。
#include <iostream>
#include <cstdint>
std::ostream & operator<<(std::ostream & os, std::uint8_t val)
{
return os << static_cast<int>(val);
}
int main()
{
std::uint8_t val = 123;
std::cout << val;
}
我没想到这会起作用,但后来我意识到
char/unsigned char/signed char
的 operator<<
重载都是 ADL 选取的 std
命名空间中的自由函数。 我猜全局函数被认为比 ADL 函数更匹配,但我对此不确定。
从 C++17 开始,一个合理的解决方案可能是将
std::uint8_t
替换为 std::byte
。这不会使其行为如您所期望的那样,但会防止隐式解释为 char
/signed char
/unsigned char
或 任何数字类型。根据 cppreference:
是一种独特的类型,它实现了 C++ 语言定义中指定的字节概念。std::byte
与
一样,它可以用来访问其他对象(对象表示)占用的原始内存,但与unsigned char
不同的是,它不是字符类型,也不是算术类型。unsigned char
仅模拟位的集合,仅支持与整数的位移操作,以及与另一个std::byte
的按位和比较操作。std::byte
这样,它就不会被隐式/无意地解释为字符或整数,如果您尝试这样做,您将收到编译器错误。修复它们将涉及显式转换,但这些转换本质上是零成本(在幕后,它仍然存储为 unsigned char
值,它只是使用
enum class
使其成为不同的类型)。您有两个选择:
,您可以为 std::ostream & operator<<(std::ostream & os, std::byte val)
定义覆盖。但与他的答案不同的是,它不会试图获得优于现有实现的优先权;
std::byte
没有实现(cppreference 自己的示例定义了 std::ostream
的 operator<<
的本地覆盖)。您需要做的就是:std::ostream& operator<<(std::ostream& os, std::byte b)
{
return os << std::to_integer<int>(b);
}
和:
std::byte val{123};
std::cout << val << std::endl;
将按预期输出
123
。
uint8_t
转换为
int
”,但该策略的主要问题是:
很容易忘记一处或多处的演员表,并且std::byte
w/o
operator<<
代表 std::ostream
消除了遗忘的可能性;尝试将其发送到 std::ostream
而不进行强制转换将是一个编译时错误。然后,您可以在需要数值的位置手动添加 std::to_integer<int>(thebyte)
,并在需要 std::to_integer<char>(thebyte)
式输出时手动添加 char
,而无需全局决定是否应将 std::byte
输出为整数值或“文本”字符。
std::byte
等价物也不会那么困难(它只是带有按位运算重载的
enum class byte : unsigned char {};
和 constexpr
std::to_integer
转换,其中没有一个)需要 C++11 以外的任何内容),但理想情况下,到本答案时,C++17 应该足够广泛,不需要这样的恶作剧。