有没有办法在 C++17 中创建编译时类型映射以进行类型检查?

Kri*_*oni 3 c++ typechecking template-meta-programming typemaps c++17

我对 C++ 元编程/SFINAE 有点陌生,并且在开发检查以查看传递给方法的类型是否包含在预定义类型列表中时遇到了麻烦。这里的上下文是我想检查在我的变体中注册的类型是否与另一个结构中的输出类型匹配。在我的应用程序中注册的每个项目都通过标签(某个数字)映射到另一个项目(在结构中)。我想创建一个类型映射,如果要注册的类型与我的有线协议结构中的项目类型不匹配,可以在编译时使用它来引发断言。

所以像这样:

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

   ...
} 

Run Code Online (Sandbox Code Playgroud)

如果您能提供有关从哪里开始/如何执行此操作的指示,我将不胜感激 - 谢谢!

max*_*x66 5

遵循(和误解?)我的第一个答案中 Yakk 的评论中的建议(谢谢),我编写了一种非常不同的(更简单、更优雅,恕我直言)的方法来实现编译时映射。

首先,ct_pair. using现在,类型type(获取模板类型T参数)和函数更加复杂static,给定结构的相同索引(包装在 中std::integral_constant,从不同的实现中获得不同的类型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 {}; }
 };
Run Code Online (Sandbox Code Playgroud)

现在std::tuple,不再需要std::tuple_cat()辅助类,只需变成get_tuplect_map

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;
 };
Run Code Online (Sandbox Code Playgroud)

现在完整的示例(不幸的是 C++17 而不是之前,当另一个我的答案应该与 C++11/C++14 兼容时)变成

#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> );
 }
Run Code Online (Sandbox Code Playgroud)