C++函数模板的编译方式

C++函数模板的编译方式

目前支持函数模板分离编译的编译器相当稀少,VC和g++都不支持。
模板的文件组织两种方法(<<The C++ programming language>>):
第一种 包含编译方式:
实现和声明放在一个编译单位中,这样这个模板定义所依靠的一些东西就被带到了包含这个编译单位的文件里。坏处是:增大编译器的处理信息量,而且用户会意外的依赖了原本只是为定义这个模板而引进的东西。解决方案:使用名字空间、避免宏定义、以及一般性的减少包含进来的信息量,可以减小这种危害影响。

第二种 分离编译模式:
这种处理就和一般的非inline函数处理一样。不过这里需要用到export关键字了,export关键字的作用就是告诉编译器这个东西别的编译单位可以访问;否则按照一般规则,任何地方使用模板,都要求其定义在作用域中。这种方法的优点是:思路清晰。缺点:因为模板被单独编译了,因此在需要时候,找到合适的定义成了实现者(编译器的责任),要实现者在需要时候找到唯一的一个版本,想想编译器这家伙可就头疼了,因此很少编译器做到这一点。

第三种 显式实例化声明:
标准C++提供了显式实例化声明来帮助程序员控制模板实例化发生的时间。在显式实例化声明中,关键字template后面是函数模板实例的声明,其中显式地指定了模板实参。下例中提供了sum(int* , int)的显式实例化声明:

template<class Type> Type sum( Type op1, int op2 ) {} // 函数模板sum的定义必须给出
// 显式实例化声明
template int* sum< int* >( int*, int );   
    
    该显式实例化声明要求用模板实参int*实例化模板sum()。对于给定的函数模板实例,显式实例化声明在一个程序中只能出现一次。
总结了上面的两种情况后,我们可以看到,第一种在编译时候,任何需要这个模板的地方都引用了这个模板定义,因此编译器据此来优化,去掉冗余的版本。第二种方法就给实现者(编译器)增加了负担,不是去掉冗余的版本,而是在需要时找到这个唯一版本。

函数模板实例化:如果一个函数模板在好几个文件中都有实例化调用,那么我们就称这每一个实例化调用处为模板的一个实例化点。在这若干个实例化点处,对于同一种实例化调用,编译器都有可能进行实例化。一般来说编译器会在这种实例化所有的点中只选择一个实例化点处进行实例化,其他点处的调用都使用该点实例化后的具体函数定义。但是一些编译器(大部分都是老式的编译器)会在每一个实例化点处都进行实例化,生成一个具体的函数定义,然后在这些实例化后的具体定义中选择一个作为这种实例化调用最终的实例化具体定义,其他的具体定义视而不见。这样做的效果虽然同先选择一个实例化点再进行实例化,然后其他实例化调用处使用该点定义的方式一样,但是会使得编译的效率极差,而且随着程序的修改,如果该模板这种实例化调用用的越来越多,那么实例化出来的被视而不见的定义就越来越多,程序的体积就越来越大,越来越臃肿。因此C++标准中加入了显式实例化,使得程序编写者可以通过显式实例化声明来通知编译器:该在此处进行这种实例化,别的地方就不用了。以避免前面那种因编译器不够智能带来的问题。
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值