Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to create a compile time type map in C++17 for type-checking?

I'm a little new to C++ meta-programming/SFINAE, and I'm having trouble with developing a check to see if a type passed in to a method is contained within a predefined type-list. The context here is that I'd like to check against if the type that's being registered in my variant matches the output type in another structure. Each item that's registered in my application is mapped to another item (in a structure) via a tag (some number). I'd like to create a type-map that can be used at compile time to raise an assertion if the type that is to be registered doesn't match the type of the item in my wire protocol structure.

So something like:

// register elements in type map:
type_map::register(ID_1, decltype(wire_type_item_1)); 
type_map::register(ID_2, decltype(wire_type_item_2));
... etc.

// and when types are registered
template<typename T>
void add_item(const uint32_t id, const T item)
{
   // add static_assert here
   // look up type based on ID, and compare to type passed in
   // when add_item is called
   static_assert(std::is_same<type_map::find(id), decltype(T), 
                 "Attempted to register type that does not match wire type"); 

   ...
} 

I'd appreciate any pointers on where to start/how to go about doing this - thanks!

like image 905
Krishna Soni Avatar asked Jan 31 '26 03:01

Krishna Soni


1 Answers

Following (and misunderstanding?) a suggestion in a comment from Yakk (thanks) at my first answer, I've written a really different (simpler and more elegant, IMHO) way to implement the compile time map.

First of all, the ct_pair. Now is more complex with a using type type (to get the template type T parameter) and a static function that, given the same index of the struct (wrapped in a std::integral_constant, to have different types from different implementation of ct_pair)

template <std::size_t I, typename T>
struct ct_pair
 { 
   using type = T;

   static ct_pair get_pair (std::integral_constant<std::size_t, I>)
    { return {}; }
 };

Now std::tuple, std::tuple_cat() and the helper class get_tuple aren't needed anymore and ct_map simply become

template <typename ... Ps>
struct ct_map : public Ps...
 {
   using Ps::get_pair...;

   template <std::size_t I>
   using find_type
      = typename decltype(get_pair(
            std::integral_constant<std::size_t, I>{}))::type;
 };

Now the full example (unfortunately C++17 and not before, when the other my answer should be C++11/C++14 compatible) become

#include <tuple>
#include <iostream>
#include <type_traits>

template <std::size_t I, typename T>
struct ct_pair
 { 
   using type = T;

   static ct_pair get_pair (std::integral_constant<std::size_t, I>)
    { return {}; }
 };

template <typename ... Ps>
struct ct_map : public Ps...
 {
   using Ps::get_pair...;

   template <std::size_t I>
   using find_type
      = typename decltype(get_pair(
            std::integral_constant<std::size_t, I>{}))::type;
 };

using type_map = ct_map<ct_pair<2u, char>,
                        ct_pair<3u, int>,
                        ct_pair<5u, long>,
                        ct_pair<7u, long long>>;

int main()
 {
   static_assert( std::is_same_v<type_map::find_type<5u>, long> );
 }
like image 115
max66 Avatar answered Feb 02 '26 17:02

max66



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!