理解可变模板函数中的点 [英] Understanding the dots in variadic template function

查看:121
本文介绍了理解可变模板函数中的点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有下面的代码。我在很大程度上理解。

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

现在我对于 ... 应出现在变量名称之前或之后。这就是为什么我很困惑。



语句A,如下所示

  template< class。 ..Args> 

建议 ...

 >  void foo_imp(const Args& ... args)

我喜欢的类型是Args这是模板类型,但 ... 后添加 Args 困惑我?



然后将值分配给向量进一步混淆

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

为什么在args后有 ...



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

解决方案

< class ... Args> 声明 Args 参数包,其中每个参数的(meta-)类型 class 。为了这个解释,让我们假设这可以被认为是类似于:

 < class Args1,class Args2, Args3等。 

变量类型参数包可以出现在可能出现类型列表的任何位置,但必须使用 ... 。例如 void foo_imp(Args)不合法,但

  void foo_imp(Args ...)

将等效于

  void foo_imp(Args1,Args2,Args3等)


b $ b

... 使用参数包的值将事件扩展到左边。所以在你的实例中,

  void foo_imp(const Args& ...)



将等同于

  void foo_imp const Args1& const Args2& const Args3&等)

模板参数包作为固定大小的类型列表的想法;



但是我们不能在电话时间提供任何模板的参数? !我听到你说。这是因为 foo_imp 是一个函数,其模板参数是基于其正常参数推导的。这意味着(const Args1& const Args2& const Args3&)列表的长度由函数调用确定,并且每个 ArgsN 类型由函数模板类型推导的正常规则确定。






code> args 。与 Args 类似, args 是一个可变参数包,因此必须在使用时进行扩展。

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

等同于(使用我们之前的解释命名系统)

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

变数参数包不会自动展开,因为它们可以扩展为较大表达式的一部分,因此自动扩展可能是模糊的或不正确的。例如:

  std :: forward< Args>(args)... 
//扩展为:
std :: forward< Args1>(args1),std :: forward< Args2>(args2),std :: forward< Args3>(args3)等。
/ pre>

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

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

它甚至不会编译,因为 std :: forward 只需要一个参数。






总之。如果 ... 出现在包含任何可变参数包的表达式的右侧,则将该表达式作为列表展开,列表的每个元素都具有每个

  // Foo和bar是可变参数包
Foo .. 。=> Foo1,Foo2,Foo3等
std :: vector< Foo> ... => std :: vector< Foo1>,std :: vector< Foo2>,std :: vector< Foo3>等。
std :: tuple< Foo ...>(bar ...) std :: tuple< Foo1,Foo2,Foo3等>(bar1,bar2,bar3等)
& bar ... = & bar1,& bar2,& bar3等

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

  template< typename ... Baz> => Baz是一个变长的可变参数包,它是一个`typename`s 
void bar(Baz ... baz)=> baz是`Baz`s的一个参数包
void bar(Baz& ... baz)=> baz是`baz&`s的参数包


Suppose I have the following piece of code. Which I understand to a large extent.

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

Now I am a bit confused as to where the ... should appear before or after the name of the variable. Here is why I am confused.

The statement A, given below

template <class ...Args>  

suggests that ... is the variable type and Args is the variable name (which is fine)

The statement B, given below

void foo_imp(const Args&... args) 

This seems to me like the type is Args which was the template type however the addition of ... after Args confuses me?

and then assigning the value to vector is further confusing

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

why are there ... after args ?

Any ideas on how I could remember the above code so that it would make sense to me ?

解决方案

<class ...Args> declares Args to be a variadic parameter pack where the (meta-)type of each parameter is class. For the sake of this explanation, let's suppose this can be thought of as similar to:

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

Variadic type parameter packs can appear wherever lists of types may appear, but must be expanded with .... So for example void foo_imp(Args) is not legal, but

void foo_imp(Args...)

would be equivalent to

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

The ... expands the thing to its left, using the values of the parameter pack. So in your actual example,

void foo_imp(const Args&...)    

would be equivalent to

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

Now it is time to abandon the idea of the template parameter pack as a fixed sized list of types; in actuality, its length is determined by the number of arguments supplied at call time.

"BUT WE DON'T SUPPLY ANY TEMPLATE ARGUMENTS AT CALL TIME!?!" I hear you say. This is because foo_imp is a function whose template arguments are deduced on the basis of its normal arguments. This means that the length of the (const Args1&, const Args2&, const Args3&) list is determined by the function call, and each ArgsN type is determined by the normal rules for function template type deduction.


Now on to args. Similarly to Args, args is a variadic parameter pack, and so must be expanded whenever it is used.

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

is equivalent to (using our explanatory naming system from earlier)

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

Variadic parameter packs do not automatically expand themselves, because they can be expanded as part of larger expressions, and so automatic expansion could be ambiguous or incorrect. For example:

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

is able to work because it individually forwards each argument. If it were expanded as

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

it wouldn't even compile, because std::forward only takes a single parameter.


In conclusion. If ... appears to the right of an expression containing any variadic parameter packs, it expands that expression as a list, with each element of the list having the nth value from every contained parameter pack in place of that parameter pack.

//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

If such an expanded expression appears in a parameter list, it can be captured by a variadic parameter pack variable. In this case, if the expression does not contain any variadic parameter packs, the parameter list is freed to take an arbitrary number of parameters.

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

这篇关于理解可变模板函数中的点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆