resueltos - operador de resolucion de ambito c++
¿Es posible determinar el número de elementos de una clase de enumeración de c++? (7)
¿Es posible determinar la cardinalidad de una enum class
c ++?
enum class Example { A, B, C, D, E };
Intenté usar sizeof
, sin embargo, devuelve el tamaño de un elemento enum.
sizeof(Example); // Returns 4 (on my architecture)
¿Hay una forma estándar de obtener la cardinalidad (5 en mi ejemplo)?
Hay un truco basado en X () - macros: imagen, tiene la siguiente enumeración:
enum MyEnum {BOX, RECT};
Reformatearlo a:
#define MyEnumDef /
X(BOX), /
X(RECT)
Entonces el siguiente código define el tipo de enumeración:
enum MyEnum
{
#define X(val) val
MyEnumDef
#undef X
};
Y el siguiente código calcula el número de elementos de enumeración:
template <typename ... T> void null(T...) {}
template <typename ... T>
constexpr size_t countLength(T ... args)
{
null(args...); //kill warnings
return sizeof...(args);
}
constexpr size_t enumLength()
{
#define XValue(val) #val
return countLength(MyEnumDef);
#undef XValue
}
...
std::array<int, enumLength()> some_arr; //enumLength() is compile-time
std::cout << enumLength() << std::endl; //result is: 2
...
No directamente, pero podrías usar el siguiente truco:
enum class Example { A, B, C, D, E, Count };
Entonces, la cardinalidad está disponible como (int)Example::Count
.
Por supuesto, esto solo funciona bien si permite que los valores de la enumeración se asignen automáticamente, comenzando desde 0. Si ese no es el caso, puede asignar manualmente la cardinalidad correcta a Cuenta, lo que realmente no es diferente de tener que mantener una constante separada de todas formas:
enum class Example { A = 1, B = 2, C = 4, D = 8, E = 16, Count = 5 };
La única desventaja es que el compilador le permitirá usar Example::Count
como un argumento para un valor de enumeración, ¡así que tenga cuidado si usa esto! (Sin embargo, personalmente encuentro que esto no es un problema en la práctica).
No, tienes que escribirlo en el código.
También puede considerar static_cast<int>(Example::E) + 1
que elimina el elemento extra.
Un truco que puedes probar es agregar un valor de enumeración al final de tu lista y usarlo como tamaño. En tu ejemplo
enum class Example { A, B, C, D, E, ExampleCount };
constexpr auto TEST_START_LINE = __LINE__;
enum class TEST { // Subtract extra lines from TEST_SIZE if an entry takes more than one
ONE = 7
, TWO = 6
, THREE = 9
};
constexpr auto TEST_SIZE = __LINE__ - TEST_START_LINE - 3;
Esto se deriva de la respuesta de UglyCoder, pero la mejora de tres maneras.
- No hay elementos adicionales en la enumeración de type_safe (
BEGIN
andSIZE
) ( la respuesta de Cameron también tiene este problema).- El compilador no se quejará de que falten en una instrucción switch (un problema importante)
- No se pueden pasar inadvertidamente a funciones que esperan su enumeración. (no es un problema común)
- No requiere fundición para su uso. ( La respuesta de Cameron también tiene este problema.)
- La resta no se mete con el tamaño del tipo de clase enum.
Retiene la ventaja de UglyCoder sobre la respuesta de Cameron de que a los enumeradores se les pueden asignar valores arbitrarios.
Un problema (compartido con UglyCoder pero no con Cameron ) es que hace que las líneas nuevas y los comentarios sean significativos ... lo que es inesperado. Entonces, alguien podría agregar una entrada con espacios en blanco o un comentario sin ajustar el cálculo de TEST_SIZE
.
enum class TEST
{
BEGIN = __LINE__
, ONE
, TWO
, NUMBER = __LINE__ - BEGIN - 1
};
auto const TEST_SIZE = TEST::NUMBER;
// or this might be better
constexpr int COUNTER(int val, int )
{
return val;
}
constexpr int E_START{__COUNTER__};
enum class E
{
ONE = COUNTER(90, __COUNTER__) , TWO = COUNTER(1990, __COUNTER__)
};
template<typename T>
constexpr T E_SIZE = __COUNTER__ - E_START - 1;