详解C++函数模板与分离编译模式
1.分离编译模式
一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件连接起来形成单一的可执行文件的过程称为分离编译模式。
2.使用函数模板在链接时出错
在C++程序设计中,在一个源文件中定义某个函数,然后在另一个源文件中使用该函数,这是一种非常普遍的做法。但是,如果定义和调用一个函数模板时也采用这种方式,会发生编译错误。
下面的程序由三个文件组成:func.h用来对函数模板进行申明,func.cpp用来定义函数模板,main.cpp包含func.h头文件并调用相应的函数模板。
/***func.h***/ templatevoidfunc(constT&); /***endfunc.h***/ /***func.cpp***/ #include usingnamespacestd; #include"func.h" template voidfunc(constT&t) { cout< #include"func.h" intmain() { func(3); } /***endmain.cpp***/
这是一个结构非常清晰的程序,但是它不能通过编译。在VS2017下的出错信息是:
errorLNK2019:无法解析的外部符号"void__cdeclfunc
(intconst&)"(??$func@H@@YAXABH@Z)
原因出现在分离编译模式上。在分离编译模式下,func.cpp会生成一个目标文件为func.obj,由于在func.cpp文件中,并没有发生函数模板调用,所以不会将函数模板func
3.解决办法
3.1将函数模板的定义放到头文件
一个简单的解决办法就是将函数模板func
(1)函数模板的定义写进了头文件,暴露了函数模板的实现细节。
(2)不符合分离编译模式的规则,因为分离编译模式要求函数原型申明放在头文件,定义放在源文件。
注意:这样做,如果在多个目标文件中存在相同的函数模板实例化后的模板函数实体,链接时并不会报函数重定义的错误,这与普通函数不同,因为编译器会对实例化后的重复的模板函数实体进行优化,只保留一份代码实体。如果不同的源文件中都保留一份函数模板实体,会造成代码冗余,实际上,这也是一种代码冗余的解决办法。
3.2仍然采用分离编译模式
有什么办法可以让函数模板实例化时能够找到相应的模板函数的代码呢?一个可能的解决办法就是使用关键字export。也就是说,在func.cpp里定义函数模板的时候,将函数模板头写成:
exporttemplatevoidfunc(constT&t);
这样做的目的是告诉编译器,这个函数模板可能再其他源文件中被实例化。这是一个对程序员来说负担最轻的解决办法,但是,目前几乎所有的编译器都不支持关键字export,包括VC++和GNUC++。
3.3显示实例化
显示实例化也称为外部实例化。在不发生函数调用的时候将函数模板实例化,或者在不使用类模板的时候将类模板实例化称之为模板显示实例化。
上面遇到的问题是main.obj和func.obj中找不到模板函数func
templatevoidfunc(constint&);//函数模板显示实例化
这样,就可以在func.cpp产生模板函数func
以上就是详解C++函数模板与分离编译模式的详细内容,更多关于C++函数模板与分离编译模式的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。