一、模板的概念
模板概念:
- 模板实现了通用类型的代码,不需要关心数据的类型,因此 C++标准模板库STL产生。模板可以分为:类模板和函数模板,其类型推导和具体代码生成都是在编译阶段。
- 没有实例化的模板:编译器只是对模板进行简单的语法检测,并不会生成代码
- 实例化之后:根据用户对模板实例化的类型来生成代码,并且对生成的代码进行语法检测
模板类型的参数:
- 类型模板参数:类型不确定的,实例化后才生成对应代码
- 非类型模板参数:类型已经具体化
- 如果有缺省或者传参时,必须是常数,因为要在编译阶段确定大小
- 浮点数、类对象以及字符串不允许作为非类型模板参数
template <class T, size_t N = 5> // 非类型模板参数缺省时,必须是常数
class arr
{
public:
arr()
:_size(0)
{
}
T& operator[](const int index){
return _arr[index];}
void insert(const T& data){
_arr[_size++] = data;}
private:
T _arr[N];
size_t _size;
};
int main()
{
arr<int, 10> a; // 非类型模板参数传参时必须是常数,否则报错
return 0;
}
模板的编译链接过程:
- 有以下加法模板函数:函数声明:a.h头文件中,函数定义:a.cpp中
a.h头文件:加法模板的声明
#pragma once
template <class T>
T Add(const T& left, const T& right);
a.cpp源文件:加法模板的定义
#include "a.h"
template <class T>
T Add(const T& left, const T& right)
{
return left + right;
}
main.cpp
#include "a.h"
int main()
{
int sum = Add(1, 2);
return 0;
}
注意:这段代码在链接过程中会发生错误,找不到 int 类型的模板函数地址!
- 原因:模板的分离编译,没有生成对应类型的代码,造成链接时找不到函数地址入口
- 编译:对程序进行语法正误检测,检查无误后生成汇编代码。注意:头文件不参加编译,并且编译器对一个工程中的多个源文件是分离编译的。
- 链接:将对个 .obj 目标文件合并成一个,并处理未解决符号表中的地址问题,到其他源文件的导出符号表中寻找对应函数地址。
- 分离编译:同一项目有多个源文件共同实现,而每个源文件都是单独生成目标文件,最后才将所有文件链接起来形成单一的可执行文件。
- a.cpp源文件在编译时,编译器没有看到对 Add 模板函数的实例化,因此不会生成具体的 int 类型代码
- main.obj 目标文件在连接时,去其他目标文件找 Add< int >的函数地址,没有找到因此报连接错误。
解决:
- 在模板定义处显示实例化,不推荐
- 将模板声明和定义放到同一 .hpp 头文件中
1.在模板定义处显示实例化
#include "a.h"
template <class T>
T Add(const T& left, const T& right)
{
return left + right;
}
void Test()