¿Cómo verificar si el valor enum es válido?

Estoy leyendo un valor enum de un archivo binario y me gustaría comprobar si el valor es realmente parte de los valores enum . ¿Cómo puedo hacerlo?

 #include  enum Abc { A = 4, B = 8, C = 12 }; int main() { int v1 = 4; Abc v2 = static_cast( 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; } } 

¿Tengo que usar el operador del switch o hay una mejor manera?

EDITAR

Tengo valores enum establecidos y desafortunadamente no puedo modificarlos. Para empeorar las cosas, no son continuos (sus valores van de 0, 75,76,80,85,90,95,100, etc.)

enum valor enum es válido en C ++ si está dentro del rango [A, B], que se define mediante la regla estándar a continuación. Entonces, en caso de enum X { A = 1, B = 3 } , el valor de 2 se considera un valor enum válido.

Considere 7.2 / 6 de estándar:

Para una enumeración donde emin es el enumerador más pequeño y emax es el más grande, los valores de la enumeración son los valores del tipo subyacente en el rango bmin a bmax, donde bmin y bmax son, respectivamente, los valores más pequeños y más grandes de los más pequeños campo de bits que puede almacenar emin y emax. Es posible definir una enumeración que tiene valores no definidos por ninguno de sus enumeradores.

No hay retrospección en C ++. Un enfoque a seguir es enumerar los valores enum en una matriz adicionalmente y escribir una envoltura que haría la conversión y posiblemente lanzar una excepción en caso de falla.

Vea una pregunta similar sobre cómo convertir int a enum para más detalles.

Tal vez use enum así:

 enum MyEnum { A, B, C }; 

y para verificar

 if (v2 >= A && v2 <= C) 

Si no especifica valores para las constantes enum, los valores comienzan en cero y aumentan en uno con cada movimiento hacia abajo en la lista. Por ejemplo, dado enum MyEnumType { ALPHA, BETA, GAMMA }; ALPHA tiene un valor de 0, BETA tiene un valor de 1 y GAMMA tiene un valor de 2.

La única forma que he encontrado para hacerlo “fácil”, fue crear (macro) una matriz ordenada de las enumeraciones y verificar con eso.

El truco del switch falla con las enum porque una enum puede tener más de un enumerador con un valor dado.

Es un problema molesto, de verdad.

En C ++ 11 hay una manera mejor si está preparado para enumerar sus valores enum como parámetros de plantilla. Puedes ver esto como algo bueno, permitiéndote aceptar subconjuntos de los valores enum válidos en diferentes contextos; a menudo útil al analizar códigos de fonts externas.

Una posible adición útil al siguiente ejemplo sería algunas aserciones estáticas alrededor del tipo subyacente de EnumType relativo a IntType para evitar problemas de truncamiento. Izquierda como ejercicio.

 #include  template class EnumCheck; template class EnumCheck { public: template static bool constexpr is_value(IntType) { return false; } }; template class EnumCheck : private EnumCheck { using super = EnumCheck; public: template static bool constexpr is_value(IntType v) { return v == static_cast(V) || super::is_value(v); } }; enum class Test { A = 1, C = 3, E = 5 }; using TestCheck = EnumCheck; 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); } 

Managed Extensions para C ++ admite la siguiente syntax:

 enum Abc { A = 4, B = 8, C = 12 }; Enum::IsDefined(Abc::typeid, 8); 

Referencia: MSDN ” Extensiones administradas para la progtwigción en C ++ ”

Hablando de un idioma, no hay mejor manera, los valores enum existen solo en tiempo de comstackción y no hay forma de enumerarlos programáticamente. Sin embargo, con una infraestructura bien pensada, aún podrá evitar enumerar todos los valores varias veces. Consulte la forma fácil de usar variables de tipos enum como cadena en C?

Su muestra puede ser reescrita utilizando el “enumFactory.h” proporcionado allí como:

 #include "enumFactory.h" #define ABC_ENUM(XX) \ XX(A,=4) \ XX(B,=8) \ XX(C,=12) \ DECLARE_ENUM(Abc,ABC_ENUM) int main() { int v1 = 4; Abc v2 = static_cast< Abc >( v1 ); #define CHECK_ENUM_CASE(name,assign) case name: std::cout<< #name < 

o incluso (usando algunas instalaciones más que ya existen en ese encabezado):

 #include "enumFactory.h" #define ABC_ENUM(XX) \ XX(A,=4) \ XX(B,=8) \ XX(C,=12) \ DECLARE_ENUM(Abc,ABC_ENUM) DEFINE_ENUM(Abc,ABC_ENUM) int main() { int v1 = 4; Abc v2 = static_cast< Abc >( v1 ); const char *name = GetString(v2); if (name[0]==0) name = "no match found"; std::cout << name << std::endl; } 

Un poco necro, pero … hace una comprobación de rango de int en los valores de enum primero / último (se puede combinar con la idea de janm para hacer comprobaciones exactas), C ++ 11:

Encabezamiento:

 namespace chkenum { template  struct RangeCheck { private: typedef typename std::underlying_type::type val_t; public: static typename std::enable_if::value, bool>::type inrange(val_t value) { return value >= static_cast(begin) && value <= static_cast(end); } }; template struct EnumCheck; } #define DECLARE_ENUM_CHECK(T,B,E) namespace chkenum {template<> struct EnumCheck : public RangeCheck {};} template inline typename std::enable_if::value, bool>::type testEnumRange(int val) { return chkenum::EnumCheck::inrange(val); } 

Declaración de Enum:

 enum MinMaxType { Max = 0x800, Min, Equal }; DECLARE_ENUM_CHECK(MinMaxType, MinMaxType::Max, MinMaxType::Equal); 

Uso:

 bool r = testEnumRange(i); 

Principalmente la diferencia de arriba lo propuso que la función de prueba depende solamente del tipo de enumeración.

Otra forma de hacerlo:

 #include  #include  #include  template struct enum_traits { static constexpr void* values = nullptr; }; namespace detail { template constexpr bool is_value_of(int, void*) { return false; } template constexpr bool is_value_of(int v, U) { using std::begin; using std::end; return std::find_if(begin(enum_traits::values), end(enum_traits::values), [=](auto value){ return value == static_cast(v); } ) != end(enum_traits::values); } } template constexpr bool is_value_of(int v) { return detail::is_value_of(v, decltype(enum_traits::values) { }); } //////////////////// enum Abc { A = 4, B = 8, C = 12 }; template<> struct enum_traits { static constexpr auto values = { A, B, C }; }; decltype(enum_traits::values) enum_traits::values; enum class Def { D = 1, E = 3, F = 5 }; int main() { std::cout << "Abc:"; for(int i = 0; i < 10; ++i) if(is_value_of(i)) std::cout << " " << i; std::cout << std::endl; std::cout << "Def:"; for(int i = 0; i < 10; ++i) if(is_value_of(i)) std::cout << " " << i; std::cout << std::endl; return 0; } 

La parte "fea" de este enfoque en mi humilde opinión debe definir:

 decltype(enum_traits::values) enum_traits::values 

Si no se opone a las macros, puede envolverlo dentro de una macro:

 #define REGISTER_ENUM_VALUES(name, ...) \ template<> struct enum_traits { static constexpr auto values = { __VA_ARGS__ }; }; \ decltype(enum_traits::values) enum_traits::values;