代码中实际上省略了扩展的基本要素std::tuple<T...>
:您需要获取第二个参数:除了类型列表之外,std::tuple<...>
您还需要一个带有索引的参数包0, 1, ..., n
。一旦你有了这两个参数包,你就可以一前一后地展开它们:
template <typename F, typename... T, int... N>
void call_impl(F&& fun, std::tuple<T...>&& t) {
fun(std::get<N>(t)...);
}
真正的魔力在于当你只有一个std::tuple<T...>
. 它需要一些模板编程。这是一种创建索引列表的方法:
template <int... Indices> struct indices;
template <> struct indices<-1> { typedef indices<> type; };
template <int... Indices>
struct indices<0, Indices...>
{
typedef indices<0, Indices...> type;
};
template <int Index, int... Indices>
struct indices<Index, Indices...>
{
typedef typename indices<Index - 1, Index, Indices...>::type type;
};
template <typename T>
typename indices<std::tuple_size<T>::value - 1>::type const*
make_indices()
{
return 0;
}
所以,如果你有一个函数模板,让我们调用它call()
,它接受一个函数对象和一个std::tuple<T...>
带有函数参数的 a。一个简单的方法是重写call_impl()
上面提到的处理推导索引:
template <typename F, typename Tuple, int... N>
void call_impl(F&& fun, Tuple&& t, indices<Indices...> const*)
{
fun(std::get<N>(t)...);
}
template <typename F, typename Tuple>
void call(F&& fun, Tuple&& t)
{
call_imle(std::forward<F>(fun), std::forward<Tuple>(t), make_indices<Tuple>());
}
这段代码并没有真正扩展的是在调用函数时正确使用std::forward<...>()
各种std::tuple<...>
元素。仅仅使用std::forward<Tuple>(t)
是行不通的,因为它可能会移动整个而不是std::tuple<...>
移动元素。我认为可以完成类似 a 的适当元素移动,std::tuple<...>
但我还没有完成。