views:

85

answers:

1

In response to the earlier SO question "Enumerate over an enum in C++", I came up with the following reusable solution that uses type-safe enum idiom. I'm just curious to see the community feedback on my solution. This solution makes use of a static array, which is populated using type-safe enum objects before first use. Iteration over enums is then simply reduced to iteration over the array. I'm aware of the fact that this solution won't work if the enumerators are not strictly increasing.

template<typename def, typename inner = typename def::type>
class safe_enum : public def
{
  typedef typename def::type type;
  inner val;

  static safe_enum array[def::end - def::begin];
  static bool init;

  static void initialize()
  {
    if(!init) // use double checked locking in case of multi-threading.
    {
      unsigned int size = def::end - def::begin;
      for(unsigned int i = 0, j = def::begin; i < size; ++i, ++j)
        array[i] = static_cast<typename def::type>(j);
      init = true;
    }
  }

public:

  safe_enum(type v = def::begin) : val(v) {}
  inner underlying() const { return val; }

  static safe_enum * begin()
  {
    initialize();
    return array;
  }

  static safe_enum * end()
  {
    initialize();
    return array + (def::end - def::begin);
  }

  bool operator == (const safe_enum & s) const { return this->val == s.val; }
  bool operator != (const safe_enum & s) const { return this->val != s.val; }
  bool operator <  (const safe_enum & s) const { return this->val <  s.val; }
  bool operator <= (const safe_enum & s) const { return this->val <= s.val; }
  bool operator >  (const safe_enum & s) const { return this->val >  s.val; }
  bool operator >= (const safe_enum & s) const { return this->val >= s.val; }
};

template <typename def, typename inner>
safe_enum<def, inner> safe_enum<def, inner>::array[def::end - def::begin];

template <typename def, typename inner>
bool safe_enum<def, inner>::init = false;

struct color_def
{
  enum type
  {
      begin, red = begin, green, blue, end
  };
};

typedef safe_enum<color_def> color;

template <class Enum>
void f(Enum e)
{
  std::cout << static_cast<unsigned>(e.underlying()) << std::endl;
}

int main()
{
  std::for_each(color::begin(), color::end(), &f<color>);
  color c = color::red;
}
A: 

I haven't looked at the rest of the code, but the "double checked locking" doesn't work -- what if two threads check the flag concurrently while it's still false? You need to use a real lock if you want to support multithreading.

Amnon
I think that was intended as a comment to say "make sure to use double checked locking" if you need to.
James McNellis
I think you're right :)
Amnon