转换枚举中整数的安全方法
Safe way to convert an integer in an enum
如果我将一个整数强制转换到枚举类中,但该值不在枚举中,会发生什么?例如:我想要一个函数来测试一个整数是否有来自枚举类的值:
enum class EnumClass { A, B = 4, C = 9, D = 60 };
bool checkEnumClass( int v )
{
switch( static_cast< EnumClass >( v ) )
{
case EnumClass::A:
case EnumClass::B:
case EnumClass::C:
case EnumClass::D:
return true;
default:
return false;
}
}
checkEnumClass( 0 ) == true;
checkEnumClass( 7 ) == false; // is this true?
这是检查整数是否可转换为枚举的正确方法吗?
我没有看到比OP提供的解决方案更好的根本解决方案。然而,它有一个小缺陷,我可以建议(非标准)解决方案。
问题如下。假设今天的代码与OP中的代码相同,但有一天,有人向EnumClass
添加了一个新的枚举器,该枚举器变为:
enum class EnumClass { A, B = 4, C = 9, D = 60, E = 70 };
还假设这个人忘记更新checkEnumClass
的定义(这不太可能发生,尤其是当代码在另一个文件中时)。然后,
checkEnumClass( 70 );
将返回CCD_ 3,尽管70现在是有效值。单元测试可能有助于捕捉这个错误,但用户必须记住更新测试。(回想一下,他们一开始就忘了更新代码!)
不幸的是,标准C++没有提供一种方法来强制enum
上的switch
覆盖所有情况(不像D提供final switch
语句)。
但是,有一些编译器特定的功能可以为您做到这一点。
对于GCC(我相信还有Clang),您可以添加编译器选项-Wswitch
(或-Wall
,意味着-Wswitch
)。对于Visual Studio,您可以添加
#pragma warning(error : 4062)
到包含checkEnumClass
的文件(而不是包含枚举定义的文件)
最后,您必须稍微更改checkEnumClass
,因为default
标签告诉编译器所有情况都已涵盖。代码应该是这样的:
bool checkEnumClass( int v )
{
switch( static_cast< EnumClass >( v ) )
{
case EnumClass::A:
case EnumClass::B:
case EnumClass::C:
case EnumClass::D:
return true;
}
return false;
}
使用此解决方法,包含枚举器E
但忘记相应更新checkEnumClass
的人员将收到以下错误/警告:
GCC:
警告:枚举值"E"未在交换机[-Wswitch]中处理
Visual Studio:
错误C4062:未处理枚举"EnumClass"的开关中的枚举器"E"
交换机(static_cast<EnumClass>(v))
更新1:根据elvis.dukaj.的评论
将-Werror
添加到GCC的选项中,将所有警告转化为错误,这是一个很好的做法。
更新2:比-Wswitch
更好的是-Wswitch-enum
,即使有default
标签,它也会引发警告(如果是-Werror
,则会引发错误)。不幸的是,我不知道Visual Studio中有任何类似的功能。
枚举可以容纳最小值和最大值之间的任何值,因此您所拥有的基本正确。您需要额外做的唯一一件事是确保integer参数在正确的范围内,因为如果您试图强制转换枚举范围之外的int,则会出现未定义的行为:
bool checkEnumClass( int v )
{
if (v < static_cast<int>(EnumClass::A)) return false;
if (v > static_cast<int>(EnumClass::D)) return false;
switch( static_cast< EnumClass >( v ) )
{
case EnumClass::A:
case EnumClass::B:
case EnumClass::C:
case EnumClass::D:
return true;
default:
return false;
}
}
如果您需要在编译时检查枚举值,您可以尝试以下操作:
template <int I> struct check_enum { static const bool value = false; };
template <> struct check_enum<static_cast<int>(EnumClass::A)>
{ static const bool value = true; };
template <> struct check_enum<static_cast<int>(EnumClass::B)>
{ static const bool value = true; };
template <> struct check_enum<static_cast<int>(EnumClass::C)>
{ static const bool value = true; };
template <> struct check_enum<static_cast<int>(EnumClass::D)>
{ static const bool value = true; };
然后,你可以这样使用它:
static_assert(check_enum<0>::value, "invalid enum value"); // ok!
static_assert(check_enum<1>::value, "invalid enum value"); // compile error
现场演示。
编辑:对于C++14模板变量,同样的方法也是可行的。
template <int I> constexpr bool check_enum = false;
template <> constexpr bool check_enum<static_cast<int>(EnumClass::A)> = true;
template <> constexpr bool check_enum<static_cast<int>(EnumClass::B)> = true;
template <> constexpr bool check_enum<static_cast<int>(EnumClass::C)> = true;
template <> constexpr bool check_enum<static_cast<int>(EnumClass::D)> = true;
static_assert(check_enum<0>, "invalid enum value"); // ok!
static_assert(check_enum<1>, "invalid enum value"); // compile error
这些方法的主要缺点是努力专门化每一个价值,你必须思考这些努力是否值得。如果错过了一些值,那么可能很难找到并解决问题。
只需检查int是否不大于检查类中可能的最大值,不需要switch语句,只需使用if语句,或者更好的是,只使用bool。
bool checkEnumClass(int i)
{
return (i <= 7);
}
- 将传入的网络"char*"数据转换为"uint8_t"并返回的安全方法是什么?
- 在 c++ 中从执行的 shell 命令获取返回状态的安全方法是什么?
- 在C++线程内实现多个计时器的最安全方法
- 最有效的安全方法将 std::map<int, std::shared_ptr> 转换为 std::<Base>map<int, std::shared_ptr<D
- 重新分配指针阵列的一部分的安全方法
- 将整数添加到数组值而无需调用它的最安全方法
- 使用括号运算符实现矩阵类的安全方法
- 将空隙动态铸造到类型的安全方法?
- C/通过套接字发送time_t的最安全方法
- 交换两个类实例的最安全方法
- 将uint16_t投射到wchar_t的安全方法
- 从字符串中读取溢出双倍作为'inf'的安全方法
- 期货是检查单个线程完成情况的安全方法吗
- 在C++中动态分配向量的安全方法是什么
- 在C++类中构建互斥保护的线程安全方法
- C++和跳出动态生成代码的安全方法
- 这是实现错误处理的安全方法吗
- 将长整数转换为字符数组的最安全方法是什么
- 缓存 PID 到端口映射窗口的安全方法
- 将无符号长整整除以无符号长整型的最安全方法