假设我有以下代码。我在很大程度上理解这一点。
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
会让我困惑吗?
然后将值赋给vector会进一步混淆
std::vector<int> vec = { args... };
为什么在args之后有...
?
关于我如何记住上述代码以便对我有意义的任何想法?
答案 0 :(得分:15)
<class ...Args>
声明Args
是一个可变参数包,其中每个参数的(meta-)类型为class
。为了便于解释,我们假设这可以被认为类似于:
<class Args1, class Args2, class Args3, etc.>
Variadic类型参数包可以出现在可能出现类型列表的位置,但必须使用...
进行扩展。例如,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.)
现在是时候放弃模板参数包的想法作为固定大小的类型列表;实际上,它的长度取决于在通话时提供的参数数量。
&#34;但是我们不打算在电话时间提供任何模板参数!?!#&#34; 我听到你说。这是因为foo_imp
是一个函数,其模板参数是根据其正常参数推导出来的。这意味着(const Args1&, const Args2&, const Args3&)
列表的长度由函数调用确定,每个ArgsN
类型由函数模板类型推导的常规规则确定。
现在开始args
。与Args
类似,args
是一个可变参数包,因此必须在使用时进行扩展。
std::vector<int> vec = {args...};
等同于(使用我们之前的解释性命名系统)
std::vector<int> vec = {args1, args2, args3, etc.};
Variadic参数包不会自动扩展,因为它们可以作为较大表达式的一部分进行扩展,因此自动扩展可能不明确或不正确。例如:
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个值,而不是该参数包。 / p>
//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