是否有一种方法可以在C ++ 17中创建编译时类型映射以进行类型检查?

问题描述 投票:0回答:4

我是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"); 

   ...
} 

我非常感谢您从何处开始/如何进行此操作的任何指示,谢谢!

c++ c++17 metaprogramming typechecking typemaps
4个回答
0
投票

这是在类之间创建编译时映射的一种方法。

#include <type_traits>

struct foo {};
struct bar {};
struct ID_1 {};
struct ID_2 {};
struct ID_3 {};

template <class T>
struct type_map {};

template <>
struct type_map<ID_1> { using type = foo; }; // map ID_1 -> foo
template <>
struct type_map<ID_2> { using type = bar; }; // map ID_2 -> bar

int main() {
    static_assert(std::is_same_v<type_map<ID_1>::type, foo>);
    static_assert(std::is_same_v<type_map<ID_2>::type, bar>);
    static_assert(std::is_same_v<type_map<ID_3>::type, int>); // fails, ID_3 isn't in map
    static_assert(std::is_same_v<type_map<ID_1>::type, bar>); // fails, ID_1 is mapped to foo, not bar
}

但是,在您的代码示例中,您具有以下行:static_assert(std::is_same<type_map::find(id), decltype(T), "Attempted to register type that does not match wire type");与此相关的问题是id是运行时变量。您不能在运行时使用static_assert

如果您确实想在运行时在此映射中查找类型,则要复杂一些。我建议使用像hana这样的元编程库,因为它允许您在运行时执行诸如遍历编译时数据结构的所有元素之类的事情。


0
投票

不确定您到底想要什么...无论如何...

当然不能使用const std::uint32_t id value来获取(find(id))可在static_assert()中使用的类型(作为函数的值吗?)>>

template <typename T>
void add_item (std::uint32_t const id, T const item)
// ................................^^  the value id is unusable in a static_assert()

如果您知道id compile

time的值(否则您的问题就没有意义了),您可以将其(我建议为std::size_t)作为模板值传递给std::integral_constant
template <std::size_t ID, uintypename T>
void add_item (std::integral_constant<std::size_t, ID>, T const item)

或者更好,我想,您必须显式调用add_item()作为模板参数。

无论如何...对于类型映射,我首先建议在ct_pair和类型之间使用std::size_t(编译时间对)

template <std::size_t, typename>
struct ct_pair
 { };

还提供如下几个辅助结构

template <std::size_t, std::size_t, typename>
struct get_tuple
 { using type = std::tuple<>; };

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

您可以使用模板专门化来创建ct_map(编译时间图),将std::tuple_cat()的功效与std::get_val()decltype()一起使用,如下所示

template <typename ...>
struct ct_map;

template <std::size_t ... Is, typename ... Ts>
struct ct_map<ct_pair<Is, Ts>...>
 {
   template <std::size_t I>
   static constexpr auto find_type_func ()
    -> decltype( std::get<0>( std::tuple_cat(
             std::declval<typename get_tuple<I, Is, Ts>::type>()...)) );

   template <std::size_t I>
   using find_type
      = std::remove_reference_t<decltype( find_type_func<I>() )>;
 };

要在地图上注册元素,您必须定义using

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

并且static_assert()检查变为以下内容

static_assert( std::is_same_v<type_map::find_type<5u>, long> );

下面是一个完整的C ++ 17编译示例

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

template <std::size_t, typename>
struct ct_pair
 { };

template <std::size_t, std::size_t, typename>
struct get_tuple
 { using type = std::tuple<>; };

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

template <typename ...>
struct ct_map;

template <std::size_t ... Is, typename ... Ts>
struct ct_map<ct_pair<Is, Ts>...>
 {
   template <std::size_t I>
   static constexpr auto find_type_func ()
    -> decltype( std::get<0>( std::tuple_cat(
             std::declval<typename get_tuple<I, Is, Ts>::type>()...)) );

   template <std::size_t I>
   using find_type
      = std::remove_reference_t<decltype( find_type_func<I>() )>;
 };

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

0
投票
template<auto i>
using constant = std::integral_constant<decltype(i), i>;

template<class T>
struct tag_t {
  using type=T;
  // comparison with other tags!
  constexpr auto operator==( tag_t<T> ) const { return std::true_type{}; }
  constexpr auto operator!=( tag_t<T> ) const { return std::false_type{}; }
  template<class U>
  constexpr auto operator==( tag_t<U> ) const { return std::false_type{}; }
  template<class U>
  constexpr auto operator!=( tag_t<U> ) const { return std::true_type{}; }
};
template<class T>
constexpr tag_t<T> tag = {};

0
投票

[跟随(误解?)Yakk的评论中的一个建议(谢谢),在我的第一个答案上,我写了一种完全不同的(更简单,更优雅的恕我直言)的方式来实现编译时间图。

© www.soinside.com 2019 - 2024. All rights reserved.