函数模板:
1.模板函数中的参数是const&
2.尽量减少对实参类型的要求(如在支持”<”后可以不支持”>”)CP581
3 模板类型参数的类型转换CP601
- const转换(顶层const被忽略)
template <typename T> T f1(T&);
template <typename T> T f2(const T&);
string s1("hi");
const string s2("hi");
f1(s2);//const被忽略
f2(s1);//s1转化为const
- 数组或函数指针转换(引用不会转换为指针)
- 禁止其他类型的转换 E46
E24 证明只有非成员函数能够进行类型转换。为了使编译器知道具现化时类型参数T的实际类型,
template <typename T>
class Rational{
…
};
template <typename T>
const Rational<T> operator*(const Rational<T>& r1
const Rational&<T> r2);
编译器在推导函数模板第2个参数时不会考虑隐式类型转换
Rational<int> R1(1,2);
Rational<int> result=R1*2;//错误
利用友元在模板类内声明模板函数,并不是为了访问非公有部分,而是为了能在类模板内声明非成员函数(使函数被自动具现化)
由于此非成员函数只被声明在类模板内,所以无法在类外提供定义。
template <typename T>
class Rational{
public:
friend
const Rational operator*(const T& r1,const T& r2)//省略<T>
{
//为了减小inline带来的负担,在定义时只调用辅助函数
return dosomething(r1,r2);
//该辅助函数也是模板函数
}
…
};
由于类模板不需要实参推导,所以在具现化时已得到T的类型,所以operator*变成普通函数,可以调用隐式转换。
- 如果希望进行正常的类型转换,可以在模板参数列表添加新的类型参数
template <typename T>
int compare(const T &v1,const T &v2);
template <typename T1,typename T2>
int compare(const T1 &v1,const T2 &v2);
- 非类型参数进行正常的类型转换
4.显式模板实参
希望用户控制模板实例化或者函数的返回类型与参数列表的类型不一致。
//由于编译器按从左至右的顺序进行参数匹配
//最好将显式模板实参放在最左边
template <typename T1,typename T2>
//T1的类型无法从模板参数列表推出
T1 compare(const T2 &v1,const T2 &v2);
//显式模板实参在函数名之后,实参列表之前
auto it=compare<int>(110,120);
//T2的类型根据函数实参类型推断出来
5.无法通过显式模板实参确定返回类型CP604
- 返回类型与函数形参有关
template <typename T>
auto compare(T v)->decltype(*v)
//由于在遇到函数的参数列表之前v是不存在的,通过尾置返回类型
{
…
}
- 无法直接获得所需的类型
例如在需要返回元素的时候,迭代器操作只能返回元素的引用。可以使用remove_reference获得元素类型。
remove_reference<decltype(*v)>::type
6.可以被其他模板或非模板函数重载。
当有多个函数的匹配度相同(参数类型可以互相转换),优先顺序按照特殊化程度为:非模板函数;特例化函数;模板函数
假设有下列函数
template <typename T>
string debug_rep(const T &t)
{…}
template <typename T>
string debug_rep(T *t)
{…}
假设实参是string,因为string不能转换为指针,只有debug_rep(const T &t)可行。
假设实参是string*,因为第1个函数需要类型转换为const,所以匹配第2个
再添加1个函数
string debug_rep(const string &t)
{…}
注意在使用debug_rep函数时,该非模板函数需要和所有模板函数声明在同一作用域中。防止调用非期望的版本。CP618
template <typename T>
string debug_rep(const T &t);
template <typename T>
string debug_rep(T *t);
string debug_rep(const string &t);
当实参为”…”(C语言的字符串字面常量)时,由于非模板函数需要用户定义的从指针到string的转换,没有模板函数的匹配度高。所以选择第2个。
7.模板特例化CP624
有的时候通用模板不适用于对特定类型。(例如 E25 缺省的swap不能做到只交换指针。)可以为其定义template specialization(模板特例化)版本。
该版本是模板的实例化,需要为所有的模板参数指定为特定的类型。
//原模板函数
template <typename T> int compare(const T&,const T&)
//模板特例化
template <> //为所有模板参数提供实参
int compare(const string&,const string&)
模板和其特例化版本应声明在同一个头文件中,将所有同名模板的声明放在前面。