447

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?

7
  • 2
    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. Commented Nov 4, 2008 at 16:22
  • Linked items have some interesting responses. Commented Jun 13, 2013 at 1:27
  • 1
    These answers don't seem to cover the problem that int may not be big enough! ([C++03: 7.2/5]) Commented Jun 21, 2013 at 10:03
  • Interestingly, you can define operator++ on enums; however, so you can do for(Enum_E e = (Enum_E)0; e < ENUM_COUNT; e++). Note you have to cast 0 to Enum_E because C++ forbids assignment operators on enums. Commented Jun 25, 2014 at 22:52
  • If there was a compile time operator, similar to the way sizeof works, that could emit a std::initializer_list literal comprised of the values of the enum, we would have a solution and would not involve any runtime overhead. Commented Dec 13, 2017 at 23:56

29 Answers 29

342

The typical way is as follows:

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

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

Please note, the enum Last is meant to be skipped by the iteration. Utilizing this "fake" Last enum, you don't have to update your terminating condition in the for loop to the last "real" enum each time you want to add a new enum. If you want to add more enums later, just add them before Last. The loop in this example will still work.

Of course, this breaks down if the enum values are specified:

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

This illustrates that an enum is not really meant to iterate through. The typical way to deal with an enum is to use it in a switch statement.

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

If you really want to enumerate, stuff the enum values in a vector and iterate over that. This will properly deal with the specified enum values as well.

Sign up to request clarification or add additional context in comments.

11 Comments

Note that, in the first part of the example, if you want to use 'i' as a Foo enum and not an int, you will need to static cast it like: static_cast<Foo>(i)
Also you are skipping Last in the loop. Should be <= Last
@Tony Last is meant to be skipped. If you want to add more enums later, add them before Last... the loop in the first example will still work. By utilizing a "fake" Last enum, you don't have to update your terminating condition in the for loop to the last "real" enum each time you want to add a new enum.
Note that for this enum definition to be safe for updates one should define a value UNKNOWN = 0. Additionally, I would suggest to just drop the default case when switching over enum values since it might hide cases where handling of values was forgotten until runtime. Instead one should hardcode all values and use the UNKNOWN field to detect incompatibilities.
@timidpueo That's why I prefer to call the last entry Count. Makes it a little more obvious.
|
98
#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;
}

3 Comments

Thanks! Note that if you're crossing files/classes and if MS compatibility is giving you issues with header-declared non-integer constants, it helps under my compiler to explicitly put the size in the type in the header: static const Type All[3]; and then I'm able to initialize in the source: const MyEnum::Type MyEnum::All[3] = { a, b, c }; Before doing that, I was getting obnoxious Error in range-based for... errors (because the array had an unknown size). Figured this out thanks to a related answer
The array version is very friendly of copy paste. The most satisfactory answer besides, "NO" or "only for sequential". Probably macro friendly even.
this might be a good solution for enums with small number of items, but for enums with big number of items it must not fit well.
50

With C++11, there actually is an alternative: writing a templatized custom iterator.

Let's assume your enum is

enum class foo {
  one,
  two,
  three
};

This generic code will do the trick, quite efficiently. Place it in a generic header, and it'll serve you for any enum you may need to iterate over:

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

You'll need to specialize it

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

And then you can iterate using range-for

for (foo i : fooIterator() ) { // Notice the parentheses!
   do_stuff(i);
}

The assumption that you don't have gaps in your enum is still true; there is no assumption on the number of bits actually needed to store the enum value (thanks to std::underlying_type).

15 Comments

@lepe ? You just make a different typedef for a different enum.
@lepe That's like saying that std::vector isn't generic because std::vector<foo> is tied to foo.
typedef Iterator<color, color::green, color::red> colorIterator; Make sure you understand how the template instantiations work.
Oh, I see the issue -- foo operator*() { ... should be C operator*() { ....
@KyleStrand: You got it! that makes totally sense now. Should the code be updated? Thanks everyone for your explanations.
|
32

These solutions are too complicated. I do like this:

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

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

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

10 Comments

I expect it was because the entries need to be maintained in two places.
@thegreatjedi Since C++11 you can, even simpier : for(auto pos : NodePositionVector) {..}
@thegreatjedi It would have been quicker to search, or even compile a test program, than to ask that question. But yes, since C++11 it is perfectly valid C++ syntax, which the compiler translates to the equivalent (and far more verbose/less abstracting) code, usually via iterators; see cppreference. And, as Enzojz said, C++11 also added auto, so you don't have to declare the type of the elements explicitly, unless you (A) need to use a conversion operator or (B) don't like auto for some reason. Most range-for users use auto AFAICT
Approach is ok, imlementation is flawed. I do not recommend naming arrays as Vectors (it is outright confusing), and re-using NodePositionVector , while potentially technically valid, is outright confusing, which insults Almighty Readability. -1.
How about using MACRO to keep those entries in one place?
|
22

I often do it like this:

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

Or if not successive, but with regular steps (e.g., bit flags):

    enum EAnimalCaps
    {
        E_None    = 0,
        E_First   = 0x1,
        E_CanFly  = E_First,
        E_CanWalk = 0x2
        E_CanSwim = 0x4,
        E_Last
    }

    class MyAnimal
    {
       EAnimalCaps m_Caps;
    }

    class Frog
    {
        Frog() :
            m_Caps(EAnimalCaps(E_CanWalk | E_CanSwim))
        {}
    }

    for (EAnimalCaps= E_First; i < E_Last; i = EAnimalCaps(i << 1))
    {}

6 Comments

but, what's the use of printing the values bit-wise?
To use enums to create bitmasks. e.g. combine several options in single variable, then using the FOR to test for every option. Fixed my post with better example.
I still can't get the use of it(& your post still shows the old example)! Using enum as bitmasks are really helpful, but didn't able to connect the dots! could you please elaborate a bit in your example in details, you can put the additional code as well.
@anu Sorry did not see your comment. Added Frog class as bitmask example
Wouldn't you need to start at your 0x1 element? Otherwise you're bitshifting a whole lot 0s, and thereby remain at the first element indefinitely
|
16

If your enum starts with 0 and the increment is always 1.

enum enumType
{
    A = 0,
    B,
    C,
    enumTypeEnd
};

for(int i=0; i<enumTypeEnd; i++)
{
   enumType eCurrent = (enumType) i;
}

If not, I guess the only way is to create something like a

vector<enumType> vEnums;

add the items, and use normal iterators...

2 Comments

The "<" operator is not available for enums.
i<enumTypeEnd does also do an implicit cast
14

Assuming that enum is numbered sequentially is error prone. Moreover, you may want to iterate over selected enumerators only. If that subset is small, looping over it explicitly might be an elegant choice:

enum Item { Man, Wolf, Goat, Cabbage }; // or enum class

for (auto item : {Wolf, Goat, Cabbage}) { // or Item::Wolf, ...
    // ...
}

2 Comments

This is a nice option I think. Must be part of a newer C++ spec than I was using when I asked the question I'm guessing?
Yes. It iterates over an std::initializer_list<Item>. link.
11

Casting the variable to an int& lets you increment while keeping the type readable.

#include <iostream>

enum MyEnum
{
    ONE,
    TWO,
    THREE,
    FOUR,
};

int main()
{
    for (MyEnum v = MyEnum::ONE; v <= MyEnum::FOUR; ++(int&)v)
    {
        std::cout << v << std::endl;
    }

    return 0;
}
0
1
2
3

Comments

9

Something that hasn't been covered in the other answers = if you're using strongly typed C++11 enums, you cannot use ++ or + int on them. In that case, a bit of a messier solution is required:

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)

}

1 Comment

...but C++11 introduces the range based for that is shown in other answers. :-)
8
enum class A {
    a0=0, a3=3, a4=4
};
constexpr std::array<A, 3> ALL_A {A::a0, A::a3, A::a4}; // constexpr is important here

for(A a: ALL_A) {
  if(a==A::a0 || a==A::a4) std::cout << static_cast<int>(a);
}

A constexpr std::array can iterate even non-sequential enums without the array being instantiated by the compiler. This depends on things like the compiler's optimization heuristics and whether you take the array's address.

In my experiments, I found that g++ 9.1 with -O3 will optimize away the above array if there are 2 non-sequential values or quite a few sequential values (I tested up to 6). But it only does this if you have an if statement. (I tried a statement that compared an integer value greater than all the elements in a sequential array and it inlined the iteration despite none being excluded, but when I left out the if statement, the values were put in memory.) It also inlined 5 values from a non-sequential enum in [one case|https://godbolt.org/z/XuGtoc]. I suspect this odd behavior is due to deep heuristics having to do with caches and branch prediction.

Here is a link to a simple test iteration on godbolt that demonstrates the array does not always get instantiated.

The price of this technique is writing the enum elements twice and keeping the two lists in sync.

1 Comment

I like simple range-like for-loop semantics and I think it will evolve even more which is why I like this solution.
6

You can't with an enum. Maybe an enum isn't the best fit for your situation.

A common convention is to name the last enum value something like MAX and use that to control a loop using an int.

2 Comments

There are several examples here that demonstrate the opposite. I your own statement you are contradicting yourself (second line).
@Niki He is right when telling "can't with enum". All the answers demonstrate "tricks" to iterate over another thing, as if iterating over enum.
5

Limitation for this entire answer: the enum has to be continuous, with no gaps (skipped integers not assigned to an enum member) between the two enum values you want to iterate between.

For C++20 or later

For C++20 or later, you can now do this magic, iterating over an enum with a range-based for loop:

for (const MyErrorType enum_element : 
    enum_range(MyErrorType::begin, MyErrorType::end))
{
    // switch statement here, operating on `enum_element`
}

...where enum_range() is this custom C++20 range-generator function:

// Generate a C++20 "range" iterating from the enum value `first` to `last`,
// inclusive, to be used in modern C++ range-based for loops.
// - This is also using the C++20 feature of "abbreviated function templates",
//   or "template argument deduction for functions", where `auto` can be used
//   for all input parameter types and for the return type in place of making
//   this a function template. 
constexpr inline auto enum_range(auto first, auto last) 
{
    auto enum_range = 
        std::views::iota(
            static_cast<std::underlying_type_t<decltype(first)>>(first), 
            static_cast<std::underlying_type_t<decltype(last)>>(last) + 1
        ) 
        | std::views::transform([](auto enum_val) 
            {
                return (decltype(first))enum_val; 
            }
        ); 

    return enum_range; 
};

...and your enum definition is like this:

// weak, non-scoped enum
enum MyErrorType 
{
    SOMETHING_1 = 0,
    SOMETHING_2,
    SOMETHING_3,
    SOMETHING_4,
    SOMETHING_5,
    
    // Helpers
    count,
    begin = 0,
    end = count - 1,
};

// OR this: strong, scoped enum class
enum class MyErrorType 
{
    SOMETHING_1 = 0,
    SOMETHING_2,
    SOMETHING_3,
    SOMETHING_4,
    SOMETHING_5,
    
    // Helpers
    count,
    begin = 0,
    end = count - 1,
};

For a full explanation and details, see my answer here: What are commonly-used ways to iterate over an enum class in C++?

I first learned about this from 康桓瑋 (Kang Huanwei) in their answer here.

For pre-C++20


Here are some very readable and easy-to-understand approaches, for both weakly-typed C and C++ regular enums, and strongly-typed C++ enum classes.

I recommend compiling all examples below with -Wall, -Wextra, and -Werror by adding -Wall -Wextra -Werror to your build command. This gives you the added safety that if you forget to cover any enum value in the switch case your compiler will throw a compile-time switch error! This forces you to keep your enum definition and switch cases in-sync, which is an extra safety measure for your code. This tip works so long as you:

  1. Cover all enum values in your switch case, and
  2. Do not have a default switch case.
  3. Build with the -Wall -Wextra -Werror flags.

I recommend you follow all three of those points, as it is a good practice and creates better code.

1. For a standard, weakly-typed C or C++ enum:

C definition (this is also valid C++):

typedef enum my_error_type_e
{
    MY_ERROR_TYPE_SOMETHING_1 = 0,
    MY_ERROR_TYPE_SOMETHING_2,
    MY_ERROR_TYPE_SOMETHING_3,
    MY_ERROR_TYPE_SOMETHING_4,
    MY_ERROR_TYPE_SOMETHING_5,
    /// Not a valid value; this is the number of members in this enum
    MY_ERROR_TYPE_count,
    // helpers for iterating over the enum
    MY_ERROR_TYPE_begin = 0,
    MY_ERROR_TYPE_end = MY_ERROR_TYPE_count,
} my_error_type_t;

C++ definition:

enum my_error_type_t
{
    MY_ERROR_TYPE_SOMETHING_1 = 0,
    MY_ERROR_TYPE_SOMETHING_2,
    MY_ERROR_TYPE_SOMETHING_3,
    MY_ERROR_TYPE_SOMETHING_4,
    MY_ERROR_TYPE_SOMETHING_5,
    /// Not a valid value; this is the number of members in this enum
    MY_ERROR_TYPE_count,
    // helpers for iterating over the enum
    MY_ERROR_TYPE_begin = 0,
    MY_ERROR_TYPE_end = MY_ERROR_TYPE_count,
};

C or C++ iteration over this weakly-typed enum:

Note: incrementing an enum by doing my_error_type++ is not allowed--not even on C-style enums, so we must do this instead: my_error_type = (my_error_type_t)(my_error_type + 1). Notice that my_error_type + 1 is allowed, however, since this weak enum is automatically implicitly cast to an int here to make this addition possible without having to manually cast it to an int like this: my_error_type = (my_error_type_t)((int)my_error_type + 1).

for (my_error_type_t my_error_type = MY_ERROR_TYPE_begin;
        my_error_type < MY_ERROR_TYPE_end;
        my_error_type = (my_error_type_t)(my_error_type + 1))
{
    switch (my_error_type)
    {
        case MY_ERROR_TYPE_SOMETHING_1:
            break;
        case MY_ERROR_TYPE_SOMETHING_2:
            break;
        case MY_ERROR_TYPE_SOMETHING_3:
            break;
        case MY_ERROR_TYPE_SOMETHING_4:
            break;
        case MY_ERROR_TYPE_SOMETHING_5:
            break;
        case MY_ERROR_TYPE_count:
            // This case will never be reached.
            break;
    }
}

2. For a scoped, strongly-typed C++ enum class:

C++ definition:

enum class my_error_type_t
{
    SOMETHING_1 = 0,
    SOMETHING_2,
    SOMETHING_3,
    SOMETHING_4,
    SOMETHING_5,
    /// Not a valid value; this is the number of members in this enum
    count,
    // helpers for iterating over the enum
    begin = 0,
    end = count,
};

C++ iteration over this strongly-typed enum:

Notice the extra (size_t) cast (or (int) would be acceptable too) required to forcefully increment the enum class variable! I also chose to use the C++-style static_cast<my_error_type_t> cast here, but a C-style (my_error_type_t) cast, as done above, would have been fine as well.

for (my_error_type_t my_error_type = my_error_type_t::begin;
        my_error_type < my_error_type_t::end;
        my_error_type = static_cast<my_error_type_t>((size_t)my_error_type + 1))
{
    switch (my_error_type)
    {
        case my_error_type_t::SOMETHING_1:
            break;
        case my_error_type_t::SOMETHING_2:
            break;
        case my_error_type_t::SOMETHING_3:
            break;
        case my_error_type_t::SOMETHING_4:
            break;
        case my_error_type_t::SOMETHING_5:
            break;
        case my_error_type_t::count:
            // This case will never be reached.
            break;
    }
}

Also notice the scoping. In the C++ strongly-typed enum class I used my_error_type_t:: to access each scoped enum class member. But, in the C-style weakly-typed regular enum, very similar scoping can be achieved, as I demonstrated, simply be prefixing each enum member name with MY_ERROR_TYPE_. So, the fact that the C++ strongly-typed enum class adds scoping doesn't really add much value—it's really just a personal preference in that regard.

And the fact that the C++ strongly-typed enum class has extra type-safety also has pros and cons. It may help you in some cases but it definitely makes incrementing the enum and iterating over it a pain-in-the-butt, which, honestly, means it is doing its job.

By making it harder to increment the scoped enum class variable as though it was an integer, the C++ strongly-typed enum class is doing exactly what it was designed to do. Whether or not you want that behavior is up to you. Personally, I frequently do not want that behavior, and so it is not uncommon for me to prefer to use C-style enums even in C++.

See also:

  1. [my answer] Is there a way to initialize a vector by index in c++11?
  2. [my Q&A] What are commonly-used ways to iterate over an enum class in C++?
  3. My answer on some of the differences between enum classes (strongly-typed enums) and regular enums (weakly-typed enums) in C++: How to automatically convert strongly typed enum into int?
  4. Some of my personal notes on the -Wall -Wextra -Werror and other build options, from my eRCaGuy_hello_world repository.

Comments

4

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 the disassembly in VC++. The code is extremely efficient. Don't be put off by 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.

2 Comments

That's a wonderful hack! Although it is more appropriate for C than for C++, one might say.
_A1 is not an allowed name, it is a leading underscore with a following capital letter.
3

Here's another solution which only works for contiguous enums. It gives the expected iteration, except for ugliness in the increment, which is where it belongs, since that's what's broken in C++.

enum Bar {
    One = 1,
    Two,
    Three,
    End_Bar // Marker for end of enum; 
};

for (Bar foo = One; foo < End_Bar; foo = Bar(foo + 1))
{
    // ...
}

2 Comments

Incrementing can be shortened to foo = Bar(foo + 1).
Thanks, HolyBlackCat, I've incorporated your excellent suggestion! I also notice that Riot has pretty much this same solution, but conformant with strong typing (and thus more verbose).
3

Upsides: enums can have any values you like in any order you like and it's still easy to iterate over them. Names and values are defined once, in the first #define.

Downsides: if you use this at work, you need a whole paragraph to explain it to your coworkers. And, it's annoying to have to declare memory to give your loop something to iterate over, but I don't know of a workaround that doesn't confine you to enums with adjacent values (and if the enum will always have adjacent values, the enum might not be buying you all that much anyway.)

//create a, b, c, d as 0, 5, 6, 7
#define LIST x(a) x(b,=5) x(c) x(d)
#define x(n, ...) n __VA_ARGS__,
enum MyEnum {LIST}; //define the enum
#undef x //needed
#define x(n,...) n ,
MyEnum myWalkableEnum[] {LIST}; //define an iterable list of enum values
#undef x //neatness

int main()
{
  std::cout << d;
  for (auto z : myWalkableEnum)
    std::cout << z;
}
//outputs 70567

The trick of declaring a list with an undefined macro wrapper, and then defining the wrapper differently in various situations, has a lot of applications other than this one.

1 Comment

I don't believe this should be downvoted. It's a portable solution that works with enums that are not consecutive; and other answers involving arrays were upvoted. Mine has the advantage that you don';t have to define the enum values twice and keep two definitions in sync, and it showcases a useful trick for interpreting tokens multiple ways with undef and define that is generally applicable to many problems. Unless and until we get enum ++, -- and iterators, there's simply no clean way to do it. This is the cleanest of the workarounds.
2

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

3 Comments

You can't overload any operators on C or C++ enumerated types. Unless you were to create a struct/class that emulated an enumeration of values.
C++ allows overloading operators on enums. See stackoverflow.com/questions/2571456/… .
Overloading the increment/decrement requires making a decision on what to do when there is an overflow
2

If you do not like to pollute you enum with a final COUNT item (because maybe if you also use the enum in a switch then then the compiler will warn you of a missing case COUNT:), you can do this:

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

Comments

2

In Bjarne Stroustrup's C++ programming language book, you can read that he's proposing to overload the operator++ for your specific enum. enum are user-defined types and overloading operator exists in the language for these specific situations.

You'll be able to code the following:

#include <iostream>
enum class Colors{red, green, blue};
Colors& operator++(Colors &c, int)
{
     switch(c)
     {
           case Colors::red:
               return c=Colors::green;
           case Colors::green:
               return c=Colors::blue;
           case Colors::blue:
               return c=Colors::red; // Managing overflow
           default:
               throw std::exception(); // Or do anything else to manage the error...
     }
}

int main()
{
    Colors c = Colors::red;
    // Casting in int just for convenience of output. 
    std::cout << (int)c++ << std::endl;
    std::cout << (int)c++ << std::endl;
    std::cout << (int)c++ << std::endl;
    std::cout << (int)c++ << std::endl;
    std::cout << (int)c++ << std::endl;
    return 0;
}

Test code: http://cpp.sh/357gb

Mind that I'm using enum class. The code also works fine with enum. But I prefer enum class since they are strongly typed and can prevent us from make a mistake at compile time.

5 Comments

A downvote was cast on this post. Any reason why would it will not answer to the question ?
The reason is probably because this is a terrible solution architecturally speaking: it forces you to write global-meant-to logic binded to a specific component (your enumeration), moreover if your enumeration does change for whatever reason you are forced to edit your ++ operator too, as an approach it is not sustainable for any medium-large scale project, it is not a surprise it comes from a Bjarne Stroustrup's recommendation, back in the days software architecture was like science fiction
Original question is about having operator to an enum. It wasn't a architectural question. I don't believe that in 2013 C++ was a science fiction.
I don't think people here are looking for bad solutions, which this one definitely is, and therefore downvoted. I just added my downvote too btw
I upvote as it is an interesting concept, functional, and the other statements are personal bias.
2

There is already a discussion about std::initializer_list (C++11) in the comments. I am mentioning an example to iterate over the enum.

Or std::initializer_list and a simpler syntax:

enum E {
    E1 = 4,
    E2 = 8,
    // ..
    En
};

constexpr std::initializer_list<E> all_E = {E1, E2, /*..*/ En};

and then

for (auto e : all_E) {
    // Do job with e
}

Reference

1 Comment

What comments? Where?
2

(Taking Marski's answer as a big hint...)

Since the body of an enum definition is the same as an initialiser list, it is possible to do this without repeating the item list if we use a simple macro to write out the values:

#define ITEM_LIST_MACRO Wolf, Goat, Cabbage

enum Item { ITEM_LIST_MACRO }; // Define the enum

// Now iterate through it
for (auto item : { ITEM_LIST_MACRO }) {
}

Pros: It is simple, without any repetition, and there isn't any need to maintain annoying first/last sentinel values. (Indeed I think this might be the only solution suggested so far that does not require the user to remember to update an 'end' marker when a new item is added to the list.)

Cons: It doesn't work with scoped enums (enum class), because the initialiser list would need the scope (Item::Wolf, etc.). Also, it doesn't work if you want to specify the values of the enum members rather than having them defaulted.

Comments

1

For Microsoft 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.

1 Comment

This was written ~5 years after decltype became standard C++, so you should not recommend the outdated typeof from ancient GCC. Vaguely recent GCC handles decltype just fine. There are other issues: C-style casts are discouraged, & macros worse. Proper C++ features can give the same generic functionality. This would be better rewritten to use static_cast & a template function: template <typename T> auto inc_enum(T const t) { return static_cast<T>(static cast<int>(t) + 1); }. And casts aren't needed for non-enum class. Alternatively, operators can be overloaded per enum type (TIL)
1

Extending Eponymous's answer: It's great, but it doesn't provide a general syntax. Here's what I came up with:

File Common/EnumTools.h

#pragma once

#include <array>

namespace Common {

// Here we forward-declare metafunction for mapping enums to their values.
// Since C++<23 doesn't have reflection, you have to populate it yourself :-(
// Usage: After declaring enum class E, add this overload in the namespace of E:
// inline constexpr auto allValuesArray(const E&, Commob::EnumAllValuesTag) { return std::array{E::foo, E::bar}; }
// Then `AllValues<NS::E>` will call `allValuesArray(NS::E{}, EnumAllValuesTag)` which will resolve
// by ADL.
// Just be sure to keep it sync'd with your enum!

// Here's what you want to use in, e.g., loops: "for (auto val : Common::AllValues<MyEnum>) {"

struct EnumAllValuesTag {}; // So your allValuesArray function is clearly associated with this header.

template <typename Enum>
static inline constexpr auto AllValues = allValuesArray(Enum{}, EnumAllValuesTag{});
// ^ Just "constexpr auto" or "constexpr std::array<Enum, allValuesArray(Enum{}, EnumAllValuesTag{}).size()>" didn't work on all compilers I'm using, but this did.

} // namespace Common

Then in your namespace:

#include "Common/EnumTools.h"

namespace MyNamespace {

enum class MyEnum {
    foo,
    bar = 4,
    baz = 42,
};

// Making this not have to be in the `Common` namespace took some thinking,
// but is a critical feature since otherwise there's no hope in keeping it sync'd with the enum.
inline constexpr auto allValuesArray(const MyEnum&, Common::EnumAllValuesTag) {
    return std::array{ MyEnum::foo, MyEnum::bar, MyEnum::baz };
}

} // namespace MyNamespace

Then wherever you need to use it:

for (const auto& e : Common::AllValues<MyNamespace::MyEnum>) { ... }

So even if you've typedef'd:

namespace YourNS {
using E = MyNamespace::MyEnum;
} // namespace YourNS

for (const auto& e : Common::AllValues<YourNS::E>) { ... }

I can't think of anything much better, short of the actual language feature everyone looking at this page want.

Future work:

  1. You should be able to add a constexpr function (and so a metafunction) that filters Common::AllValues<E> to provide a Common::AllDistinctValues<E> for the case of enums with repeated numerical values like enum { foo = 0, bar = 0 };.
  2. I bet there's a way to use the compiler's switch-covers-all-enum-values to write allValuesArray such that it errors if the enum has added a value.

1 Comment

That's interesting. I ended up using only inline constexpr auto allValuesArray() { return std::array{ MyEnum::foo, MyEnum::bar, MyEnum::baz }; } since I need to spell it out one by one anyway. That's for me the simplest solution. (btw: with your code I saw clang-7 crashing. fun fun fun XD)
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.

Comments

0
typedef enum{
    first = 2,
    second = 6,
    third = 17
}MyEnum;

static const int enumItems[] = {
    first,
    second,
    third
}

static const int EnumLength = sizeof(enumItems) / sizeof(int);

for(int i = 0; i < EnumLength; i++){
    //Do something with enumItems[i]
}

2 Comments

This solution will create a unnecessarily static variables in memory while the objective of enum is just to create a 'mask' to constants inlined
Unless changed to constexpr static const int enumItems[]
0
template< class Enum > requires std::is_enum_v<Enum>
constexpr auto enum_view( Enum first, Enum sentinel ) {
    return views::iota( std::to_underlying(first), std::to_underlying(sentinel) )
        | views::transform( []( auto value ) { return Enum(value); } );
    }

Comments

0

Using a lambda, I found this is the best (modern) way of looping over enums. This highly improves the abstraction.

One can even make it a template, so it's applicable to any enum. This code neither gives you issues with Clang (and Clang-Tidy).

#include <functional>

/// @brief Loop over all enum values where the last enum value is the invalid one
void forEachAction(std::function<void(Enum)> &&doThis) {
    for (int value = 0; value != static_cast<int>(Enum::LastValue); ++value ) {
        doThis(static_cast<Enum>(value ));
    }
}

...

forEachAction([this](Enum value) {
    ...  // What you want to execute for every enum
});

Of course, this requires updating LastValue, should it change.

Comments

-1

Most solutions are based on loops over the (MIN, MAX) range, but they overlook the fact that might be holes in the enum.

My suggestions is:

        for (int i = MYTYPE_MIN; i <= MYTYPE_MAX; i++) {
            if (MYTYPE_IsValid(i)) {
                MYTYPE value = (MYTYPE)i;
                // DoStuff(value)
            }
        }

2 Comments

Awesome! So now all we need to do is implement MYTYPE_IsValid. Doing so leaves you with two options: 1 An implementation whose name doesn't lie but is useless in always returning true. 2 An implementation that does something else than its name implies, but cannot be implemented in a generic fashion. It becomes invalid with every change to the enum definition, that cannot be diagnosed.
@IInspectable YMMV but I think it is not that hard to define a maintainable MYTYPE_IsValid(int) function by relying on a switch case and warnings related to non-handled enumerated value in switch case. This type of function is also useful to perform checks before casting the value when you get your value as a raw integer. (For what it's worth, my snippet was initially written for protobuf enums which do define an IsValid function).
-2

Just make an array of ints and loop over the array, but make the last element say -1 and use it for exit condition.

If enum is:

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

then create array:

int Array[] = {Hay,Grass,Beer,-1};

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

This does not break down no matter the ints in the representation as long as -1 check does not collide with one of the elements of course.

Comments

-3

C++ doesn't have introspection, so you can't determine this kind of thing at run-time.

7 Comments

Could you explain to me why "introspection" would be needed to iterate over an enum?
Maybe the term is Reflection?
I'm trying to say 2 things: 1) Per many other answers C++ can accomplish this so if you're going to say it cannot, a link or further clarification is required. 2) In it's current form this is at best a comment, certainly not an answer.
Downvote my answer then - I think you've more than justified it
I'll again cram in 2 comments: 1) I don't downvote because I find that receiving a downvote demotivates site participation, I find that counterproductive 2) I still don't understand what you're trying to say but it sounds like you understand something I don't in which case I'd prefer you elaborate rather than delete a downvoted answer.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.