I have a class templated on a type parameter and parameter pack, and am confused about type-deduction of this type; while writing an output-streaming operator I discovered a par
What is happening is that a template function with a template parameter pack class... Ts
, and a parameter type (P) of foo
is being deduced against an argument type (A) of foo
.
14.8.2.5/9 says of this:
If P has a form that contains
or
[it does], then each argument Pi [
Ts...
] of the respective template argument list P is compared with the corresponding argument Ai [int
] of the corresponding template argument list of A. If the template argument list of P contains a pack expansion that is not the last template argument, the entire template argument list is a non-deduced context. [the pack expansion is last, so the previous doesnt apply] If Pi is a pack expansion [Ts...
, it is], then the pattern of Pi is compared with each remaining argument in the template argument list of A (int
). Each comparison deduces template arguments for subsequent positions in the template parameter packs expanded by Pi.
So class... Ts
should be deduced as the one element list int
, and consequently the function template should be instantiated with the parameter type const foo
, and be viable.
It is a compiler bug. Your code is well-formed.
More succinctly this is well-formed:
template struct S { };
template void f(S) { }
int main() { f(S()); }
but fails similarly on at least gcc 4.7.2 with:
error: parameter 1 of ‘void f(S) [with C = {int, C}]’
has incomplete type ‘S’
C
is incorrectly deduced as C = {int, C}
(a nonsensical recursion) instead of C = {int}
. The broken deduction of C
leads to further garbage that S
has an incomplete type.