I was trying to ensure that a std::map
has the same size as an enum
class at compile time. Avoiding the use of macros, if possible.
I tried with static_assert
, but reading Stack Overflow I concluded that it can't be done because std::map
is "constructed" at runtime. Or at least it's what I understood. So I get this "expression must be a constant value" error.
Looking at the code must be clearer than my poor explanations:
// event_types.h
enum class EventTypes {
InitSuccessfull,
KeyPressed,
StartedCleanup,
FinishedCleanup,
Exit,
count
};
static const std::map<EventTypes, std::string> kEventTypesNames = {
{ EventTypes::InitSuccessfull, "InitSuccessfull" },
{ EventTypes::KeyPressed, "KeyPressed" },
{ EventTypes::StartedCleanup, "StartedCleanup" },
{ EventTypes::FinishedCleanup, "FinishedCleanup" },
{ EventTypes::Exit, "Exit" }
};
// this doesn't work, "expression must have a constant value"(kEventTypesNames.size())
static_assert(kEventTypesNames.size() == static_cast<std::underlying_type<kuge::EventTypes>::type>(EventTypes::count));
// this neither works
const unsigned int map_size = kEventTypesNames.size();
static_assert(map_size == static_cast<std::underlying_type<kuge::EventTypes>::type>(EventTypes::count));
So, what I want is to ensure that the size of the map is the same as the enum
count so I don't forget to add the event on both places.
Any idea on how to do it? Or maybe I should think of another (better) way of getting the events "stringified" that doesn't require a map?
You can store the data in a datatype that can be inspected at compile time, such as an array.
static const std::map<EventTypes, std::string>::value_type kEventTypesNamesData[] = {
// Note "value_type", here ^^^^^^^^^^
{ EventTypes::InitSuccessfull, "InitSuccessfull" },
{ EventTypes::KeyPressed, "KeyPressed" },
{ EventTypes::StartedCleanup, "StartedCleanup" },
{ EventTypes::FinishedCleanup, "FinishedCleanup" },
{ EventTypes::Exit, "Exit" }
};
// Compile-time size check
static_assert(end(kEventTypesNamesData)-begin(kEventTypesNamesData) == static_cast<std::underlying_type<EventTypes>::type>(EventTypes::count));
// Construct from data
static const std::map<EventTypes, std::string> kEventTypesNames( begin(kEventTypesNamesData), end(kEventTypesNamesData) );