【问题标题】:Understanding the dots in variadic template function了解可变参数模板函数中的点
【发布时间】:2014-06-22 12:46:27
【问题描述】:

假设我有以下代码。我在很大程度上理解这一点。

template <class ...Args>               //---> Statement A
void foo_imp(const Args&... args)      //---> Statement B
{
    std::vector<int> vec = {args...};  //---> Statement C
}

现在我有点困惑... 应该出现在变量名称之前还是之后。这就是我感到困惑的原因。

下面给出的语句A

template <class ...Args>  

建议...是变量类型,Args是变量名(这很好)

下面给出的语句 B

void foo_imp(const Args&... args) 

在我看来,类型是 Args,这是模板类型,但是在 Args 之后添加 ... 让我感到困惑?

然后将值分配给向量会更加混乱

 std::vector<int> vec = { args... };

为什么args后面有...

关于如何记住上面的代码以便对我有意义的任何想法?

【问题讨论】:

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


    【解决方案1】:

    &lt;class ...Args&gt;Args 声明为可变参数包,其中每个参数的(元)类型为class。为了便于解释,我们假设这可以被认为类似于:

    <class Args1, class Args2, class Args3, etc.>
    

    可变类型参数包可以出现在类型列表可能出现的任何地方,但必须使用... 扩展。所以例如void foo_imp(Args)是不合法的,但是

    void foo_imp(Args...)
    

    相当于

    void foo_imp(Args1, Args2, Args3, etc.) 
    

    ... 使用参数包的值将事物向左扩展。所以在你的实际例子中,

    void foo_imp(const Args&...)    
    

    相当于

    void foo_imp(const Args1&, const Args2&, const Args3&, etc.)  
    

    现在是时候放弃将模板参数包作为固定大小的类型列表的想法了;实际上,它的长度取决于调用时提供的参数数量。

    “但我们在通话时不提供任何模板参数!?!” 我听到你说。这是因为foo_imp 是一个函数,其模板参数是根据其普通参数推导出来的。这意味着(const Args1&amp;, const Args2&amp;, const Args3&amp;)列表的长度由函数调用决定,每个ArgsN类型由函数模板类型推导的常规规则决定。


    现在转到args。与Args 类似,args 是可变参数包,因此在使用时必须对其进行扩展。

    std::vector<int> vec = {args...};
    

    相当于(使用我们之前的解释性命名系统)

    std::vector<int> vec = {args1, args2, args3, etc.};
    

    可变参数包不会自动扩展自身,因为它们可以作为较大表达式的一部分进行扩展,因此自动扩展可能不明确或不正确。例如:

    std::forward<Args>(args)...
    //expands as:
    std::forward<Args1>(args1), std::forward<Args2>(args2), std::forward<Args3>(args3), etc.
    

    能够工作,因为它单独转发每个参数。如果它被扩展为

    std::forward<Args...>(args...)
    //expands as:
    std::forward<Args1, Args2, Args3, etc.>(args1, args2, args3, etc)    
    

    它甚至无法编译,因为std::forward 只接受一个参数。


    总之。如果... 出现在包含任何可变参数包的表达式的右侧,它将将该表达式扩展为一个列表,列表中的每个元素都具有来自每个包含的参数包的第 n 个值来代替该参数包。

    //Foo and bar are variadic parameter packs
    Foo...                     => Foo1, Foo2, Foo3, etc
    std::vector<Foo>...        => std::vector<Foo1>, std::vector<Foo2>, std::vector<Foo3>, etc.
    std::tuple<Foo...>(bar...) => std::tuple<Foo1, Foo2, Foo3, etc>(bar1, bar2, bar3, etc)
    &bar...                    => &bar1, &bar2, &bar3, etc
    

    如果这样的扩展表达式出现在参数列表中,它可以被可变参数包变量捕获。在这种情况下,如果表达式不包含任何可变参数包,则参数列表将被释放以获取任意数量的参数。

    template<typename ...Baz> => Baz is a variable length variadic parameter pack of `typename`s
    void bar(Baz ...baz)      => baz is a parameter pack of `Baz`s
    void bar(Baz &&...baz)    => baz is a parameter pack of `Baz&&`s
    

    【讨论】:

    • 多么棒的答案!我一直在努力解决完全相同的问题。感谢您花时间纠正如此出色而详细的答案。
    猜你喜欢
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-01
    • 2016-10-05
    相关资源
    最近更新 更多