Let's first introduce a helper type that represents a parameter pack:
template<typename... T> struct Pack { };
Now, here's the function with the weird behaviour:
template<typename... TT, typename T>
void f(Pack<TT...>, Pack<T>, std::type_identity_t<TT>..., std::type_identity_t<T>);
std::type_identity_t
is used here to disable deduction from the last two parameters in case that would introduce any ambiguity.
First, I tried to call it like so:
f(Pack<int>{}, Pack<int>{}, 5, 5);
GCC raises an error and gives the following explanation:
<source>:12:6: note: candidate expects 3 arguments, 4 provided
12 | f(Pack<int>{}, Pack<int>{}, 5, 5);
| ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
That's not the kind of error I expected, I assumed that deduction would result in T = int
and TT... = int
. But okay, let's do what the note says and provide one less argument:
f(Pack<int>{}, Pack<int>{}, 5);
It still gives an error, but this time it's:
<source>:12:6: error: too few arguments to function 'void f(Pack<TT ...>, Pack<T>, std::type_identity_t<TT>..., std::type_identity_t<T>) [with TT = {int}; T = int; std::type_identity_t<T> = int]'
10 | f(Pack<int>{}, Pack<int>{}, 5);
| ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now it's too few of them. Also notice that this error message confirms my assumption about the deduced T
and TT...
.
At this point I switched to Clang to see whether it'd compile this code, but both of the above calls to f
(with 3 and 4 arguments) result in the same error, with the note:
<source>:8:6: note: candidate template ignored: deduced packs of different lengths for parameter 'TT' (<int> vs. <>)
void f(Pack<TT...>, Pack<T>, std::type_identity_t<TT>..., std::type_identity_t<T>);
^
I also tried compiling the code with MSVC, and it did compile without errors.
What is going on? Is there something that makes this code invalid? Is it a compiler bug, due to the strange error messages?
std::type_identity_t<TT>...
to avoid deduction here? – LipTT...
must still match what they deduceTT...
to be. If they do not match, deduction fails. – Fiorenzastd::type_identity
changes nothing' would suffice. Regarding what @Fiorenza said, I very much doubt that there's a deduction problem with the last two parameters, due tostd::type_identity
not having any effect. – Alphabeticstd::type_identity
. I I'll just edit the question. – Alphabeticstd::type_identity
makes no difference as theTT...
s are in a non-deduced context anyway. The core of this question is why then they cannot be deduced from thePack<TT...>
and simply "inserted and expanded" from that deduction in the non-deduced context of the third function parameter (TT...
).. – VersedT
a the end still a deduced context? If so that certainly can't be deduced. – Sinistrousf(Pack<int, int>{}, Pack<int>{}, 5, 5, 5);
should also compile? It doesn't. – Netta