Search code examples
c++arraysenumsstatic-initialization

How to detect a missing string-array-item-initializer at compile-time?


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)?


Solution

  • 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);