如果我将一个整数转换为枚举类会发生什么,但枚举中不存在该值?例如:我想要一个函数来测试整数是否具有来自枚举类的某个值:
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?
Run Code Online (Sandbox Code Playgroud)
这是检查整数是否可以转换为枚举的正确方法吗?
Cas*_*eri 14
我没有看到任何比OP提供的解决方案更好的解决方案.但是,它有一个小缺陷,我可以建议(非标准)解决方法.
问题如下.假设今天的代码与OP中的代码相同,但有一天,有人添加了一个新的枚举器,EnumClass
其变为:
enum class EnumClass { A, B = 4, C = 9, D = 60, E = 70 };
Run Code Online (Sandbox Code Playgroud)
假设此人忘记更新定义checkEnumClass
(这不太可能发生,特别是如果代码在另一个文件中).然后,
checkEnumClass( 70 );
Run Code Online (Sandbox Code Playgroud)
false
尽管70现在是有效值,但将返回.单元测试可能有助于捕获此错误,但此人必须记住更新测试.(回想一下,他们忘了在第一时间更新代码!)
不幸的是,标准C++不提供一种方法来强制switch
上enum
,以覆盖所有的情况下(与d它提供的final switch
声明).
但是,有一些特定于编译器的功能可以为您执行此操作.
对于GCC(我相信,Clang也是如此),您可以添加编译器选项-Wswitch
(或-Wall
暗示-Wswitch
).对于Visual Studio,您可以添加
#pragma warning(error : 4062)
Run Code Online (Sandbox Code Playgroud)
到包含的文件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;
}
Run Code Online (Sandbox Code Playgroud)
通过此解决方法,包含枚举器E
但忘记更新的人checkEnumClass
将收到以下错误/警告:
GCC:
警告:在交换机[-Wswitch]中未处理枚举值"E"
视觉工作室:
错误C4062:枚举'EnumClass'的开关枚举'E'不被处理
交换机(的static_cast <EnumClass>(v))中
更新1:继elvis.dukaj的评论之后.
作为一个好的做法,添加-Werror
GCC的选项可以将所有警告变成错误.
更新2:知足者常乐-Wswitch
是-Wswitch-enum
这将提高警告(或错误如果-Werror
),即使有一个default
标签.不幸的是,我不知道Visual Studio中有任何类似的功能.
枚举可以保持其最小值和最大值之间的任何值,因此您拥有的主要是正确的.您还需要做的唯一事情是确保整数参数在适当的范围内,因为如果您尝试转换超出枚举范围的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;
}
}
Run Code Online (Sandbox Code Playgroud)
如果您需要对枚举值进行编译时检查,您可以尝试以下操作:
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; };
Run Code Online (Sandbox Code Playgroud)
然后,您可以这样使用它:
static_assert(check_enum<0>::value, "invalid enum value"); // ok!
static_assert(check_enum<1>::value, "invalid enum value"); // compile error
Run Code Online (Sandbox Code Playgroud)
现场演示。
编辑:对于 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
Run Code Online (Sandbox Code Playgroud)
这些方法的主要缺点是专门化每个值的努力,您必须考虑这种努力是否值得。如果遗漏了某些价值,则可能很难找到并解决问题。