2017-10-08 93 views
0

我正在阅读由Andrei Alexandrescu撰写的Modern C++设计,我尝试使用他给出的一些类型列表示例。在下面的例子中,我想创建一个包含一个类型和一个整数的Option结构体的列表。后来我想创建这些选项的类型列表,然后将它们与一个整数一起传递给另一个结构体FindTypeForMapping。如果整数与选项列表中设置的任何整数相匹配,则表达式应计算为该选项的类型,否则应计算为我的自定义类型NullType使用模板参数包而不是宏

的作品

第一种方法是将OptionsList与宏创建,并有我对的Option s各自数列表成立,其中每个宏nOption s的使用宏n-1Option s宏。

然后我想在模板参数中使用参数包到列表中。此版本的名单名为OptionsList2。在OptionsList2我递归建立列表,但是当我通过这个列表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; 
    */  
} 
+1

无论错误消息多么复杂,您当然明白没有专门的'FindTypeForMapping'接受'OptionsList2',只有'OptionsList'。这些是**不同的**模板! – StoryTeller

+0

是的,谢谢。我添加了一个'FindTypeMapping'副本,接受一个'OptionsList2'。仍然是一个错误,但稍有不同。 错误:使用不完整类型的结构体FindTypeForMapping */ – Andreas

+0

海事组织正在以错误的方式前进。而不是重复的东西,只专注于摆脱宏观。添加一个'MakeOptionList '元函数,该元函数公开一个'OptionsList'作为它的':: type'。然后你会摆脱宏观。 – StoryTeller

回答

1

很抱歉,但......你为什么不干脆用std::tuple而不是变参OptionList2

FindTypeForMapping型特征可以简单地写成(抱歉,如果我在很短的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; }; 

下面是一个完整的工作(以及...编译)例如

#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>>{}, "!"); 
} 
+0

谢谢。很好的解决方案,它删除OptionsList和CheckedMappedInt。 – Andreas

相关问题