模板参数推导失败,函数参数/参数不匹配

Template Argument Deduction Failure and Function Parameters/Arguments Mismatch

本文关键字:参数 函数 不匹配 失败      更新时间:2023-10-16

考虑以下程序:

template <class T> struct A { using X = typename T::X; };
template <class T, typename A<T>::X* = nullptr> void f(T, int);
void f(...);
template <class T> void g(T, int, typename A<T>::X* = nullptr); // #
void g(...);
int main() {
// f(0, nullptr); // error
g(0, nullptr); // ok       
}

g(0, nullptr)编译而f(0, nullptr)不编译(在Godbolt上的GCC主干和Clang主干下测试(。似乎在#的模板参数推导过程中,编译器发现参数nullptr与参数int不匹配时,并没有实例化A<int>。标准在哪里规定了这种行为?

这是CWG1391:

如果所有包含参与模板参数推导的模板参数,并且所有模板参数都是显式指定、推导或从默认模板参数中获取,其余参数为然后与相应的自变量进行比较。对于剩余的每个参数P的类型在替换之前是非依赖的任何显式指定的模板参数,如果参数A不能隐式转换为P,推导失败。

您可能被DR#1844咬伤。在[临时扣除]/8中,它表示:

如果替换导致类型或表达式无效,则类型推导失败。如果使用替换的参数编写,则无效类型或表达式是格式错误的类型或表达式,需要诊断。[注意:如果不需要诊断,则程序仍然不正确。访问检查是作为替换过程的一部分进行的--end note]只有函数类型、其模板参数类型和显式说明符的直接上下文中的无效类型和表达式才会导致推导失败。[注意:对类型和表达式的替换可能会导致类模板专门化和/或函数模板专门化的实例化、隐式定义函数的生成等效果。这些效果不在"直接上下文"中,可能会导致程序格式错误--尾注]

这里的问题是"即时上下文"没有真正给出定义,导致编译器之间存在差异。