2015-08-08 25 views
8

Jak przekazać std::integer_sequence jako parametr szablonu do funkcji meta (tj. Nie do szablonu funkcji)?Przekazywanie std :: integer_sequence jako parametru szablonu do funkcji meta

Podany np. następujący przypadek użycia (ale bez ograniczania do niego):

Chcę użyć sekwencji całkowitej, aby usunąć ostatnie typy N z pakietu parametrów. Pomyślałem, że mogę użyć selector z this SO question, ale nie mogę przekazać sekwencji całkowitej do tej funkcji meta.

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

błąd kompilatora

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

Jak mijam sekwencję liczb całkowitych?

Odpowiedz

10

Musisz (częściowo) specjalizują selector tak że indeksy są wywnioskować 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

niesamowicie szybko! –

1

Dla przypadku, w ten prosty, można również napisać metafunkcji jako szablon funkcji zamiast .

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>())); 
}; 

Nawiasem mówiąc, realizacja tuple_element z selector jest na ogół dość nieefektywne, ponieważ liczba rekurencyjnych dawałaby szablonów wymagane jest kwadratowa. This answer pokazuje jeden sposób, aby liczba wystąpień szablonu była wymagana liniowo w liczbie typów na liście.

Powiązane problemy