How to check if enum value is valid?
enum
value is valid in C++ if it falls in range [A, B], which is defined by the standard rule below. So in case of enum X { A = 1, B = 3 }
, the value of 2
is considered a valid enum value.
Consider 7.2/6 of standard:
For an enumeration where emin is the smallest enumerator and emax is the largest, the values of the enumeration are the values of the underlying type in the range bmin to bmax, where bmin and bmax are, respectively, the smallest and largest values of the smallest bit-field that can store emin and emax. It is possible to define an enumeration that has values not defined by any of its enumerators.
There is no retrospection in C++. One approach to take is to list enum values in an array additionally and write a wrapper that would do conversion and possibly throw an exception on failure.
See Similar Question about how to cast int to enum for further details.
Maybe use enum like this:
enum MyEnum
{
A,
B,
C
};
and to check
if (v2 >= A && v2 <= C)
If you don't specify values for enum constants, the values start at zero and increase by one with each move down the list. For example, given
enum MyEnumType { ALPHA, BETA, GAMMA };
ALPHA has a value of 0, BETA has a value of 1, and GAMMA has a value of 2.
In C++ 11 there is a better way if you are prepared to list your enum values as template parameters. You can look at this as a good thing, allowing you to accept subsets of the valid enum values in different contexts; often useful when parsing codes from external sources.
A possible useful addition to the example below would be some static assertions around the underlying type of EnumType relative to IntType to avoid truncation issues. Left as an exercise.
#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);
}
The only way I ever found to make it 'easy', was to create (macro) a sorted array of the enums and checking with that.
The switch
trick fail with enum
s because an enum
may have more than one enumerator with a given value.
It's an annoying issue, really.