当前位置:网站首页>关于模板函数声明与定义的问题[通俗易懂]
关于模板函数声明与定义的问题[通俗易懂]
2022-07-26 10:17:00 【全栈程序员站长】
大家好,又见面了,我是你们的朋友全栈君。
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上面只说了类模板的成员函数可以不在头文件中定义,却始终感觉说得不清不楚,因为实际上像普通类那样类的定义与实现放在不同的文件中的话,是会链接出错的。总之,若你不想出现任何未定的错误,将类模板或函数模板的定义与声明放在同一个文件中就行了。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/126778.html原文链接:https://javaforall.cn
边栏推荐
- Learning about tensorflow (I)
- Like, "new programmer" e-book is free for a limited time!
- Redis realizes the correct posture of token bucket
- SQL Server 2008 server engine failed to start?
- 数通基础-网络基础知识
- 分布式网络通信框架:本地服务怎么发布成RPC服务
- Tower of Hanoi II | tower of Hanoi 4 columns
- Usage of the formatter attribute of El table
- Uniapp common error [wxml file compilation error]./pages/home/home Wxml and using MySQL front provided by phpstudy to establish an independent MySQL database and a detailed tutorial for independent da
- Yarn 'TSC' is not an internal or external command, nor is it a runnable program or batch file. The problem that the command cannot be found after installing the global package
猜你喜欢

On the compilation of student management system of C language course (simple version)

论文笔记(SESSION-BASED RECOMMENDATIONS WITHRECURRENT NEURAL NETWORKS)

Review of database -- 3. SQL language

How to write a million reading article

万字详解“用知识图谱驱动企业业绩增长”

Flask framework beginner-03-template

PLC概述

Necessary for beginners: debug breakpoint debugging skills in idea and common breakpoint skills

【Halcon视觉】形态学膨胀

Jpg to EPS
随机推荐
面试突击68:为什么 TCP 需要 3 次握手?
Okaleido生态核心权益OKA,尽在聚变Mining模式
Interview shock 68: why does TCP need three handshakes?
Using undertow, Nacos offline logout delay after service stop
Session based recommendations with recurrent neural networks
The fourth week of summer vacation
30 minutes to thoroughly understand the synchronized lock upgrade process
PHP executes shell script
El table implements adding / deleting rows, and a parameter changes accordingly
【Halcon视觉】形态学腐蚀
Docker configuring MySQL Cluster
Review of database -- 3. SQL language
【Halcon视觉】图像的傅里叶变换
Production of a-modal drag function in antui
Self encapsulated database dbutils universal template
Jpg to EPS
网易云UI模仿--&gt;侧边栏
【Halcon视觉】数组
Map key not configured and uniapp routing configuration and jump are reported by the uniapp < map >< /map > component
万字详解“用知识图谱驱动企业业绩增长”