Parameter pack must be at the end of the parameter list… When and why?

It is valid for function templates but only when argument deduction can help the compiler resolve the template parameters, as it stands your function template example is virtually useless because

template<typename T, typename... Args, typename S> void fn() { }
int main() { fn<int, int, int>(); }
test.cpp: In function 'int main()':
test.cpp:2:32: error: no matching function for call to 'fn()'
 int main() { fn<int, int, int>(); }
                                ^
test.cpp:1:57: note: candidate: template<class T, class ... Args, class S> void fn()
 template<typename T, typename... Args, typename S> void fn() { }
                                                         ^
test.cpp:1:57: note:   template argument deduction/substitution failed:
test.cpp:2:32: note:   couldn't deduce template parameter 'S'
 int main() { fn<int, int, int>(); }

the compiler has no way of determining which template parameters belong to the parameter pack, and which to S. In fact as @T.C. points out it should actually be a syntax error because a function template defined in this manner cannot ever be instantiated.

A more useful function template would be something like

template<typename T, typename... Args, typename S> void fn(S s) { }

as now the compiler is able to unambiguously match the function parameter s with the template type S, with the side effect that S will always be deduced – all explicit template parameters after the first will belong to Args.

None of this works for (primary) class templates, parameters aren’t deduced and it’s expressly forbidden:

From draft n4567

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4567.pdf

[temp.param] / 11

[…]If a template-parameter of a primary class template or alias
template is a template parameter pack, it shall be the last
template-parameter.[…]

(if they were deduced it would be ambiguous as in the function template example).

Leave a Comment