2017-10-08 28 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

相關問題