泛型编程:代码复用的一种手段,通过模板来实现泛型编程,实现无类型代码实例化有类型代码。
模板分为: 函数模板、类模板
函数模板 :代表一个函数,该函数与类型无关,在使用时参数化,根据参数的类型来实例化函数的类型。
函数模板实例化:编译器用模板产生指定的类或者函数的特定类型版本,这个过程叫做函数模板的实例化。
#include <iostream>
#include <typeinfo>
using namespace std;
template <class T>
T Add(T a , T b)
{
return a + b ;
}
int main()
{
cout<<Add(1,2)<<endl;
//相当于实例化为
//int Add(int a, int b)
//{return a+b;}
cout<<Add(1.2 , 2.3)<<endl;
//相当于实例化为
//double Add(double a, double b)
//{return a+b;}
cout<<Add(1,(int)'2')<<endl;
//在实例化的时候,将'2',强制类型转换成 int
//相当于实例化为
//int Add(int a, int b)
//{return a+b;}
cout<<Add<int>(1.2,2.3)<<endl;
//在实例化的时候,将浮点型转化为整形
//相当于实例化为
//int Add(int a, int b)
//{return a+b;}
system("pause");
return 0;
}
5.在实例化的时候,编译器将模板编译了两次:
实例化之前,检查模板本身的代码有没有问题;
在实例化的期间,查看是否所有的调用都没有错误。
6.实参的推演:在将参数传到模板的参数列表的时候,模板会根据参数的类型来推演出模板所要实例化出来的函数、类的类型。
template <class T>
T Add(T a , T b)
{
return a + b ;
}
//正常的情况
template <class T1,class T2>
T Add(T1 a , T2 b)
{
return a + b ;
}
//有多种类型的时候,会有两个不同的模板参数
template <class T, P>
T Add(T a , P b)
{
return a + b ;
}
//要在P的前面加上class,否则会有错误
7.模板函数的特化:有时候并不总是能够写出对所有可能被实例化的类型都最合适的模板,在某些情况下,通用模板定义对于某个类型可能是完全错误的,或者不能编译,或者做一些错误的事情。
分为全特化,偏特化
全特化:
template <typename T>
class SeqList
{
public:
SeqList();
~SeqList();
private:
int _size;
int _capacity;
T* _data;
};
template<typename T>
SeqList <T>::SeqList()
: _size(0)
, _capacity(10)
, _data(new T[_capacity])
{
cout << "SeqList<T>" << endl;
}
template<typename T>
SeqList <T>::~SeqList()
{
delete[] _data;
}
template <>
class SeqList <int>
{
public:
SeqList(int capacity);
~SeqList();
private:
int _size;
int _capacity;
int* _data;
};
// 特化后定义成员函数不再需要模板形参
SeqList <int>::SeqList(int capacity)
: _size(0)
, _capacity(capacity)
, _data(new int[_capacity])
{
cout << "SeqList<int>" << endl;
}
// 特化后定义成员函数不再需要模板形参
SeqList <int>::~SeqList()
{
delete[] _data;
}
void test1()
{
SeqList<double > sl2;
SeqList<int > sl1(2);
}
偏特化:
template <typename T1, typename T2>
class Data
{
public:
Data();
private:
T1 _d1;
T2 _d2;
};
template <typename T1, typename T2>
Data<T1, T2>::Data()
{
cout << "Data<T1, T2>" << endl;
}
// 局部特化第二个参数
template <typename T1>
class Data <T1, int>
{
public:
Data();
private:
T1 _d1;
int _d2;
};
template <typename T1>
Data<T1, int>::Data()
{
cout << "Data<T1, int>" << endl;
}
全特化是将所有的参数进行特化,而偏特化是将部分的参数进行特化。模板的全特化和偏特化是在已定义的模板基础上存在的,不能单独的存在。
8.模板函数的重载:
1、一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。
2、对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调动非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数,那么将选择模板。
3、显式指定一个空的模板实参列表,该语法告诉编译器只有模板才能来匹配这个调用,而且所有的模板参数都应该根据实参演绎出来。
4、模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。
int Max(const int& left, const int & right)
{
return left>right? left:right;
}
template<typename T>
T Max(const T& left, const T& right)
{
return left>right? left:right;
}
template<typename T>
T Max(const T& a, const T& b, const T& c)
{
return Max(Max(a, b), c);
};