Enr*_*lis 5 c++ templates language-lawyer template-meta-programming c++17
来自C++ 模板 - 完整指南第 2 版:
此外,此类参数不能有效地放置在模板参数包之后或出现在部分特化中,因为无法明确指定或推导它们。
Run Code Online (Sandbox Code Playgroud)template<typename ...Ts, int N> void f(double (&)[N+1], Ts ... ps); // useless declaration because N // cannot be specified or deduced
其中此类参数指(我认为)与那些永远无法推导出的模板参数相对应的模板参数。即在上面的例子中N是无法推导的参数,因为N+1“太复杂了无法推导”。
但为什么指定它是不可能的?我知道不可能指定N并...Ts推论,但为什么不能全部指定它们?换句话说,指定Ts=[int]和N=2通过以下有什么问题?
template<typename ...Ts, int N>
void f(double (&)[N+1], Ts ... ps); // useless declaration because N
// cannot be specified or deduced
Run Code Online (Sandbox Code Playgroud)
即上例中的
N参数无法推导,因为N+1“太复杂而无法推导”。
正式来说,这是[temp.deduct.type]/5.3
非推导的上下文是:
- [...]
- /5.3 非类型模板参数或其中子表达式引用模板参数的数组边界。
正如以下问答中已经介绍的:
特别是在函数模板的模板头中
Run Code Online (Sandbox Code Playgroud)template<typename ...Ts, int N> // ... function template
函数模板的模板参数包后面不应跟有另一个模板参数,除非该模板参数可以从函数模板的参数类型列表([dcl.fct])推导出来或具有默认实参([temp.fct])。扣除])。
具体来说,根据函数模板的特殊规则(由于函数模板参数推导),模板参数N 必须可以从函数的参数列表中推导。根据[temp.deduct.type]/5.3,它不是,并且f在以下示例中永远无法调用(重载解析永远不会将其视为可行的候选者):
Run Code Online (Sandbox Code Playgroud)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);
Run Code Online (Sandbox Code Playgroud)
但为什么指定它是不可能的呢?
正如链接到问答中所讨论的,尽管“编译器支持这一点是有意义的”,但标准却没有,并且领先的模板参数包贪婪地包含所有显式提供的模板参数,即使是那些作为一部分无效的参数扩展包(例如,类型模板参数包的非类型模板实参)。