2015-08-08 2 views
8

Как передать std::integer_sequence в качестве параметра шаблона в метафункцию (т. Е. Не шаблон функции)?Передача std :: integer_sequence в качестве параметра шаблона для мета-функции

Показано, например, следующий прецедент (но не ограничиваясь этим):

Я хочу использовать целую последовательность для удаления последних N типов из пакета параметров. Я думал, что могу использовать selector от this SO question, но я не могу передать целую последовательность этой метафункции.

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

ошибка компилятора

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

Как бы я пройти целую последовательность?

ответ

10

Вам необходимо (частично) специализируются selector так, что индексы выведены из 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

невероятный быстро! –

1

Для случая использования этого простого, вы можете также записать metafunction в качестве шаблона функции вместо ,

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

Кстати, tuple_element реализация selector, как правило, весьма неэффективна, так как количество рекурсивных конкретизации шаблона требуется квадратичное. This answer показывает один из способов сделать число экземпляров шаблона необходимым линейным по количеству типов в списке.