2017-10-08 18 views
0

나는 Andrei Alexandrescu의 Modern C++ 디자인을 읽으며 자신이 제공하는 형식 목록 예제 중 일부를 사용하려고합니다. 아래 예제에서는 형식 및 정수를 보유하는 Option 구조체 목록을 만들려고합니다. 나중에 해당 옵션의 유형 목록을 만든 다음 정수와 함께 다른 구조체 FindTypeForMapping에 전달하려고합니다. 정수가 옵션 목록에 설정된 정수 중 하나와 일치하면 식은 해당 옵션의 유형으로 평가되어야합니다. 그렇지 않으면 내 사용자 정의 유형 NullType으로 평가됩니다. 작동매크로 대신 템플릿 매개 변수 팩 사용

첫 번째 방법은 OptionsList이 매크로를 만들어 졌는지, 그리고 거기에 내가 nOption의 각 매크로 n-1Option 초 동안 매크로를 사용하는 목록을 보유하고 있음을 Option의 각 번호에 대한 매크로를 가지고있다.

그런 다음 템플릿 매개 변수의 매개 변수 팩을 목록에 사용하고 싶습니다. 이 버전의 목록은 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

간단하게 쓸 수있다 에러 메시지가 얼마나 복잡한 지에 관계없이'OptionsList2' 만 허용하는'FindTypeForMapping'과'OptionsList' 만 허용한다는 점은 분명히 이해할 수 있습니다. 그것들은 ** 다른 ** 템플릿입니다! – StoryTeller

+0

네, 고마워요. 나는 OptionsList2를 받아들이는 FindTypeMapping의 복사본을 추가했다. 여전히 오류는 있지만 약간 다릅니다. /* 오류 : 불완전한 유형의 'struct FindTypeForMapping

+0

잘못된 방식으로 진행되는 IMO. 물건을 복제하는 대신 매크로 제거에 집중하십시오. 'OptionsList'를':: type'으로 드러내는'MakeOptionList '메타 함수를 추가하십시오. 그런 다음 매크로를 제거합니다. – StoryTeller

답변

1

죄송하지만 ... 왜 당신은 단순히 std::tuple 대신 가변 OptionList2를 사용하지 않는? 다음 (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; }; 

전체 작업입니다

귀하의 FindTypeForMapping 유형의 특성은 (음 ... 컴파일) 예를

#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

감사합니다. OptionList 및 CheckedMappedInt를 제거하는 좋은 솔루션입니다. – Andreas