从元组中解压缩参数

时间:2013-09-24 20:57:27

标签: c++ templates c++11 variadic-templates

所以我想弄清楚它是如何工作的:C++11: I can go from multiple args to tuple, but can I go from tuple to multiple args?

我不明白的黑魔法是这段代码片段:

f(std::get<N>(std::forward<Tuple>(t))...)

这是我不理解的f内的表达。

我理解表达式以某种方式将t内的内容解压缩/扩展为参数列表。但有人可以解释如何做到这一点?当我查看std::gethttp://en.cppreference.com/w/cpp/utility/tuple/get)的定义时,我看不出N如何适合......?据我所知,N是一个整数序列。

根据我可以观察到的内容,我假设E<X>...形式的表达式X是类型X1的序列。 X2,... Xn,表达式将扩展为E<X1>, E<X2> ... E<Xn>。这是它的工作原理吗?

编辑:在这种情况下,N不是类型序列,而是整数。但我猜这种语言结构适用于类型和价值观。

2 个答案:

答案 0 :(得分:6)

我认为@ Xeo的评论总结得很好。从C ++ 11标准的14.5.3开始:

  

包扩展包含模式省略号,   其实例化产生零个或多个实例化   列表中的模式。

在你的情况下,当你完成递归模板实例化并最终进入部分特化时,你有

f(std::get<N>(std::forward<Tuple>(t))...);

...其中N是四个int s 0123的参数包。从上面的标准来看,这里的模式

std::get<N>(std::forward<Tuple>(t))

...省略号应用于上述模式使其以列表形式扩展为四个实例,即

f(std::get<0>(t), std::get<1>(t), std::get<2>(t), std::get<3>(t));

答案 1 :(得分:2)

扩展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...>带有函数的参数。一种简单的方法是重写上面提到的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<...>而不是移动元素。我认为类似于std::tuple<...>的合适元素移动的东西可以完成,但我还没有完成它。