Solution 1: Operator overloading.
This is my current favorite. Overload unary operator+
and operator++
to explicitly convert to integral type and increment within the enumerated type, respectively.
Using an enumeration_traits
template, overloads can be activated rather than copying boilerplate code. But the boilerplate is just a couple one-liners.
Library code (templates, see below for non-template alternative):
template< typename e >
struct enumeration_traits;
struct enumeration_trait_indexing {
static constexpr bool does_index = true;
};
template< typename e >
constexpr
typename std::enable_if< enumeration_traits< e >::does_index,
typename std::underlying_type< e >::type >::type
operator + ( e val )
{ return static_cast< typename std::underlying_type< e >::type >( val ); }
template< typename e >
typename std::enable_if< enumeration_traits< e >::does_index,
e & >::type
operator ++ ( e &val )
{ return val = static_cast< e >( + val + 1 ); }
User code:
enum class ducks { huey, dewey, louie, count };
template<> struct enumeration_traits< ducks >
: enumeration_trait_indexing {};
double duck_height[ + ducks::count ];
Boilerplate code (if not using library, follows enum
definition):
int operator + ( ducks val )
{ return static_cast< int >( val ); }
ducks &operator ++ ( ducks &val )
{ return val = static_cast< ducks >( + val + 1 ); }
Solution 2: Manual scoping.
Scoped enumerator syntax also works on unscoped (non enum class
) enumerations, which do implicitly convert to int
. Hiding the enumeration inside a class or namespace and importing it with typedef
or using
makes it pseudo-scoped.
But if multiple enumerations go into the same namespace, the enumerator names may collide, so you might as well use a class (or many namespaces).
struct ducks_enum {
enum ducks { huey, dewey, louie, count };
};
typedef ducks_enum::ducks ducks;
double duck_height[ ducks::count ]; // C++11
double duck_weight[ ducks_enum::count ]; // C++03
This has some benefits. It works with C++03, but only with syntax ducks_enum::count
. The enumerators are unscoped inside the struct, and it can be used as a base for any class that makes frequent use of the enumerators.