template
T func(T a,T b)
{
return a+b;
}
函数模板的调用与普通函数没有区别,因为他是根据实参推断类型,不需要我们显式指定;
Templa的尖括号中不仅可以给类型参数,还可以给非类型参数,如:
template
int func(){
return a+b;
}
调用的时候:
func<12,13>();//要注意这里<>里边必须是常量或常量表达式,以确保在编译阶段就能确定版本;
template
int func(T c){
return (int)c+ a+b;
}
func
template
class ClassName{
...
}
由于实例化一个具体类的时候需要类模板的所有信息,因此类模板的声明,定义,实现等都要放在.h文件里完成,不像一般的类实现在cpp中;其他要使用这个类模板的直接#include即可;
直接写在类模板的定义的时候,成为隐式inline;当然也可以声明与定义分开来写,但是都要在.h文件中;
与一般成员函数的区别在于,类模板的成员函数具有模板参数:
先声明后定义的写法:
声明:
public:
void myfunc();
定义:
template
void myvector
总结:这里要将“类模板名<类型>”当做普通类名来使用就对了;
类即使被实例化,但是它的成员函数也只有在调用的时候才会进行实例化;
在类模板内部使用类模板名,是否紧跟<参数模板>是等同的,也就是说在内部使用可以直接使用不带参数模板的类模板名;
但是在类外使用,一定是带<>才能等同,相当于普通类的使用方法;
与函数模板类似,也有非类型的模板参数,使用的时候注意尖括号里边的内容:
定义:
template
class myarray{
T arr[size];
}
使用:myarray
myarray
要注意此时实例化的类名要包含<>,因此类外实现成员函数的写法:
template
void myarray
注意:


类模板
就是普通类的成员函数定义为函数模板:

所谓特化是泛化的对立面,泛化讲究不固定于特定类型,但是有的时候针对有的类型不能对模板实例化(编译出错),此时就要提供一个对特定类型的特化版本,这就叫做特化;
特化是相对于泛化的,得先有泛化版本才能有对应的特化版本作为补充;因此放置位置一般泛化特化都在一个.h中,且特化放在泛化后边一点;
泛化版本:
template
struct TC{
...
};
特化版本:
template <>
struct TC
...
};
特化版本执行的优先级高于泛化版本,也就是说如果能找到完全匹配的特化版本是不会调用泛化版本成员与函数的;
template<>
void TC
要注意全特化就是带上template<>,然后在合适的位置显式指定类型;
这是一个与全特化对立的概念,意思就是局部特化,不全,一半显式指定(特化),一半依赖泛化;
数量上的偏特化:

1.没有特化的部分保留在template中;
2.要保留特化与泛化的顺序;
参数范围上的偏特化
参数范围:int与const int,T与T*,这样的类型范围实际是变化了,这就是参数范围的概念;

template
void func(T& t,U& u)
{
...
}
template <>
void func(double& t,int& u)
{
...
}
与类相似,保留template<>但是空置参数列表,在后续指定特化;
函数还涉及一个重载的问题,比如还定义了一个普通函数func(double& t,int& u);那么要注意优先顺序:重载普通函数>特化函数>泛化函数
不好意思,函数模板不能偏特化(真是太好了……)

使用using可以简化长模板名取别名的问题;


从左到右依次指定或者推断,从左到右如果省略了一个参数的指定,那后边也要都省略,类似于指定默认值从左到右都要(坑真多)!