16.3重载与模板
如果同样好的函数中没有非模板函数,而有多个函数模板,且其中一个模板比其他模板更特例化,则选择此模板
编写重载模板
template<typename T>
string debug_rep(const T& t)
{
ostringstream os;
os << t;
return os.str(); //返回os绑定的string的一个副本
}
template<typename t>
string debug_rep(t* p)
{
ostringstream os;
os << "pointer: " << p; //打印指针本身的值,也就是地址
if (p) //是否为空
{
os << " " << debug_rep(*p); //打印p指向的值
}
else
{
os << "null pointer"; //p是空的
}
return os.str();//返回os绑定的string的一个副本
}
int main()
{
string s("你好 靓仔");
cout << debug_rep(s) << endl;
//第二个版本需要的是一个指针
//如何没有第二个版本将执行第一个版本实例化的版本
//T是string *
cout<< debug_rep(&s) << endl;
//下面的代码都是精确匹配,但是第二个版本是更特例化的版本
//所以执行的是第二个版本
const string* sp = &s;
cout << debug_rep(sp) << endl;
}
非模板和模板重载
第一个函数模板也可以实例化出,const string &
一样的参数列表,编译器会选择非模板版本, 一个非模板函数比一个函数模板更好
string debug_rep(const string& s)
{
return '"' + s + '"';
}
string s("HI");
cout << debug_rep(s) << endl;
重载模板和类型转换
string debug_rep(const string& s)
{
return '"' + s + '"';
}
void test01()
{
string s("你好 靓仔");
cout << debug_rep(s) << endl;
//第二个版本需要的是一个指针
//如何没有第二个版本将执行第一个版本实例化的版本
//T是string *
cout << debug_rep(&s) << endl;
//下面的代码都是精确匹配,但是第二个版本是更特例化的版本
//所以执行的是第二个版本
const string* sp = &s;
cout << debug_rep(sp) << endl;
}
//把字符指针转回为string ,并调用 string版本的debug_reg
string debug_rep(char* p)
{
return debug_rep(string(p));
}
string debug_rep(const char* p)
{
return debug_rep(string(p));
}
int main()
{
string s("hi");
cout << debug_rep(s) << endl;
//debug_rep(cosnt T&) ,T被绑定到 char[10];
//debug_rep( T*) ,T被绑定到 char *;
//debug_rep(cosnt string&) ,要求从 const char* 到string的类型转换
//T*版本更加特例化,只需要进行一次数组到指针的转换
cout << debug_rep("iworld ") << endl;
}
缺少声明可能导致程序行为异常
template<typename T>string debug_rep(const T& t);
template<typename t>string debug_rep(t*p);
string debug_rep(const string&);
string debug_rep(char* p);
string debug_rep(char* p)
{
return debug_rep(string(p));
}
string debug_rep(const char* p)
{
return debug_rep(string(p));
}
在定义任何函数之前记得声明所有重载的函数版本,这样就不必担心编译器由于未遇到你希望调用的函数而实例化一个并非你所需的版本
非模板和模板重载
debug_rep(cosnt string &)第一个模板, T被绑定到string *,
而编译器只会选择下面的非模板函数,
string debug_rep(const string& s)
{
return '"' + s + '"';
}
string s("hi");
cout << debug_rep(s) << endl;
如果一个非函数模板与一个函数模板提供同样好的匹配,则选择非模板版本
重载模板和类型转换
//对于这条代码 有三个debug_rep版本可以用
cout<<debug_rep("hi world");//但只执行最优的版本 debug_rep(T*)
debug_rep(const T&); //T是char[10]; 有结束符
debug_rep(T*) ;//是const char
debug_rep(const string&) ;//要求是const char*到string的类型转换
//将字符指针转换string ,同时调用string版本的debug_reg
string debug_rep(char* p)
{
return debug_rep(string(p));
}
string debug_rep(const char* p)
{
return debug_rep(string(p));
}
缺少声明可能导致程序行为异常
//把字符指针转回为string ,并调用 string版本的debug_reg
template<typename T>string debug_rep(const T& t);
template<typename t>string debug_rep(t*p);
string debug_rep(const string&);
string debug_rep(char* p)
{
//如果没有const string &版本的声明
//就执行const T&t版本
return debug_rep(string(p));
}
16.3节练习
16。49
g(42); 调用 g(T)
g§;调用g(T*)
g(ci); 调用g(T)
g(p2);调用g(T*)
f(42);调用f(T)
f§;调用f(T) //为什么是T ,不是const T * 只能说int推断的类型,要比int推断的类型高 ,因为他是int 不是 &,T最完美的特例化是接受一个地址,而不是指针
f(ci);调用f(T)
f(p2);调用f(const T)
练习16.50
只能说int推断的类型,要比int*推断的类型高
template<typename T>void f(T) { cout << "打印f(T)"<<endl; }
template<typename T>void f(const T*) { cout << "打印f(const T*)"<<endl; }
template<typename T>void g(T) { cout << "打印g(T)" << endl; }
template<typename T>void g(T*) { cout << "打印g(T*)"<<endl; }
int main()
{
int i = 42;
int* p = &i;
const int ci = 0 , * p2 = &ci;
g(42);
g(p);
g(ci);
g(p2);
f(42);
f(p);
f(ci);
f(p2);
}