90

I have a recurrent chunk of code where I loop over all the members of an enum class.

The for loop that I currently use looks very unwieldly compared to the new range-based for.

Is there any way to take advantage of new C++11 features to cut down on the verbosity for my current for loop?

Current Code that I would like to improve:

enum class COLOR
{
    Blue,
    Red,
    Green,
    Purple,
    First=Blue,
    Last=Purple
};

inline COLOR operator++( COLOR& x ) { return x = (COLOR)(((int)(x) + 1)); }

int main(int argc, char** argv)
{
  // any way to improve the next line with range-based for?
  for( COLOR c=COLOR::First; c!=COLOR::Last; ++c )
  {
    // do work
  }
  return 0;
}

In other words, it would be nice if I could do something like:

for( const auto& c : COLOR )
{
  // do work
}
8
  • 23
    Interesting. Ada's had this feature since 1983. Commented Dec 14, 2011 at 1:05
  • 8
    (COLOR)(((int)(x) + 1)) Instead of int, consider using std::underlying_type<COLOR>::type. Commented Dec 14, 2011 at 1:06
  • 8
    Is it expected that Purple is skipped? Commented Dec 14, 2011 at 1:09
  • 4
    @kfmfe04 std::underlying_type is not supported on GCC 4.6. It will be supported on 4.7. There's an approximate emulation here: stackoverflow.com/a/7932617/46642. Commented Dec 14, 2011 at 1:20
  • 5
    Gah! so fast to accept. I usually wait 24 hours just to give all timezones a chance to come up with a better answer. Commented Dec 14, 2011 at 2:01

14 Answers 14

64

I personally don't like overloading the ++ operator for enums. Often incrementing an enum value doesn't really make sense. All that is really wanted is a way to iterator over the enum.

Below is an generic Enum class that supports iteration. It's functional but incomplete. A real implementation would do well to restrict access to the constructor and add all the iterator traits.

#include <iostream>

template< typename T >
class Enum
{
public:
   class Iterator
   {
   public:
      Iterator( int value ) :
         m_value( value )
      { }

      T operator*( void ) const
      {
         return (T)m_value;
      }

      void operator++( void )
      {
         ++m_value;
      }

      bool operator!=( Iterator rhs )
      {
         return m_value != rhs.m_value;
      }

   private:
      int m_value;
   };

};

template< typename T >
typename Enum<T>::Iterator begin( Enum<T> )
{
   return typename Enum<T>::Iterator( (int)T::First );
}

template< typename T >
typename Enum<T>::Iterator end( Enum<T> )
{
   return typename Enum<T>::Iterator( ((int)T::Last) + 1 );
}

enum class Color
{
   Red,
   Green,
   Blue,
   First = Red,
   Last = Blue
};

int main()
{
   for( auto e: Enum<Color>() )
   {
      std::cout << ((int)e) << std::endl;
   }
}
Sign up to request clarification or add additional context in comments.

4 Comments

Agreed. This is much, much better than overloading operators on the enumeration type itself.
+1 Nice - I have modified my own Enum class to follow your format (not in OP). The type-safety is nice, but T from_string( const string& T ) is a bit of a pain as in C++, we can't overload on the return enum value. The same problem exists whether or not I use a template-Enum, but with template-Enum, it's just a little more verbose.
Working complete implementation, also note that I changed the value of Last to be more consistent with normal iterator ranges.
this is a nice but incomplete workaround: enum class Color { red, green, blue, white = 20, First = red, Last=white } - with the wrapper-class this will not produce the correct output. It only works with dense numbers.
49
enum class Color {
    blue,
    red,
    green = 5,
    purple
};
const std::array<Color,4> all_colors = {Color::blue, Color::red, Color::green, Color::purple};

Then:

for (Color c : all_colors) {
    //...
}

Many times I use it like this, where I want a 'none' value:

// Color of a piece on a chess board
enum class Color {
    white,
    black,
    none
};
const std::array<Color,3> colors = {Color::white, Color::black};

template <typename CONTAINER>
bool has_item (CONTAINER const & c, typename CONTAINER::const_reference v) {
    return std::find(c.begin(), c.end(), v) != c.end();
}

bool is_valid (Color c) {
    return has_item(colors, c) || c == Color::none;
}

bool do_it (Color c) {
    assert(has_item(colors, c)); // here I want a real color, not none
    // ...
}

bool stop_it (Color c) {
    assert(is_valid(c));         // but here I just want something valid
    // ...
}

4 Comments

This is a great answer! The redundancy of having the items in two places is a pity, but it's a much cleaner solution than the other solutions; this has no casting, and as you mention the values don't have to start at zero or be contiguous. You can also easily specify subsets of values e.g. darkColors and lightColors. It relies a bit on enums having a fairly small number of values, but they usually do anyway.
An addendum to your answer: with this solution you can get the count of values with colors.size(). If you need a compile time constant (for the size of another array, for example) you can use std::tuple_size(decltype(colors))::value, which is admittedly a bit long winded but totally safe.
Why is the size of the array specified as 3? Shouldn't it be 2? And if so, doesn't this illustrate that violating the DRY principle always leads to hard-to-see bugs?
Really bad if someone adds a value. Than your array is not covering all values!!
40

Iterating enumerations with the enumeration itself as an iterator is a poor idea, and I recommend using an actual iterator as in deft_code's answer. But if this is really what you want:

COLOR operator++(COLOR& x) {
    return x = (COLOR)(std::underlying_type<COLOR>::type(x) + 1); 
}

COLOR operator*(COLOR c) {
    return c;
}

COLOR begin(COLOR r) {
    return COLOR::First;
}

COLOR end(COLOR r) {
    COLOR l=COLOR::Last;
    return ++l;
}

int main() { 
    //note the parenthesis after COLOR to make an instance
    for(const auto& c : COLOR()) {
        //do work
    }
    return 0;
}

Working here: http://ideone.com/cyTGD8


On the iterator side of things, the easiest way is simply:
const COLOR COLORS[] = {COLOR::Blue, COLOR::Red, COLOR::Green, COLOR::Purple};
const COLOR (&COLORREF)[(int)COLOR::Last+1] = COLORS;

int main() { 
    for(const auto& c : COLORS) {
        //do work
    }
    return 0;
}

As seen here: http://coliru.stacked-crooked.com/a/5d356cc91556d6ef

(The separate defintinion and the reference of the array makes it a compiler error if the number of colors doesn't match the number of elements in the array. Excellent easy safety check.)

13 Comments

Needs an operator* to make COLOR an input iterator.
@R.MartinhoFernandes what should the signature of this operator* look like?
@kfmfe04 I added it to the answer.
@R.MartinhoFernandes: Thanks, I don't have access compiler with ranged based for loops. Though it was beginning to occur to me that I should use an actual iterator to iterate instead of the colors themselves. That's probably the better answer. Does ++c work with an enum class? Probably not...
@MooingDuck ++ doesn't work on strong typed enums, but kfmfe04 has an implementation on his question.
|
8

I'm sure that you can iterate over the members of a C++ initializer_list, so I reckon I've done this in the past:

enum class Color {Red, Green, Blue};

for (const Color c : {Color::Red, Color::Green, Color::Blue})
{
}

Whether there are issues with this, I don't know, but I thought I'd suggest it as it is concise, but not ideal if there are a lot of Colors.

2 Comments

This works but is not maintenance friendly. Consider when you are adding an new enum. We tag our enums with begin and end (e.g. eCol0rBegin = 0 and eColorEnd) and preferably you want the code to pick it up everywhere automatically.
Yes @gast128 - you're right. If that was going to be a potential issue, then I would add an end marker to the enum like: enum class Color {Red, Green, Blue, Count}; I can then static_assert that Count has not changed.
7

You could probably do something clever with boost::mpl, a rough version might look like:

#include <typeinfo>

// ---------------------------------------------------------------------------|
// Boost MPL
// ---------------------------------------------------------------------------|
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/iterator_range.hpp>
#include <boost/mpl/range_c.hpp>

namespace mpl = boost::mpl;

using namespace std;

enum class COLOR 
{ 
   Blue,
   Red,
   Green,
   Purple,
   Last
};

struct enumValPrinter
{
    template< typename T >
    void operator() (const T&)
    {
        cout << "enumValPrinter with: " << typeid( T ).name() << " : " 
             << T::value << "\n";
    }
};

int main(int, char**)
{
    typedef mpl::range_c< int, static_cast<int>( COLOR::Blue ), 
                            static_cast<int>( COLOR::Last ) > Colors;
    mpl::for_each< Colors >( enumValPrinter() );
    return 0;
}

Comments

4

Here's a tested example (GCC 4.6.1):

enum class COLOR
{
    Blue,
    Red,
    Green,
    Purple,
    First=Blue,
    Last=Purple
};

COLOR operator++( COLOR& x ) { return x = (COLOR)(((int)(x) + 1)); }

COLOR operator*(COLOR c) {return c;}

COLOR begin(COLOR r) {return COLOR::First;}
// end iterator needs to return one past the end!
COLOR end(COLOR r)   {return COLOR(int(COLOR::Last) + 1);}


int main()
{
    for (const auto& color : COLOR()) std::cout << int(color); //0123
    return 0;
}

1 Comment

This does also work with Intel C++ 2013 SP1 on Linux, when you install Update 1 this fails to compile, we reported an issue to Intel Engineering for that.
4

If you're a terrible person you can get this behavior with the preprocessor, something like:

#include <vector>
#include <cstdio>

#define ENUM_NAME COLOR
#define ENUM_VALUES \
    ENUM_VALUE(Blue) \
    ENUM_VALUE(Red) \
    ENUM_VALUE(Green) \
    ENUM_VALUE(Purple)

// This block would be a #include "make_iterable_enum.h"
#define ENUM_VALUE(v) v,
enum class ENUM_NAME {ENUM_VALUES};
#undef ENUM_VALUE
#define ENUM_VALUE(v) ENUM_NAME::v,
#define VECTOR_NAME(v) values_ ## v
#define EXPAND_TO_VECTOR_NAME(v) VECTOR_NAME(v)
const std::vector<ENUM_NAME> EXPAND_TO_VECTOR_NAME(ENUM_NAME){ENUM_VALUES};
#undef ENUM_VALUE
#undef ENUM_NAME
#undef ENUM_VALUES
#undef VECTOR_NAME
#undef EXPAND_TO_VECTOR_NAME
// end #included block

int main() {
    for (auto v : COLOR_values) {
        printf("%d\n", (int)v);
    }
}

With minor modifications this could also support eg. ENUM_SETVALUE(Blue, 4) and making a const map from eg. COLOR::Blue to "Blue". And vice-versa.

I wish the standard had just built these features in as options to enum class. None of the workarounds are good.

Comments

2

I like the idea a lot and have often wished for it.

The problem I see is what happens when there is a repeated numeric value for an enum item. All the implementations I see above require casts to integral type and ++. Ultimately, I think language support might be required to truly iterate over each item in all cases. It would remove the need to have First, Last or Begin, End although I don't object to this too much. It's like looking for begin() end() for containers.

enum class COLOR 
{
   Blue,
   Red,
   Green,
   Mauve = 0,
   Purple,
   Last
};

The numbering starts over at Mauve.

1 Comment

Yeah or when there are gaps.
2

My two cents: as a complete unashamed hijacking of @matthiascy solution, and coming back to @deft_code philosophy, I introduced default values to _First and _Last template's arguments in order to be able to loop through part of the enum. Doing so, of course, we need again the First and Last in the enum class (which is why this is a hijacking).

template< typename T, T _First = T::First, T _Last= T::Last >
class Enum
{
public:
   class Iterator
   {
   public:
      Iterator( int value ) :
         m_value( value )
      { }

      T operator*( void ) const
      {
         return (T)m_value;
      }

      void operator++( void )
      {
         ++m_value;
      }

      bool operator!=( Iterator rhs )
      {
         return m_value != rhs.m_value;
      }

   private:
      int m_value;
   };

};

template< typename T, T _First = T::First, T _Last= T::Last >
typename Enum<T, _First, _Last >::Iterator begin( Enum<T, _First, _Last> )
{
   return typename Enum<T, _First, _Last>::Iterator( (int)_First );
}

template< typename T, T _First = T::First, T _Last= T::Last >
typename Enum<T, _First, _Last>::Iterator end( Enum<T, _First, _Last> )
{
   return typename Enum<T, _First, _Last>::Iterator( ((int)_Last) + 1 );
}

For example, to loop through all the pins of an Arduino board:

  for( auto p: Enum<PIN>() ) {
    ...
  }

Or only through the pins of a bus:

  for( auto p: Enum<PIN, PIN::D0, PIN::D6>() ) {
    ...
  }

1 Comment

Very interesting idea!
1

Whether or not you approve of incrementing enums there are times when it is useful. So here's a simple way of doing so:

enum class COLOR
{
    Blue,
    Red,
    Green,
    Purple,
    First=Blue,
    Last=Purple
};

COLOR c;

++( *reinterpret_cast<int*>( &c));

There is no overhead since the compiler will take care of the casting and de-referencing. Add range checking or other capabilities as necessary.

1 Comment

For every complex problem there is an answer that is clear, simple, and wrong. -- H. L. Mencken
1

As a modification of @deft_code's answer, you don't need to define the First and the Last in your enum class, just add two parameters for the templated Enum class.

template< typename T, T _Fist, T _Last >
class Enum
{
public:
   class Iterator
   {
   public:
      Iterator( int value ) :
         m_value( value )
      { }

      T operator*( void ) const
      {
         return (T)m_value;
      }

      void operator++( void )
      {
         ++m_value;
      }

      bool operator!=( Iterator rhs )
      {
         return m_value != rhs.m_value;
      }

   private:
      int m_value;
   };

};

template< typename T, T _Fist, T _Last >
typename Enum<T, _First, _Last >::Iterator begin( Enum<T, _First, _Last> )
{
   return typename Enum<T, _First, _Last>::Iterator( (int)_First );
}

template< typename T, T _Fist, T _Last >
typename Enum<T, _First, _Last>::Iterator end( Enum<T, _First, _Last> )
{
   return typename Enum<T, _First, _Last>::Iterator( ((int)_Last) + 1 );
}

Comments

1

Extending, but also simplifying the previous answer from @rubenvb (wow, December 2016th already).

To easily iterate over the colors and have a means of providing a numerical or string value to each color (e.g. when you want the values in some Xml file).

enum class COLOR
{
    Blue,
    Red,
    Green,
    Purple,
};

std::map<COLOR,std::string> colors = {
 {COLOR::Blue,"Blue"},
 {COLOR::Red,"Red"},
 {COLOR::Green,"Green"},
 {COLOR::Purple,"Purple"}, // yay Whoopi, great movie
};

for (auto pair : colors) {
  do_something_with_color(pair.first);
  and_maybe_even_do_something_with_color_value(pair.second);
}

Maintenance is not even so hard, just make sure you got all your enums in the map.

Comments

0

I build up on the user1594322 and rubenvb nice solution above with templates.

#include "enum_support.h"
enum class Color { blue, red, green, purple, count };
// use as follows
for (Color c : all_values<Color>) { /* ... /* }

The supporting code is in "enum_support.h" that defines a constexpr templated array variable all_values<E> and fills it with values:

template<typename E, size_t count = size_t(E::count)>
constexpr std::array<E, count> enumerate_enum_values() {
    std::array<E, count> arr;
    typename std::underlying_type_t<E> i = 0;
    for (auto& elem : arr) {
        elem = static_cast<E>(i++);
    }
    return arr;
}

template<typename E>
constexpr std::array<E, size_t(E::count)> all_values = enumerate_enum_values<E>();

There is no golden cow and it has prerequisite that 1) the range of values in the enum starts from zero and is continous, and 2) enums define variable count at the end of their lists.

EDIT: Shorter code utilizing templated lambda since C++20 for your liking:

template<typename T, size_t count = size_t(T::count)>
constexpr std::array <T, count> all_values = []<typename E = T>() {
    std::array<E, count> arr;
    typename std::underlying_type_t<E> i = 0;
    for (auto& elem : arr) {
        elem = static_cast<E>(i++);
    }
    return arr;
}();

Comments

0

Although the question is tagged C++11, it's worth mentioning that language proposal P2996 introduces new introspection facilities, enabling us to write something like this if/when it's adopted:

  template for (constexpr auto e: std::meta::enumerators_of(^E)) {
      COLOR const c = [:e:];
      // ...
  }

Or more concisely, if range splicers are available:

  for (auto c: [: ...std::meta::enumerators_of(^E) :]) {
      // ...
  }

P2996 is targeting C++26, though range splicers aren't included at this stage. They may be proposed for some later C++ version, when we have more implementation experience.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.