如何检查枚举值是否有效?

BЈо*_*вић 44 c++ enums

我正在读取enum二进制文件中的值,并想检查该值是否真的是enum值的一部分.我该怎么做?

#include <iostream>

enum Abc
{
    A = 4,
    B = 8,
    C = 12
};

int main()
{
    int v1 = 4;
    Abc v2 = static_cast< Abc >( v1 );

    switch ( v2 )
    {
        case A:
            std::cout<<"A"<<std::endl;
            break;
        case B:
            std::cout<<"B"<<std::endl;
            break;
        case C:
            std::cout<<"C"<<std::endl;
            break;
        default :
            std::cout<<"no match found"<<std::endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

我是否必须使用switch操作员或有更好的方法吗?

编辑

我设置了枚举值,不幸的是我无法修改它们.更糟糕的是,它们不是连续的(它们的值为0,75,76,80,85,90,95,100等)

Leo*_*nid 24

enum如果值落在[A,B]范围内,则该值在C++中有效,该范围由下面的标准规则定义.因此,在这种情况下enum X { A = 1, B = 3 },值2被视为有效的枚举值.

考虑7.2/6的标准:

对于枚举,其中emin是最小的枚举数且emax是最大的,枚举的值是bmin到bmax范围内的基础类型的值,其中bmin和bmax分别是最小值和最小值的最小值.可以存储emin和emax的位字段.可以定义具有未由其任何枚举​​器定义的值的枚举.

在C++中没有回顾.一种方法是另外列出数组中的枚举值,并编写一个可以进行转换的包装器,并可能在失败时抛出异常.

有关更多详细信息,请参阅有关如何将int转换为枚举的类似问题.

  • 实际上,例如,如果值是1和5,则后者需要至少3位,因此6和7也将是枚举器的有效值. (12认同)
  • 这个答案仍然不正确.@visitor指出了一个例子,你的例子失败了.他说"如果值为1和5,则后者需要至少3位,因此6和7也将是枚举器的有效值".你的答案暗示在这种情况下只有{1,2,3,4,5}是有效值.您对该标准的引用是正确的,但您的示例具有误导性. (6认同)
  • 你误解了标准引用,有效值中不仅有"[A,B]`. (3认同)

And*_*rew 11

也许使用这样的枚举:

enum MyEnum
{
A,
B,
C
};
Run Code Online (Sandbox Code Playgroud)

并检查

if (v2 >= A && v2 <= C)
Run Code Online (Sandbox Code Playgroud)

如果未指定枚举常量的值,则值从零开始,并在列表中向下移动时增加1.例如,给定 enum MyEnumType { ALPHA, BETA, GAMMA }; ALPHA的值为0,BETA的值为1,GAMMA的值为2.

  • 我喜欢它的简单性,并通过始终将枚举中的第一项定义为SOMETYPE_UNKNOWN并将最后一项定义为SOMETYPE_MAX来扩展它。然后测试将始终为AssertTrue(v2&gt; = SOMETYPE_UNKNOWN &amp;&amp; v2 &lt;= SOMETYPE_MAX)。当然,只有在UNKNOWN之后和MAX之前添加项目。 (2认同)

jan*_*anm 10

在C++ 11中,如果您准备将枚举值列为模板参数,则有更好的方法.您可以将此视为一件好事,允许您在不同的上下文中接受有效枚举值的子集; 在从外部源解析代码时通常很有用.

下面示例的一个可能有用的补充是围绕相对于IntType的基础类型EnumType的一些静态断言,以避免截断问题.留下来作为锻炼.

#include <stdio.h>

template<typename EnumType, EnumType... Values> class EnumCheck;

template<typename EnumType> class EnumCheck<EnumType>
{
public:
    template<typename IntType>
    static bool constexpr is_value(IntType) { return false; }
};

template<typename EnumType, EnumType V, EnumType... Next>
class EnumCheck<EnumType, V, Next...> : private EnumCheck<EnumType, Next...>
{
    using super = EnumCheck<EnumType, Next...>;

public:
    template<typename IntType>
    static bool constexpr is_value(IntType v)
    {
        return v == static_cast<IntType>(V) || super::is_value(v);
    }
};

enum class Test {
    A = 1,
    C = 3,
    E = 5
};

using TestCheck = EnumCheck<Test, Test::A, Test::C, Test::E>;

void check_value(int v)
{
    if (TestCheck::is_value(v))
        printf("%d is OK\n", v);
    else
        printf("%d is not OK\n", v);
}

int main()
{
    for (int i = 0; i < 10; ++i)
        check_value(i);
}
Run Code Online (Sandbox Code Playgroud)

  • 你是对的 - 抱歉不是“递归”本身,而是函数调用链。有趣的是,编译器可以优化所有这些。并感谢您跟进 3 年前的答案:) (2认同)

Mat*_* M. 7

我发现使其"简单"的唯一方法是创建(宏)枚举的排序数组并检查它.

switch技巧enum因s而失败,因为enum可能有多个具有给定值的枚举器.

真的,这是一个烦人的问题.


Bre*_*ett 5

C ++托管扩展支持以下语法:

enum Abc
{
    A = 4,
    B = 8,
    C = 12
};

Enum::IsDefined(Abc::typeid, 8);
Run Code Online (Sandbox Code Playgroud)

参考:MSDN“ C ++编程的托管扩展

  • @BЈовић:`managed c ++`是`c ++`的Microsoft变体,它能够使用`.NET framework'的库。看起来是c ++,因为在这样的c#中未定义`::`运算符。 (3认同)

小智 5

有点死灵,但是......对 int 进行 RANGE 检查到第一个/最后一个枚举值(可以与 janm 的想法结合起来进行精确检查),C ++ 11:

标题:

namespace chkenum
{
    template <class T, T begin, T end>
    struct RangeCheck
    {
    private:
        typedef typename std::underlying_type<T>::type val_t;
    public:
        static
        typename std::enable_if<std::is_enum<T>::value, bool>::type
        inrange(val_t value)
        {
            return value >= static_cast<val_t>(begin) && value <= static_cast<val_t>(end);
        }
    };

    template<class T>
    struct EnumCheck;
}

#define DECLARE_ENUM_CHECK(T,B,E) namespace chkenum {template<> struct EnumCheck<T> : public RangeCheck<T, B, E> {};}

template<class T>
inline
typename std::enable_if<std::is_enum<T>::value, bool>::type
testEnumRange(int val)
{
    return chkenum::EnumCheck<T>::inrange(val);
}
Run Code Online (Sandbox Code Playgroud)

枚举声明:

enum MinMaxType
{
     Max = 0x800, Min, Equal
};
DECLARE_ENUM_CHECK(MinMaxType, MinMaxType::Max, MinMaxType::Equal);
Run Code Online (Sandbox Code Playgroud)

用法:

bool r = testEnumRange<MinMaxType>(i);
Run Code Online (Sandbox Code Playgroud)

上面提出的主要区别是测试函数仅依赖于枚举类型本身。