2015-08-08 12 views
8

Come posso passare un std::integer_sequence come parametro di modello a una meta funzione (ad esempio, non un modello di funzione)?Passaggio di std :: integer_sequence come parametro del modello a una meta funzione

Dato per es. il seguente caso d'uso (ma non limitato ad esso):

Desidero utilizzare una sequenza intera per rimuovere gli ultimi tipi N da un pacchetto di parametri. Ho pensato di poter usare selector da this SO question, ma non riesco a passare la sequenza intera a questa meta funzione.

#include <tuple> 
#include <utility> 

template <typename T, std::size_t... Is> 
struct selector 
{ 
    using type = std::tuple<typename std::tuple_element<Is, T>::type...>; 
}; 

template <std::size_t N, typename... Ts> 
struct remove_last_n 
{ 
    using Indices = std::make_index_sequence<sizeof...(Ts)-N>; 
    using type = typename selector<std::tuple<Ts...>, Indices>::type; // fails 
}; 

int main() 
{ 
    using X = remove_last_n<2, int, char, bool, int>::type; 
    static_assert(std::is_same<X, std::tuple<int, char>>::value, "types do not match"); 
} 

errore del compilatore

main.cpp:15:55: error: template argument for non-type template parameter must be an expression 

using type = typename selector<std::tuple<Ts...>, Indices>::type; // fails 

                ^~~~~~~ 

main.cpp:5:38: note: template parameter is declared here 

template <typename T, std::size_t... Is> 

live on coliru

Come dovrei passare la successione di interi?

risposta

10

È necessario (in parte) specializzarsi selector in modo che gli indici sono dedotte da std::index_sequence:

#include <tuple> 
#include <utility> 
#include <type_traits> 

template <typename T, typename U> 
struct selector; 

template <typename T, std::size_t... Is> 
struct selector<T, std::index_sequence<Is...>> 
{ 
    using type = std::tuple<typename std::tuple_element<Is, T>::type...>; 
}; 

template <std::size_t N, typename... Ts> 
struct remove_last_n 
{ 
    using Indices = std::make_index_sequence<sizeof...(Ts)-N>; 
    using type = typename selector<std::tuple<Ts...>, Indices>::type; 
}; 

int main() 
{ 
    using X = remove_last_n<2, int, char, bool, int>::type; 
    static_assert(std::is_same<X, std::tuple<int, char>>::value, "types do not match"); 
} 

DEMO

+0

incredibile veloce! –

1

Per un caso d'uso questo semplice, è possibile anche scrivere il metafunction come modello funzione invece .

template<class...> class wrapper{}; 

template <typename T, std::size_t... Is> 
std::tuple<typename std::tuple_element<Is, T>::type...> 
    selector_impl(wrapper<T, std::index_sequence<Is...>>);  

template <std::size_t N, typename... Ts> 
struct remove_last_n 
{ 
    using Indices = std::make_index_sequence<sizeof...(Ts)-N>; 
    using type = decltype(selector_impl(wrapper<std::tuple<Ts...>, Indices>())); 
}; 

Per inciso, l'implementazione di tuple_elementselector è generalmente piuttosto inefficiente, perché il numero di istanze di modello ricorsive richiesto è quadratica. This answer mostra un modo per rendere il numero di istanze di modello richieste lineare nel numero di tipi nell'elenco.

Problemi correlati