//第一版本//打印任何类型template<typename T>string debug_rep(const T &t){ostringstream ret;ret << t;return ret.str();}//第二版本//参数为指针类型的//注意:此函数不能用于char*(字符指针),因为IO库为char*值定义了一个<<版本,//此<<版本假定指针表示一个空字符结尾的字符数组,并打印数组的内容而非地址值(我们将在下面介绍如何处理字符指针)template<typename T>string debug_rep(T *p){ostringstream ret;ret << "pointer: " << p; //打印指针自身的值//如果有内容,打印指针所指的内容if (p)ret << " " << debug_rep(*p);//调用上一版本的debug_rep函数elseret << " null pointer";return ret.str();}
std::string s("hi");std::cout << debug_rep(s) << std::endl;
std::string s("hi");std::cout << debug_rep(&s) << std::endl;
std::string s("hi");const std::string *sp = &s;std::cout << debug_rep(sp) << std::endl;
//第三版本//打印双引号包围的stringstring debug_rep(const string &s){return '"' + s + '"';}
std::string s("hi");std::cout << debug_rep(s) << std::endl;
std::cout << debug_rep("hi world!") << std::endl; //最终调用debug_rep(T*)
//将字符指针转换为string,并调用string版本的debug_repstring debug_rep(char *p){return debug_rep(string(p)); //调用第三版本的}string debug_rep(const char *p){return debug_rep(string(p)); //调用第三版本的}
template<typename T> string debug_rep(const T &t);template<typename T> string debug_rep(T *p);//为了使debug_rep(char*)的定义正常工作,此debug_rep()的声明必须在作用域中//否则debug_rep(char*)将调用模板函数版本的string debug_rep(const string &s);string debug_rep(char *p){//如果接收一个const string&的版本的声明不在作用域中//返回语句将调用debug_rep(const T&)的T实例化为string的版本return debug_rep(string(p));}
//第一版本:可以比较任意两个类型template<typename T>int compare(const T&, const T&);//第二版本:处理字符串字面常量template<size_t N,size_t M>int compare(const char(&)[N], const char(&)[M]);
const char *p1 = "hi", *p2 = "mom";compare(p1, p2); //调用第一版本compare("hi", "mom"); //调用第二版本
template<typename T>int compare(const T&, const T&);template<size_t N,size_t M>int compare(const char(&)[N], const char(&)[M]);//compare的特例化版本,处理字符数组的指针template<>int compare(const char* const &p1,const char* const &p2){return strcmp(p1, p2);}
template<typename T>int compare(const T&, const T&);
函数重载与模板特例化
namespace std {template<>struct hash<Sales_data>{typedef size_t result_type;typedef Sales_data argument_type;size_t operator()(const Sales_data& s)const;};size_t hash<Sales_data>::operator()(const Sales_data& s)const{//下面的hash类都是标准库针对特定的数据类型进行的特例化,我们直接调用就可以了return hash<std::string>()(s.bookNo) ^hash<unsigned>()(s.units_sold) ^hash<double >()(s.revenue);}}
template<class T> class std::hash; //友元声明class Sales_data {private:std::string bookNo;unsigned units_sold;double revenue;friend class std::hash<Sales_data>; //特例化版本的hash为其友元};
//使用hash<Sales_data>和Sales_data的operator==unordered_multiset<Sales_data> SDset;
为了让Sales data的用户能使用hash的特例化版本,我们应该在Sales_ data 的头文件中定义该特例化版本。
我们只能部分特例化类模板,而不能部分特例化函数模板。
//原始的、最通用的版本template<class T>struct remove_reference {typedef T type;};//部分特例化版本template<class T>struct remove_reference<T&> { //针对于左值引用的typedef T type;};template<class T>struct remove_reference<T&&> { //针对于右值引用的typedef T type;};
int i;//调用原始模板remove_reference<decltype(42)>::type a;//i为左值引用,调用第一个(T&)部分特例化版本remove_reference<decltype(i)>::type b;//std::move(i)返回右值,调用第二个(T&&)部分特例化版本remove_reference<decltype(std::move(i))>::type c;//a、b、c均为int
//下面是一个模板类template<typename T>struct Foo {Foo(const T &t = T()) :mem(t) {}void Bar() {//通用的Bar()函数}T mem;};//特例化Foo<int>版本的的成员Bartemplate<>void Foo<int>::Bar(){//...}
Foo<string> fs; //实例化Foo<string>::Foo()fs.Bar(); //实例化Foo<string>::Bar()Foo<int> fi; //实例化Foo<int>::Foo()fi.Bar(); //实例化Foo<int>::Bar()