c++ - 我想了解 C++ 中的参数解包

标签 c++ templates c++11

我尝试使用可变参数模板编写我的第一个程序。专门为延迟函数调用打包参数。我最初假设调用如下所示的函数指针没有工作:

template<typename... params>
void TypeX<params...>::delayed_call()
{
    auto xs = get_saved_args(); // returns tuple
    (*func)(xs...);
}

环顾四周后,我找到了这个答案 C++11: I can go from multiple args to tuple, but can I go from tuple to multiple args?

用户 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));
}

我知道这是一个递归解决方案,一旦达到部分专用版本就会终止。虽然我无法理解流程,f(std::get<N>(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,
                  // This is the tricky part: Initial N... is empty, so
                  // sizeof...(N) is going to be 0, which is fed to next
                  // call_impl. On subsequent invokation of "call" N will
                  // contain a single entry - '0'. All subsequent invokations
                  // will keep adding numbers to N until
                  // Total == 1 + sizeof...(N)
                  // evaluates to true. At that point template
                  // specialization below gets invoked and completes the
                  // recursive chain.
                  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)
    {
        // This is the last call in the recusrive chain, so int... N is
        // actually a tuple of numbers (unless the function being invoked takes
        // no arguments)
        // Ellipsis(...) causes the line below to be expanded to however many
        // numbers the int... N contains:
        // f(std::get<0>(std::forward<Tuple>(t)),
        //   std::get<1>(std::forward<Tuple>(t)),
        //   std::get<2>(std::forward<Tuple>(t))
        //   ...
        // );
        f(std::get<N>(std::forward<Tuple>(t))...);
    }   
};      

// user invokes this
template <typename F, typename Tuple>
void call(F f, Tuple && t)
{
    // Strip all qualifiers from Tuple: constness, volatility, reference
    // and return the typedef of underfyling Tuple type
    typedef typename std::decay<Tuple>::type ttype;

    // ttype should now be a plain tuple type, so tuple_size will return its
    // size
    // IMPORTANT: The int... N is not given below, which drives the recursive
    // compilation
    call_impl<F,
              Tuple,
              0 == std::tuple_size<ttype>::value, // for no argument functions this is
              // always true, which doesn't trigger recursive call_impl, but
              // immediately drops to partially specialized call_impl, which
              // invokes the given function.
              std::tuple_size<ttype>::value
              /*int... N would go here, but nothing is supplied */
             >::call(f, std::forward<Tuple>(t));
}

关于c++ - 我想了解 C++ 中的参数解包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26950783/

相关文章:

c++ - 使用特殊类中的类模板的内部类型

c++ - 如果方法不进行类型检查,为什么 C++ 模板会匹配?

c++ - 为值/对象包装器 move 构造函数?

c++ - 使用 boost::spirit 解析类似 c-struct 的声明

c++ - 链接到可执行文件时如何强制将目标文件包含在静态库中?

c++ - g++ 默认参数

C++ : template class specialization and type traits

c++ - is_greater_than 模板元编程

c++ - C++ 中的部分专用模板实例化忽略编译时错误

c++ - 类中的唯一指针