From C++ Templates - The Complete Guide 2nd edition:
Moreover, such parameters can't usefully be placed after a template parameter pack or appear in a partial specialization, because there would be no way to explicitly specify or deduce them.
template<typename ...Ts, int N> void f(double (&)[N+1], Ts ... ps); // useless declaration because N // cannot be specified or deduced
where such parameters refers (I think) to the template parameters corresponding to those template arguments that can never be deduced. I.e. in the example above N
is the parameter that cannot be deduced because N+1
is "too complicated to be deduced".
But why specifying it is not possible? I understand that it's not possible to specify N
and let ...Ts
be deduced, but why isn't it possible to specify them all? In other words, what is wrong in specifying Ts=[int]
and N=2
via the following?
double x[3];
f<int,2>(x,1);
I.e. in the example above
N
is the parameter that cannot be deduced becauseN+1
is "too complicated to be deduced".
Formally, this is [temp.deduct.type]/5.3
The non-deduced contexts are:
- [...]
- /5.3 A non-type template argument or an array bound in which a subexpression references a template parameter.
As is already covered in the following Q&A:
particularly that in a template-head of a function template
template<typename ...Ts, int N> // ... function template
as per [temp.param]/14
A template parameter pack of a function template shall not be followed by another template parameter unless that template parameter can be deduced from the parameter-type-list ([dcl.fct]) of the function template or has a default argument ([temp.deduct]).
specifically as per the special rule for function templates (due to function template argument deduction), the template argument N
must be deducible from the function's parameter list. As per [temp.deduct.type]/5.3, it is not, and f
in the following example can never invoked (overload resolution will never consider it a viable candidate):
template<typename ...Ts, int N> void f(double (&)[N+1], Ts ... ps);
whereas the following functions can both be found by overload resolution:
template<typename ...Ts, int N>
void g(double (&)[N], Ts ... ps); // N deducible from function parameter
template<typename ...Ts, int N = 2> // N has a default-template-argument
void h(double (&)[N+1], Ts ... ps);
But why specifying it is not possible?
As discussed in the linked to Q&A, although it "would make sense for a compiler to support this", the standard does not, and a leading template parameter pack greedily includes all explicitly provided template arguments, even those that would not be valid as part of the expanded pack (e.g. non-type template arguments to a type template parameter pack).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With