Trying to increase robustness of a piece of embedded code - simplified like this:
enum tags {
TAG1,
TAG2,
NUM_TAGS
};
const char* const vals_ok[] = { "val1", "val2" };
// Doesn't work (I understand why, but I look for ideas how to get it working again)
const char** const vals = []() constexpr {
const char* rval[NUM_TAGS] = {0};
rval[TAG2] = "val2";
rval[TAG1] = "val1";
return rval;
}();
I'm trying to ensure that the tags and values don't get out of sync with one another, if someone forgets to add a value in one but not the other place.
Since it's an embedded system, I want it to be a const-of-const array, reordered at compile-time - essentially I want the compiler to come up with the exact same output as in vals_ok - but with added maintainability.
It "works" with declaring the inner lambda variable rval
static
- but lands in .bss
with a runtime copy initializer..
I'm trying to ensure that the tags and values don't get out of sync with one another, if someone forgets to add a value in one but not the other place.
"Idiot-proofing" code like that would be tricky if the strings were defined in a different place than the tags. This is a good use of X macros, like:
// All entries are managed here:
#define TAG_ENUM_DATA(F) \
F(TAG1, "val1") \
F(TAG2, "val2")
// Macro-expanded, do not touch:
#define TAG_ENUM_ENUMERATOR(tag, str) tag,
#define TAG_ENUM_STRING(tag, str) str,
enum {
// expands to: TAG1, TAG2,
TAG_ENUM_DATA(TAG_ENUM_ENUMERATOR)
NUM_TAGS
};
constexpr const char* vals_ok[] = {
// expands to "val1", "val2",
TAG_ENUM_DATA(TAG_ENUM_STRING)
};
constexpr const char* vals[] = {
// expands to "val1", "val2",
TAG_ENUM_DATA(TAG_ENUM_STRING)
// one extra entry corresponding to NUM_TAGS
nullptr
};
When someone wants to add a new entry or modify an existing one, they would just be modifying the TAG_ENUM_DATA
macro; the enum
and array are generated from that data.
Note that modern, idiomatic C++ should probably use std::array
instead of plain arrays, std::string_view
instead of const char*
, and enum class
instead of enum
.
I assume you have good reasons to avoid these things, seeing that this is embedded.