【问题标题】:How does this code extract arguments from tuple?此代码如何从元组中提取参数?
【发布时间】:2014-08-08 15:20:13
【问题描述】:

所以我遇到了将可变参数存储在元组中以便稍后使用这些调用函数的问题。我找到了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 的主题)。

【问题讨论】:

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


    【解决方案1】:

    第一次调用:

    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... 表示“零个或多个 ints”。所以它从零开始ints。

    Done 为假,除非ttype 为空。

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

    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));
    

    0 填充N...Done 设置为真当且仅当 Total==1。如果不是,我们递归并最终将N... 设置为0,1,重复直到Done。一旦Done 为真,我们就有一个N... 填充有0, 1, 2, ... 直到Total-1

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

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

    调用哪个。

    现在,这是一种奇怪而尴尬的技术,您可以根据Total 构建该序列,然后将包含该序列的类型作为参数传递给函数,并从类型中推断出序列.但上述技术有效。

    【讨论】:

    • 哦,快!我完全忘记了int... N 实际上可能是空的,并且递归可以从那里开始。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2013-01-11
    • 1970-01-01
    • 2018-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-08
    • 1970-01-01
    相关资源
    最近更新 更多