[C++] How can I iterate over an enum?


Answers

One of many approaches: When enum Just Isn't Enough: Enumeration Classes for C++.

And, if you want something more encapsulated, try this approach from James Kanze.

Question

I just noticed that you can not use standard math operators on an enum such as ++ or +=

So what is the best way to iterate through all of the values in a C++ enum?




too much complicated these solution, i do like that :

enum NodePosition { Primary = 0, Secondary = 1, Tertiary = 2, Quaternary = 3};

const NodePosition NodePositionVector[] = { Primary, Secondary, Tertiary, Quaternary };

for (NodePosition pos : NodePositionVector) {
...
}



One of the answers says: "If you knew that the enum values were sequential, for example the Qt:Key enum".

Qt::Key values are not sequential. Some segments in the enum are.

This thread is about iterating over all values in enum. This actually is possible in Qt due to its use of Meta Object System:

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

See also QObject::metaObject() and Q_ENUM macro.

I think this kind of stuff will become easier with C++20? But I haven't looked into it.




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



If you knew that the enum values were sequential, for example the Qt:Key enum, you could:

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

It works as expected.




You can try and define the following 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))

Now you can use it:

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

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

It can be used to iterate backwards and forwards through unsigned, integers, enums and chars:

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


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

Despite its awkward definition it is optimized very well. I looked at disassembler in VC++. The code is extremely efficient. Don't be put off but the three for statements: the compiler will produce only one loop after optimization! You can even define enclosed loops:

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

You obviously cannot iterate through enumerated types with gaps.




For MS compilers:

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

Note: this is a lot less code than the simple templatized custom iterator answer.

You can get this to work with GCC by using typeof instead of decltype, but I don't have that compiler handy at the moment to make sure it compiles.




You can also overload the increment/decrement operators for your enumerated type.