当积分值可能不在枚举值范围内时,如何安全地将未知类型的积分值与强类型枚举进行比较?
将整数值与枚举进行比较的最明显方法是将整数值a
强制转换为枚举类型E
,并与枚举值{{1}进行比较},像这样:
b
但是,如果template <typename I, typename E>
bool compare(I a, E b) { return static_cast<E>(a) == b; }
不在枚举值的范围内,则会导致未指定的行为,根据[expr.static.cast] / 10:
可以将整数或枚举类型的值显式转换为枚举类型。如果原始值在枚举值(7.2)的范围内,则该值不变。否则,结果值未指定(可能不在该范围内)。
这可以在结果失败中看到(a
如上所述):
compare
可以将枚举转换为整数类型,但如果整数类型不能表示所有枚举值,则可能导致错误的结果:
enum E : uint8_t { A = 0 };
compare(256, E::A); // returns true, 256 == E::A, but E::A = 0
答案 0 :(得分:9)
枚举可以转换为其底层整数类型,保证能够表示所有枚举值。
enum E : int { A = 256 };
template <typename I, typename E>
bool compare(I a, E b) { return a == static_cast<I>(b); }
compare((uint8_t)0); // returns true, 0 == E::A, but E:A = 256
如果整数类型和枚举类型在signededness上不同,那么通常的算术转换仍然存在问题。
template <typename I, typename E>
bool compare(I a, E b) { return a == static_cast<std::underlying_type_t<E>>(b); }
此处,enum class : int32_t { A = -1 };
compare(4294967295u, E3::A); // returns true
= E::A
转换为(int32_t)-1
,不能代表-1,将其转换为(最有可能)4294967295。
只有当一个类型是无符号的而另一个类型具有负值(因此必须是有符号类型)时,才会发生整数到另一个不能表示其值的整数类型的转换。由于无符号值和负值不可能相等,我们可以告诉比较结果而无需比较确切的值。
unsigned int
这将正确捕获案例,如果负值将转换为无符号值,然后可以匹配其他操作数。由于编译器在编译时知道类型,因此它可以根据template <typename I, typename E>
bool compare(I a, E b) {
using UTE = std::underlying_type_t<E>;
return !(std::is_unsigned_v<I> && static_cast<UTE>(b) < 0) &&
!(std::is_unsigned_v<UTE> && a < 0) &&
a == static_cast<UTE>(b);
}
和a<0
的类型优化符号检查表达式,b<0
或a
。