这段代码如何从元组中提取参数?

时间:2014-08-08 15:20:13

标签: c++ templates tuples variadic-templates template-meta-programming

所以我遇到了在元组中存储可变参数的问题,以便稍后用这些来调用函数。我找到了Kerrek SB的答案,这样做非常好,但我不明白它到底是做什么的。这是代码:

// implementation details, users never invoke these directly
namespace detail
{
    template <typename F, typename Tuple, bool Done, int Total, int... N>
    struct call_impl
    {
        static void call(F f, Tuple && t)
        {
            call_impl<F, Tuple, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(f, std::forward<Tuple>(t));
        }
    };

    template <typename F, typename Tuple, int Total, int... N>
    struct call_impl<F, Tuple, true, Total, N...>
    {
        static void call(F f, Tuple && t)
        {
            f(std::get<N>(std::forward<Tuple>(t))...);
        }
    };
}

// user invokes this
template <typename F, typename Tuple>
void call(F f, Tuple && t)
{
    typedef typename std::decay<Tuple>::type ttype;
    detail::call_impl<F, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value>::call(f, std::forward<Tuple>(t));
}

基本上,困扰我的部分如下:

template <typename F, typename Tuple, bool Done, int Total, int... N>
    struct call_impl
    {
        static void call(F f, Tuple && t)
        {
            call_impl<F, Tuple, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(f, std::forward<Tuple>(t));
        }
    };

我理解N...sizeof...(N)存在某种TMP递归,它会将Done设置为true的部分特化停止,这发生在条件Total == 1 + sizeof...(N)已经过验证。

我无法理解的是N...来自哪里。我无法看到它的起源......

有人可以解释这个实现是如何工作的吗? (如果那不是SO的话题。)

1 个答案:

答案 0 :(得分:2)

第一次调用:

typedef typename std::decay<Tuple>::type ttype;
detail::call_impl<
  F, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value
>::call(f, std::forward<Tuple>(t));

请注意,他们将4个参数传递给call_impl

<typename F, typename Tuple, bool Done, int Total, int... N>
struct call_impl

在这里你可以看到它需要4个参数,然后是int...int...表示“零或更多int s”。所以它从零int开始。

但除非Done为空,否则ttype为false。

如果Done为false,则使用基本实例:

call_impl<F, Tuple, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(f, std::forward<Tuple>(t));

最初N...为空,因此sizeof...(N)0。这最终以

结束
call_impl<F, Tuple, Total == 1 + 0, Total, 0>::call(f, std::forward<Tuple>(t));

使用N...填充0。如果Done,则Total==1设置为true。如果没有,我们会递归,最后将N...设置为0,1,重复到Done。一旦Done成立,我们就会N...填充0, 1, 2, ...最多Total-1

Done为true会导致调用此特化:

template <typename F, typename Tuple, int Total, int... N>
struct call_impl<F, Tuple, true, Total, N...>

进行通话。

现在,这是一种奇怪而又笨拙的方法,可以使用Total构建基于{{1}}的序列,然后将包含该序列的类型作为参数传递给函数,并推导出序列。类型。但上述技术有效。