9

所以我试图弄清楚它是如何工作的:C++11:我可以从多个 args 转到 tuple,但我可以从 tuple 转到多个 args 吗?

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

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

f这是我不明白的里面的表达。

我知道表达式以某种方式将里面的内容解包/扩展t为参数列表。但是有人可以解释一下这是如何完成的吗?当我查看std::get( http://en.cppreference.com/w/cpp/utility/tuple/get ) 的定义时,我不知道如何N适应...?据我所知,N 是一个整数序列。

根据我的观察,我假设表达式形式为E<X>...where Xis the sequence of types X1X2, ... Xn,表达式将扩展为E<X1>, E<X2> ... E<Xn>。这是它的工作原理吗?

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

4

2 回答 2

6

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

包扩展由一个模式和一个省略号组成,其实例化会在列表中产生零个或多个模式的实例化。

在您的情况下,当您完成递归模板实例化并最终进入部分专业化时,您已经

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

...其中N是四个ints ( 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));
于 2013-09-24T22:15:57.850 回答
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...>带有函数参数的 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<...>但我还没有完成。

于 2013-09-24T22:37:52.850 回答