一,什么模板
模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。
使用模板的目的就是能够让程序员编写与类型无关的代码。
二,模板分类
模板分为模板函数和模板类
(1)模板函数
格式:
template <class 形参名1,class 形参名2 ...>
返回类型 函数名(参数列表)
{
}
栗子:
template <class T>
bool IsEqual(const T& left, const T& right)
{
return left == right;
}
void test()
{
string s1("s1");
string s2("s2");
cout << IsEqual(s1, s2) << endl;//参数类型为string
cout << IsEqual(1, 1) << endl;//参数类型为int
}
注意:编译调用模板函数时,编译器会根据传入的参数自动推演出模板形参的类型,并生成对应的代码。比如IsEqual(s1,s2)其中s1和s2是string型,这时模板函数swap中的形参T就会被string所代替,模板函数就变为swap(const string & left, const string & right)。而当IsEqual(1,1)其中1和1是int类型时,模板函数会被替换为IsEqual(const int& left, const int& right)。
注意:模板函数在编译时,不检查函数内部的语法。
模板参数匹配及显式实例化
template <class T>
bool IsEqual(const T& left, const T& right)
{
return left == right;
}
void test()
{
cout << IsEqual(1, 1) << endl;
//cout << IsEqual(1, 1.2) << endl; //参数不匹配
cout << IsEqual<int>(1, 1.2) << endl; //显式实例化
cout << IsEqual<double>(1, 1.2) << endl;//显式实例化
}
上述代码中IsEqual(1,1.2),其中1是int型,1.2是double型,在推演时,导致模板参数’T’不明确,所以运行出错。
,
要解决上面的问题除了显式实例化,还可以重载函数模板。
template <class T>
bool IsEqual(const T& left, const T& right)
{
return left == right;
}
template <class T1,class T2>
bool IsEqual(const T1&left,const T2& right)
{
return left == right;
}
void test()
{
cout << IsEqual(1, 1) << endl;
cout << IsEqual(1, 1.2) << endl; //参数不匹配
}
(2) 模板类
格式:
template <class T1,class T2 ....>
class 类名
{
}
栗子:
template<class T>
class Vector
{
private:
T* _first;
T* _finish;
T* _endofstorage;
};
非类型的函数模板参数
template <class T, int value>
T Add (const T& x )
{
return x + value;
}
这里的value就是非类型的模板参数
非类型的类模板参数
// 静态顺序表
//template<typename T, size_t MAX_SIZE>
template <typename T, size_t MAX_SIZE = 10> //带缺省模板参数
class Vector
{
public :
Vector();
private :
T _array [MAX_SIZE];
int _size ;
};
template <typename T, size_t MAX_SIZE>
Vector <T, MAX_SIZE>::Vectoer ()
: _size(0)
{}
void Test ()
{
Vector<int > s1;
Vector<int , 20> s2;
}
注意:浮点型不能作为非类型的类模板参数
三,类模板特化
(1)全特化
//原模板
template <class T>
class Vector
{
Vector()
:_data(new T[10])
{
cout << "T" << endl;
}
~Vector()
{
delete[] _data;
}
private:
T* _data;
};
//特化后
template <>
class Vector<int>
{
Vector()
:_data(new int [10])
{
cout << "int" << endl;
}
~Vector()
{
delete[] _data;
}
private:
int* _data;
};
全特化就是将模板中的某种类型单独提取出来实现,比如说,上面将int类型单独实现。
例如实现一个Equal方法,用来比较两个参数是否相等;,在实际开发中,对于float类型或者double的参数,绝对不能直接使用“==”符号进行判断。所以,对于float或者double类型,我们需要进行特殊处理。
(2)偏特化
template <typename T1, typename T2>
class Data
{
public :
Data()
{
cout << "Data<T1, T2>" << endl;
}
private:
T1 _d1;
T2 _d2;
};
//局部特化第二个参数
template <typename T1>
class Data <T1, int>
{
public :
Data()
{
cout << "Data<T1, int>" << endl;
}
private:
T1 _d1;
int _d2;
};
// 局部特化两个参数为指针类型
template <class T1,class T2>
class Data <T1*, T2*>
{
public :
Data()
{
cout << "Data<T1, int>" << endl;
}
private:
T1* _d1;
T2* _d2;
};
注意:模板的全特化和偏特化都是在已定义的模板基础之上,不能单独存在。
模板的分离编译
模板最好将声明和定义放到一个文件 “xxx.h” 里面,因为,编译器编译时,将不同的文件编译生成不同的文件,而模板在编译时不进行类型检查,在运行时推演,这样会导致在链接过程中会链接不上。