这是Primer c ++ 5th中的练习:
template <typename T> void f(T); //1
template <typename T> void f(const T*); //2
template <typename T> void g(T); //3
template <typename T> void g(T*); //4
int i = 42, *p = &i;
const int ci = 0, *p2 = &ci;
g(42); g(p); g(ci); g(p2);
f(42); f(p); f(ci); f(p2);
这是答案:
g(42); //type: int(rvalue) call template 3 T: int instantiation: void g(int)
g(p); //type: int * call template 4 T: int instantiation: void g(int *)
g(ci); //type: const int call template 3 T: const int instantiation: void g(const int)
g(p2); //type: const int * call template 4 T: const int instantiation: void g(const int *)
f(42); //type: int(rvalue) call template 1 T: int instantiation: void f(int)
f(p); //type: int * call template 1 T: int * instantiation: void f(int *)
f(ci); //type: const int call template 1 T: const int instantiation: void f(const int)
f(p2); //type: const int * call template 2 T:int instantiation: void f(const int *)
我的问题是,为什么f(p)
倾向于实例化f(T)
而不是f(const T *)
答案 0 :(得分:1)
简而言之,将函数模板包含在重载解析中的规则是:
名称查找确定了一组可见的功能,对象和功能模板。
集合中的每个函数模板都可以从任何显式参数,推论和/或默认模板参数中确定其模板参数,并在可能的情况下替换这些参数以获得一个特定的具体函数签名。 (在不可能的情况下,仅将函数模板扔出集合。当模板参数推导失败时,以及将参数替换为签名失败时,也称为“ SFINAE”规则,就会发生这种情况。)
使用正常的重载解析规则对函数进行比较,将来自模板的签名完全视为普通的非模板函数。
仅当第3步认为其中两个功能不明确时,这些平局决胜规则才适用:
a。如果一个功能签名来自模板,而一个不是来自模板,则认为非模板功能更好。
b。如果两个功能签名都来自模板,并且一个模板比另一个模板“更专业”,则认为更专业的模板更好。 (简而言之,“更专业”意味着我们可以证明对更专业模板的任何有效参数也对不那么专业模板的有效参数,反之亦然。)
在此示例的f(p)
表达式中,在步骤2中,模板#1推导T=int*
,模板#2推导T=int
,因此签名为:
void f(int*); // from 1
void f(const int*); // from 2
在步骤3中,参数p
的类型为int*
,因此#1的void f(int*);
使用身份转换(完全匹配),而#2的void f(const int*);
使用使用指针转换,因此#1的void f(int*);
获胜,并且该函数模板的专业化是命名的。
确实,模板#2 void f(const T*);
比模板#1 void f(T);
更专业。但是,由于第3步确定了答案,因此我们永远都不会进入第4步,因此这里无关紧要。 (步骤4确实输入了另一个表达式f(p2)
。)
答案 1 :(得分:0)