2016-03-31 17 views
1

Ich implementiere einen Typ Extraktor extract_type<Class, nth-type> für jede Vorlagenklasse. Eine Beispielverwendung ist wie folgt dargestellt:Einen Typ aus einer Vorlagenklasse extrahieren

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 

Hier ist meine Implementierung.

// 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... > { 
}; 

jedoch der Compiler beschwert sich über

Typ/Wert Mismatch bei Argument 1 in Vorlage Parameterliste für ‚Template-Klasse C, lange unsigned int idx, Klasse T, Klasse ... RestT> struct Open :: extract_type‘ struct extract_type < ungültig, 0, RestT ...>

Wie kann ich dieses Problem gelöst werden?

+0

Verwandte: http://stackoverflow.com/questions/16928669/how-to -get-n-th-type-from-a-tuple – kennytm

+0

'template Klasse C' ist ein Template-Template-Parameter, der plötzlich zu einem Typ-Template-Parameter in einer räumlichen Zuordnung wird. Darüber hinaus sind '', das sind nicht-type Template-Parameter, so dass 'class C' nicht einmal mit' template class C' abgeglichen werden kann. –

+1

Sind Sie sicher, dass Sie 'extract_type wollen ', und nicht' extract_type , 1> '? –

Antwort

0

Meinst du sowas (minimales, funktionierendes Beispiel)?

#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; 
} 

Dieses würde Ihr Code (feste und Arbeitsversion) sein statt:

#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; 
} 

ziemlich hässlich, ist es nicht?

Das Problem besteht darin, dass Sie es definieren, als ob die Vorlagenklasse getrennt von seinen Parametern übergeben werden soll, so dass die erste keine Rolle innerhalb extract_type hat.
Es bedeutet, dass Sie es definiert haben könnte als:

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

So wäre es wie verwendet:

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

Mit dem gleichen Ergebnis: double.

Haben Sie den Fehler in Ihrem Beispiel (abgesehen von der syntaktischen natürlich)?

+0

Hallo Skypjack. Danke für die Hilfe!! – Jes

+0

@Jes Sie haben 'typename ... RestT' in Ihrem Code verwendet. Was heißt das? Es ist ein [Parameter Pack] (http://en.cppreference.com/w/cpp/language/parameter_pack), was noch? – skypjack

+0

Ja. Ich habe verstanden.Es gibt einen Fehler, den ich bei der Deklaration der Template-Spezialisierung gemacht habe. – Jes

-1

Hier ist meine Implementierung.

#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, ""); 
} 
  • die Parameterlisten von C
  • holen n-te Parameter

Live Demo

+0

Was gegen Vererbung? – skypjack

+0

@skypjack: Einige Compiler (\ * hust \ * VC++ \ * hust \ *) geben Warnungen aus, wenn der Vererbungsbaum eines Typs eine bestimmte Anzahl von Zeichen überschreitet. Abgesehen davon ist es nur persönliche Vorliebe AFAIK. – ildjarn

Verwandte Themen