I want to map values of a enum to some other values. For instance, here I map Color
to Group
:
enum class Color {
Red, Green, Blue, Cyan, Magenta, Yellow, White, Black
};
enum class Group {
Primary, Secondary, Neutral
};
One particular interesting case is to map enum to a string (serialize), but I'm interested in the general case. I came out with three possibilities of doing this:
Group GetColorGroupMap(Color color)
{
static const std::map<Color, Group> color2group = {
{ Color::Red, Group::Primary },
{ Color::Green, Group::Primary },
{ Color::Blue, Group::Primary },
{ Color::Cyan, Group::Secondary },
{ Color::Magenta, Group::Secondary },
{ Color::Yellow, Group::Secondary },
{ Color::White, Group::Neutral },
{ Color::Black, Group::Neutral }
};
// Shall I check the iterator here?
return color2group.find(color)->second;
}
Group GetColorGroupArr(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
};
// Shall I check the index here?
return color2group[size_t(color)];
}
Group GetColorGroupSwitch(Color color)
{
switch (color)
{
case Color::Red: return Group::Primary;
case Color::Green: return Group::Primary;
case Color::Blue: return Group::Primary;
case Color::Cyan: return Group::Secondary;
case Color::Magenta: return Group::Secondary;
case Color::Yellow: return Group::Secondary;
case Color::White: return Group::Neutral;
case Color::Black: return Group::Neutral;
}
// Shall I handle this branch here?
throw std::logic_error("How did we get here?");
}
Questions
- What is the best solution among these and why? Maybe there are others?
- Shall I do the checks, mentioned in each function?
- Is there a way to make these functions robust to refactoring, e.g. when another color is added?
My thoughts
About question 1
GetColorGroupMap
: potentially the most slow function, since it traversesstd::map
on each call.GetColorGroupArr
: the least obvious structure, since colors are not mentioned explicitly, they are deduced from array indices. Additionally, it won't work with non-sequential enums.GetColorGroupSwitch
: a little verbose and smells a little old-school. I do not see any particular problems with it here, though.
About question 2
I think no checks are necessary, since failures are possible only if passed Color
is out of specified range, which means, something went wrong before.
About question 3
The only possibility I see is to modify GetColorGroupArr
by adding static_assert
to check that array size is equal to the number of items in Color
. For this, we may add an extra item COUNT
to Color
. I do not like this approach, since we need to check against this special item in every place enum is used.
traits<>
class defining the mappings at compile time? \$\endgroup\$ – Keith Feb 19 '15 at 3:53Color
is extended, not group. \$\endgroup\$ – Keith Feb 19 '15 at 22:39