首先定义模板类型:
#include
template
T Sum(T a,T b)
{
std::cout<< typeid(T).name()<(10,20)<< std::endl;
std::cout<< Sum(20,30)<
上面的代码是对两个数求和,其中<>是模板类型参数列表,其中在定义模板类型参数时 typename和class作用相同
那么在其编译阶段是怎么编译的?
1.在定义点,只编译模板头部 2.在调用点,模板函数
什么是模板函数函数?
在调用点的时候,编译器先把函数模板转换为模板函数
#include
/* 模板函数
int Sum(int a,int b)
{
return a+b;
}
double Sum(double a,double b)
{
return a+b;
}
char Sum(char a,char b)
{
return a+b;
}
*/
template
T Sum(T a,T b)
{
std::cout<< typeid(T).name()<(10,20)<< std::endl;
std::cout<< Sum(20,30)<
4.模板的实参推演
注意事项
1.不能产生二义性
2.有实参
#include
template
T Sum(T a,T b)
{
std::cout<< typeid(T).name()<
T* Func()
{
T* ptmp = new T();
return ptmp;
}
int main()
{
std::cout << Sum(10,20)<< std::endl;//给出类型
std::cout<< Sum(20,30)<();//没有参数,但是给定了类型
//Func();错误,没有给定类型,并且没有给实参,不能推理出类型
return 0;
}
其错误是:
5.模板特例化:模板不能满足特殊类型的需要时,要是独立实现
调用优先级:特例化的调用优先级 > 模板实例化版本(特例化应该符合模板的实例化逻辑)
例如:两个数比较,我们可以用 '>','<', '=='比较大小,但是当我们遇到字符串比较大小的时候,我们就不能这样比较了。于是我们可以把字符串比较大小独立写出来,使其特例化:
#include
#include
#include
#include
using namespace std;
template
bool compare( T v1, T v2)
{
bool Result = false;
if(v1>v2)
{
Result = true;
}
printf("普通类型比较\n");
return false;
}
template <>
bool compare( char* v1, char* v2)
{
bool Result = false;
if( strcmp(v1,v2)==0)
{
Result = true;
}
printf("字符串比较\n");
return Result;
}
int main()
{
compare(20,30);
char *p1="hello";
char *p2="world";
compare<>(p1,p2);
}
运行结果为:
6.模板的非类型参数:
非类型模板参数是有类型限制的。一般而言,它可以是常整数(包括enum枚举类型)或者指向外部链接对象的指针。
浮点数和类对象(class-type)不允许作为非类型模板参数:
template // ERROR: 浮点数不可作为非类型模板参数
double process(double v)
{
return v * VAL;
}
运行结果为:
但是,我们可以稍微修改一下,就可以使用了:
#include
#include
#include
#include
using namespace std;
template
double process(const double& x)
{
return x * (*PVAL);
}
double a = 1.0;
double b=2.0;
template
int add(int p)
{
return T * p;
}
int main()
{
cout<< add<10>(20)<(a)<
运行结果为:
7,模板的重载:
1、重载:函数名相同,但函数的定义不同。编译系统会根据实参的类型和个数选择匹配度最高的函数进行调用。
重载的过程规律(执行顺序如下):
(1)首先会查找普通函数,寻找和使用函数名和参数类型最匹配的函数,如果找到则调用;
(2)若普通函数没有,则在函数模板中查找,将模板实例化,若和调用的函数匹配,则调用该函数模板;
(3)若经过上述两步还是未能找到,则可以通过类型转换转换进行参数匹配的函数重载,如果转换后能匹配则调用。
上述就是重载函数的过程,如果到最后一步还未能找到匹配的函数,则会产生调用错误;若有多个可以匹配则会产生二义性。
2、函数模板重载的分类:
(1)函数模板可以和函数模板进行重载;
(2)函数模板可以和显示特化后的模板进行重载;
(3)函数模板和普通函数的重载。
注意:在模板重载的时候,调运优先级为:
普通函数版本 > 模板特例化版本 > 普通模板版本(精确匹配)
#include
#include
#include
#include
using namespace std;
template
void func(T t)//普通模板
{
cout<< "In generic version template "<
void func(T* t)//指针特例化
{
cout << "In pointer version template "<< *t << endl;
}
void func(string* s)//普通函数
{
cout << "In normal function " << *s << endl;
}
int main()
{
int i=10;
func(i);//调用普通模板函数,推演
func(i);//调用普通模板函数,
func(&i);//调用指针特例化,推演
func(&i);//调用指针特例化
string a ="a";
func(&a);//调用普通函数
func(a);//调用普通模板函数
func(&a);//规定是模板,所以调用指针特例化,没有调用普通函数
return 0;
}
运行结果为:
C++中,类模板的写法如下:
template <类型参数表>
class 类模板名{
成员函数和成员变量
};
类型参数表的写法如下:
class类塑参数1, class类型参数2, ...
类模板中的成员函数放到类模板定义外面写时的语法如下:
template <类型参数表>
返回值类型 类模板名<类型参数名列表>::成员函数名(参数表)
{
...
}
用类模板定义对象的写法如下:
类模板名<真实类型参数表> 对象名(构造函数实际参数表);
如果类模板有无参构造函数,那么也可以使用如下写法:
类模板名 <真实类型参数表> 对象名;
类模板看上去很像一个类。下面以 Pair 类模板为例来说明类模板的写法和用法。
#include
#include
#include
#include
using namespace std;
template
class Pair{
public:
T1 key;
T2 value;
Pair(T1 k,T2 v):key(k),value(v){};
bool operator<(const Pair&rhs);
};
template
bool Pair::operator<(const Pair&rhs)
{
return value < rhs.value ;
}
int main()
{
Pairstudent("Tom",20);
Pairstudent1("Jarry",30);
if(student < student1)
{
cout<<"hello"<
运行结果为:
在类模板中,调运的优先级为:普通方法 > 特例化方法 > 模板版本
类模板
1.构造 析构函数不建议加模板类型参数
2.其他建议加上模板类型
1.类模板 选择性实例化
一定要在使用时指明实例化的类型
typename
1.定义模板类型参数
2.声明类型
1.拷贝构造函数的模板 ==》 构造函数
#include
#include
#include
#include
using namespace std;
template
class CLink
{
public:
CLink()
{
std::cout << "template class CLink" << std::endl;
phead = new Node();
}
CLink(const CLink& rhs)
{
std::cout << "CLink(const CLink& rhs)" << std::endl;
phead = new Node();
Node* ptail = phead;
Node* pCur = rhs.phead->pnext;
while (pCur != NULL)
{
Node* pnewnode = new Node(pCur->mdata);
ptail->pnext = pnewnode;
pCur = pCur->pnext;
ptail = ptail->pnext;
}
}
template
CLink(const CLink& rhs)// 退化成构造函数
{
std::cout << "template CLink(const CLink& rhs)" << std::endl;
phead = new Node();
Node* ptail = phead;
CLink::Node* pCur = rhs.phead->pnext;
while (pCur != NULL)
{
Node* pnewnode = new Node(pCur->mdata);
ptail->pnext = pnewnode;
pCur = pCur->pnext;
ptail = ptail->pnext;
}
}
~CLink()
{
Node* pCur = phead;
Node* pNext = pCur;
while (pCur != NULL)
{
pNext = pCur->pnext;
delete pCur;
pCur = pNext;
}
phead = NULL;
}
bool InsertTail(T val)
{
Node* pnewnode = new Node(val);
Node* ptail = phead;
while (ptail->pnext != NULL)
{
ptail = ptail->pnext;
}
ptail->pnext = pnewnode;
return true;
}
void Show()
{
Node* pCur = phead->pnext;
while (pCur != NULL)
{
std::cout << pCur->mdata << " ";
pCur = pCur->pnext;
}
std::cout << std::endl;
}
class Node;
Node* Find(T val)//普通方法
{
std::cout << "Node* CLink::Find(T)" << std::endl;
Node* pCur = phead->pnext;
Node* prt = NULL;
while (pCur != NULL)
{
if (pCur->mdata == val)
{
prt = pCur;
break;
}
pCur = pCur->pnext;
}
return prt;
}
template
Node* Find(E val) //模板版本
{
std::cout << "template Node* CLink::Find(E)" << std::endl;
Node* pCur = phead->pnext;
Node* prt = NULL;
while (pCur != NULL)
{
if (pCur->mdata == val)
{
prt = pCur;
break;
}
pCur = pCur->pnext;
}
return prt;
}
template<>
Node* Find(char* val) //特例化的版本
{
std::cout << "template<> Node* CLink::Find(char*)" << std::endl;
Node* pCur = phead->pnext;
Node* prt = NULL;
while (pCur != NULL)
{
if (strcmp(pCur->mdata,val) == 0)
{
prt = pCur;
break;
}
pCur = pCur->pnext;
}
return prt;
}
private:
class Node
{
public:
Node(T val = T()) :mdata(val), pnext(NULL){}
public:
T mdata;
Node* pnext;
};
template
friend class CLink;
Node* phead;
};
int main()
{
CLink ilink;//无参构造,我们调运函数的无参构造
CLink dlink(ilink);//拷贝构造函数,函数的拷贝构造只能拷贝构造相同数据类型的,不匹配,所以调用模板的拷贝构造
CLink ilink1(ilink);//拷贝构造,因为类型都是int类型,所以调用函数的拷贝构造
for(int i=0;i<5;i++)
{
ilink.InsertTail(i+1);
}
ilink.Show();
ilink.Find(5);//调运Find函数的普通函数
ilink.Find(5);//参数不符合特例化版本,所以调用模板;
return 0;
}
运行结果为:
对整个类的特例化:
#include
#include
#include
#include
using namespace std;
template
class Test
{
public:
Test(T1 a, T2 b) :ma(a), mb(b)
{
std::cout << "template class Test" << std::endl;
}
private:
T1 ma;
T2 mb;
};
template
class Test
{
public:
Test(T1 a, int b) :ma(a), mb(b)
{
std::cout << "template class Test" << std::endl;
}
private:
T1 ma;
int mb;
};
int main()
{
Test test1(10, 20.1);//调运普通模板
Test test2(10.1, 20);//调用特例化模板
Test test3(10, 20);//调运特例化模板
return 0;
}
运行结果为: