2016-03-31 3 views
1

Я реализую экстрактор типа extract_type<Class, nth-type> для любого шаблона. Пример использования показан ниже:Извлечь тип из шаблонного класса

template <int, short, float, double, char> class C; 

extract_type<C, 0>::type => int 
extract_type<C, 1>::type => short 
extract_type<C, 2>::type => float 
extract_type<C, 3>::type => double 
extract_type<C, 4>::type => char 

Вот моя реализация.

// extract_type: recursive definition. 
template <template <typename...> class C, size_t idx, typename T, typename... RestT> 
struct extract_type; 

// extract_type: base 
template <template <typename...> class C, typename T, typename... RestT> 
struct extract_type< C<RestT...>, 0, RestT... > { 
    using type = T; 
}; 


// extract_type: recursive definition. 
template <template <typename...> class C, size_t idx, typename T, typename... RestT> 
struct extract_type : public extract_type< C<RestT...>, idx-1, RestT... > { 
}; 

Однако компилятор жалуется

типа/несовпадение значения в аргументе 1 в списке параметров шаблона для «шаблонного класса C, долго без знака INT IDX, класс T, класс ... RestT> структура OpenCluster :: extract_type» структура extract_type < пустота, 0, RestT ...>

Как я могу получить это решить?

+0

Связанные: http://stackoverflow.com/questions/16928669/how-to -get-n-th-type-from-a-tuple – kennytm

+0

'template class C' - это шаблонный шаблонный параметр, который внезапно становится параметром шаблона типа в пространственной сортировке. Кроме того, '', это несимвольные параметры шаблона, поэтому 'class C' нельзя даже сопоставить с шаблоном class C' –

+1

Вы действительно хотите' extract_type ', а не' extract_type , 1> '? –

ответ

0

Вы имеете в виду что-то вроде этого (минимальный, рабочий пример)?

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

template<int, typename...> 
struct extract_type; 

template<int N, typename T, typename... O, template<typename...> typename U> 
struct extract_type<N, U<T, O...>>: extract_type<N-1, U<O...>> { }; 

template<typename T, typename... O, template<typename...> typename U> 
struct extract_type<0, U<T, O...>> { using type = T; }; 

int main() { 
    using MyTuple = std::tuple<int, double, char>; 
    // true 
    std::cout << std::is_same<extract_type<1, MyTuple>::type, double>::value << std::endl; 
    // false 
    std::cout << std::is_same<extract_type<2, MyTuple>::type, double>::value << std::endl; 
} 

Это один будет ваш код (фиксированная и рабочая версия) вместо:

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

// extract_type: recursive definition. 
template <template <typename...> class C, size_t idx, typename T, typename... RestT> 
struct extract_type; 

// extract_type: base 
template <template <typename...> class C, typename T, typename... RestT> 
struct extract_type< C, 0, T, RestT... > { 
    using type = T; 
}; 

// extract_type: recursive definition. 
template <template <typename...> class C, size_t idx, typename T, typename... RestT> 
struct extract_type : public extract_type< C, idx-1, RestT... > { }; 

int main() { 
    // true 
    std::cout << std::is_same<extract_type<std::tuple, 1, int, double, char>::type, double>::value << std::endl; 
    // false 
    std::cout << std::is_same<extract_type<std::tuple, 2, int, double, char>::type, double>::value << std::endl; 
} 

Довольно некрасиво, не так ли?

Проблема заключается в том, что вы определяете его так, как если бы он передавал класс шаблона, отделенный от его параметров, так что первый не имеет никакой роли в пределах extract_type.
Это означает, что вы могли бы определить его как:

template <size_t idx, typename T, typename... RestT> 
struct extract_type; 

Таким образом, это был бы использован как:

extract_type<1, int, double, char>::type 

С тем же результатом: double.

Получил ошибку в вашем примере (кроме синтаксического, конечно)?

+0

Hi Skypjack. Спасибо за помощь!! – Jes

+0

@Jes Вы использовали 'typename ... RestT' в своем коде. Что это значит? Это [пакет параметров] (http://en.cppreference.com/w/cpp/language/parameter_pack), что еще? – skypjack

+0

Да. Я понял.Я ошибался в объявлении специализации шаблона. – Jes

-1

Вот моя реализация.

#include "iostream" 

template<class ...Ts> struct C {}; 

template<int N, class ...Ts> 
struct extract_type_impl; 

template<class C, int N> 
struct extract_type; 

template<template<class ...> class C, class ...Ts, int N> 
struct extract_type<C<Ts...>, N> { 
    typedef typename extract_type_impl<N, Ts...>::type type; 
}; 

template<int N, class T, class ...Ts> 
struct extract_type_impl<N, T, Ts...> { 
    typedef typename extract_type_impl<N - 1, Ts...>::type type; 
}; 

template<class T, class ...Ts> 
struct extract_type_impl<0, T, Ts...> { 
    typedef T type; 
}; 

int main() { 
    static_assert(std::is_same<extract_type<C<int, float, char, double>, 3>::type, double>::value, ""); 
    // static_assert(std::is_same<extract_type<C<int, float, char, double>, 3>::type, int>::value, ""); 
} 
  • Получить список параметров из C
  • Получить п-ый параметр

Live Demo

+0

Что против наследования? – skypjack

+0

@skypjack: Некоторые компиляторы (\ * cough \ * VC++ \ * cough \ *) предоставляют предупреждения, когда дерево наследования типа превышает определенное количество символов. Помимо этого, это просто личное предпочтение AFAIK. – ildjarn