cout uint8_t 作为整数而不是字符

问题描述 投票:0回答:2
#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
来实现此目的吗?

c++ stream
2个回答
4
投票

我绝对不会容忍我即将提出的解决方案。 我还怀疑标准可能不允许它,但到目前为止我还无法证明这一点。 如果有人可以给我提供一个参考,表明这是不允许的,那么我会删除这个答案。 不管怎样,到目前为止我的测试表明,简单地在全局范围内重载运算符似乎是可行的。

#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 函数更匹配,但我对此不确定。


0
投票

从 C++17 开始,一个合理的解决方案可能是将

std::uint8_t
替换为
std::byte
。这不会使其行为如您所期望的那样,但会防止隐式解释为
char
/
signed char
/
unsigned char
任何数字类型。根据 cppreference

std::byte
是一种独特的类型,它实现了 C++ 语言定义中指定的字节概念。

unsigned char
一样,它可以用来访问其他对象(对象表示)占用的原始内存,但与
unsigned char
不同的是,它不是字符类型,也不是算术类型。
std::byte
仅模拟位的集合,仅支持与整数的位移操作,以及与另一个
std::byte
的按位和比较操作。

这样,它就不会被隐式/无意地解释为字符或整数,如果您尝试这样做,您将收到编译器错误。修复它们将涉及显式转换,但这些转换本质上是零成本(在幕后,它仍然存储为 unsigned char 值,它只是使用

enum class
使其成为不同的类型)。
您有两个选择:

    类似于
  1. Benjamin Lindley 的答案

    ,您可以为 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

    
    

  2. 或者,您可以不定义此类重载,而只需在每个使用点手动转换。我理解您不愿意“每次都将
  3. 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
    输出为整数值或“文本”字符。
    
    

  4. 坦率地说,即使在 C++17 之前,定义自己的
std::byte

等价物也不会那么困难(它只是带有按位运算重载的

enum class byte : unsigned char {};
constexpr
std::to_integer
转换,其中没有一个)需要 C++11 以外的任何内容),但理想情况下,到本答案时,C++17 应该足够广泛,不需要这样的恶作剧。
    

© www.soinside.com 2019 - 2024. All rights reserved.