c++enumsmetaprogrammingenumeration

Enumerate over an enum in C++


In C++, Is it possible to enumerate over an enum (either runtime or compile time (preferred)) and call functions/generate code for each iteration?

Sample use case:

enum abc
{    
    start
    a,
    b,
    c,
    end
}    
for each (__enum__member__ in abc)
{    
    function_call(__enum__member__);    
}

Plausible duplicates:


Solution

  • To add to StackedCrooked's answer, you can overload operator++, operator-- and operator* and have iterator-like functionality.

    enum Color {
        Color_Begin,
        Color_Red = Color_Begin,
        Color_Orange,
        Color_Yellow,
        Color_Green,
        Color_Blue,
        Color_Indigo,
        Color_Violet,
        Color_End
    };
    
    namespace std {
    template<>
    struct iterator_traits<Color>  {
      typedef Color  value_type;
      typedef int    difference_type;
      typedef Color *pointer;
      typedef Color &reference;
      typedef std::bidirectional_iterator_tag
        iterator_category;
    };
    }
    
    Color &operator++(Color &c) {
      assert(c != Color_End);
      c = static_cast<Color>(c + 1);
      return c;
    }
    
    Color operator++(Color &c, int) {
      assert(c != Color_End);
      ++c;
      return static_cast<Color>(c - 1);
    }
    
    Color &operator--(Color &c) {
      assert(c != Color_Begin);
      return c = static_cast<Color>(c - 1);
    }
    
    Color operator--(Color &c, int) {
      assert(c != Color_Begin);
      --c;
      return static_cast<Color>(c + 1);
    }
    
    Color operator*(Color c) {
      assert(c != Color_End);
      return c;
    }
    

    Let's test with some <algorithm> template:

    void print(Color c) {
      std::cout << c << std::endl;
    }
    
    int main() {
      std::for_each(Color_Begin, Color_End, &print);
    }
    

    Now, Color is a constant bidirectional iterator. Here is a reusable class I coded while doing it manually above. I noticed it could work for many more enums, so repeating the same code all over again is quite tedious.

    // Code for testing enum_iterator
    // --------------------------------
    
    namespace color_test {
    enum Color {
      Color_Begin,
      Color_Red = Color_Begin,
      Color_Orange,
      Color_Yellow,
      Color_Green,
      Color_Blue,
      Color_Indigo,
      Color_Violet,
      Color_End
    };
    
    Color begin(enum_identity<Color>) {
      return Color_Begin;
    }
    
    Color end(enum_identity<Color>) {
      return Color_End;
    }
    }
    
    void print(color_test::Color c) {
      std::cout << c << std::endl;
    }
    
    int main() {
      enum_iterator<color_test::Color> b = color_test::Color_Begin, e;
      while(b != e)
        print(*b++);
    }
    

    An implementation follows.

    template<typename T>
    struct enum_identity {
      typedef T type;
    };
    
    namespace details {
    void begin();
    void end();
    }
    
    template<typename Enum>
    struct enum_iterator
      : std::iterator<std::bidirectional_iterator_tag,
                      Enum> {
      enum_iterator():c(end()) { }
    
      enum_iterator(Enum c):c(c) {
        assert(c >= begin() && c <= end());
      }
    
      enum_iterator &operator=(Enum c) {
        assert(c >= begin() && c <= end());
        this->c = c;
        return *this;
      }
    
      static Enum begin() {
        using details::begin; // re-enable ADL
        return begin(enum_identity<Enum>());
      }
    
      static Enum end() {
        using details::end; // re-enable ADL
        return end(enum_identity<Enum>());
      }
    
      enum_iterator &operator++() {
        assert(c != end() && "incrementing past end?");
        c = static_cast<Enum>(c + 1);
        return *this;
      }
    
      enum_iterator operator++(int) {
        assert(c != end() && "incrementing past end?");
        enum_iterator cpy(*this);
        ++*this;
        return cpy;
      }
    
      enum_iterator &operator--() {
        assert(c != begin() && "decrementing beyond begin?");
        c = static_cast<Enum>(c - 1);
        return *this;
      }
    
      enum_iterator operator--(int) {
        assert(c != begin() && "decrementing beyond begin?");
        enum_iterator cpy(*this);
        --*this;
        return cpy;
      }
    
      Enum operator*() {
        assert(c != end() && "cannot dereference end iterator");
        return c;
      }
    
      Enum get_enum() const {
        return c;
      }
    
    private:
      Enum c;
    };
    
    template<typename Enum>
    bool operator==(enum_iterator<Enum> e1, enum_iterator<Enum> e2) {
      return e1.get_enum() == e2.get_enum();
    }
    
    template<typename Enum>
    bool operator!=(enum_iterator<Enum> e1, enum_iterator<Enum> e2) {
      return !(e1 == e2);
    }