Understanding points in the variation template function

Suppose I have the following piece of code. I understand this to a great extent.

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

      

Now I'm a bit confused as to where ...

should appear before or after the variable name. This is why I am confused.

Statement A below

template <class ...Args>  

      

assumes ...

is the type of the variable and Args is the name of the variable (which is good)

Statement B below

void foo_imp(const Args&... args) 

      

It seems to me that the Args type was a template type, but the addition ...

after it Args

confuses me?

and then assigning a value to a vector confuses even more

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

      

why is there ...

after args?

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

+1


source to share


1 answer


<class ...Args>

declares Args

as a package of variational parameters, where (meta) is the type of each parameter class

. For this explanation, let's assume it can be considered similar to:

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

      

Variadic parameter packages can appear wherever type lists can appear, but must be extended with ...

. So, for example, is void foo_imp(Args)

not legal, but

void foo_imp(Args...)

      

would be equivalent

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

      

...

expands the element to its left using the values ​​in the parameter pack. So in your actual example

void foo_imp(const Args&...)    

      

would be equivalent

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

      

Now it's time to abandon the idea of ​​a template parameter package as a fixed-size list of types; in fact, its length is determined by the number of arguments provided at the time of the call.

"BUT WE DO NOT SUPPLY ANY PATTERN ARGUMENTS WHEN CALLING!?!" I can hear you talking. This is because it foo_imp

is a function whose template arguments are inferred based on its normal arguments. This means that the length of the list (const Args1&, const Args2&, const Args3&)

is determined by the function call, and each type ArgsN

is determined by the normal rules for inferring the type of a function template.


Now on Args

. Likewise Args

, it Args

is a package of variation parameters and therefore must be expanded whenever it is used.



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

      

equivalent (using our explanatory naming system earlier)

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

      

Variadic parameter packages are not automatically expanded because they can be expanded as part of larger expressions, so automatic expansion may 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.

      

might work because it redirects each argument individually. If it was expanded as

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

      

it doesn't even compile because it std::forward

only takes one parameter.


Finally. When ...

displayed to the right of an expression containing any parameter packs, it expands that expression as a list, with each list item having the nth value from each contained parameter pack instead 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 extended expression appears in the parameter list, it can be written to the variable of the package variable. In this case, if the expression does not contain variational parameter packets, the parameter list is freed to accept 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

      

+12


source







All Articles