C++ --- 模板为什么不能分离编译?

news2024/11/16 10:36:39

模板为甚么不能分离编译,但普通函数却可以?

  • 一、前置知识
    • 二、普通函数能分离编译的原因
      • 三、模板不能分离编译的原因

一、前置知识

编译阶段:

  1. 源代码到目标代码:
    编译器首先将源代码(如C/C++文件)翻译成汇编语言,然后进一步翻译成目标代码(通常是机器代码1或0),这些目标代码存储在可重定位的目标文件(.o文件或.obj文件)中。
    在这个过程中,编译器会处理函数和变量的声明,并生成对它们的引用(即符号)。然而,此时编译器并不直接分配最终的内存地址给这些符号。
  2. 符号表
    编译器会为每个目标文件生成一个符号表,该表列出了文件中所有外部可见的函数和变量(即那些在文件外部被声明或引用的符号)。
    这些符号在符号表中以未定义(UND)或已定义(DEF)的状态出现,取决于它们是在当前文件中定义的还是仅在当前文件中被引用。

链接阶段:

  1. 符号解析:
    链接器的主要任务之一是解析这些符号。它遍历所有目标文件的符号表,并尝试匹配每个未定义的符号(即引用)到一个已定义的符号(即定义)。
    如果链接器成功找到所有符号的定义,它将为这些符号分配最终的内存地址。这些地址是程序在运行时实际使用的地址。
  2. 重定位:
    在分配了地址之后,链接器会修改目标代码中的引用,以反映这些符号的最终地址。这个过程称为重定位。
    通过重定位,链接器确保程序中的每个函数调用和变量访问都指向正确的内存位置。

二、普通函数能分离编译的原因

以下方例子为例:
在这里插入图片描述
test.cpp会先进行编译:
先将头文件func.h展开,找到了Add(int ,int)函数的声明 ,然后生成Add函数的符号,编译后生成test.obj文件。
再到func.cpp编译:
先将头文件func.h展开,找到了Add(int ,int)函数的声明 ,然后生成Add函数的符号并对Add函数的定义进行编译,编译后生成func.obj文件。

最后在链接阶段时,链接器会根据两个.obj文件的符号表,发现func.obj文件中有与test.obj文件中对应的Add函数的符号,这时链接器就回为该函数分配地址,运行时就可根据该地址实现特定的功能。

三、模板不能分离编译的原因

如下模板分离编译例子:
在这里插入图片描述
报错:
在这里插入图片描述
可以看到,这里是报了链接错误。

原因需要结合模板实例化机制说明:

  1. 模板本身并不生成代码,只有当模板被实例化时,编译器才会根据模板定义生成相应的代码。这意味着在编译过程中,如果模板的定义不可见(例如,当模板的声明与定义分离,并且定义在另一个文件中时),编译器在实例化模板时可能找不到对应的模板定义,从而导致编译或链接错误。
  2. 符号表记录了程序中所有符号(如函数名、变量名等)的信息,包括它们的类型、作用域等。对于模板来说,如果模板在某个源文件中被实例化,那么实例化后的函数或对象将会出现在该源文件的符号表中。但是,如果模板的声明与定义分离,且定义在另一个文件中,而这个文件在链接前没有被正确编译或包含,那么实例化后的符号可能就不会出现在最终的符号表中,从而导致链接错误。

因此,当test.cpp编译时,虽然展开.h文件找到了Add函数的声明,但是由于定义不再.h文件中,即使明确了T的类型,也无法实例化Add函数。而对于func.cpp,由于它编译时并不确定Add( T x,T y) 函数的T的类型,因此也无法实例化Add函数,因此Add函数就没有被定义。在链接过程中,因为找不到Add的定义,因此报链接错误。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2170184.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

初学51单片机之I2C总线与E2PROM

首先先推荐B站的I2C相关的视频I2C入门第一节-I2C的基本工作原理_哔哩哔哩_bilibili 看完视频估计就大概知道怎么操作I2C了,他的LCD1602讲的也很不错,把数据建立tsp和数据保持thd,比喻成拍照时候的摆pose和按快门两个过程,感觉还是…

CentOs-Stream-9 设置静态IP外网访问

CentOs-Stream-9 设置静态IP,实现外网访问。这里面有些需要注意的地方,比如IP网段跟我们的宿主机不一样,需要查看具体的网络适配器网段,这样可以快速实现网络互通;另外它的网络配置文件也是不一样的。网络适配器对应的…

放弃 startActivityForResult,Activity Result API 优雅使用

放弃 startActivityForResult,Activity Result API 优雅使用 Activity Result API 是 androidx 中的一个新 api,旨在替代原有的 startActivityForResult 方法,用于在两个 Activity 或 Fragment 交换数据、获取返回结果。 过去如果 Activity…

了解独享IP的概念及其独特优势

在网络世界中,IP地址是用来识别和定位设备的标识符。独享IP是一种服务模式。使用代理服务器时,用户拥有一个不与其他用户共享的专用独立IP地址。与共享IP相比,独享IP为用户提供了更高的独立性和隐私保护。下面详细介绍独享IP的定义、工作原理…

OJ在线评测系统 后端 代码沙箱原生实现 初始化项目

代码沙箱Java原生实现 之前我们完成了快速的前端页面开发 重点是在后端 历史问题修复 Java原生代码沙箱实现 docker代码沙箱实现 解决历史遗留问题 代码编辑器切换语言失败 监听language属性 动态更改编辑器的语言 我们在这里实现的是一个线程形式的监听 watch(() > …

总结拓展十一:S4 HANA和ECC区别

第一节 S/4 HANA系统简介 SAP系统的产品线 R/1版本——主要财务模块R/3版本——基本实现全模块ECC6.0——2005年推出(ECC是2004年推出)HANA——数据库产品——属于内存数据库BW on HANA——HANA与数据分析相结合 拓展: 数据库类型&#x…

易盾滑块验证码

前言 这玩意我就搞定get请求和check请求,那个b接口的d参数还是有点问题,还有就是b接口的返回参数怎么用,是不是只是加了cookie我也不确定,所以有高手的话希望可以指导一下。我的虽然能够成功,但是只有前2次成功&#x…

ARM V8 A32常用指令集

文章目录 1. 算术指令1.1 加法命令ADD\ADDS1.2 带进位加法命令ADC\ADCS1.3减法命令SUB\SUBC1.4带借位减法命令SBC\SBCS 2.逻辑运算指令2.1逻辑与指令AND、ANDS2.2位清零指令BIC2.3逻辑或指令ORR\ORRS2.4逻辑异或指令2.5 逻辑左移LSL2.6逻辑右移LSR 3.比较指令3.1直接比较指令CM…

2024年华为杯研究生数学建模竞赛C题 波形机理建模+GBDT 完整文章代码|进阶可视化

2024年华为杯研究生数学建模竞赛C题 波形机理建模GBDT 完整文章代码|进阶可视化 全部问题已经更新完成,可视化图表20余张,代码量千余行,实在累到了… 由于篇幅原因,此处放出部分内容供参考~ 完整内容可以从底部名片的群中获取~ …

vue3监听子组件的生命周期

1.Vue3使用vue&#xff0c;vue2使用hook template:<compG vue:mounted"doSomething"></compG>script://监听子组件生命周期let doSomething (e: any) > {console.log("没有啊11", e);}; 2.打印结果

昇思MindSpore进阶教程--轻量化数据处理

大家好&#xff0c;我是刘明&#xff0c;明志科技创始人&#xff0c;华为昇思MindSpore布道师。 技术上主攻前端开发、鸿蒙开发和AI算法研究。 努力为大家带来持续的技术分享&#xff0c;如果你也喜欢我的文章&#xff0c;就点个关注吧 正文开始 在资源条件允许的情况下&#…

【趣学Python算法100例】数制转换

问题描述 给定一个M进制的数x&#xff0c;实现对x向任意一个非M进制的数的转换。 问题分析 要搞定这道题&#xff0c;关键在于学会不同数制之间的转换&#xff0c;主要是二进制、八进制、十六进制和十进制这几种。理解下面这几个概念非常重要&#xff1a; 基数&#xff1a;…

Go基础学习06-Golang标准库container/list(双向链表)深入讲解;延迟初始化技术;Element;List;Ring

基础介绍 单向链表中的每个节点包含数据和指向下一个节点的指针。其特点是每个节点只知道下一个节点的位置&#xff0c;使得数据只能单向遍历。 示意图如下&#xff1a; 双向链表中的每个节点都包含指向前一个节点和后一个节点的指针。这使得在双向链表中可以从前向后或从后…

Docker仓库搭建

目录 一、Docker Hub 二、私有Registry仓库搭建 1、下载并开启仓库镜像registry 2、Registry加密传输 3、建立一个registry仓库 4、为客户端建立证书 5、测试 6、为仓库建立登录认证 三、Harbor仓库搭建 Docker 仓库&#xff08;Docker Registry&#xff09; 是用于存…

8种数值变量的特征工程技术:利用Sklearn、Numpy和Python将数值转化为预测模型的有效特征

特征工程是机器学习流程中的关键步骤&#xff0c;在此过程中&#xff0c;原始数据被转换为更具意义的特征&#xff0c;以增强模型对数据关系的理解能力。 特征工程通常涉及对现有数据应用转换&#xff0c;以生成或修改数据&#xff0c;这些转换后的数据在机器学习和数据科学的…

书生大模型实战营学习[9] OpenCompass 评测 InternLM-1.8B 实践

准备工作 打开开发机&#xff0c;选择cuda11.7环境&#xff0c;A100选择10%&#xff0c;点击创建&#xff0c;然后进入开发机即可&#xff0c;和之前的操作一样。接下来创建环境&#xff0c;下载必要的依赖包 conda create -n opencompass python3.10 conda install pytorch2…

什么是网络安全自动化以及优势与挑战

目录 网络安全自动化的工作原理 网络安全自动化的好处 增强的安全功能 改善表现和姿势 降低安全成本 简化的安全合规性和审计 更好的端点管理 网络安全自动化的挑战 耗时且容易出错的安全流程 可见性降低&#xff0c;风险和成本增加 合规管理 有用的网络安全自动化…

2024年合肥市职业院校技能大赛(中职组)赛 网络安全 竞赛样题

2024年合肥市职业院校技能大赛(中职组)赛 网络安全 竞赛样题 (总分100分) 培训、环境、资料、考证 公众号&#xff1a;Geek极安云科 网络安全群&#xff1a;624032112 网络系统管理群&#xff1a;223627079 网络建设与运维群&#xff1a;870959784 极安云科专注于技能提升&am…

基于nodejs+vue的旅游管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

Docker启动失败,Failed to start docker,只需三个步骤,看我怎么搞定它!

在项目部署上线的时候 1打开hyper-v虚拟机 怎么打开呢&#xff1f; 命令提示符输入control,点击回车&#xff0c;打开控制面板&#xff0c;打开“程序和功能”&#xff0c;“启用和关闭windows功能”&#xff0c;选择Hyper-v&#xff0c;勾选下面的每一项内容。完成之后又点…