g++模板显式实例化big file例子

前言

模板是编程中高级工具,类似C语言的宏生成代码,但却比宏更强大,例如,对于调试的支持,以及实现更严格的语法检查。

如果用是否可以节省代码来定义工具的好坏,无疑,不管是用C语言宏来生成代码,或者是用C++的模板,抑或其它代码自动生成技术都是非常可取的!

问题

在g++中使用到模板相关的引用,特别发布目标为共享SO库的模块,会特别用到-fno-implicit-templates的编译选项,用来禁止隐式模板实例化,以节省编译和链接期的代价,详细见官网说明。

根据官网建议,对于简单点的场景,可以选择在各个需要的模块自行模板实例化,如下所示:

/*declaration 头文件*/
#include "Foo.h"

/*implementation 实现文件*/
#include "Foo.cc"

/*显式实例化模板类*/
template class Foo<int>;

/*显式实例化模板方法*/
template ostream& operator <<
                (ostream&, const Foo<int>&);

但我觉得更具工程价值的实施方案,是官网中建议的big file实施方案,原因如下:

  • 各个obj模块自行添加显式模板实例化,但还是会遇到公共模板实例化需要往big file中增加
  • 统一往big file中增加,便于维护,特别是引用依赖组件的模板,例如,ACE组件中的模板,可以进行归类划分

模板显式实例化弊端

模板实例化使用显式实例化的方法,有时即使对于简单的STL模板std::vector<char>的实例化,操作起来都比较繁琐。

在某些平台上会出现undefined reference to std::vector<char, std::allocator<char> >::)M_insert_aux(...)的链接异常,所以,官网同时也建议控制 -fno-implicit-templates 选项进行分开编译。

Compile your code with -fno-implicit-templates to disable the implicit generation of template instances, and explicitly instantiate all the ones you use.

If you use one big file to do the instantiations, you may want to compile it without -fno-implicit-templates, so you get all of the instances required by your explicit instantiations (but not by any other files) without having to specify them as well.

std::vector实例化简单例子

#include<iostream>
#include <vector>

int main(void)
{
  std::vector<char> v;
  v.push_back('a');
  
  std::cout << "Hello World! no-implicit-templates , item: " << v[0] << std::endl;
  
  return 0;
}

即使如此简单的使用STL模板类,如果使用显式实例化模板,也不太容易维护,因为依赖的依赖比较多

对于Big File特别使用隐式实例化的编译策略

.PHONY: app main clean cleanObjs
app: main

vpath %.h .
vpath %.cpp .

SRC=$(wildcard *.cpp)
OBJS=$(patsubst %.cpp,%.o, $(SRC))
TARGET=a.out

CCFLAGS:=-g3 -O0 -W -Wall -pipe -Wno-unused-variable -Wno-unused-parameter -fno-implicit-templates 
LDFLAGS:=-lstdc++

main: $(OBJS)
    @echo "Link vector no-implicit-templates test program ..."
    g++ -pipe $(OBJS) -o $(TARGET) $(LDFLAGS)

# depend & nested
$(OBJS): cleanObjs
tmplinst.o: tmplinst.cpp
    @echo "Build $@ specially for big file of explicit template instantiation by removing -fno-implicit-templates option ..."
    g++ $(strip $(subst -fno-implicit-templates, , $(CCFLAGS))) -c $< -o $@
%.o: %.cpp
    @echo "Build $< to $@ commonly ..."
    g++ $(CCFLAGS) -c $< -o $@
    
clean: 
    @echo "Clean all obj & target ..."  
    rm -rf $(OBJS) $(TARGET)
    @echo "Finish clean all obj & target ..."   

cleanObjs:
    @echo "Clean all objs ..."  
    rm -rf $(OBJS)
    @echo "Finish clean all objs ..."   

对于其它编译目标统一使用默认的-fno-implicit-templates选项;但对于big file通过编译脚本命令subst ,特殊地去除-fno-implicit-templates选项,以达到转换成隐式实例化模板的目的

结束语

曾为std::vector<char>在不同的平台奋战过模板显式实例化,依赖比较多,非常繁琐;后期如果再增加其他模板使用,估计也非常不方便。

同时在ACE组件的模板显式实例化维护时,也反复遭遇增加其它依赖的依赖模板显式实例化的修改。

所以,从工程角度来看,不如单独对于big file特别使用隐式实例化编译策略,以达到自动化的目的!

对于有兴趣研究模板实例化过程的同学,可以使用全手工模板实例化

官网参考

GCC Template-Instantiation.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值