(一)函数模板
(1)模板编译过程(在编译期间):
- 在定义点只编译模板头部
- 在调用点编译模板函数
template(关键字)<模板参数列表>
template:定义模板类型参数,指明模板中的类型
template<typename T>
T Sum(T a , T b)
{
couture<<typeid(T).name<<endl;
return a+b;
}
int main()
{
Sum<int>(10,20)//使用方法
return 0;
}
(2)模板的实例化
模板实参传递给模板形参,int替换T。替换过程就叫模板实例化,在编译期间完成typedef替换。
int Sum(int a , int b)
{
couture<<typeid(int).name<<endl;
return a+b;
}
(3)模板函数
模板实例化生成的函数就是模板函数
(4)模板实参推演
通过参数的类型推演出模板的参数类型,两个参数类型相同都为int。模板实例化生成int版本的模板函数。
注意事项:当这样调用时Sum(10,20.1)编译器报错类型不明确。所以1、不能让编译器产生二义性2、要有实参。
(5)模板特例化
模板不能满足特殊类型的需求,例如:
template <typename T>
bool Compare(T a, T b)
{
return a > b;
}
int main()
{
Compare<char*>("hello", "world");
}
//生成的模板函数
bool Compare(char* a, char* b)//比较的是地址的值并不是比较的是值
{
return a > b;
}
需要实现特例化的版本:
template<>
bool Compare<char*>(char* a,char* b)
{
return strcmp(a,b) > 0;
}
- 完全特例化:函数模板 char* 类模板char*
- 部分特例化:类模板T*
部分函数特例化:较小函数不满足,对函数实现特例化;
较多函数不满足,对所有函数实现特例化
(6)模板的类型参数
<>能存放模板类型参数
#include<iostream>
using namespace std;
template <typename T>
void Sort(T *arr, int len)
{
for(int i = 0; i < len - 1; i++)
{
for (int j = 0; j < len - i - 1; j++)
{
if (arr[j] > arr[j+ 1])
{
T temp;
temp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = temp;
}
}
}
}
template < typename Type >
void Show(Type *arr, int len)
{
for (int i = 0; i < len; i++)
cout << arr[i] << " ";
}
int main()
{
int arr[10] = {36,53,28,95,25,4,56,34,5,67};
int len = sizeof(arr) / sizeof(arr[0]);
Sort<int>(arr, len);
Show<int>(arr, len);
}
(7)模板的非类型参数
- 模板的非类型参数是一个常量
- 不能用float,double等类型
#include<iostream>
using namespace std;
template <typename T,int LEN>
void Sort(T *arr)
{
for (int i = 0; i < LEN - 1; i++)
{
for (int j = 0; j < LEN - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
T temp;
temp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = temp;
}
}
}
}
template < typename Type>
void Show(Type *arr,int len)
{
for (int i = 0; i < len; i++)
cout << arr[i] << " ";
}
int main()
{
int arr[10] = { 36, 53, 28, 95, 25, 4, 56, 34, 5, 67 };
const int len = sizeof(arr) / sizeof(arr[0]);//非类型参数是常量,不能做左值,要用const修饰
Sort<int,len>(arr);
Show<int>(arr,len);
}
(8)模板默认值C++11
(9)接收模板的不明确类型的返回值用auto
(10)模板重载
调用的优先级:普通版本、模板特例化版本、模板实例化版本
(二)类模板
构造函数和析构函数可以缺省类型参数,其他地方不要缺省。
类模板实例化:选择实例化,调用的时候对要调用的成员方法进行实例化。
#include<iostream>
using namespace std;
template <typename T>
class Clink;//前置声明
template <typename _Vty>
class Node//类模板名
{
public:
//模板名<类型参数>==类名
Node<_Vty>(_Vty val = _Vty()) : value(val), pnext(NULL)//零构造,零初始化并不清楚T是什么类型,就申请T类型的大小初始化为0。
//char*类型的零初始化,要使用typedef char* *CHAR char* p = *CHAR()
{}
~Node<_Vty>()
{}
/*template<typename E>//友元,Clink是Node的朋友,多对多
friend class Clink;*/
friend class Clink<_vty>;//一对一的友元
private:
_Vty value;
Node<_Vty>* pnext;
};
template <typename T>
class Clink
{
public:
Clink()
{
phead = new Node<T>();
}
~Clink()
{
Node<T>* pCur = phead;
Node<T>* pNext = pCur;
while (pCur != NULL)
{
pNext = pCur->pnext;//不能访问私有成员
delete pCur;
pCur = pNext;
}
phead = NULL;
}
void Insert(T val);
void Delete(T val);
void Show()
{
Node<T>* pCur = phead->pnext;
for (pCur; pCur != NULL; pCur = pCur->pnext)
{
cout << pCur->value;
}
}
private:
Node<T>* phead;
Node<T>* Find(T val);
};
//类模板成员方法在类外的定义
template <typename T>
void Clink<T>::Insert(T val)
{
Node<T>*pnewnode = new Node<T>(val);
pnewnode->pnext = phead->pnext;
phead->pnext = pnewnode;
}
template <typename T>
Node<T>* Clink<T>::Find(T val)
{
Node<T>*pCur = phead->pnext;
while (pCur->pnext != NULL)
{
if (pCur->pnext->value == val)
{
return pCur;
}
pCur = pCur->pnext;
}
return NULL;
}
template <typename T>
void Clink<T>::Delete(T val)
{
Node<T>* pfront = Find(val);
if (pfront != NULL)
{
Node<T>*pCur = pfront->pnext;
pfront->pnext = pCur->pnext;
delete pCur;
}
}
int main()
{
Clink<int> link;//类模板使用时必须指定类型
link.Insert(10);
link.Show();
return 0;
}