c++types

Compile time map of type string name to types in C++


In C++ is it possible to generate a compile time map of stringified type names to types. I am aware types themselves can't be mapped but could we for example map to template metafunctions which expose a type?

So specifically could we for example have one varadic template metafunction which takes some initial set of types, then at compile time constructs a static map using a fold expression for example such that at runtime we could access an exposed type and use it as a template parameter to another function, something like this

TypeMapper::Map["Type1"]::type

So then at runtime if we wanted to for example execute a specific templated function we could do

MyTypeProcessor<TypeMapper::Map["Type1"]::type>();

If this is not possible due to limitations in the language I am curious as to what limitation specifically, because individually I believe the individual parts of the idea are somewhat feasible but I'm just unsure how, so if I'm missing something here any assistance would be greatly appreciated. I am still somewhat new to stuff so I could be misunderstanding some things.


Solution

  • It is possible with a different syntax.

    We would like string literals to be usable as non-type template parameters, but currently C++ doesn't allow this. So let's build a replacement that is as good funcvtionally, although less convenient.

      template <std::size_t N>
      struct ct_string
      {
          char value[N] = {};
          consteval ct_string(const char (&str)[N]) : value{}
          {
              for (std::size_t i = 0; i < N; ++i) value[i] = str[i];
          }
      };
      
      
      template <std::size_t N>
      consteval auto make_ct_string(const char (&str)[N])
      {
          return ct_string<N>(str);
      }
    

    Now make_ct_string("foo") returns a value that is usable as a NTTP. We can use it to tag types with strings.

      template <typename K>
      struct is_ct_string_t : public std::false_type {};
      template <std::size_t N>
      struct is_ct_string_t<ct_string<N>> : public std::true_type {};
      
      template <typename K>
      concept is_ct_string = is_ct_string_t<K>::value;
      
      template <auto cst> requires is_ct_string<decltype(cst)>
      struct tagged_with_string
      {
          static constexpr auto value = cst;
          consteval static std::string_view tag() { return cst.value; }
      };
    

    From here we can use types like tagged_with_string<make_ct_string("foo")>.

      using tagged_abc = tagged_with_string<make_ct_string("abc")>;
      constexpr auto abc_tag = tagged_abc::tag();
    

    You can build a map this way:

      template <auto cst> requires is_ct_string<decltype(cst)> struct Map {}
      template <auto cst> requires is_ct_string<decltype(cst)> struct Map {};
      template <> struct Map <make_ct_string("int")> { using type = int; };
      template <> struct Map <make_ct_string("double")> { using type = double; };
    
      using foo = Map<make_ct_string("double")>::type;
      static_assert(std::is_same_v<foo, double>);
    

    Note, I don't know if this is what you want, because nothing whatsoever here waits for run time. But this is definitely what I want for one of my pet projects.