代码编译运行环境:VS2017+Debug+Win32


1.分离编译模式

一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件连接起来形成单一的可执行文件的过程称为分离编译模式。

2.使用函数模板在链接时出错

在 C++ 程序设计中,在一个源文件中定义某个函数,然后在另一个源文件中使用该函数,这是一种非常普遍的做法。但是,如果定义和调用一个函数模板时也采用这种方式,会发生编译错误。

下面的程序由三个文件组成:func.h 用来对函数模板进行申明,func.cpp 用来定义函数模板,main.cpp 包含 func.h 头文件并调用相应的函数模板。

/***func.h***/
template<class T> void func(const T&);
/***end func.h***//***func.cpp***/
#include "func.h"
#include <iostream>
using namespace std;template<class T> void func(const T& t)
{cout<<t<<endl;
}
/***end func.cpp***//***main.cpp***/
#include <stdio.h>
#include "func.h"int main()
{func(3);
}
/***end main.cpp***/

这是一个结构非常清晰的程序,但是它不能通过编译。在VS2017下的出错信息是:

error LNK2019: 无法解析的外部符号 "void __cdecl func< int>(int const &)" (??$func@H@@YAXABH@Z)

原因出现在分离编译模式上。在分离编译模式下,func.cpp 会生成一个目标文件为 func.obj,由于在func.cpp 文件中,并没有发生函数模板调用,所以不会将函数模板func<T>实例化为模板函数func<int>,也就是说,在 func.obj 中无法找到关于模板函数func<int>的实现代码。在源文件 main.cpp 中,虽然函数模板被调用,但由于没有模板代码,也不能将其实例化。也就是说,在 main.obj 中也找不到模板函数func<int>的实现代码。这样,在链接的时候就会出现func<int>没有定义的错误。

3.解决办法

3.1 将函数模板的定义放到头文件

一个简单的解决办法就是将函数模板func<T>的定义写到头文件 func.h 中。这样的话,只要包含了这个头文件,就会把函数模板的代码包含进来,一旦发生函数调用,就可以依据函数模板代码将其实例化。这个办法虽然简单可行,但是有如下不足。
(1)函数模板的定义写进了头文件,暴露了函数模板的实现细节。
(2)不符合分离编译模式的规则,因为分离编译模式要求函数原型申明放在头文件,定义放在源文件。

注意: 这样做,如果在多个目标文件中存在相同的函数模板实例化后的模板函数实体,链接时并不会报函数重定义的错误,这与普通函数不同,因为编译器会对实例化后的重复的模板函数实体进行优化,只保留一份代码实体。如果不同的源文件中都保留一份函数模板实体,会造成代码冗余,实际上,这也是一种代码冗余的解决办法。

3.2 仍然采用分离编译模式

有什么办法可以让函数模板实例化时能够找到相应的模板函数的代码呢?一个可能的解决办法就是使用关键字export。也就是说,在 func.cpp 里定义函数模板的时候,将函数模板头写成:

export template<class T> void func(const T& t);

这样做的目的是告诉编译器,这个函数模板可能再其他源文件中被实例化。这是一个对程序员来说负担最轻的解决办法,但是,目前几乎所有的编译器都不支持关键字 export,包括 VC++ 和 GNU C++。

3.3 显示实例化

显示实例化也称为外部实例化。在不发生函数调用的时候将函数模板实例化,或者在不使用类模板的时候将类模板实例化称之为模板显示实例化。

上面遇到的问题是 main.obj 和 func.obj 中找不到模板函数func<int>的实现代码,那么就在 func.cpp 中将函数模板func<T>显示实例化为模板函数func<int>

template void func<int>(const int&);   //函数模板显示实例化

这样,就可以在 func.cpp 产生模板函数func<int>的实例化代码,编译之后就会产生函数的二进制代码,供其它源文件链接,程序就可以正常运行。当类模板的成员函数的实现定义在源文件中,通过模板类的对象调用成员函数时也会出现找不到函数定义的错误,可以使用同样的方法解决,不再赘述。


参考文献

[1] 陈刚.C++高级进阶教程[M].武汉:武汉大学出版社,2008.C6.5模板与分离编译模式.P223-P225
[2] 深入理解C++11[M].北京:机械工业出版社.C2.12外部模板.P50-P54

C++ 函数模板与分离编译模式相关推荐

  1. C++ 泛型编程(二):非类型模板参数,模板特化,模板的分离编译

    目录 非类型模板参数 函数模板的特化 类模板的特化 全特化 偏特化 部分参数特化 参数修饰特化 模板分离编译 问题分析 解决方法 非类型模板参数 模板的参数分为两种,一种是非类型参数,一种是类型参数. ...

  2. c++模板函数声明定义分离编译错误详解

    今天看到accelerated c++上有个简单的vector容器的实现Vec,就再vs2008上编译了下: /  Vec.h #ifndef GUARD_VEC_H #define GUARD_VE ...

  3. 如何解决类模板的分离编译问题?

    一模板: 模板不是数据类型,只能算是一种行为集合的表示.编译器在使用模板时,通过更换模板参数来创建数据类型.这个过程就是模板实例化(Instantiation), 从模板类创建得到的类型称之为特例(s ...

  4. C++模板(函数模板,类模板)的基本使用与非类型模板参数与模板的特化

    C++模板 模板初阶 泛型编程 函数模板 函数模板概念 函数模板格式 函数模板的原理 函数模板的实例化 隐式实例化 显式实例化:在函数名后的<>中指定模板参数的实际类型 模板参数的匹配原则 ...

  5. c++ swap函数头文件_C++函数模板(泛型编程)

    模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码. 模板是创建泛型类或函数的蓝图或公式.库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念. 每个容器都有一个单 ...

  6. c++ 函数模板_C++函数模板(泛型编程)

    模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码. 模板是创建泛型类或函数的蓝图或公式.库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念. 每个容器都有一个单 ...

  7. C++模板——模板特化、分离编译

    这里写目录标题 一.泛型编程与模板 二.函数模板 1.概念 2.原理 3.函数模板的实例化 3. 模板实现复数类的加法 4.模板参数的匹配原则 三.类模板 1.定义格式 用类模板实现顺序表 2.非类型 ...

  8. 关于模板函数/模板类编译成DLL

    ]关于模板函数/模板类编译成DLL Posted on 2011-08-16 08:48 单鱼游弋 阅读( 353) 评论( 0) 编辑 收藏 要编译成DLL,就要声明和实现分开. 首先文件组织是这样 ...

  9. 前后端分离开发模式下后端质量的保证 —— 单元测试

    概述 在今天, 前后端分离已经是首选的一个开发模式.这对于后端团队来说其实是一个好消息,减轻任务并且更专注.在测试方面,就更加依赖于单元测试对于API以及后端业务逻辑的较验.当然单元测试并非在前后端分 ...

最新文章

  1. 使用Python和OpenCV检测图像中的物体并将物体裁剪下来
  2. 什么时候z检验什么时候t检验?
  3. Java基础查漏补缺(2)
  4. 数据分析 绩效_如何在绩效改善中使用数据分析
  5. python推导式多行书写_python三种推导式的详细介绍及其应用示例,强调字典推导的重要性...
  6. drools 7.11.0.Final使用
  7. 表单绑定复选框的值和图片上传
  8. jsp页面中显示word/excel文档方法
  9. vim源码编译启用python
  10. JSP技术-02-内置对象/作用域/EL表达式/JSTL标签库
  11. 谷歌离线地图开发API
  12. CocosCreator 基于Assembler实现的图片切割破碎效果及自定义遮罩
  13. mtk系统如何制作差分包且正确签名?
  14. 合并报表口诀_《中级会计实务》合并报表学不会?据说把他的讲义抄6遍就能过!...
  15. 【矩阵论】线性空间与线性变换(5)
  16. 计算机网络期末考试试题,计算机网络期末考试题库.docx
  17. jbuilder的set!方法重构接口
  18. 如何更好地进行销售预测
  19. 在这个大数据时代,如何保护好自己的隐私?
  20. php下载pdf并保存图片大小,php根据URL下载图片、压缩包、pdf等远程文件到本地

热门文章

  1. Android 3.0 r1 API中文文档(108) —— ExpandableListAdapter
  2. linux中rlwrap安装
  3. POJ 2010 Moo University - Financial Aid【堆的应用】
  4. tablesorter,jquery
  5. Ice-E(Embedded Internet Communications Engine)移植到s3c2440A(arm9)linux(2.6.12)上的 -转
  6. 蓝桥杯 ADV-206 算法提高 不大的数
  7. 蓝桥杯 ADV-193算法提高 盾神与条状项链
  8. 【数据库原理】滨江学院姜青山 期末试卷知识点笔记整理 南京信息工程大学
  9. L2-015. 互评成绩-PAT团体程序设计天梯赛GPLT
  10. 一致 先验分布 后验分布_「分布式技术」分布式事务最终一致性解决方案,下篇...