将std::integer_sequence作为模板参数传递给元函数

Passing std::integer_sequence as template parameter to a meta function

本文关键字:参数传递 函数 integer std sequence      更新时间:2023-10-16

如何将std::integer_sequence作为模板参数传递给元函数(即不是函数模板)?

给出以下用例(但不限于此):

我想使用整数序列从参数包中删除最后的N类型。我想我可以从这个SO问题中使用selector,但我未能将整数序列传递给这个元函数。

#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

如何传递整数序列?

您需要(部分地)专门化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");
}

对于这么简单的用例,您也可以将元函数写成函数模板。

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>()));
};
顺便提一下,selectortuple_element实现通常效率很低,因为所需的递归模板实例化的数量是二次的。这个答案显示了一种使所需模板实例化的数量与列表中类型的数量成线性关系的方法。