1、概念
C++模版分两类:函数模版和类模版
1)函数模板的格式
template <class 形参名,class 形参名,......> 返回类型 函数名(参数列表)
{函数体
}
例如:
template <class T> void swap(T& a, T& b)
{T t = a;a = b;b = t;
}
2)类模版的格式
template<class 形参名,class 形参名,…> class 类名
{ ... };
例如:
template<class T> class A
{
public: T a; T b; T add(T &c, T &d);
};
注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。
C++模版概念参见博客:https://blog.csdn.net/qq_52905520/article/details/127455728
2、模版的编译
1)预处理
模版虽然和宏相似,但是模版是在编译阶段处理的,而不是在预处理阶段。
下面是执行预处理的结果:(g++ -E AddDouble.cpp -o AddDouble.i)
2)编译
模版在不同的源码中,被实例化为相同的类型时,会产生很多重复的代码。
例如在两个源码中使用了模版实例化为相同的类型(int),后编译为汇编代码时(g++ -S),产生的函数标志相同:_Z7addTempIiET_S0_S0_
3)链接
重复代码消除:模版在不同的源码中,被实例化为相同的类型时,会产生很多重复的代码,C++编译器在链接时,会消除重复的代码。
查看汇编代码,可以看到 模版函数被标记为 comdat
什么是comdat?
comdat(Common Data Area)是链接器用来处理重复代码和数据的一种机制,它允许链接器在生成最终的可执行文件或库时,合并(或“折叠”)相同的函数和数据定义,以减少最终程序的大小。
comdat 的工作原理:
- 编译时:当使用编译器编译C++代码时,编译器会识别出可以安全合并的代码和数据(如内联函数、模板实例化等),并将它们放置在带有comdat属性的段中。
- 链接时:链接器遍历所有输入对象文件(.obj),查找带有comdat属性的段。对于每个comdat段,链接器会检查是否已经有一个相同的段被包含在了最终的程序中。如果是,链接器会丢弃当前遇到的这个段,因为它已经被之前的某个段所代表。这样,相同的代码或数据只会在最终的程序中出现一次。