Search code examples
c++dictionarytemplate-meta-programmingcompile-time

In C++, how do I populate a map at compile-time, given a vector of strings?


Given a vector of strings which is known at compile-time (and say some numbers they should map to), I wish to create such a map (f.e. unordered_map) at compile-time. The goal is to start up quickly and perform just look-ups at runtime. Take this example:

enum category {fruit, vegetable};
const std::vector<std::string> fruits = {"apple", "pear", "orange"};
const std::vector<std::string> vegetables = {"cucumber", "zucchini", "tomato"};
const std::unordered_map<std::string, category> lookup_category = // ?

However, constexpr forbids the use of non-literals. Templating is a solution, however it is a massive headache to implement and maintain.

Does C++(17?) have something in the STL which can aid me in the construction of such map at compile time?


Solution

  • There are no vectors, strings, or maps at compile time. In fact, an object of class type with a non-trivial destructor can't be used in a constexpr context. So this simply can't be done.

    From c++20, you can have non-trivial destructors, so this is possible in principle. As far as I know, only vector and string are available in constexpr contexts though, and even then, all the storage that they allocate, must be deallocated before run-time. So you can't even have a vector or string at compile time that you can also use at run-time.

    From c++20, you can guarantee that the vector or string, or map is initialized at program-load time though, using the keyword constinit.

    In case you just want to do a complex initialization of a const map, you can do that with an IIILE (immediately invoked initializing lambda expression) even before c++20. e.g.

    const map<string, int> m = [] {
      map<string,int> x; // construct a map ...
      x["hi"] = 42;  // populate it
      return x;// return it
    }();   // and call the expression straight away.