366 votes

Comment puis-je effectuer une itération sur un enum ?

Je viens de m’apercevoir que vous ne pouvez pas utiliser des opérateurs mathématiques standard sur un enum tels que ++ ou + =

Alors, ce qui est le meilleur moyen de parcourir toutes les valeurs dans un enum du C++ ?

299voto

andreas buykx Points 4710

Typique de la façon suivante:

enum Foo {
  One,
  Two,
  Three,
  Last
};

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

Bien sûr, cela se brise si les valeurs enum sont spécifiés:

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

Ceci illustre qu'un enum n'est pas vraiment le but de parcourir. Typique de la façon de traiter avec un enum est de l'utiliser dans une instruction switch.

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

Si vous voulez vraiment énumérer, des choses que l'énumération des valeurs dans un vecteur et parcourir plus de cela. Cela permettra de traiter correctement spécifié les valeurs de l'enum.

32voto

Don Wakefield Points 4684

Une des nombreuses approches : quelle enum Just n’est pas suffisant : Classes d’énumération pour C++.

Et, si vous voulez quelque chose de plus encapsulé, essayez cette approche de James Kanze.

18voto

João Augusto Points 1614

Si votre enum commence par 0 et l’incrément est toujours 1.

Si je ne devine pas le pourquoi seul est de créer quelque chose comme un

Ajoutez le code et utiliser les itérateurs normales...

8voto

Corey Trager Points 11334

Vous ne pouvez pas avec un enum. Un enum n’est peut-être pas la meilleure solution pour votre situation.

Une convention courante est de nommer la dernière valeur enum quelque chose comme MAX et qui permettent de contrôler une boucle à l’aide d’un int.

4voto

Mikhail Semenov Points 309

Vous pouvez essayer et de définir la macro suivante:

#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))

Maintenant, vous pouvez utiliser:

enum Count { zero, one, two, three }; 

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

Il peut être utilisé pour effectuer une itération en arrière et en avant à travers non signés, les entiers, les énumérations et les chars:

for_range (unsigned, i, 10,0)
{
    cout << "backwards i: " << i << endl;
}


for_range (char, c, 'z','a')
{
    cout << c << endl;
}

En dépit de son maladroit définition, il est très bien optimisé. J'ai regardé désassembleur de VC++. Le code est extrêmement efficace. Ne soyez pas rebutés, mais les trois états: le compilateur produira une seule boucle après l'optimisation! Vous pouvez même définir clos boucles:

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;
    }

Ne peut bien évidemment pas itérer sur les types énumérés avec des lacunes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X