Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Allow for Range-Based For with enum classes?

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 } 
like image 911
kfmfe04 Avatar asked Dec 14 '11 00:12

kfmfe04


People also ask

Can you loop through an enum C ++?

Yes. It iterates over an std::initializer_list<Item>. link.

Can I inherit an enum class?

As we have learned, we cannot inherit enum classes in Java. However, enum classes can implement interfaces.

What is range of enum?

the range of enum constants is -129 through -127. This range only falls within the ranges of short (signed short) and int (signed int). Because short (signed short) is smaller, it will be used to represent the enum.

Can enum class contain methods?

The enum class body can include methods and other fields. The compiler automatically adds some special methods when it creates an enum. For example, they have a static values method that returns an array containing all of the values of the enum in the order they are declared.


2 Answers

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;    } } 
like image 190
deft_code Avatar answered Sep 17 '22 20:09

deft_code


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     // ... } 
like image 42
user1594322 Avatar answered Sep 18 '22 20:09

user1594322