anatolyg
anatolyg

Reputation: 28241

How to define increment/decrement/etc operator automatically?

I have a bunch of enum types, like this:

enum Color {COLOR_RED = 0, COLOR_GREEN = 1, COLOR_BLUE = 2, COLOR_NUM};
enum Direction {DIRECTION_FORWARD, DIRECTION_BACKWARD, DIRECTION_NUM};
enum Choice {CHOICE_THIS, CHOICE_THAT, CHOICE_NUM}; // i've just made it up

In many places in my code I would like to do a loop over all possible values; I would like it to look like this:

for (Color c = COLOR_RED; c != COLOR_NUM; ++c)
{
    ...
}

For that, I define operator++ together with Color:

enum Color {COLOR_RED = 0, COLOR_GREEN = 1, COLOR_BLUE = 2, COLOR_NUM};

inline Color& operator++(Color& c)
{
    c = static_cast<Color>(c + 1);
    return c;
}

I also define postfix operator++ for people that are used to coding loops with i++ instead of ++i:

inline Color operator++(Color& c, int)
{
    Color r = c;
    c = static_cast<Color>(c + 1);
    return r;
}

I would like to know how to use templates to have the compiler generate these operators without me having to write too much boring code. I have just found boost::unit_steppable that supposedly generates the postfix operator++ from the prefix one, but it does only half the work: I still have to provide the prefix operator++ myself.

The following works but is too "powerful" in my opinion:

template <class T> T operator++(T x)
{
    return static_cast<T>(x + 1);
}

I would like to have the operators defined only for selected enums.

Upvotes: 0

Views: 508

Answers (1)

Daniel Frey
Daniel Frey

Reputation: 56863

The following should get you started, extend as needed:

#include <type_traits>

enum Foo { RED, GREEN, BLUE, SIZE };

template< typename T > struct my_enum_is_unit_steppable { enum { value = false }; };

// for each type you want the operator(s) to be enabled, do this:
template<> struct my_enum_is_unit_steppable< Foo > { enum { value = true }; };

// protect the operators with enable_if
template< typename T >
typename std::enable_if< my_enum_is_unit_steppable< T >::value, T >::type
operator++( T value )
{
    return T( value + 1 );
}

int main()
{
    for( Foo foo = RED; foo != SIZE; ++foo ) {}
}

Of course, this uses C++11's std::enable_if, but Boost has C++03-versions available.

Upvotes: 2

Related Questions