如何拥有类似于 unsigned char 的类型,但不允许别名?

gez*_*eza 5 c++ c++17

我想要一个类型,如下所示unsigned char

\n\n
    \n
  • 大小为 1
  • \n
  • 可以为其分配整数值(无需任何强制转换)
  • \n
  • 允许位操作
  • \n
  • 算术是允许的,但不是必须的
  • \n
  • 未签名
  • \n
  • 可以简单地复制
  • \n
\n\n

但是,与 不同的是unsigned char,它不允许使用别名。我的意思是,一种没有例外的类型[basic.lval/11.8]

\n\n
\n

如果程序尝试通过以下类型之一以外的泛左值访问对象的存储值,则行为未定义:

\n\n

[...]

\n\n
    \n
  • 一个 char,无符号字符或 std\xe2\x80\x8b::\xe2\x80\x8bbyte 类型。
  • \n
\n
\n\n

有可能有这样的类型吗?

\n\n

原因是:我几乎从不使用unsigned char\ 的别名属性。因此,我想使用一种类型,它不会阻止某些类型的优化(注意,我问这个问题是因为我实际上有一些函数,由于允许别名,因此没有很好地优化)的财产unsigned char)。因此,我希望有一种类型能够满足这一点:“不要为不使用的东西付费”。

\n\n
\n\n

这是一个unsigned char阻止优化的示例:使用此指针会导致热循环中奇怪的去优化

\n

Jus*_*tin 5

标准的该部分调用了charunsigned charstd::byte。但是,您可以创建自己的类型,类似于std::byte并且不允许使用别名:

enum class my_byte : unsigned char {};
Run Code Online (Sandbox Code Playgroud)

使用它并不是那么好,因为你必须强制转换unsigned char才能用它做任何有意义的事情。但是,您可以重载按位运算符和算术运算符,以使其更易于使用。


我们可以通过以下简单的函数来验证这一点:

auto foo(A& a, B& b) {
    auto lhs = b;
    a = 42;
    auto rhs = b;
    return lhs + rhs;
}
Run Code Online (Sandbox Code Playgroud)

如果A允许使用别名B,编译器将必须生成两个加载:一个用于lhs,一个用于rhs。如果A不允许使用 别名B,编译器可以生成单个加载并将值添加到自身。让我们测试一下

// int& cannot alias with long&
auto foo(int& a, long& b) {
    auto lhs = b;
    a = 42;
    auto rhs = b;
    return lhs + rhs;
}

// std::byte& can alias with long&    
auto bar(std::byte& a, long& b) {
   auto lhs = b;
    a = (std::byte)42;
    auto rhs = b;
    return lhs + rhs;
}

// if my_byte& can alias with long&, there would have to be two loads
auto baz(my_byte& a, long& b) {
    auto lhs = b;
    a = (my_byte)42;
    auto rhs = b;
    return lhs + rhs;
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

foo(int&, long&):
        mov     rax, QWORD PTR [rsi]
        mov     DWORD PTR [rdi], 42
        add     rax, rax
        ret
bar(std::byte&, long&):
        mov     rax, QWORD PTR [rsi]
        mov     BYTE PTR [rdi], 42
        add     rax, QWORD PTR [rsi]
        ret
baz(my_byte&, long&):
        mov     rax, QWORD PTR [rsi]
        mov     BYTE PTR [rdi], 42
        add     rax, rax
        ret
Run Code Online (Sandbox Code Playgroud)

因此my_byte不会继承与char和相同的别名属性std::byte

  • 我打算在我的代码库中用这个假设类型替换“unsigned char”。这意味着需要很多额外的演员阵容。这是噪音,我不喜欢它。 (2认同)