Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
218 views
in Technique[技术] by (71.8m points)

c++ - Elegant way to ensure a std::map has a concrete size in compilation time

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?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...