给定以下代码,为什么选择foo(T*)
函数?
如果我删除它(foo(T*)
),代码仍然可以编译并正常工作,但是G++ v4.4.0(可能还有其他编译器)将生成两个foo()
函数:一个用于char [4]和一个用于char [7]。
#include <iostream>
using namespace std;
template< typename T >
void foo( const T& )
{
cout << "foo(const T&)" << endl;
}
template< typename T >
void foo( T* )
{
cout << "foo(T*)" << endl;
}
int main()
{
foo( "bar" );
foo( "foobar" );
return 0;
}
最佳答案
形式上,比较转换序列时,将忽略左值转换。转换分为几类,例如资格调整(T*
-> T const*
),左值转换(int[N]
-> int*
,void()
-> void(*)()
)等。
您的两个候选人之间的唯一区别是左值转换。字符串文字是转换为指针的数组。第一个候选对象通过引用接受数组,因此不需要左值转换。第二个候选者需要左值变换。
因此,如果有两个候选者通过仅查看转换就可以同时实现两个功能模板特化,那么规则是通过对二者进行部分排序来选择更专业的一个。
让我们通过查看它们的函数参数列表的签名来比较两者
void(T const&);
void(T*);
如果我们为第一个参数列表选择某种唯一类型的
Q
并尝试与第二个参数列表进行匹配,那么我们会将Q
与T*
进行匹配。这将失败,因为Q
不是指针。因此,第二个至少与第一个一样专业。如果相反,我们将
Q*
与T const&
匹配。引用被删除,顶级限定符被忽略,剩下的T
变为Q*
。出于部分排序的目的,这是精确匹配,因此成功地针对第二个候选者推导出了第二个的转换后的参数列表。由于另一个方向(相对于第二个方向)没有成功,因此第二个候选人比第一个更专业-因此,如果存在歧义,那么过载解决方案将优先选择第二个。在
13.3.3.2/3
处:然后
13.3.3/1
最后,这是隐式转换表,可以在
13.3.3.1.1/3
上参与标准转换序列。Conversion sequences http://img259.imageshack.us/img259/851/convs.png
关于c++ - 从重载模板函数中进行选择的规则是什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1177739/