我想要一个类型,如下所示unsigned char:
但是,与 不同的是unsigned char,它不允许使用别名。我的意思是,一种没有例外的类型[basic.lval/11.8]:
\n\n\n如果程序尝试通过以下类型之一以外的泛左值访问对象的存储值,则行为未定义:
\n\n[...]
\n\n\n
\n- 一个 char,无符号字符或 std\xe2\x80\x8b::\xe2\x80\x8bbyte 类型。
\n
有可能有这样的类型吗?
\n\n原因是:我几乎从不使用unsigned char\ 的别名属性。因此,我想使用一种类型,它不会阻止某些类型的优化(注意,我问这个问题是因为我实际上有一些函数,由于允许别名,因此没有很好地优化)的财产unsigned char)。因此,我希望有一种类型能够满足这一点:“不要为不使用的东西付费”。
这是一个unsigned char阻止优化的示例:使用此指针会导致热循环中奇怪的去优化
标准的该部分调用了char、unsigned char和std::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