Here's a simple code-pattern that keeps biting me in our codebase:
// in some_header_file.h
enum Color {
red = 0,
green,
blue,
max_item
};
// in some_other_file.cpp
static const char * color_names[max_item] = {
"red",
"green",
"blue"
};
std::string get_color_name(Color c) {
if ((c >= 0) && (c < max_item)) return color_names[c];
return "Unknown color";
}
... the above is all well and good, until one day, some careless programmer (okay, it's usually me) comes by and inserts a new color (e.g. yellow
) into the Colors
enum in some_header_file.h
(just before max_item
), but forgets to also add the new color's string (e.g. "yellow"
) to the end of the color_names[max_item]
array in some_other_file.cpp
.
After that happens, the code compiles fine with no errors or warnings, but future calls to get_color_name(yellow)
will (at best) not return the expected result or (at worst) invoke undefined behavior and maybe crash.
What I'd like is for this mistake to be caught at compile-time, so that I can avoid introducing runtime-error when updating enums. Is there a way in C++ to enforce at compile-time that the number of initializer-strings for color_names
must be equal to the array's length (i.e. to max_item
)?
The easiest would probably be to remove max_item
from the array size and let it be automatically sized and then static_assert
on the size:
static const char* color_names[] = { // `max_item` removed here
"red",
"green",
"blue"
};
// and a static_assert added after the definition of the array:
static_assert(std::size(color_names) == max_item);