谈谈C++中模板分离式编译出现的一些问题

news2024/11/24 11:00:28

什么是分离式编译

通俗的来讲就是将声明和定义分离在不同文件中

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


正常函数与模板分离式编译

看代码,先区分两个

正常函数的分离式编译

//------------------------ Test.h 存放函数的声明-----------------------
#pragma once
#include "iostream"
using namespace std;
//正常函数的声明
int Add(const int& num1, const int& num2);
//------------------------ Test.h-----------------------

//------------------------ Test.cpp  存放函数的定义 -----------------------
#include"Test.h"

int Add(const int& num1, const int& num2)
{
	cout << "int Add(const int& num1, const int& num2)" << endl;
	return 0;
}
//------------------------ Test.cpp -----------------------

//------------------------ main.cpp -----------------------
#include"Test.h"

int main()
{
	Add(1, 1);
	return 0;
}
//------------------------ main.cpp -----------------------

在这里插入图片描述

模板的分离式编译

//------------------------ Test.h 存放声明-----------------------
#pragma once
#include "iostream"
using namespace std;

//函数模板的声明
template <class T>
T Add(const T& num1, const T& num2);
//------------------------ Test.h-----------------------

//------------------------ Test.cpp  存放定义 -----------------------
#include"Test.h"

template<class T>
T Add(const T& num1, const T& num2)
{
	cout << "T Add(const T& num1, const T& num2)" << endl;
}
//------------------------ Test.cpp -----------------------

//------------------------ main.cpp -----------------------
#include"Test.h"

int main()
{
	Add(1, 1);
	return 0;
}
//------------------------ main.cpp -----------------------

在这里插入图片描述
此时我们看到出现了一个链接错误,那么问题来了:为什么模板的分离式编译会出现错误?为什么会出现这个错误?怎么解决模板分离式编译的问题呢?


为什么模板分离式编译会出错?

C++Primer中这么说:当使用一个vector这样的泛型类型,或者find这样的泛型函数时,我们提供足够的信息,将模板转化为特定的类或者函数(实例化)。这样的转换发生在编译阶段
我们知道了模板的实例化发生在编译阶段

回顾编译过程
  • 预处理阶段
    头文件展开、条件编译指令、宏替换
  • 编译阶段
    将第一步产生的文件同其他文件一起编译成汇编代码
  • 汇编阶段
    将汇编源码转换成可重定位目标文件
  • 链接阶段
    进行符号解析和重定位,将可重定位目标文件链接成可执行目标文件

我们通过编译过程中的第一个环节:预处理之后,此时就把.h文件展开到.cpp文件当中,所以此时两个.cpp文件里面就分别包含了函数模板的声明(Test.cpp中包含了函数模板的声明和实现,main.cpp中包含了函数模板的声明和调用),这两个文件经过编译之后会生成汇编代码,经过汇编之后会生成符号表,但是在汇编这一步中,编译器会生成符号表,符号表里面存着各各函数的地址,在链接的时候由main函数中调用的Add函数去符号表里寻找地址,这时出错了! 符号表里面这时没有存Add的地址, 因为在编译过程中两个文件是独立的,正因为是独立的,在编译阶段模板才没能够进行实例化,因此符号表中并不会生成Add的地址,所以分离编译模板在链接时出错了,因为链接时会去调用Add,但是没有地址,链接出错。


解决方案:

1、显式实例化

//在声明的.cpp文件里面显式实例化模板
#include"Test.h"

template<class T>
T Add(const T& num1, const T& num2)
{
	cout << "T Add(const T& num1, const T& num2)" << endl;
	return num1 + num2;
}

//显式实例化模板
template 
int Add<int>(const int& num1, const int& num2);

缺陷:显式实例化只能实例化一种类型,当遇到操作数是其他类型,还需要进行其他类型的显式实例化

1、分离式编译

将声明和定义放在同一个.h文件里面,这样预处理的时候就可以让模板的声明、定义、调用出现在一个.cpp文件中,进而编译过程就可以实例化模板

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

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

相关文章

生物制剂\化工\化妆品等质检损耗、制造误差处理作业流程图(ODOO15/16)

生物制剂、化工、化妆品等行业&#xff0c;因为产品为液体&#xff0c;产品形态和质量容易在各个业务环节发生变化&#xff0c;常常导致实物和账面数据不一致&#xff0c;如果企业业务流程不清晰&#xff0c;会导致系统大量的库存差异&#xff0c;以及财务难以核算的问题&#…

上门服务小程序源码 理疗,足疗,美容SAP上门服务小程序源码

上门服务小程序源码 理疗&#xff0c;足疗&#xff0c;美容SAP上门服务小程序源码 运行环境&#xff1a;Nginx 1.20PHP7.1MySQL 5.6 通过HBuilder X编译小程序APP版本 一、上门预定操作 1、技师管理。 技师满意度进行统一跟踪评估&#xff0c;进行分级管理&#xff0c;分级…

Web测试框架SeleniumBase

首先&#xff0c;SeleniumBase支持 pip安装&#xff1a; > pip install seleniumbase它依赖的库比较多&#xff0c;包括pytest、nose这些第三方单元测试框架&#xff0c;是为更方便的运行测试用例&#xff0c;因为这两个测试框架是支持unittest测试用例的执行的。 Seleniu…

Canal安装

安装和配置Canal Canal Framework 是阿里巴巴开源的一款基于数据库增量日志解析和同步的数据中间件。它主要用于解决分布式系统中数据同步的问题&#xff0c;支持多种数据源&#xff0c;如 MySQL、SQL Server、PostgreSQL、Oracle 等&#xff0c;同时也支持多种数据目标&#…

函数栈帧的创建与销毁(保姆级讲解)

局部变量是怎么创建的? 在为main函数开辟栈帧空间时&#xff0c;在一定范围内初始化成0CCCCC&#xff0c;再把里面0CCCC的一些开辟空间给局部变量使用。 为什么局部变量的值是随机值? 因为我们在为main函数开辟栈帧空间时&#xff0c;会将一定范围内空间初始成0CCCCCC里面…

【宏实现二进制奇偶位交换】

文章目录 一. 二进制奇偶位交换说明意思&#xff1f;二. 解题思路三. 代码验证四. 总结 一. 二进制奇偶位交换说明意思&#xff1f; 就是一个int类型的整数在操作系统下是32位二进制01序列&#xff0c;第一位和第二位交换&#xff0c;第二位和第三位交换&#xff0c;依次类推。…

口袋参谋:生意参谋指数转换工具,比对手更了解对手!

​所谓“知己知彼&#xff0c;百战不殆”&#xff0c;比对手更了解对手&#xff0c;就是提升自己的好机会。 在竞争如此激烈的淘宝天猫上&#xff0c;淘宝平台为了保护商家店铺数据&#xff0c;将真实数值全部隐藏&#xff0c;变成了指数。 所以我们查看市场排行、市场大盘、竟…

awvs安装教程和使用

awvs安装和使用 文章目录 awvs安装和使用安装&#xff08;awvs&#xff09;Acunetix-v23.9-Windows1 安装前准备1.1 查看帮助文档&#xff0c;修改此文件1.2 追加hosts 参数1.3 根据REANME.txt帮助文档提示&#xff0c;启动工具(Now install the tool)&#xff0c;双击 1.4 安装…

(vue3)大事记管理系统 文章管理页

[element-plus进阶] 文章列表渲染&#xff08;带搜索&到分页&#xff09; 表单架设&#xff1a;当前el-form标签配置一个inline属性&#xff0c;里面的元素就会在一行显示了 中英国际化处理&#xff1a;App.vue中el-config-provider标签包裹组件&#xff0c;意味着整个组…

Cesium 问题:加载 geojson 文件后使用 remove 方法移除,但浏览器内存会持续增长并为得到释放直到浏览器崩掉

文章目录 需求分析解决需求 在开发中,加载了 geojson 文件后,浏览器内存会增长,当使用remove方法移除后再次添加,浏览器内存持续增长并未减少,直到第三次交互添加,浏览器崩掉了 分析 在处理大量实体或长时间运行的应用程序中,及时释放不需要的实体是一种良好的做…

数据结构 - 3(链表12000字详解)

一&#xff1a;LinkedList的使用 1.1 ArrayList的缺陷 上篇文章我们已经基本熟悉了ArrayList的使用&#xff0c;并且进行了简单模拟实现。由于其底层是一段连续空间&#xff0c;当在ArrayList任意位置插入或者删除元素时&#xff0c;就需要将后序元素整体往前或者往后搬移&am…

Java设计模式:Callback

介绍 回调&#xff08;Callback&#xff09;是一种设计模式&#xff0c;在这种模式中&#xff0c;一个可执行的代码被作为参数传递给其他代码&#xff0c;接收方的代码可以在适当的时候调用它。 在真实世界的例子中&#xff0c;当我们需要在任务完成时被通知时&#xff0c;我…

【Linux】从零开始学习Linux基本指令(一)

&#x1f6a9;纸上得来终觉浅&#xff0c; 绝知此事要躬行。 &#x1f31f;主页&#xff1a;June-Frost &#x1f680;专栏&#xff1a;Linux入门 &#x1f525;该文章主要了解Linux操作系统下的基本指令。 目录&#xff1a; ⌛️指令的理解⏳目录和文件的理解⏳一些常见指令✉…

C++入门篇11 模板进阶

一、非类型模板参数 模板参数分为类型形参和非类型形参 类型形参&#xff1a;出现在模板参数列表里&#xff0c;跟在class/typename之后的参数类型名称非类型参数&#xff1a;就是用一个常量作为类(函数)模板的一个参数&#xff0c;在类(函数)模板中可将参数当作常量来使用 …

SRAM电路设计

RAM是随机存取存储器&#xff08;random access memory&#xff09;&#xff0c;是计算机内部存储器中的一种&#xff0c;也是其中最重要的&#xff0c;计算机和手机中一般把其叫做&#xff08;运行&#xff09;内存&#xff0c;它的速度要比硬盘快得多&#xff0c;所以用运行程…

设计师都应该知道的事:极简主义家具该怎么去用

这座房子有黑暗而沉重的特征&#xff0c;包括棕色和白色的马赛克浴室瓷砖&#xff0c;弯曲的锻铁壁灯和土黄色的威尼斯石膏墙。但由于房屋与他们的风格相去甚远&#xff0c;白色&#xff0c;干净和简约&#xff0c;接下来我们就着这个方向去帮助房主进行改造。 她解释说&#x…

uniapp 小程序实现图片宽度100%、高度自适应的效果

因为image组件默认是有宽度跟高度的&#xff0c;所以这个高度不怎么好写 通过load事件来控制图片的高度 话不多说&#xff0c;直接上代码&#xff0c; <image class"img" src"/static/image.png" :style"{ height: imgHeight px }"mode&q…

【linux】E45: ‘readonly‘ option is set (add ! to override)

vim 编辑文件保存时 E45:设置了“只读”选项&#xff08;添加&#xff01;以覆盖&#xff09; 输入&#xff1a; wq! 提示 "/etc/my.cnf" E212: Cant open file for writing 依然是没有权限&#xff1a; 解决一&#xff1a; 切换用户&#xff1a; su root 解…

Elastic Cloud v.s. Zilliz Cloud:性能大比拼

Elastic Cloud v.s. Zilliz Cloud:性能大比拼 Zilliz 经常会收到来自开发者和架构师的提问:“Zilliz Cloud 和 Elastic Cloud 比起来,谁进行向量处理能力比较强?” 诸如此类的问题很多,究其根本,大都是开发者/架构师在为语义相似性检索系统进行数据库选型时缺少决策依据有…

网络层:常见的面试题和答案

1、什么是IPv4和IPv6&#xff1f;它们有什么区别&#xff1f; 答&#xff1a;IPv4是32位的IP地址格式&#xff0c;而IPv6是128位的IP地址格式。IPv4地址空间有限&#xff0c;而IPv6地址空间更大&#xff0c;可以提供更多的地址。 2、说说 HTTP 和HTTPS 的区别&#xff1f; H…