对不可推导的函数模板参数的误解

Misunderstanding about non-deducible function template arguments

来自 C++ 模板 - 完整指南第 2 版

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指的是(我认为)那些永远无法推导的模板参数对应的模板参数。 IE。在上面的例子中 N 是无法推导的参数,因为 N+1 “太复杂了,无法推导”。

但为什么无法指定呢?我知道不可能指定 N 并推导 ...Ts ,但为什么不能指定它们?换句话说,通过以下方式指定 Ts=[int]N=2 有什么问题?

    double x[3];
    f<int,2>(x,1);

I.e. in the example above N is the parameter that cannot be deduced because N+1 is "too complicated to be deduced".

形式上,这是 [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.

正如以下问答中所涵盖的那样:

特别是在函数模板的模板头中

template<typename ...Ts, int N>
// ... function template

根据[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]).

特别是根据函数模板的特殊规则(由于函数模板参数推导),模板参数 N 必须可以从函数的参数列表 中推导出来。根据 [temp.deduct.type]/5.3,它不是,并且永远不会调用以下示例中的 f(过载解析永远不会将其视为可行的候选者):

template<typename ...Ts, int N>
void f(double (&)[N+1], Ts ... ps);

而以下函数都可以通过重载解析找到:

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?

正如在 Q&A 链接中所讨论的,虽然“编译器支持这一点是有意义的”,但标准并不支持,并且领先的模板参数包贪婪地包含所有显式提供的模板参数,即使是那些会作为扩展包的一部分无效(例如,类型模板参数包的非类型模板参数)。