1)模板的编译过程:
先扫描模板名——–再依次遍历成员名,成员方法声明,成员变量,嵌套类
2)类:抽象一个实体 模板:抽象一个类型
3)模板的关键字:template
template<typename T,typename E>//模板参数列表
4)编译阶段模板不参与编译,因为模板中的类型不确定,无法生成符号。
5)调用模板:
模板名 <T , E > (10,20)
模板在被调用的时候,会实例化模板,从而产生相应的模板函数或模板类
6)函数模板实例化分两种:显式实例化和隐式实例化
隐式实例化: compare (10,20) // compare为模板名
//产生符号 bool compare (int ,int )
显式实例化: template bool compare (int a ,int b )
隐式和显示实例化都产生符号
7)当函数模板定义在另一个源文件中时,可以在编译之前给需要调用该模板的函数之前加上一个显式实例化的声明:
template bool compare (int ,int )
由于原模版代码不产生符号,可以将其放入头文件中或调用之前可以看到的地方 。
8)模板的实参推演(类模板没有,函数模板有实参推演):
9)模板的特例化(特殊化/专用化): 模板实例特殊化
也就是自己实现一个可供调用的模板函数
格式:
template <>
bool compare<int>(int a,int b)
{
Return a>b ? true :false;
}
模板的特例化主要是因为有的范型不适合于个别类型时,我们需要自己进行模板实例化
在对函数模板实例化,特殊实例化,非模板函数这三种进行调用时,调用的顺序: 非模板函数——-特例化—–模板实例化—非模板函数的重载(隐式转化) , 模板函数没有隐式转化
10)特例化又分为:完全特例化和部分特例化
部分特例化只能适用于类模板,函数模板不可以 。
在匹配特例化版本时,当类型作为函数名/函数符号的一部分时,如果两者产生的符号不一致,则不能匹配;
11)在模板的实例化时:类型是进行了类型重定义而不是宏替换
#define T char * //宏定义,预处理替换
Const T a -》 const char* a
Typedef char* T //类型重定义
const T a -》 char* const a
12)还有就是一般字符串常量存储在.rodata段中,该段为只读段
.data是可读可写
Char *p=”hello”, *p=’a’; // 编译阶段可以但运行会出错
13)模板非类型参数:
用函数模板写一个冒泡排序:
14)在模板中,除了构造和析构函数名后可以省略< T>,只写模板函数名
其他的最好都不省略< T >
虽然在模板定义范围之类可以省略类型列表,模板的作用范围是在定义之后直到第一个大括号/分号结束,如果一个模板中出现同种类型的模板,内层范围小的会覆盖范围大的同名类型模板
15)
自定义类型(); // 默认构造
内置类型(); //零初始化 或 伪构造
16)模板友元类:
a)类的前项声明
b)友元的关系一对多,一对一
c)模板中的嵌套类
17)因为在编译阶段模板不产生符号,所以在进行嵌套类的构造时,需要指定返回值的类型属于哪一个作用域时,我们可以在其前面加typename来告诉编译器自己身后的是一个类型,eg:
由于模板只有在被调用时,才知道是何种类型,因此方法的实现只有被调用时才编译。这点我们要注意。