I am trying to understand the following code:
template <class...Ts, class...Us> void f(void) {};
int main() {
f<int, char, float, double>();
}
I don't know how template argument deduction deduces Ts
and Us
. In this answer, I learned that parameter packs are greedy, so Ts
will match all specified arguments: [ Ts = int, char, float, double ]
. But what about Us
: it has not been deduced yet? or what happens in this case?
I expect that the compiler throws a deduction error since it cannot figure out what Us
is expanded to.
Can I somehow, in the template argument-list, tell the compiler that I need Ts
to be int, char
, and Us
to be float, double
? how I can do that? I mean, can the call expression be something like that:
f<{int, char}, {float, double}>();
I found out that when I edit the above code to be as follows, this will fit my needs:
template <class...> struct S{};
template <class...Ts, class...Us> void g(S<Ts...>, S<Us...>)
{
};
int main() {
S<int, char> s1;
S<float, double> s2;
g(s1 ,s2);
}
But I still need to understand why in this case Ts
is [int, char]
, and Us
is [float, double]
.
What I think in this case is that: Since parameter packs are greedy, template argument deduction deduces Ts
as [S<int, char>, S<float, double>]
and Us
is left off un-deduced or just empty. Right?
This makes me think that
First, [int, char]
gets substituted in the place of Ts...
in the first function parameter S<Ts..>
, so it gets expanded into S<int, char>
. Then [float, double]
gets substituted in the place of Us...
in the second function parameter S<Us..>
, so it gets expanded into S<float, double>
.
Second, template argument deduction deduces Ts
as [int, char]
and Us
as [float, double]
.
Is my understanding correct in this case?
Regarding the second part of the question (second example).
Template argument deduction deduces parameter packs Ts
as [int, char]
, and Us
as [ float, double ]
the same way it deduces T
if you have the following:
template <class> struct B {};
template <class T> void h(B<T>)
.. and you call h(B<int>())
, template argument deduction is applied as follows:
P = B<T>, A = B<int> -> [ T = int ] not [ T = B<int> ]
The same is applied in the second example:
P1 = S<Ts...>, A1 = S<int, char> --> [ Ts = int, char ];
P2 = S<Us...>, A2 = S<float, double> --> [ Us = float, double ];