繁体   English   中英

安全地将整数与强类型枚举进行比较

[英]Safely compare integer to strongly typed enum

当积分值可能不在枚举值范围内时,如何安全地将未知类型的积分值与强类型枚举进行比较?

将积分值与枚举进行比较的最明显方法是将积分值a转换为枚举类型E ,并与枚举值b进行比较,如下所示:

template <typename I, typename E>
bool compare(I a, E b) { return static_cast<E>(a) == b; }

但是,如果a不在枚举值的范围内,则会导致未指定的行为,对于[expr.static.cast] / 10:

可以将整数或枚举类型的值显式转换为枚举类型。 如果原始值在枚举值(7.2)的范围内,则该值不变。 否则, 结果值未指定 (可能不在该范围内)。

这可以在结果失败中看出( compare如上):

enum E : uint8_t { A = 0 };
compare(256, E::A); // returns true, 256 == E::A, but E::A = 0

可以将枚举转换为整数类型,但如果整数类型不能表示所有枚举值,则可能导致错误的结果:

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

枚举可以转换为其底层整数类型,保证能够表示所有枚举值。

template <typename I, typename E>
bool compare(I a, E b) { return a == static_cast<std::underlying_type_t<E>>(b); }

如果整数类型和枚举类型在signededness上不同,那么通常的算术转换仍然存在问题。

enum class : int32_t { A = -1 };
compare(4294967295u, E3::A); // returns true

这里, E::A = (int32_t)-1被转换为unsigned int ,它不能表示-1,将其转换为(最有可能)4294967295。

只有当一个类型是无符号的而另一个类型具有负值(因此必须是有符号类型)时,才会发生整数到另一个不能表示其值的整数类型的转换。 由于无符号值和负值不可能相等,我们可以告诉比较结果而无需比较确切的值。

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<0b<0适合于ab的类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM