I want to map values of a (scoped) enum to some other values. For instance, here I map Color to other enum Group:
enum class Color {
  Red, Green, Blue, Cyan, Magenta, Yellow, White, Black, 
  COUNT  // Needed to know the number of items
};
enum class Group {
  Primary, Secondary, Neutral
};
Group GetGroupOfColor(Color color);  // Mapping function I'm going to implement
I want to make sure that if anyone changes the number of elements in Color enum, this function will fail to compile.
I came up with the only solution to this problem:
Group GetGroupOfColor(Color color)
{
  static const Group color2group[] = {
    Group::Primary,    // Red
    Group::Primary,    // Green
    Group::Primary,    // Blue
    Group::Secondary,  // Cyan
    Group::Secondary,  // Magenta
    Group::Secondary,  // Yellow
    Group::Neutral,    // White
    Group::Neutral     // Black
  };
  static_assert(ARRAY_SIZE(color2group) == size_t(Color::COUNT), "DEADBEEF!");
  auto index = size_t(color);
  assert(index < size_t(Color::COUNT));
  return color2group[index];
}
where ARRAY_SIZE may be implemented like the following:
template <typename T, size_t N>
constexpr size_t ARRAY_SIZE(T(&)[N])
{
  return N;
}
This implementation does what I want, but it has a bunch of drawbacks:
- Adds this ugly COUNTitem inColorenum (bothers me most)
- Will fail silently if someone reorders items of Color
- Not applicable for not-continuous enums, i.e. with explicitly assigned values (this one is not really important)
My question is, is there a way to improve this implementation? Maybe some different approach I did not even think about. Maybe with its own drawbacks, which I will find less annoying.
See also:
 
     
     
     
    