这一直是合法的 C++。
14.5.6/2:
一个函数模板可以被其他函数模板和普通(非模板)函数重载。普通函数与函数模板无关(即,它从不被视为特化),即使它与可能生成的函数模板特化具有相同的名称和类型。
当使用类似的“template-id”语法add<int>
时,只考虑具有足够模板参数的模板函数。所以a.add<int>()
甚至不看非模板是否add
匹配。
当标识符同时命名普通函数和函数模板时,编译器将尝试推断函数模板的模板参数以获得模板函数特化。然后通过通常的函数重载逻辑比较所有普通函数和所有模板函数特化。[见 13.3.1/7。]
在您的示例中,调用a.add()
无法推断T
模板版本的模板参数。所以唯一可行的功能是非模板重载。
在类似情况下还会出现另一条规则:如果非模板函数和模板函数特化否则会是模棱两可的重载,则非模板函数获胜。[这条规则在第 13.3.3 节中,在给定参数集的定义中,是什么使一个函数比另一个函数更好。]
class B
{
public:
int f(int n) { return n+1; }
template<typename T>
T f(T n) { return n; }
};
int main() {
B b;
b.f(1); // both are viable, non-template wins
b.f<int>(1); // only the template is viable
return 0;
}
这是有道理的,因为模板仍然可以被其他专业化使用,或者显式使用<
尖括号>
。因此,使用非模板函数重载函数模板有点像添加显式特化,但麻烦更少。