使用模板参数包代替宏 [英] Using template parameter pack instead of macro

查看:35
本文介绍了使用模板参数包代替宏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读 Andrei Alexandrescu 的现代 C++ 设计,我正在尝试使用他提供的一些类型列表示例.在下面的示例中,我想创建一个包含类型和整数的 Option 结构的列表.后来我想创建这些选项的类型列表,然后将它与一个整数一起传递给另一个结构 FindTypeForMapping.如果整数匹配选项列表中设置的任何整数,则表达式应计算为该选项的类型,否则应计算为我的自定义类型 NullType.

第一种可行的方法是 OptionsList 是用宏创建的,并且我在列表中保存了每个 Option 数量的宏,其中每个宏用于n Options 正在使用 n-1 Options 的宏.

然后我想在模板参数列表中使用一个参数包.此版本的列表名为 OptionsList2.在 OptionsList2 中,我递归地构建了列表,但是当将此列表传递给 FindTypeForMapping 时,我得到了一个编译时间错误(见下文).

struct NullType { };模板<类T,类U>结构体选项列表{typedef T头;typedef U 尾;};模板结构体选项列表2{typedef T头;typedef typename std::conditional>::type Tail;};template结构选项{枚举{int_mapping = n};typedef N 映射类型;};模板struct CheckMappedInt;模板struct CheckMappedInt{枚举 { is_the_same = 1};};模板struct CheckMappedInt{枚举 { is_the_same = 0};};templatestruct FindTypeForMapping;模板struct FindTypeForMapping{typedef NullType 映射类型;};模板struct FindTypeForMapping, n>{私人的:枚举 {temp = CheckMappedInt::is_the_same };typedef typename FindTypeForMapping::mapped_type temp_type;民众:typedef typename std::conditional<温度 == 1,类型名称 OP::MappedType,temp_type>::type mapping_type;};//在 SoryTellers 评论后添加此内容模板struct FindTypeForMapping, n>{私人的:枚举 {temp = CheckMappedInt::is_the_same };typedef typename FindTypeForMapping::mapped_type temp_type;民众:typedef typename std::conditional<温度 == 1,类型名称 OP::MappedType,temp_type>::type mapping_type;};#define OPTION_LIST_1(op1) OptionsList#define OPTION_LIST_2(op1, op2) OptionsList#define OPTION_LIST_3(op1, op2, op3) OptionsList#define OPTION_LIST_4(op1, op2, op3, op4) OptionsList#define OPTION_LIST_5(op1, op2, op3, op4, op5) OptionsList#define OPTION_LIST_6(op1, op2, op3, op4, op5, op6) OptionsList#define OPTION_LIST_7(op1, op2, op3, op4, op5, op6, op7) OptionsList#define OPTION_LIST_8(op1, op2, op3, op4, op5, op6, op7, op8, op9) OptionsList#define OPTION_LIST_9(op1, op2, op3, op4, op5, op6, op7, op8, op9) OptionsListint main(int argc, char* argv[]){typedef Option<1, char>o1;typedef Option<2, int>o2;//作品typedef OPTION_LIST_2(o1, o2) ol;typedef typename FindTypeForMapping

::mapped_type ResolvedType;//作品typedef OptionsList2ol2;typedef typename FindTypeForMapping

::mapped_type ResolvedType2;/*错误:不完整类型struct FindTypeForMapping, 1>"的无效使用typedef typename FindTypeForMapping::mapped_type temp_type;*/}

解决方案

抱歉,但是...为什么不简单地使用 std::tuple 代替可变参数 OptionList2> ?

你的 FindTypeForMapping 类型特征可以简单地写成(对不起,如果我在 FTFM 中缩短了名称)

template 结构 FTFM;模板<int n, int no, typename TypeO, typename ... Ts>struct FTFM, Ts...>, n>{ using type = typename FTFM, n>::type;};模板<int n, typename TypeO, typename ... Ts>struct FTFM, Ts...>, n>{ 使用类型 = TypeO;};模板<int n>结构FTFM<std::tuple>,n>{ 使用类型 = NullType;};

以下是一个完整的工作(好吧...编译)示例

#include <元组>#include 结构体空类型{ };模板 <int n, typename T>结构选项:公共 std::integral_constant{ 使用类型 = T;};模板 <typename, int>结构 FTFM;模板<int n, int no, typename TypeO, typename ... Ts>struct FTFM, Ts...>, n>{ using type = typename FTFM, n>::type;};模板<int n, typename TypeO, typename ... Ts>struct FTFM, Ts...>, n>{ 使用类型 = TypeO;};模板<int n>结构FTFM<std::tuple>,n>{ 使用类型 = NullType;};模板 <typename T, int I>使用 FTFM_t = typename FTFM::type;int主(){使用 opt0 = Option<0, void>;使用 opt1 = Option<1, char>;使用 opt2 = Option<2, short>;使用 opt3 = Option<3, int>;使用 opt4 = Option<4, long>;使用 opt5 = Option<5, long long>;使用 optList = std::tuple;static_assert ( std::is_same>{}, "!" );static_assert ( std::is_same>{}, "!" );static_assert ( std::is_same>{}, "!" );static_assert ( std::is_same>{}, "!" );static_assert ( std::is_same>{}, "!" );static_assert ( std::is_same>{}, "!" );static_assert ( std::is_same>{}, "!" );}

I am reading Modern C++ design by Andrei Alexandrescu and I am trying to use some of the type list examples that he his giving. In the example below I want to create a list of a Option struct that holds a type and an integer. Later I want to create a typelist of those Options and then pass that to a another struct FindTypeForMapping along with an integer. If the integer match any of the integer set in the list of Options, then the expression should evaluate to the type for that Options, otherwise it should evaluate to my custom type NullType.

First approach that works is that the OptionsList is created with macros, and there I have macros for each number of Options that the list holds, where each macro for n Options is using the macro for n-1 Options.

Then I wanted to use a parameter pack in the template parameters to the list. This version of the list is named OptionsList2. In OptionsList2 I recursively build up the list, but then I get an compilation time error (see below) when passing this list to FindTypeForMapping.

struct NullType { };

template<class T, class U>
struct OptionsList
{
  typedef T Head;
  typedef U Tail;
};

template<class T, class... U>
struct OptionsList2
{
  typedef T Head;
  typedef typename std::conditional<sizeof...(U) == 0, NullType, OptionsList2<U...>>::type Tail;
};

template<int n, typename N>
struct Option
{
  enum {
    int_mapping = n
  };
  typedef N MappedType;
};

template<int, int> struct CheckMappedInt;

template<int n>
struct CheckMappedInt<n, n>
{
  enum { is_the_same = 1};
};

template<int n, int m>
struct CheckMappedInt
{
  enum { is_the_same = 0};
};

template<typename OLT, int n> struct FindTypeForMapping;

template<int n>
struct FindTypeForMapping<NullType, n>
{
  typedef NullType mapped_type;
};


template<typename OP, typename Tail, int n>
struct FindTypeForMapping<OptionsList<OP, Tail>, n>
{
 private:
  enum {temp  = CheckMappedInt<OP::int_mapping, n>::is_the_same };
  typedef typename FindTypeForMapping<Tail, n>::mapped_type temp_type;
 public:
  typedef typename std::conditional<
          temp == 1,
          typename OP::MappedType,
          temp_type>::type mapped_type;
};

// Added this after SoryTellers comment
template<typename OP, typename Tail, int n>
struct FindTypeForMapping<OptionsList2<OP, Tail>, n>
{
 private:
  enum {temp  = CheckMappedInt<OP::int_mapping, n>::is_the_same };
  typedef typename FindTypeForMapping<Tail, n>::mapped_type temp_type;
 public:
  typedef typename std::conditional<
          temp == 1,
          typename OP::MappedType,
          temp_type>::type mapped_type;
};

#define OPTION_LIST_1(op1)                                          OptionsList<op1, NullType>
#define OPTION_LIST_2(op1, op2)                                     OptionsList<op1, OPTION_LIST_1(op2)>
#define OPTION_LIST_3(op1, op2, op3)                                OptionsList<op1, OPTION_LIST_2(op2, op3)>
#define OPTION_LIST_4(op1, op2, op3, op4)                           OptionsList<op1, OPTION_LIST_3(op2, op3, op4)>
#define OPTION_LIST_5(op1, op2, op3, op4, op5)                      OptionsList<op1, OPTION_LIST_4(op2, op3, op4, op5)>
#define OPTION_LIST_6(op1, op2, op3, op4, op5, op6)                 OptionsList<op1, OPTION_LIST_5(op2, op3, op4, op5, op6)>
#define OPTION_LIST_7(op1, op2, op3, op4, op5, op6, op7)            OptionsList<op1, OPTION_LIST_6(op2, op3, op4, op5, op6, op7)>
#define OPTION_LIST_8(op1, op2, op3, op4, op5, op6, op7, op8, op9)  OptionsList<op1, OPTION_LIST_7(op2, op3, op4, op5, op6, op7, op8)>
#define OPTION_LIST_9(op1, op2, op3, op4, op5, op6, op7, op8, op9)  OptionsList<op1, OPTION_LIST_8(op2, op3, op4, op5, op6, op7, op8, op9)>


int main(int argc, char* argv[])
{
  typedef Option<1, char> o1;
  typedef Option<2, int> o2;

  // Works
  typedef OPTION_LIST_2(o1, o2) ol;
  typedef typename FindTypeForMapping<ol, 1>::mapped_type ResolvedType; // Works

  typedef OptionsList2<o1, o2> ol2;
  typedef typename FindTypeForMapping<ol2, 1>::mapped_type ResolvedType2;
  /*
 error: invalid use of incomplete type ‘struct FindTypeForMapping<Option<2, int>, 1>’
   typedef typename FindTypeForMapping<Tail, n>::mapped_type temp_type;
  */    
}

解决方案

Sorry but... why don't you simply use std::tuple instead a variadic OptionList2 ?

Your FindTypeForMapping type traits can be written simply as (sorry if I short the name in FTFM)

template <typename, int>
struct FTFM;

template <int n, int no, typename TypeO, typename ... Ts>
struct FTFM<std::tuple<Option<no, TypeO>, Ts...>, n>
 { using type = typename FTFM<std::tuple<Ts...>, n>::type; };

template <int n, typename TypeO, typename ... Ts>
struct FTFM<std::tuple<Option<n, TypeO>, Ts...>, n>
 { using type = TypeO; };

template <int n>
struct FTFM<std::tuple<>, n>
 { using type = NullType; };

The following is a full working (well... compiling) example

#include <tuple>
#include <type_traits>

struct NullType
 { };

template <int n, typename T>
struct Option : public std::integral_constant<int, n>
 { using type = T; };

template <typename, int>
struct FTFM;

template <int n, int no, typename TypeO, typename ... Ts>
struct FTFM<std::tuple<Option<no, TypeO>, Ts...>, n>
 { using type = typename FTFM<std::tuple<Ts...>, n>::type; };

template <int n, typename TypeO, typename ... Ts>
struct FTFM<std::tuple<Option<n, TypeO>, Ts...>, n>
 { using type = TypeO; };

template <int n>
struct FTFM<std::tuple<>, n>
 { using type = NullType; };

template <typename T, int I>
using FTFM_t = typename FTFM<T, I>::type;

int main ()
 {
   using  opt0 = Option<0, void>;
   using  opt1 = Option<1, char>;
   using  opt2 = Option<2, short>;
   using  opt3 = Option<3, int>;
   using  opt4 = Option<4, long>;
   using  opt5 = Option<5, long long>;

   using  optList = std::tuple<opt0, opt1, opt2, opt3, opt4, opt5>;

   static_assert ( std::is_same<void,      FTFM_t<optList, 0>>{}, "!" );
   static_assert ( std::is_same<char,      FTFM_t<optList, 1>>{}, "!" );
   static_assert ( std::is_same<short,     FTFM_t<optList, 2>>{}, "!" );
   static_assert ( std::is_same<int,       FTFM_t<optList, 3>>{}, "!" );
   static_assert ( std::is_same<long,      FTFM_t<optList, 4>>{}, "!" );
   static_assert ( std::is_same<long long, FTFM_t<optList, 5>>{}, "!" );
   static_assert ( std::is_same<NullType,  FTFM_t<optList, 6>>{}, "!" );
 }

这篇关于使用模板参数包代替宏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆