// g++(5.4)
void func(int * const &) {}
void func(int *) {}
template <typename T> void tfunc(const T &) {}
template <typename T> void tfunc(T *) {}
int main()
{
int a = 0;
func(&a); // ambiguous
tfunc(&a); // unambiguous
return 0;
}
根据我的另一个测试,tfunc(&a)
将第一个模板实例化为void tfunc(int * const &)
,其参数类型与第一个非模板相同。
那么,为什么第一个调用不明确但第二个不是?
答案 0 :(得分:5)
鉴于两个功能模板同样如此好,过载分辨率将使用通常称为部分排序的过程选择更专业的功能模板。确切的规则非常复杂,但实际上它试图确定是否可以调用参数模板A的集合是参数集的(适当的)子集,模板B可以被调用。如果是这样,则A比B更专业,并且重载决策将更喜欢A。
因此,在你的情况下,tfunc(const T&)
可以用〜所有东西调用; tfunc(T*)
只能用指针调用。后者更专业,因此被选中。
如果您对标准和详细规则感兴趣,请参阅[temp.func.order]和[temp.deduct.partial]。
答案 1 :(得分:2)
模板函数的重载解析有一些特殊规则,其中之一是:
F1和F2是功能模板专精,根据14.5.6.2中描述的部分排序规则,F1的功能模板
比F2的模板更专业。
请参阅this question,了解如何确定哪种功能模板更专业。
这里,由于第二个模板功能更专业,因此没有任何歧义。
#include <iostream>
void func(int * const &) {}
void func(int *) {}
template <typename T> void tfunc(const T &) {std::cout << "#1\n";}
template <typename T>void tfunc(T *) {std::cout << "#2\n";}
int main()
{
int a = 0;
//func(&a); // ambiguous
tfunc(&a); // unambiguous
return 0;
}
// output: #2
修改:虽然在https://ideone.com/C9rF8b进行了测试,但我们可以看到第二个模板被选中,而不是问题中所述的第一个模板。
答案 2 :(得分:0)
因为const指针和非const指针(即T * const
和T *
)如果它们出现在函数的参数中没有区别,所以传递值(通过复制)和传递也是如此通过const引用。这就是f(&a)
含糊不清的原因。
对于第二个,因为&a
被解析为int *
,所以第二个模板匹配得更好,因为它更专业(它不能接受非指针参数)。第一个模板更通用,因此不使用它。
如果将第一个模板函数更改为此函数,它也将是不明确的:
template <typename T>
void tfunc(T * const &) {}