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
COUNT
item inColor
enum (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: