2015-06-22 19 views
5

Ho implementato una funzione di tipo Tuple che trasformano un elenco di valori in un My_enumstd::tuple dei tipi corrispondenti:Tipo Funzione che restituisce una tupla di tipi scelti

#include <tuple> 

enum My_enum{ t_int, t_double }; 

// Bind_type is a type function that given a My_enum returns the corresponding type 
template<My_enum E> struct Bind_type; 
template<> struct Bind_type<t_int>{ using type = int; }; 
template<> struct Bind_type<t_double>{ using type = double; }; 

// Tuple is a type function that given a template value parameter pack of My_enums returns a std::tuple of correspondig types 
template<My_enum First, My_enum... Others> 
struct Tuple { 
    using type = decltype(std::tuple_cat(
       typename Tuple<First>::type{}, 
       typename Tuple<Others...>::type{} 
      )); 
}; 

template<> 
struct Tuple<t_int> { 
    using type = std::tuple<Bind_type<t_int>::type>; 
}; 
template<> 
struct Tuple<t_double> { 
    using type = std::tuple<Bind_type<t_double>::type>; 
}; 

mi piacerebbe essere in grado di dichiarare la base di ricorsione per Tuple in un colpo, perché non voglio gestire manualmente la specializzazione Tuple a condizione di aggiungere o rimuovere valori a My_enum, perché è soggetto a errore (e noioso). Ho provato:

template<My_enum E> 
struct Tuple { 
    using type = std::tuple<Bind_type<E>::type>; 
}; 

ma questa non è una specializzazione valida per la versione variadic.

La mia domanda è: c'è un modo intelligente per dichiarare la specializzazione di Tuple quando ha un solo parametro di valore di modello?

risposta

6

È possibile farlo senza ricorsione, semplicemente ampliando il parametro pack direttamente in un std::tuple:

template<My_enum... Enums> 
struct Tuple { 
    using type = std::tuple<typename Bind_type<Enums>::type...>; 
}; 

Per rispondere alla tua domanda in modo più diretto, è possibile dichiarare un modello primario variadic, quindi scrivere due specializzazioni: quando ci sono almeno due parametri, e per quando ce n'è uno solo:

//primary template, takes any number of My_enums 
template <My_enum... Enums> 
struct Tuple { 
    //this case will be chosen if we instantiate a Tuple with no args 
    using type = std::tuple<>; 
} 

//specialization for when there are at least two arguments 
template<My_enum First, My_enum Second, My_enum... Others> 
struct Tuple<First,Second,Others...> { 
    using type = decltype(std::tuple_cat(
       typename Tuple<First>::type{}, 
       typename Tuple<Second,Others...>::type{} 
      )); 
}; 

//base case, only one argument left 
template<My_enum Last> 
struct Tuple<Last> { 
    using type = std::tuple<typename Bind_type<Last>::type>; 
}; 
+0

Grazie mille per entrambe le risposte :). Non sapevo che avrei potuto espandere il pacchetto di parametri in quel modo e molto molto interessante il trucco di due parametri prima di quelli variadici. –

+1

Ho trovato questa domanda davvero utile: http://stackoverflow.com/questions/17652412/what-are-the-rules-for-the-token-in-the-context-of-variadic-template. Le risposte spiegano l'uso corretto e casi d'uso dell'elipsis (...) nei modelli variadici. –

+1

Si noti che il caso con dimensioni pari a zero non funziona con la soluzione n. 2 sopra riportata. È inoltre necessaria la specializzazione '<>', che può anche essere inserita nella specializzazione primaria. – Yakk

Problemi correlati