James Franco
James Franco

Reputation: 4706

Variadic Templates - Parameter pack expansion understanding

I am having a hard time understanding parameter pack expansion. The thing that confuses me are when dots appear on the right side and when dots appear on the left side. I came across this post which helped a little. Suppose I have the following two examples

Example 1:
template <class ...A>   --> line 1
int func(A... arg)      --> line 2
{
   return sizeof...(arg);
}

int main(void)
{
   return func(1,2,3,4,5,6);
}

The post I mentioned above I believe mentions that the difference b/w ...A and A... is that the first one does Left side expansion and the second one does right side expansion. I am not sure what that means. Could anyone please clarify this with how something would look like when expanded. The only thing I understand so far regarding dots on the right hand side are the examples such as this

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

could any one please clarify what the dots expand to in line 1 and line 2 and what is the difference between left side expansion and right side expansion ?

Upvotes: 6

Views: 1808

Answers (1)

Barry
Barry

Reputation: 303027

There is no "left-side expansion", there is only "right-side expansion." When you typed:

template <class ...A>
int func(A... arg)

The ... does not apply to the A. It helps to think of it as:

 template <class... A>

As in, A names a parameter-pack consisting of classes. There is no expansion going on in that line - it's just declaring what the parameters are for the function template func.

Furthermore, as T.C. points out, the ... in the argument list grammatically binds to the argument name not its type. This helps make sense of particularly complicated declarations such as:

template <typename... T>
void foo(T (*...fs)());

where fs would be a (possibly-empty) pack of pointers to nullary functions.

As for parameter pack expansion, see my answer here for a list of examples of what parameter expansion does based on the ... placement. The short version is: all the packs in the expression immediately preceding the ... are expanded concurrently. All of the examples you listed in your question are correct. I would additionally add:

std::tuple<Foo...>(bar...) => std::tuple<Foo1, Foo2, Foo3, etc>(bar1, bar2, bar3, etc)
std::tuple<Foo>(bar)...    => std::tuple<Foo1>(bar1), std::tuple<Foo2>(bar2), ...

Upvotes: 5

Related Questions