Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Misunderstanding about non-deducible function template arguments

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);
like image 937
Enlico Avatar asked Oct 14 '22 20:10

Enlico


1 Answers

I.e. in the example above N is the parameter that cannot be deduced because N+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:

  • Which part of the C++ standard prevents explicitly specifying this template's arguments?

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).

like image 188
dfrib Avatar answered Oct 20 '22 20:10

dfrib