一些基本的模板特性:
非类参数模板
模板所声明的参数可以不是类参数,可以声明的非类参数包括整数(double,float不可以),enum,对象引用或指针。
通过模板嵌套实现类或非类参数载类方法参数上的重载(调用时实现,不在定义时实现)
友元函数模板:
直接举例:
template <typename T>
friend ostream& operator<< <T>(ostream& os, const T& t){};
内联模板函数:
模板定义必须在头文件中,所以所定义的函数并不直接是内联的,需要确定声明该函数是内联的。
inline void func(){}; //在模板类定义中
inline void A<T>:: func{}; //在模板类定义外
高级模板特性:
模板嵌套
当在某个模板类的参数调用时,无论是类参数还是非类参数,需要另一个模板参数,使用模板嵌套。
值得注意的时,模板嵌套不能handle当参数模板的参数和原模板的参数为同一个类的情况,因此,必须要保留无模板嵌套的原始情况完成模板方法函数的重载。
另外,模板嵌套的优先级是:
对于未使用参数模板,即参数全部使用原模板参数的方法,单独定义,单独调用。
一旦参数中使用了嵌套模板,则一定触发某个嵌套模板方法,触发的顺序是,
触发仅改变所有模板化参数的方法重载,如果没有,则逐级触发包括了更多未改变参数的嵌套模板。
测试代码如下:
复制代码
template <typename T,int SCORE>
class vec{
T a;
int sc;
public:
T getA()const {return a;}
int getScore() const {return sc;}
vec(T t):a(t),sc(SCORE){};
//参数中未使用模版嵌套的拷贝构造,必须有
vec(const vec<T,SCORE>& vv):a(vv.a),sc(vv.sc){cout<<"copyT is called"<<endl;};
//参数score模版化的拷贝构造
template <int OTHER>
vec(const vec<T,OTHER>& vv):a(vv.getA()),sc(vv.getScore()){cout<<"copyOther is called"<<endl;};
//参数t和score均发生模版化的拷贝构造
template <typename E,int OTHER>
vec(const vec<E,OTHER>& vv):a(vv.getA()),sc(vv.getScore()){cout<<"copy is called"<<endl;};
virtual ~vec();
};
模版偏特化与函数模版重载偏特化
模版通过重写一个具体类实现模版的偏特化(即某个具体类不按照模版实现),函数没有偏特化的功能,因此,通过重载实现。
优先级均为:
确定类,确定指针/引用/对象的模版类,任意模版类的顺序调用。
特殊的,模版全特化
所有模版参数都被特化,此时,函数可以特化,且特化类的函数重写不需要加上模版声明template<>
偏特化测试代码
#include <iostream>
template <typename T>
class pointertemp{
public:
T name;
pointertemp():name(T()){std::cout<<"original ctr callled"<<std::endl;};
};
template <typename T>
class pointertemp<T*>{
public:
T* name;
pointertemp():name(nullptr){std::cout<<"T* ctr callled"<<std::endl;};
};
template <>
class pointertemp<char*>{
public:
char* name;
pointertemp():name(nullptr){std::cout<<"char* ctr callled"<<std::endl;};
};
template <typename K>
void showK(K name){
std::cout<<"K func called";
}
template <typename K>
void showK(K* name){
std::cout<<"K* func called";
}
void showK(char* name){
std::cout<<"char* func called";
}
值得注意的是,当T为指针或者引用时,在找不到匹配的具体类的特化实现时,编译器会取找有没有指针特化或者引用特化,这些都优先于未特化模版。
且在指针特化和引用特化时,用<A*>实例化,但模版参数其实是A,也就是说<A*>实例化实际上是将A赋予T,然后使用指针特化模版。
模版继承:
模版类可以实现继承和多态,一般的,子类继承父类的同参数实例类,如果要继承任意类参数的实例类,只需要在模版中多声明一个父类类参数即可。
模版参数模版
模版嵌套用来模版化类模版的方法参数,特化用来重载模版的某一个特例类型的实现或者重载一个类集合;
常用于声明一个模版,他的参数是一个模版类实例
基本语法如下,当使用了模版参数模版后,模版的模版参数在模版的定义内实例化,不需要外部实现。
用来实例化模版参数的类可以是任意确定类或者模版声明的其他类参数。
模版参数模版的意义在于,在模版定义时即确定了其参数模版的参数,不需要在调用时由被调用者确定,应区别下面三种模版的声明:
//通过模版参数模版,使得模版的参数模版可以使用任意类,但该类在原模版的定义中实例化确定。
template <typename T, template<typename E> class container>
class temptemp{
//模版参数在这里实例化
};
//调用: temptemp<int ,vector>
//模版参数模版使用确定类,该类需要用户自己声明,但只能声明确定类,一旦声明其他类,编译器会报错
template <typename T, typename container<T>>
class A;
//调用: temptemp<int ,vector<int>>
//调用: temptemp<int ,vector<double>>是编译错误的
template <typename T, typename container<E>>
class A;
//调用: temptemp<int ,vector<int>>是编译错误的
//调用: temptemp<int ,vector<double>>
//上述两个可实现模版重载