In Andrei\'s talk on GoingNative 2012 he talks about Variadic Templates, and he explains at one point by way of the example underneath how the parameter pack expansions work. B
1.
gun(A<Ts...>::hun(vs)...)
=> gun(A<T1, T2, …, Tn>::hun(vs)...)
=> gun(A<T1, T2, …, Tn>::hun(v1),
A<T1, T2, …, Tn>::hun(v2),
…,
A<T1, T2, …, Tn>::hun(vm))
2.
gun(A<Ts...>::hun(vs...))
=> gun(A<T1, T2, …, Tn>::hun(vs...))
=> gun(A<T1, T2, …, Tn>::hun(v1, v2, …, vm))
This should be obvious.
3.
gun(A<Ts>::hun(vs)...)
=> gun(A<T1>::hun(v1), A<T2>::hun(v2), …, A<Tn>::hun(vn))
(In this case the program won't compile if the lengths of Ts and vs differ)
The ...
will expand a pattern (which includes any parameter packs) preceding it, meaning that, in foo(Ts, Us, Vs)...
, each member of the list Ts
, Us
, Vs
(enumerated in lock step) will be substituted into that pattern, and a comma separated list will be formed:
foo(Ts, Us, Vs)...
=> foo(T1, U1, V1), foo(T2, U2, V2), …, foo(Tn, Un, Vn)
And if there are nested expansions, the innermost patterns will be expanded first. Therefore, in case 1, the pattern Ts
will first be expanded into T1, T2, …, Tn
. And then, the pattern preceding the outer ...
is A<T1, T2, …, Tn>::fun(vs)
— note that Ts
has been expanded — so it will be expanded to A<T1, T2, …, Tn>::fun(v1), A<T1, T2, …, Tn>::fun(v2), …, A<T1, T2, …, Tn>::fun(vm)
by substituting v1
, v2
, etc. into vs
.
KennyTM's answer is perfect. I just also like samples. But since his answer is abstract, I didn't feel like adding demos to his answer is the correct thing. So demos for his answer are here. I'm assuming his answer is right, I know nothing myself. (If you upvote this, upvote his too)
Obviously this is all psudocode just showing the expanded states.
void foo<void*,int,char,std::string>(nullptr, 32, '7', "BANANA") {
//gun(A<Ts...>::hun(vs)...);
gun(A<void*,int,char,std::string>::hun(nullptr)
,A<void*,int,char,std::string>::hun(32)
,A<void*,int,char,std::string>::hun('7')
,A<void*,int,char,std::string>::hun("BANANA")
);
//gun(A<Ts...>::hun(vs...));
gun(A<void*,int,char,std::string>::hun(nullptr, 32, '7', "BANANA");
//gun(A<Ts>::hun(vs)...);
gun(A<void*>::hun(nullptr)
,A<int>::hun(32),
,A<char>::hun('7'),
,A<std::string>::hun("BANANA")
);
}