template<typename T>
string debug_rep(const T& t) { // const引用版本
ostringstream ret;
ret << t;
return ret.str();
}
template<typename T>
string debug_rep(T *p) { // 指针版本
ostringstream ret;
ret << "pointer: " << p;
if (p) {
ret << " " << debug_rep(*p);
}
else {
ret << " null pointer";
}
return ret.str();
}
如果传递一个非指针对象,那肯定会调用第一个版本
string s("hi");
cout << debug_rep(s) << endl; // 输出hi
如果传递的是指针,则两个版本都是可行的
string *p = &s;
debug_rep(p);
debug_rep(const string*&); // T推断为string*
debug_rep(string*); // T推断为string
由于第一个版本需要进行普通指针到const
指针的转换,所以应该选择第二个版本
现在考虑传入一个指向常量的指针
const string *sp = &s;
两个版本同样都是可行的
debug_rep(const string*&); // T推断为string*
debug_rep(const string*); // T推断为const string*
但编译器选择第二版,原因是第二版更特别,只能用于指针类型,而第一版更通用,可以应用于任何类型
当有多个重载模板对一个调用提供同样好的匹配时,应选择更特例化的版本
现在如果有一个非模板的版本
string debug_rep(const string& s) {
return '"' + s + '"';
}
string s("hi");
cout << debug_rep(s) << endl;
调用时同样有两个可行的版本
debug_rep<string>(const string&); // T推断为string
debug_rep(const string&); // 普通非模板函数
则编译器会选择非模板函数的版本
对于一个调用,如果一个非函数模板与一个函数模板提供同样好的匹配,则选择非模板版本
如果传递的是一个字符串字面常量
cout << debug_rep("hi world!") << endl; // 调用debug_rep(T*)
三个版本都是可行的
debug_rep(const char[10]&); // T推断为char[10]
debug_rep(const char*); // T推断为const char
debug_rep(const string&); // 需要将const char*转换为string
两个函数模板都是精确匹配的,第二个版本虽然需要将数组转换为指针,但这也是精确匹配。非模板版本需要类型转换,就不是精确匹配。所以,还是调用函数模板的第二个版本,因为其更特例化