Template【C++】
简介
Template是C++中的模版,一般称为模版。
模版将通用逻辑和不同数据类型的个性化逻辑进行分离,模版将通用的逻辑进行沉淀,称为模版方法。
模版方法的定义一般如 template<parameter-list> function-declaration。
C++是强类型的语言,在不知道 parameter-list 具体类型的情况下,无法确定函数需要占用的栈大小,同时也不知道函数体中具体数据类型的各种操作如何实现,所以函数模版其实不是真正的函数,只有当参数类型具像化之后才会生成具体函数,该过程叫做函数模板的实例化。
原理
模版编译
模版技术本质上是一个编译时技术,编译器将模版方法编译为继承模版类的方法。
在调用模版函数时,编译器推断出此时参数列表的真实类型,然后编译器会生成实际参数版本的函数被调用。所以相较普通函数,函数模板多了生成具体函数这一步。如果我们只是编写了函数模板,但不在任何地方使用它(也不显式实例化),则编译器不会为该函数模板生成任何代码。
函数模板实例化分为隐式实例化和显式实例化。
模版编译不支持分离编译(h文件和cpp文件分别定义模版以及实现模版)。
// swap.h
template<class T>
int Swap(T &a, T &b); // 函数声明
// swap.cpp
template<class T>
void swap(T &a, T &b)
{
T temp = a;
a = b;
b = temp;
}
// main.cpp
#include"swap.h"
int main()
{
Swap(1, 2); // 调用 Swap<int, int>
Add(1.0, 2.0); // 调用 Swap<double, double>
return 0;
}
例如有上述三个文件,swap.h,swap.cpp,以及main.cpp,在编译的时候会出现错误。
因为 main,cpp 中使用了 Swap<int, int>以及Swap<double, double>两个模版函数,所以编译器会去查找两个函数的定义,但是swap.cpp编译出来的 swap.o 文件中因为没有使用到 Swap<int, int> 等两个函数,C++ 标准明确表示,当模板没有被使用的时侯就不该被实例化,所以在 swap.cpp 编译生成的目标代码中未找到这两个函数的定义。
修改方案有两种,一种是在 swap.cpp 中声明 Swap<int, int>等两个具体化参数之后的模版函数,这样swap.cpp生成的目标文件中就会包含实例化之后的模版方法。
另一种是将swap.cpp的内容放在swap.h的文件中,这样编译main.cpp中就可以通过swap.h找到这个函数的定义。