c++ primer上说:c++模板函数的声明与定义通常放在头文件中,而普通的函数通常是声明放在头文件中,定义放在源文件中,为什么会有这样的区别呢?模板函数与普通成员函数到底有什么区别?

测试代码:

tem.h

#ifndef _TEM_H
#define _TEM_H
template<typename T> T add(T a,T b);
//{
//return a+b;
//}
#endif

tem.cpp

using namespace std;
//#include "tem.h"

template <typename T> T add(T a, T b){return a+b;}
template int add(int,int);//实例化定义,必须放在模板定义的后面

main.cpp

#include <iostream>
#include "tem.h"
using namespace std;
int main()
{
cout << add(1,2);
return 0;
}

首先明确:

对普通函数来说,声明放在头文件中,定义放在源文件中,其它的地方要使用该函数时,仅需要包含头文件即可,因为编译器编译时是以一个源文件作为单元编译的,当它遇到不在本文件中定义的函数时,若能够找到其声明,则会将此符号放在本编译单元的外部符号表中,链接的时候自然就可以找到该符号的定义了。

而对模板函数来说,首先明确,模板函数是在编译器遇到使用模板的代码时才将模板函数实例化的。若将模板函数声明放在tem.h,模板定义放在tem.cpp,在main.cpp中包含头文件,调用add,按道理说应该实例化int add(int,int)函数,即生成add函数的相应代码,但是此时仅有声明,找不到定义,因此此时,它只会实例化函数的符号,并不会实例化函数的实现,即这个时候,在main.o编译单元内,它只是将add函数作为一个外部符号,这就是与普通函数的区别,对普通函数来说,此时的add函数已经由编译器生成相应的代码了,而对模板函数来说,此时并没有生成add函数对应的代码。此时编译main.cpp单元不会报错,但链接就会出现add函数未定义的错误。

因此,我们可以通过显式的实例化定义,即通过加上语句temmplate int add(int,int),编译器看到此语句将会生成add方法的int版本,这样的话,再链接就不会报错了。此外,这样做通常也能够提高编译的效率。试想,如果在tem.h文件内定义模板,假如有三个源文件均包含了该头文件且均使用了模板(假定均调用了add模板的int版本),则在这三个源文件内必然都会生成add函数的实例。显然效率不高。而如果像上面那样使用该模板,则只会在tem.cpp文件中实例化。

最后,对于类模板来说,也同样符合上面的原则。在实际类模板的实例化时,实际上是分几步的,首先当然是类模板的实例化,然后还有类成员函数的实例化,我们知道在类的定义中,其实只是声明了类的成员函数,编译器实际上是把类的成员函数编译成修改名称后的全局函数的,因此在使用类模板的时候,首先会初始化类模板,同时初始化类模板相应的构造函数,使用类模板的实例调用相应的成员函数时,才会初始化类模板的成员函数。如果类模板的成员函数的定义与类的定义不在同一个编译单元中(分离式编译),此时调用类的成员函数便会出现未定义的错误。而当我们像代码中那样在某个地方显式的调用它的时就不会出现此类问题了。

总结:其实很明显,明确一点就可以了,即编译器只要遇到使用模板函数时就会实例化相应的函数,若在此编译单元内没有模板函数的定义,它当然不能够实例化成功了。因此通常情况下模板函数的声明与定义均放在同一文件内,因此这样就保证了在使用模板的地方一定可以实例化成功了。同时,由编译器保证只生成某种类型的一个实例版本,不用担心重复实例化的问题。

c++primer上面只说了类模板的成员函数可以不在头文件中定义,却始终感觉说得不清不楚,因为实际上像普通类那样类的定义与实现放在不同的文件中的话,是会链接出错的。总之,若你不想出现任何未定的错误,将类模板或函数模板的定义与声明放在同一个文件中就行了。

关于模板函数声明与定义的问题相关推荐

  1. 关于C++模板函数声明与定义的问题

    关于C++模板函数声明与定义的问题 关于C++模板函数声明与定义的问题 模板函数出现的问题 模板函数问题解决 模板函数出现的问题 今天在写代码的时候,发现了一个关于模板函数的问题.如下所示, demo ...

  2. VS2017 函数模板和类模板的声明、定义和使用

    模板的声明.定义分为两种. 1 将模板的声明和定义都放在头文件中,在主程序的文件中包含此头文件即可 2 将模板的声明和定义分开编写. 在<C++ primer>教材中,将模板的声明和定义分 ...

  3. C++模板类声明和定义几种写法

    为什么模板类的实现放在cpp会出错 在编译用到了模板类的编译单元时,编译器需要访问方法或者类的实现,以实例化它们. 如果这些实现不在头文件中,则它们将不可访问,因此编译器将无法实例化模板,进而会导致编 ...

  4. c语言函数声明定义参数命名,C语言函数声明与定义

    C语言函数声明与定义教程 在 C语言函数声明与定义 语法 type funcName(paramType1 param1, paramType2 param2){ // 执行语句... return ...

  5. C语言 函数声明和定义 - C语言零基础入门教程

    目录 一.简介 二.函数返回值 1.函数没有返回值 2.函数有返回值 三.函数参数 1.函数没有参数 2.函数有固定参数 3.函数有不定长度参数 四.函数声明和定义 1.函数声明:不需要实现这个函数的 ...

  6. python函数的声明_Python函数声明与定义

    Python函数声明与定义教程 在 Python函数声明与定义详解 语法 def funcName(param1, param2): # do return [val] 参数 参数 描述 def 定义 ...

  7. 搞不懂c++ 的函数声明与定义

    一.函数的声明: C++函数的声明的作业就是:告诉编译器函数名称及如何调用函数.函数的实际主体可以单独定义.(你考试考了59分告诉了你妈妈准备要打你) 二.函数的定义: 函数的定义一般主要有5个步骤: ...

  8. c++ 函数声明与定义

    文章目录 一.函数的声明 二.函数的定义 三.函数声明与定义使用区别 四.为什么 C++ 允许多次声明呢? 五.分文件开发 一.函数的声明 函数声明的作用: 告诉编译器函数名称及如何调用函数.函数的实 ...

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

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

  10. c++模板类声明和定义的问题

    这里在学习的过程中遇到的一些问题,比较简单,但还是记下来,以免下次遇到这个问题再犯,大佬们可跳过哦.先简单的介绍下模板的概念 C++模板(泛型编程) c++模板是泛型编程的基础,所谓泛型编程也是一种思 ...

最新文章

  1. 是什么岗位_文案策划的岗位职责是什么?
  2. 精通Server Core系列之一 ---Server Core简介
  3. 感觉没有学会什么真正的本领
  4. bzoj 2436: [Noi2011]Noi嘉年华
  5. cpu性能测试软件 国际象棋,国际象棋、科学计算,整机性能测试
  6. formatter java_Java编程中的Java Formatter是什么?
  7. Typora的图片根目录设置,
  8. Spark解决的问题与体系结构
  9. 黑马vue实战项目-(三)权限管理功能开发
  10. C语言的32个关键字(简单介绍加解析方便记忆)
  11. 高中计算机必修选修知识点总结,高中数学必修+选修全部知识点精华归纳总结.pdf...
  12. 全球及中国装配式建筑行业深度研究与发展模式咨询报告2022版
  13. 快速重命名文件夹,教你怎样在每个文件夹名中添加符号
  14. 在嵌入式板子ARMv7 上利用neon对彩色图转换为灰度图进行加速
  15. Java 生成 OFD 文档
  16. 这64所大学官方公布考研【专业课真题】可以直接下载!
  17. Java JSON library哪家强?
  18. vue3 pinia 状态管理(清晰明了)
  19. 鸿蒙荣耀x10max,华为nova7和荣耀x10max哪个好-华为nova7和荣耀x10max测评
  20. h5如何上传文件二进制流_前端H5中JS用FileReader对象读取blob对象二进制数据,文件传输...

热门文章

  1. 8 款好用的 React Admin 管理后台模板推荐
  2. SEO搜索引擎优化 | hexo
  3. 5G应用加速落地,酷雷曼VR直播应时而生。
  4. Educoder Python顺序结构习题
  5. 全球院士共话智能工业创新
  6. 微信公众号获取用户地理位置
  7. cf. Is your horseshoe on the other hoof?
  8. 美图秀秀api实现图片的裁剪及美化
  9. 无人机欧拉角万向节锁死详解
  10. 合天网安实验室CTF-基础100-Flag就在这儿