Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simplest method for iterating through contiguous enum values in C++ [duplicate]

What is the preferred simple method for iterating through an enum with contiguous values in C++? I found previous SO questions on this subject which involved creating custom operator++ etc, but this seems like overkill. So far the best I have come up with is:

enum {
   FOO,
   BAR,
   BLECH,
   NUM_ENUMS
} MyEnum;

//for (MyEnum m = FOO; m < NUM_ENUMS; ++m)             // compile error
//    ...

//for (MyEnum m = FOO; m < NUM_ENUMS; m = m + 1)       // compile error
//    ...

for (MyEnum m = FOO; m < NUM_ENUMS; m = MyEnum(m + 1)) // OK ?
    ...

Is this reasonable from a coding style perspective and is it likely to generate warnings (g++ -Wall ... seems happy with this) ?

like image 291
Paul R Avatar asked Jun 20 '13 11:06

Paul R


People also ask

Can you iterate through enum in C?

you can iterate the elements like: for(int i=Bar; i<=Last; i++) { ... } Note that this exposes the really-just-an-int nature of a C enum. In particular, you can see that a C enum doesn't really provide type safety, as you can use an int in place of an enum value and vice versa.

How do I iterate over an enum?

Enums don't have methods for iteration, like forEach() or iterator(). Instead, we can use the array of the Enum values returned by the values() method.

What is an enum in C?

Enumeration or Enum in C is a special kind of data type defined by the user. It consists of constant integrals or integers that are given names by a user. The use of enum in C to name the integer values makes the entire program easy to learn, understand, and maintain by the same or even different programmer.


2 Answers

It is indeed safe.

This would have been undefined: MyEnum(int(NUM_ENUMS) + 1) because the value to hold (4) would be greater than what the enum can represent ([0, 3]); since you ensure that m is strictly lower than NUM_ENUMS it is safe to use MyEnum(m + 1).

On the other hand, note that you would have issues with customized enums such as:

enum OtherEnum {
    Foo = -1,
    Bar = 2,
    Baz = 8,
    NUM_OTHERENUM
};

so it is not a generic practice.

I would advise a generated array to iterate over instead:

MyEnum const Values[] = { FOO, BAR, BLECH };

Note that it is easily generated from the definition of the enum, and also avoid polluting the interface with a nonsensical value (business-wise).

like image 64
Matthieu M. Avatar answered Sep 17 '22 16:09

Matthieu M.


Like Matthieu said it is perfectly safe to do so and does not go against the C++ standard in any way.

As a side note overloading ++ operator over enum is not only an overkill, but has issues already stated by others (e.g. if enum is not linear in values)

Therefore instead of defining an operator ++, what you need is an iterator.

I adapted the following solution from here regarding enums by deft_code but slightly tailored to your example.

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 MyEnum
{
   FOO,
   BAR,
   BLECH,
   NUM_ENUMS
};

int main()
{
   for( auto e: Enum<MyEnum>() )
   {
      std::cout << ((int)e) << std::endl;
   }
}

This may still be an overkill for you, but its much cleaner. Another piece of code but much more elegant approach is here. It is possible in the future enum classes introduced in C++11 may have an iterator in the standard.

update: Since you updated us that your values are contiguous and the fact that it is required for a C API (?) then the above will not be suitable

like image 23
woosah Avatar answered Sep 20 '22 16:09

woosah