type para libreria example enum c++ enums

c++ - para - ¿Cómo puedo iterar sobre una enumeración?



struct c++ (17)

Acabo de darme cuenta de que no se pueden usar operadores matemáticos estándar en una enumeración como ++ o + =

Entonces, ¿cuál es la mejor manera de iterar a través de todos los valores en una enumeración de C ++?


A menudo lo hago asi

enum EMyEnum { E_First, E_Orange = E_First, E_Green, E_White, E_Blue, E_Last } for (EMyEnum i = E_First; i < E_Last; i = EMyEnum(i + 1)) {}

o si no es sucesivo, pero con un paso regular (por ejemplo, banderas de bits)

enum EMyEnum { E_First, E_None = E_First, E_Green = 0x1, E_White = 0x2 E_Blue = 0x4, E_Last } for (EMyEnum i = E_First; i < E_Last; i = EMyEnum(i << 1)) {}


Algo que no se ha cubierto en las otras respuestas = si está utilizando las enumeraciones de C ++ 11 con tipos muy marcados, no puede usar ++ o + int en ellas. En ese caso, se requiere un poco de una solución más desordenada:

enum class myenumtype { MYENUM_FIRST, MYENUM_OTHER, MYENUM_LAST } for(myenumtype myenum = myenumtype::MYENUM_FIRST; myenum != myenumtype::MYENUM_LAST; myenum = static_cast<myenumtype>(static_cast<int>(myenum) + 1)) { do_whatever(myenum) }


Aquí hay otra solución que solo funciona para enumeraciones contiguas. Da la iteración esperada, excepto la fealdad en el incremento, que es a donde pertenece, ya que eso es lo que está roto en C ++.

const QMetaObject *metaObject = qt_getQtMetaObject(); QMetaEnum keyEnum = metaObject->enumerator(metaObject->indexOfEnumerator("Key")); for (int i = 0; i < keyEnum.keyCount(); ++i) { qDebug() << keyEnum.key(i); }


C ++ no tiene introspección, por lo que no puede determinar este tipo de cosas en tiempo de ejecución.


Con c ++ 11, en realidad hay una alternativa: escribir un iterador personalizado templado simple.

asumamos que tu enumeración es

enum class foo { one, two, three };

Este código genérico hará el truco, de manera bastante eficiente: colóquelo en un encabezado genérico, le servirá para cualquier enumeración que necesite repetir:

#include <type_traits> template < typename C, C beginVal, C endVal> class Iterator { typedef typename std::underlying_type<C>::type val_t; int val; public: Iterator(const C & f) : val(static_cast<val_t>(f)) {} Iterator() : val(static_cast<val_t>(beginVal)) {} Iterator operator++() { ++val; return *this; } C operator*() { return static_cast<C>(val); } Iterator begin() { return *this; } //default ctor is good Iterator end() { static const Iterator endIter=++Iterator(endVal); // cache it return endIter; } bool operator!=(const Iterator& i) { return val != i.val; } };

Tendrás que especializarlo.

typedef Iterator<foo, foo::one, foo::three> fooIterator;

Y luego puedes iterar usando range-for

for (foo i : fooIterator() ) { //notice the parenteses! do_stuff(i); }

La suposición de que no tiene brechas en su enumeración sigue siendo cierta; no se supone el número de bits realmente necesarios para almacenar el valor de enumeración (gracias a std :: subyacente_tipo)


La forma típica es la siguiente:

enum Foo { One, Two, Three, Last }; for ( int fooInt = One; fooInt != Last; fooInt++ ) { Foo foo = static_cast<Foo>(fooInt); // ... }

Por supuesto, esto se descompone si se especifican los valores de enumeración:

enum Foo { One = 1, Two = 9, Three = 4, Last };

Esto ilustra que una enumeración no está realmente destinada a iterar. La forma típica de lidiar con una enumeración es usarla en una declaración de cambio.

switch ( foo ) { case One: // .. break; case Two: // intentional fall-through case Three: // .. break; case Four: // .. break; default: assert( ! "Invalid Foo enum value" ); break; }

Si realmente desea enumerar, rellene los valores de enumeración en un vector y repita sobre eso. Esto también tratará adecuadamente con los valores de enumeración especificados.


No se puede con una enumeración. Tal vez una enumeración no es la mejor opción para su situación.

Una convención común es nombrar el último valor de enumeración algo como MAX y usarlo para controlar un bucle usando un int.


Para compiladores de MS:

#define inc_enum(i) ((decltype(i)) ((int)i + 1)) enum enumtype { one, two, three, count}; for(enumtype i = one; i < count; i = inc_enum(i)) { dostuff(i); }

Nota: este es mucho menos código que la respuesta del iterador personalizado simple y templado.

Puede hacer que esto funcione con GCC usando typeof lugar de decltype , pero no tengo ese compilador a la mano para asegurarme de que se compile.


Puedes probar y definir la siguiente macro:

#define for_range(_type, _param, _A1, _B1) for (bool _ok = true; _ok;)/ for (_type _start = _A1, _finish = _B1; _ok;)/ for (int _step = 2*(((int)_finish)>(int)_start)-1;_ok;)/ for (_type _param = _start; _ok ; / (_param != _finish ? / _param = static_cast<_type>(((int)_param)+_step) : _ok = false))

Ahora puedes usarlo:

enum Count { zero, one, two, three }; for_range (Count, c, zero, three) { cout << "forward: " << c << endl; }

Se puede utilizar para iterar hacia atrás y hacia adelante a través de números enteros sin signo, enumerados y caracteres:

for_range (unsigned, i, 10,0) { cout << "backwards i: " << i << endl; } for_range (char, c, ''z'',''a'') { cout << c << endl; }

A pesar de su definición torpe se optimiza muy bien. Miré el desensamblador en VC ++. El código es extremadamente eficiente. No se desanime, sino las tres declaraciones: ¡el compilador producirá solo un bucle después de la optimización! Incluso puedes definir bucles cerrados:

unsigned p[4][5]; for_range (Count, i, zero,three) for_range(unsigned int, j, 4, 0) { p[i][j] = static_cast<unsigned>(i)+j; }

Obviamente, no puede iterar a través de los tipos enumerados con espacios en blanco.


Si no te gusta contaminar tu enumeración con un elemento final de COUNT (porque quizás si también usas la enumeración en un interruptor, entonces el compilador te avisará de un caso COUNT faltante :), puedes hacer esto:

enum Colour {Red, Green, Blue}; const Colour LastColour = Blue; Colour co(0); while (true) { // do stuff with co // ... if (co == LastColour) break; co = Colour(co+1); }


Si su enumeración comienza con 0 y el incremento es siempre 1.

enum enumType { A = 0, B, C, enumTypeEnd }; for(int i=0; i<enumTypeEnd; i++) { enumType eCurrent = (enumType) i; }

Si no, supongo que el único por qué es crear algo como un

vector<enumType> vEnums;

agrega los elementos, y usa iteradores normales ....


Si supiera que los valores de enumeración eran secuenciales, por ejemplo, la enumeración de Qt: Key, podría:

enum Bar { One = 1, Two, Three, End_Bar // Marker for end of enum; }; for (Bar foo = One; foo < End_Bar; foo = Bar(foo + 1)) { // ... }

Funciona como se esperaba.


Simplemente haga una matriz de entradas y haga un bucle sobre la matriz, pero haga que el último elemento diga -1 y utilícelo para la condición de salida.

Si la enumeración es:

enum MyEnumType{Hay=12,Grass=42,Beer=39};

a continuación, crear matriz:

int Array[] = {Hay,Grass,Beer,-1}; for (int h = 0; Array[h] != -1; h++){ doStuff( (MyEnumType) Array[h] ); }

Esto no se rompe, sin importar los ints en la representación, siempre y cuando -1 check no choca con uno de los elementos, por supuesto.


También puede sobrecargar los operadores de incremento / decremento para su tipo enumerado.


Una de las respuestas dice: "Si supiera que los valores de enumeración eran secuenciales, por ejemplo, la enumeración de Qt: Clave".

Qt :: Los valores clave no son secuenciales . Algunos segmentos en la enumeración son.

Este hilo trata de iterar sobre todos los valores en enum. Esto es realmente posible en Qt debido a su uso de Meta Object System:

Qt::Key shortcut_key = Qt::Key_0; for (int idx = 0; etc...) { .... if (shortcut_key <= Qt::Key_9) { fileMenu->addAction("abc", this, SLOT(onNewTab()), QKeySequence(Qt::CTRL + shortcut_key)); shortcut_key = (Qt::Key) (shortcut_key + 1); } }

Vea también QObject :: metaObject () y Q_ENUM macro.

Creo que este tipo de cosas se volverán más fáciles con C ++ 20? Pero no lo he investigado.


demasiado complicada esta solución, me gusta eso:

enum NodePosition { Primary = 0, Secondary = 1, Tertiary = 2, Quaternary = 3}; const NodePosition NodePositionVector[] = { Primary, Secondary, Tertiary, Quaternary }; for (NodePosition pos : NodePositionVector) { ... }


#include <iostream> #include <algorithm> namespace MyEnum { enum Type { a = 100, b = 220, c = -1 }; static const Type All[] = { a, b, c }; } void fun( const MyEnum::Type e ) { std::cout << e << std::endl; } int main() { // all for ( const auto e : MyEnum::All ) fun( e ); // some for ( const auto e : { MyEnum::a, MyEnum::b } ) fun( e ); // all std::for_each( std::begin( MyEnum::All ), std::end( MyEnum::All ), fun ); return 0; }