C++11 extern template
C++11 extern template
PS:不知道对应的中文术语叫啥(模板声明?)
模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。
模板是创建泛型类或函数的蓝图或公式。库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念。
使用模板可以少写很多冗余代码,但是同样会带来一些开销:
中间代码体积变大
编译时间增长
我们来看一个例子(这个例子涉及到 5 个文件,可能会比较繁琐)
h.h
h.h 中定义了一个模板函数my_swap
用于交换两个值。
a.cpp
b.cpp
a.cpp 和 b.cpp 中分别有两个函数 swap_one 和 swap_two,作用是一致的,都是交换两个整数,并且在内部都调用了my_swap
模板函数。
main.cpp
main.cpp 对 a.cpp 和 b.cpp 的两个函数进行调用。
对于这样一个工程,使用g
去编译生成汇编代码,看看发生了什么:
生成的 a.asm 和 b.asm 如下:
a.asm
b.asm 如下
从汇编代码中,可以看出,在 a.cpp 和 b.cpp 中,都有_Z7my_swapIiEvRT_S1_
这个符号,这个符号其实就是my_swap
被实例化后的符号,也就是说,两个编译单元中都对my_swap
函数进行了实例化,这不仅增加了中间目标文件的体积,更增加了编译时间。
而每个编译单元对相同模板函数的相同类型实例化,而实例化后的符号为弱符号(不清楚弱符号的童鞋自行百度),最后链接也只会留下一份。所以实际上只需要做一遍实例化就可以了。所以C++11
增加了extern template
,带有extern template
声明的模块在编译的时候回跳过指定模板的实例化,链接时会去其他模块寻找相关的实例化代码。
将 a.cpp 修改为以下代码:
重新编译 a.cpp 为汇编代码 a.asm:
可以看到 a.asm 中不再有 my_swap
的实例化代码。链接的时候会去其他模块寻找相应实现。
测试一下编译:
编译顺利通过。
从上面可以看出,extern template
减少了模板类型的实例化代码编译次数,也就意味着节省了时间与空间,鱼与熊掌兼得。
使用extern template
需要注意的地方:
必需确保
extern
的模板在其他编译单元中有实例化。例如,不能同时在 a.cpp 和 b.cpp 同时使用extern template
,否则会导致模板从未被实例化,会引起undefined reference
的问题。必需确保
extern
的类型与外部的类型一致,否则不起效果。比如 a.cpp 中的extern template
修改为:
这样在编译到my_swap(a,b)
的时候,同样会再实例化my_swap<int>
的版本。
版权声明: 本文为 InfoQ 作者【SkyFire】的原创文章。
原文链接:【http://xie.infoq.cn/article/ff0b36cd953ef4f7d3e1f9a9f】。文章转载请联系作者。
评论