Öö *_*iib 21 c++ language-lawyer
所述std::byte的C++ 17需要为枚举类:
enum class byte : unsigned char {};
Run Code Online (Sandbox Code Playgroud)
我们可能希望使用它std::byte来表示原始内存而不是chars中的一个,因为它更安全类型,定义了特定于字节的运算符,并且不能int像chars那样提升为蓝色.我们需要使用显式强制转换或to_integer转换std::byte为其他整数.然而,从很多来源我们仍然得到char(或更可能是整个缓冲区char),因此可能想要转换它:
void fn(char c)
{
std::byte b = static_cast<std::byte>(c);
// ... that may invoke undefined behavior, read below
}
Run Code Online (Sandbox Code Playgroud)
可能char是实现定义的签名.因此,上面的负值可能超出范围.std::numeric_limits<char>::is_signedtruecunsigned char
现在在8.2.9 Static cast [expr.static.cast]第10段的C++ 17标准中,我们可以读到:
可以将整数或枚举类型的值显式转换为完整的枚举类型.如果原始值在枚举值(10.2)的范围内,则该值不变.否则,行为未定义.
从10.2我们可以看出,所提到的范围是基础类型的范围.因此,为了避免未定义的行为,我们必须编写更多代码.例如,我们可以添加一个强制转换unsigned char来实现在强制转换期间模块化算术的定义效果:
void fn(char c)
{
std::byte b = static_cast<std::byte>(static_cast<unsigned char>(c));
// ... now we have done it in portable manner?
}
Run Code Online (Sandbox Code Playgroud)
我误解了什么吗?这不是过于复杂和限制吗?为什么enum class那个有无符号底层类型的人不能像其底层类型一样遵循模块化算法呢?请注意,编译器的整行很可能无论如何都被编译器编译成任何东西.在char有签署必须是因为C++ 14所以它的按位表示必须相同模运算转化为后补unsigned char.谁从正式的未定义行为中受益以及如何?
gez*_*eza 10
这将在下一个标准中修复:
可以将整数或枚举类型的值显式转换为完整的枚举类型.如果枚举类型具有固定的基础类型,则首先通过整数转换将值转换为该类型(如果需要),然后再转换为枚举类型.如果枚举类型没有固定的基础类型,如果原始值在枚举值([dcl.enum])的范围内,则该值不变,否则,行为未定义
这是从(C++ 11)未指定到(C++ 17)未定义的变更背后的基本原理:
虽然问题1094澄清了枚举类型的表达式的值可能不在转换为枚举类型后的枚举值的范围内(见8.2.9 [expr.static.cast]第10段),结果只是一个未指明的值.鉴于未定义的行为使表达式非常量,这应该可以加强以产生未定义的行为.
而这里的 C++的2A修复背后的理由:
std :: byte(21.2.5 [support.types.byteops])和位掩码(20.4.2.1.4 [bitmask.types])的规范揭示了整数转换规则的问题,根据这些规则,这两个规范都有,在一般情况下,未定义的行为.问题是转换为枚举类型具有未定义的行为,除非要转换的值在枚举范围内.
对于具有无符号固定基础类型的枚举,此要求过于严格,因为将大值转换为无符号整数类型是明确定义的.