14

如果我将整数转换为枚举类,但枚举中不存在该值会怎样?例如:我想要一个函数来测试一个整数是否具有来自枚举类的某个值:

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?

这是检查整数是否可转换为枚举的正确方法吗?

4

4 回答 4

14

我没有看到任何比 OP 提供的解决方案从根本上更好的解决方案。但是,它有一个小缺陷,我可以建议一个(非标准)解决方法。

问题如下。假设今天的代码与 OP 中的代码一样,但是有一天,有人添加了一个新的枚举器,EnumClass它变为:

enum class EnumClass { A, B = 4, C = 9, D = 60, E = 70 };

还假设此人忘记更新 的定义checkEnumClass(这不太可能发生,特别是如果代码在另一个文件中)。然后,

checkEnumClass( 70 );

false尽管 70 现在是一个有效值,但仍会返回。单元测试可能有助于捕获此错误,但此人必须记住更新测试。(回想一下,他们一开始就忘记更新代码了!)

不幸的是,标准 C++ 没有提供强制 a 覆盖所有情况的方法switchenum与提供final switch 语句的 D 不同)。

但是,有一些特定于编译器的功能可以为您做到这一点。

对于 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将收到以下错误/警告:

海合会:

警告:枚举值“E”未在开关 [-Wswitch] 中处理

视觉工作室:

错误 C4062:枚举 'EnumClass' 的开关中的枚举器 'E' 未处理
switch( static_cast< EnumClass >( v ) )

更新 1:根据elvis.dukaj的评论。

作为一种好的做法,添加-WerrorGCC 的选项以将所有警告转换为错误。

更新 2:即使有-Wswitch标签也会-Wswitch-enum引发警告(或错误 if )。不幸的是,我不知道 Visual Studio 中有任何类似的功能。-Werrordefault

于 2013-07-23T14:23:01.077 回答
7

枚举可以保存其最小值和最大值之间的任何值,因此您所拥有的基本上是正确的。您唯一需要做的就是确保整数参数在正确的范围内,因为如果您尝试强制转换超出枚举范围的 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;
    }
}
于 2013-07-23T13:47:09.400 回答
5

如果你需要在编译时检查枚举值,你可以试试这个:

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

这些方法的主要缺点是努力专门化每个值,你必须考虑这种努力是否值得。如果错过了一些价值,那么可能很难找到并解决问题。

于 2013-07-23T14:24:44.787 回答
-2

只需检查 int 是否大于检查类中的最大可能值,不需要 switch 语句,只需使用 if 语句,或者更好的是,只需一个 bool。

bool checkEnumClass(int i)
{
    return (i <= 7);
}
于 2013-07-23T13:16:20.927 回答