模板(Template)
1. 类模板(class template)
设计类时,将一些类型抽出来,允许使用者任意指定
- 基本示例
template<typename T>
class complex
{
public:
complex (T r=0,T i=0)
:re(r),im(i){}
complex& operator +=(const complex&);
T real()const{return re;}
T imag()const{return im;}
private:
T re,im;
friend complex& _doapl(complex*,const complex&);
};
int main()
{
complex<double> d1(2.5,1.5);
complex<int> c2(2,6);
}
2. 函数模板(function template)
设计函数时,抽出变量类型,允许使用者任意指定
- 基本示例
template<typename T> //T只为一个符号,自己取名,避免与关键字冲突
inline const T& min(const T& a,const T& b)
{
return b<a?b:a;
}
class stone
{
public:
stone(int w,int h,int we):_w(w),_h(h),_weight(we){}
bool operator< (const stone& rhs)const{return _weight<rhs._weight;}
private:
int _w,_h,_weight;
};
stone r1(2,3),r2(3,3),r3;
r3 = min(r1,r2); //在min()中编译器推导T为stone,于是调用stone::operator<
- 编译器会对函数模板进行实参推导(
argument deduction
)
3. 成员模板(member template)
- 具体示例:下述代码中
template <class U1,class U2>
为成员模板
template <class T1,class T2>
struct pair{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair():first(T1()),second(T2()){}
pair(const T1& a,const T2& b):first(a),second(b){}
template <class U1,class U2>
pair(const pair<U1,U2>&p):first(p.first),second(p.second){}
};
- 应用上述代码如下
class Base1{ };
class Derived1:public Base1{ };
class Base2{ };
class Derived2:public Base2{ };
pair<Derived1,Derived2> p;
pair<Base1,Base2> p2(p);
//上面两行代码合为以下:
pair<Base1,Base2> p2(pair<Derived1,Derived2>()); //这里Base1,Base2为T1,T2,Derived1,Derived2为U1,U2
4. 模板特化(specialization)
// 泛化
template <class Key> 位置1
struct hash{};
// 特化
template<> //仍及保留template,但是<>里面不加入东西
struct hash<char>{ //位置2
size_t operator () (char x) const { return x; }
};
template<> //位置3
struct hash<int>{
size_t operator () (int x) const { return x; }
};
template<> //位置4
struct hash<long>{
size_t operator () (long x) const { return x; }
};
//测试
cout << hash<long>()(1000); //hash<long>()获得一个临时变量,且调用的是位置4处,后面的(1000)则调用覆写的()方法
5. 模板偏特化(partial specialization)
- 个数的偏特化:参数必须从左到右顺序特化,而不能跳跃;
//泛化
template<typename T,typename Alloc=...> //两个模板参数
class vector
{
...
};
//个数上的偏特化
template<typename Alloc=...>
class vector<bool,Alloc>
{
...
};
- 范围的偏特化:设计接收任意类型的
T
,将范围缩小为指针指向任意类型;
template <typename T>
class C //如果使用者使用的不是指针就用这套代码
{
...
};
//范围上的偏特化
template <typename T> //此处的T也可换成另外一个符号,如U,此处的T与上面的T无关
class C<T*> //如果使用者使用的指针就用这套代码
{
...
};
C<string> obj1;
C<string*> obj2;
6. 模板模板参数 (template template parameter)
- 具体示例
template< typename T,
template<typename T>
class Container
>
class XCls
{
private:
Container<T> c;
public:
...
};
//测试
template<typename T>
using Lst = list<T,allocator<T>>;
XCls<string,list> mylst1; //语法错误,此处代码将Container<T> c转为list<string> c,未指定第二个模板模板参数
XCls<string,Lst> mylst2;
- 非模板模板参数
template <class T,
class Sequence = deque<t> //这不是模板模板参数
>
class stack{
friend bool operator== <>(const stack&,const stack&);
friend bool operator< <>(const stack&,const stack&);
protected:
Sequence c; //底层容器
};
//测试
stack<int> s1; //由于第二个模板参数有默认指定,可以只指定第一个模板参数
stack<int,list<int>> s2; //此处的list<int>已经写死,不是模板了