//(1)
template <class T>
void f(T) {}
//(2)
template <class T>
void f(T*) {}
//(3)
template <>
void f<>(int*) {}
//(4)
void f(int*) {}
int main()
{
int* p;
f(p); // which function will be called?
return 0
}
Run Code Online (Sandbox Code Playgroud)
我已经知道了这个行为:
令我困扰的是,顺序很重要(因为它增加了我编写代码时的不确定性和猜测工作),特别是我知道如果那些是类特化,那么顺序无关紧要,最专业的类可以被编译器调用.
有人可以向我解释这是如何工作的吗?以及编译器遵循哪些规则来查找适当的函数特化?
基本规则实际上相当简单:函数和函数模板参与重载决策.显式函数模板特化没有.
因此,对于调用f(p),编译器执行重载决策以在(1),(2)和(4)之间进行选择.(3)从不考虑过载分辨率.
重载分辨率选择单个函数或函数模板.之后它的完成,如果选择了一个函数模板,然后将这个模板的特殊化予以考虑.
让我们分析您提供的声明的不同组合.
如果存在(4),则将明确地选择它.当其他条件相同时,非模板函数是比函数模板更好的重载匹配.
假设我们按此顺序只有(1),(2)和(3).过载分辨率选择在(1)和(2)之间.(2)更好,因为它更专业.因此,通过重载决策选择函数模板(2).
然后,编译器查看模板是否具有任何特化.事实上,它确实是专业化(3)T = int.所以选择了这种专业化.
现在,让我们说顺序是(1),(3),(2).同样,重载决策在(1)和(2)之间选择(记住特化,其中(3),从不参与重载决策).(2)再次被选中.这一次,(3)是(1)的专业化,用于T = int*.这是因为(2)在声明(3)时尚不存在,所以没有(2)专门化.但是(1)没有通过重载决策选择,因此不予考虑.
顺序(2),(3),(1)与(1),(2),(3)相同.顺序(2),(1),(3)与(1),(3),(2)相同.(1)和(2)的相对顺序无关紧要 - 它是(3)的位置,它控制着它将专门化的模板.