当前位置: 首页 > news >正文

C++ 为什么建议类模板定义在头文件中,而不定义在源文件中

类模板 XXXX

  • 模板的编译模式
    • 模板不是实际的代码,而是一个“代码生成模板”
  • 分离定义会导致链接错误
  • 补充
    • 为什么普通类可以分离定义?
    • 对比
    • C++11的export关键字(已弃用)

模板的编译模式

C++模板采用两阶段编译(Two-Phase Translation):

阶段一(定义阶段):编译器解析模板本身的语法,检查基本错误(如语法错误)。

阶段二(实例化阶段):当模板被具体使用时(例如MyTemplate),编译器才会生成特定类型的代码(实例化)。

注意:实例化发生在模板被使用的代码处(调用处),而非模板定义处。因此,模板的完整定义必须对调用者可见。

模板不是实际的代码,而是一个“代码生成模板”

(1)只有当你用具体类型实例化模板时(如MyTemplate),编译器才会根据模板定义生成该类型的实际代码。
(2)实例化的触发点:在调用模板的代码处(如main.cpp中使用了MyTemplate),编译器需要当场生成MyTemplate的代码。
(3)因为模板实例化是编译期行为,编译器必须在编译main.cpp时就能看到foo的实现,才能为int版本生成代码。
(4)当编译main.cpp时,编译器看到MyTemplate的声明,但找不到foo的实现(因为定义在另一个.cpp中)。编译器无法生成MyTemplate::foo的代码,导致链接错误。

分离定义会导致链接错误

如果将类模板的声明和实现分离到头文件(.h)和源文件(.cpp)中:

// mytemplate.h
template <typename T>
class MyTemplate {
public:void foo(T x); // 只有声明
};// mytemplate.cpp
template <typename T>
void MyTemplate<T>::foo(T x) { /* 实现 */ } // 定义在.cpp中

当其他文件(如main.cpp)使用该模板时:

// main.cpp
#include "mytemplate.h"
int main() {MyTemplate<int> obj;obj.foo(42); // 链接错误:找不到foo的实例化实现!
}

原因:
main.cpp 只看到声明,不知道 foo 的实现,无法实例化 MyTemplate::foo。
而 mytemplate.cpp 中的定义未被触发实例化(因为没有代码要求它实例化int版本)。

补充

为什么普通类可以分离定义?

(1)非模板类(普通类)的成员函数在链接时可以通过目标文件(.obj/.o)找到定义。而模板的实例化是编译期行为,需在编译调用代码时“看到”完整定义。
(2)普通类的成员函数在链接时找到定义
普通类的成员函数是实际存在的代码,编译后会保存在目标文件(.obj/.o)中。
调用普通类成员函数时,编译器只需知道函数的声明,链接器会在后续阶段从目标文件中找到定义。

对比

// ordinary.h
class Ordinary {
public:void bar(int x); // 只有声明
};// ordinary.cpp
void Ordinary::bar(int x) { /* 实现 */ } // 定义在.cpp中// main.cpp
#include "ordinary.h"
int main() {Ordinary obj;obj.bar(42); // 链接时从ordinary.obj中找到bar的定义
}
  1. 编译阶段:
    对普通类,编译器只需知道bar的声明即可编译main.cpp。
    对模板类,编译器需要当场生成代码,因此必须看到定义。
  2. 链接阶段:
    对普通类,链接器从ordinary.obj中提取bar的实现。
    对模板类,如果定义不可见,链接器找不到实例化的代码(因为根本未被生成)。

C++11的export关键字(已弃用)

C++曾尝试通过export关键字支持分离模板定义(如export template),但实现复杂且未被编译器广泛支持,最终从标准中移除。

相关文章:

C++ 为什么建议类模板定义在头文件中,而不定义在源文件中

类模板 XXXX 模板的编译模式模板不是实际的代码&#xff0c;而是一个“代码生成模板” 分离定义会导致链接错误补充为什么普通类可以分离定义&#xff1f;对比C11的export关键字&#xff08;已弃用&#xff09; 模板的编译模式 C模板采用两阶段编译&#xff08;Two-Phase Tran…...

Android studio学习之路(八)---Fragment碎片化页面的使用

fragment的用法很常见&#xff0c;你可能经常看见这样的画面&#xff1a; 通过滑动来进行切换页面&#xff0c;今天我们就来实现这样的形式 介绍 使用 Fragment 的核心价值在于 ​​模块化设计​​ 和 ​​动态适配能力​​&#xff0c;尤其适合以下场景&#xff1a; 需要…...

数据结构和算法(九)--红黑树

一、红黑树 1、红黑树 前面介绍了2-3树&#xff0c;可以看到2-3树能保证在插入元素之后&#xff0c;树依然保持平衡状态&#xff0c;它的最坏情况下所有子结点都是2-结点&#xff0c;树的高度为IgN&#xff0c;相比于我们普通的二叉查找树&#xff0c;最坏情况下树的高度为N,确…...

字节跳动开源数字人模型latentsync1.5,性能、质量进一步优化~

项目背景 LatentSync1.5 是由 ByteDance 开发的一款先进的 AI 模型&#xff0c;专门针对视频唇同步&#xff08;lip synchronization&#xff09;任务设计&#xff0c;旨在实现音频与视频唇部动作的高质量、自然匹配。随着 AI 技术的快速发展&#xff0c;视频生成和编辑的需求…...

Pygame入门:零基础打造你的第一个游戏窗口

Pygame入门:零基础打造你的第一个游戏窗口 大家好,欢迎来到本期的技术分享!今天,我们将一起探索如何使用Python中的Pygame库来创建一个简单的游戏窗口。无论你是编程新手,还是对游戏开发感兴趣的朋友,这篇文章都将帮助你迈出第一步。让我们开始吧! 什么是Pygame? 在…...

《ATPL地面培训教材13:飞行原理》——第13章:高速飞行

翻译&#xff1a;刘远贺&#xff1b;工具&#xff1a;Cursor & Cluade 3.7&#xff1b;过程稿 第13章&#xff1a;高速飞行 目录 引言声速马赫数恒定指示空速爬升对马赫数的影响恒定马赫数下真空速随高度的变化恒定飞行高度和指示空速下温度对马赫数的影响气动流动的细分…...

【C语言练习】004. 使用各种运算符进行计算

【C语言练习】004. 使用各种运算符进行计算 004. 使用各种运算符进行计算1. 算术运算符2. 关系运算符3. 逻辑运算符4. 位运算符5. 赋值运算符6. 逗号运算符综合示例输出结果004. 使用各种运算符进行计算 在C语言中,运算符用于执行各种数学和逻辑运算。以下是一些常见的运算符…...

Pygame事件处理详解:键盘、鼠标与自定义事件

Pygame事件处理详解:键盘、鼠标与自定义事件 在游戏开发中,玩家的交互是至关重要的。无论是移动角色、触发动作还是暂停游戏,都需要通过各种输入来实现。Pygame作为一个功能强大的Python库,提供了丰富的API来处理这些输入,包括键盘、鼠标以及自定义事件。本文将详细介绍如…...

16. LangChain自主智能体(Autonomous Agent):模拟人类工作流的进阶设计

引言&#xff1a;当AI学会"思考"与"行动" 2025年某跨国律所的合同审查智能体&#xff0c;通过自主规划任务流&#xff0c;将平均处理时间从8小时缩短至23分钟。本文将基于LangChain的AgentExecutor与Deepseek-R1&#xff0c;揭示如何构建能自主决策、动态…...

直接映射例题及解析

目录 基本单位换算 例题一 &#x1f4c1; Tag Directory&#xff08;标签目录&#xff09; 是什么&#xff1f; 例题二 例题三 例题四 串行访问还是并行访问的选择 例题五 例题六 例题七 &#x1f535; P1&#xff1a;&#xff08;按行访问&#xff09; &#x1…...

MAVLink协议:原理、应用与实践

目录 1. 前言 2. MAVLink 协议的基本概念 2.1 协议概述 2.2 消息格式 2.3 协议版本 3. MAVLink 协议的适应场景 3.1 无人机地面站与飞行器通信 3.2 飞行器与传感器通信 3.3 无人机集群通信 3.4 飞行模拟与测试 4. 基于 Python 的 MAVLink 协议编程实践 4.1 开发环境…...

【记一次亚马逊普华永道审计流程】

1、2025年2月21日 收到审计邮件 2、2025年2月25日未及时关注注册开发者的邮箱导致一直未回复 3、2025年3月4日亚马逊警告邮件-依旧未回复 4、2025年3月13日APP正式被亚马逊开发者商店下架 停用影响: APP从官方商店下架&#xff0c;不能授权新店铺 停用原因: 由于此邮箱为注册…...

Java 异常处理全解析:从基础到自定义异常的实战指南

Java 异常处理全解析&#xff1a;从基础到自定义异常的实战指南 一、Java 异常体系&#xff1a;Error 与 Exception 的本质区别 1. 异常体系核心架构 Java把异常当作对象来处理&#xff0c;并定义一个基类java.lang.Throwable作为所有异常的超类。 在Java API中已经定义了许…...

二、UI自动化测试02--元素定位方法

目录 一、定位⼀组元素⽅法二、XPath 定位⽅法1. 路径策略1.1 路径值获取⽅法 2. 利⽤元素属性策略利⽤元素属性策略的注意事项 3. 属性和逻辑结合4. 层级和属性结合策略5. XPath 延伸⽅法 三、CSS 定位⽅法1. CSS 策略: id选择器/class选择器/元素选择器/属性选择器2. 属性选择…...

第二章 信息技术发展(2.1 信息技术及其发展)

2.1 信息技术及其发展 2.1.1 计算机软硬件 计算机硬件 (Computer Hardware) 是指计算机系统中由电 、机械和光电元件等组成 的各 种物理装置的总称计算机软件 (Computer Software) 是指计算机系统中的程序及其文档,程序是计 算任务的处理对象和处理规则的描述;文档是为了便千…...

【SwitchyOmega安装教程】

目录 一、插件安装 1. 下载安装文件 2. 打开浏览器扩展安装页面 3. 安装插件 二、界面详情 三、配置信息 3.1 设置IP 1、查看IP地址信息 2、批量测试IP是否有效 3、点击扩展程序&#xff0c;选择 Proxy SwitchyOmega 4、 点击选项进行配置 5、配置页面 一、插件安装 1…...

驱动开发硬核特训 · Day 21(上篇加强版):深入理解子系统机制与实战初探

&#x1f4c5; 日期&#xff1a;2025-04-27 &#x1f4da; 技术平台&#xff1a;嵌入式Jerry&#xff08;B站&#xff09; 1. 为什么要有子系统&#xff1f;&#xff08;深度版&#xff09; 在 Linux 内核发展早期&#xff0c;设备管理较为混乱&#xff0c;每种设备&#xff0…...

GoFly快速开发框架新增UI素材库-帮助开发者快速开发管理后台UI基于ArcoDesign框架开发

说明&#xff1a; 为开发者提供管理台的UI素材&#xff0c;社区将持续为开发开发后台系统常用UI界面&#xff0c;让开发时能有一半的界面可以直接从UI库获取&#xff0c;减少开发者自己排版界面的时间&#xff0c;帮助开发者快速开发后台业务。 使用的前端版本要求&#xff1…...

Unity-Shader详解-其二

前向渲染和延迟渲染 前向渲染和延迟渲染总的来说是我们的两种主要的渲染方式。 我们在Unity的Project Settings中的Graphic界面能够找到渲染队列的设定&#xff1a; 我们也可以在Main Camera这里进行设置&#xff1a; 那这里我们首先介绍一下两种渲染&#xff08;Forward R…...

Windows 安装 Neo4j 教程

Windows 安装 Neo4j 教程 Neo4j 是一个开源的图数据库&#xff0c;它以图形结构存储数据&#xff0c;适合用于处理高度连接的数据&#xff0c;广泛应用于社交网络、推荐系统、欺诈检测等场景。本文将为你介绍如何在 Windows 系统上安装和配置 Neo4j 数据库。 一、安装前准备 …...

Neo4j 常用查询语句

Neo4j 常用查询语句 Neo4j 是一个图数据库&#xff0c;查询语言是 Cypher&#xff0c;它类似于 SQL 但针对图形数据进行了优化。Cypher 语法直观易懂&#xff0c;适合用来处理图数据。本文将介绍一些 Neo4j 中常用的查询语句&#xff0c;帮助你快速掌握图数据的操作方法。 一…...

机器学习(10)——神经网络

文章目录 1. 神经网络基本原理1.1. 什么是神经网络1.2. 核心思想 2. 基础组件3. 前向传播&#xff08;Forward Propagation&#xff09;4. 反向传播&#xff08;Backpropagation&#xff09;5. 激活函数对比6. 网络架构类型7. 优化策略8. Python示例&#xff08;PyTorch&#x…...

Qt软件开发-摄像头检测使用软件V1.1

系列文章目录 Qt软件开发-摄像头检测使用软件V1.1 文章目录 系列文章目录前言一、V1.1增加了哪些功能&#xff1f;二、代码构成1.总体结构2. 代码内容 三、效果展示图总结 前言 之前&#xff0c;在Qt软件开发-摄像头检测使用软件&#xff1a;https://blog.csdn.net/xuming204…...

AI日报 - 2025年04月26日

&#x1f31f; 今日概览(60秒速览) ▎&#x1f916; 模型竞赛 | OpenAI与Google新模型在Arena榜单激烈角逐&#xff0c;性能指标各有千秋。 OpenAI发布o3/o4-mini等新模型&#xff0c;Gemini 2.5 Pro紧随其后&#xff0c;数学、编程能力成焦点。 ▎&#x1f4bc; 商业动向 | 并…...

ES6 Map/WeakMap/Set/WeakSet 全解指南

一、设计思想与核心概念 1. 解决传统结构的痛点 Object&#xff1a;键只能是字符串/Symbol、无序、无size属性Array&#xff1a;查找效率低(O(n))、无自动去重机制核心突破&#xff1a;// 传统方式 vs ES6方式 const obj { [{}]: value }; // 键会被转为"[object Obje…...

【Python】使用uv管理python虚拟环境

本文介绍了python虚拟环境管理工具uv&#xff0c;包括uv的作用、uv的常用命令等等。 参考&#xff1a;UV - 管理Python 版本、环境、第三方包 1. 介绍uv 官网&#xff1a;https://docs.astral.sh/uv/ uv是一个python虚拟环境管理工具&#xff0c;可以用来替代pip、pyenv、vir…...

求解,如何控制三相无刷电机?欢迎到访评论

问题&#xff1a;通过一个集成的TF2104芯片控制H桥上桥臂和下桥臂&#xff0c;如何控制&#xff1f;还是说得需要PWM_UH和PWM_UL分开控制&#xff1f;...

002 六自由度舵机机械臂——姿态解算理论

00 DH模型的核心概念 【全程干货【六轴机械臂正逆解计算及仿真示例】】 如何实现机械臂的逆解计算-机器谱-robotway DH模型是机器人运动学建模的基础方法&#xff0c;通过​​四个参数​​描述相邻关节坐标系之间的变换关系。其核心思想是将复杂的空间位姿转换分解为绕轴旋转…...

部署大模型需要多少GPU显存?以DeepSeek R1部署为例

引言 部署大型语言模型&#xff08;LLM&#xff09;时究竟需要多少GPU显存&#xff1f;本文将进行一次简单测算。 如何计算 算法1 可以用一个简单的公式来计算显存占用&#xff08;单位GB&#xff09;&#xff1a; 参数说明如下&#xff1a; 符号 含义 M 所需的 GPU 显存…...

C++?类和对象(下)!!!

一、前言 在之前我们已经讨论过了有关类和对象的前置知识以及类中的六大默认成员函数&#xff0c;在本期我们继续再讨论类和对象中剩余的友元、初始化列表等相关知识&#xff0c;如果需要再了解之前的知识的话&#xff0c;链接奉上&#xff1a;C&#xff1f;类和对象&#xff0…...

function,bind,lambda的用法

C中的std::function、std::bind与Lambda表达式详解 一、std::function std::function是C11标准引入的类模板&#xff0c;用于封装任意类型的可调用对象&#xff0c;例如函数指针、Lambda表达式、函数对象等。通过std::function可以实现不同形式可调用对象的统一存储与调用…...

Maven的聚合工程与继承

目录 一、为什么需要使用Maven工程 二、聚合工程的结构 三、聚合工程实现步骤 四、父工程统一管理版本 五、编译打包 大家好&#xff0c;我是jstart千语。想着平时开发项目似乎都是用maven来管理的&#xff0c;并且大多都是聚合工程。而且在maven的聚合工程中&#xff0c…...

‌C/C++对时间的处理

1. 两种数据结构 time_t‌ 是一个在C和C++编程语言中用于表示时间的类型。time_t类型通常是一个长整型(long int)或整数类型,用于表示从特定参考点(通常是1970年1月1日00:00:00 UTC)经过的秒数。 time_t定义在<ctime>头文件中,通常用于记录时间戳,比如获取当前时间…...

Spring Boot 支持政策

&#x1f9d1;&#x1f4bb; Spring Boot 支持政策 ✒️ Andy Wilkinson 于2023年12月7日编辑本页 32次修订 &#x1f4cc; 核心政策 &#x1f6e1;️ VMware Tanzu 开源支持政策 Spring Boot 针对关键错误和安全问题提供支持 &#x1f4c6; 版本支持周期 1️⃣ 主要版本&a…...

实验四 进程调度实验

一、实验目的 1、了解操作系统CPU管理的主要内容。 2、加深理解操作系统管理控制进程的数据结构--PCB。 3、掌握几种常见的CPU调度算法&#xff08;FCFS、SJF、HRRF、RR&#xff09;的基本思想和实现过程。 4、用C语言模拟实现CPU调度算法。 5、掌握CPU调度算法性能评价指…...

静态多态和动态多态的区别

C多态机制深度解析 多态是面向对象编程的核心特性&#xff0c;允许通过统一接口执行不同实现。在C中&#xff0c;多态表现为基类指针或引用调用虚函数时&#xff0c;根据实际对象类型执行对应派生类的函数逻辑。 基础实现示例 定义基类与派生类&#xff0c;演示动态绑定…...

现代化Android开发:Compose提示信息的最佳封装方案

在 Android 开发中&#xff0c;良好的用户反馈机制至关重要。Jetpack Compose 提供了现代化的 UI 构建方式&#xff0c;但提示信息(Toast/Snackbar)的管理往往显得分散。本文将介绍如何优雅地封装提示信息&#xff0c;提升代码可维护性。 一、基础封装方案 1. 简单 Snackbar …...

Android学习总结之Retrofit篇

1. 注解原理概述 在 Java 里&#xff0c;注解是一种元数据&#xff0c;它为代码提供额外信息但不影响程序的实际逻辑。注解可以在类、方法、字段等元素上使用&#xff0c;并且能在编译时、运行时通过反射机制被读取。Retrofit 充分利用了 Java 注解机制&#xff0c;通过自定义…...

Python 第 12、13 节课 - 元组和列表

- 第 94 篇 - Date: 2025 - 04 - 26 Author: 郑龙浩/仟墨 【Python 在校课堂笔记】 Python 第 12、13 节课 - 元组和列表 上课时间: 2025-04-21&#xff08;12&#xff09; 2025-04-24&#xff08;13&#xff09; 文章目录 Python 第 12、13 节课 - 元组和列表一 元组1 元组的…...

新特性版本升级指引

✨ 升级到新特性版本时的配置迁移 1️⃣ &#x1f527; 配置迁移工具说明 当您将应用升级到新特性版本时&#xff0c;可能需要处理部分配置属性的重命名或移除问题。 2️⃣ &#x1f680; 启用方法 Spring Boot 提供了环境分析工具&#xff1a; 应用启动时打印诊断信息运行时…...

6.1 客户服务:智能客服与自动化支持系统的构建

随着企业数字化转型的加速&#xff0c;客户服务作为企业与用户交互的核心环节&#xff0c;正经历从传统人工服务向智能化、自动化服务的深刻变革。基于大语言模型&#xff08;LLM&#xff09;和智能代理&#xff08;Agent&#xff09;的技术为构建智能客服与自动化支持系统提供…...

从新手到高手:小程序开发进阶技巧分享

小程序开发从入门到精通需要经历技术积累、架构优化和工程化实践等多个阶段。以下是结合真实项目经验的进阶路线与核心技术要点&#xff0c;涵盖性能优化、架构设计、跨平台开发等关键领域&#xff1a; 一、性能调优实战技巧 1. 首屏渲染加速方案 // 预请求关键数据&#xff…...

S参数的含义

S参数的含义&#xff1a; 在低速设计时代&#xff0c;工程界普遍使用等效集总电路模型来描述互连通道的过孔、连接器等各部分。对于上升时间达到几个ns的低速数字信号&#xff0c;甚至可以使用一个0Ω电阻代替连接器&#xff0c;分析的结果也不会和实际情况有太大的差别。但是当…...

职场十二法则-马方

马方老师的《职场十二法则》,献给初入职场工作中迷茫的自己。 1.挣钱是能力的副产品&#xff0c;能力比挣钱重要&#xff0c;让自己值钱比有钱更重要。成长比赚钱重要&#xff0c;年轻时把成长放第一位&#xff0c;挣钱放第二位&#xff0c;通过提升能力实现长期收益。 2.成长…...

安装docker,在docker上安装mysql,docker上安装nginx

目录 一.安装docker 1.1查看Linux版本的命令这里推荐两种&#xff1a; 1.2查看内核版本有三种方式&#xff1a; 2.安装 2.1 如果之前安装了docker&#xff0c;先删除旧版本的doker 2.2 安装需要的软件包&#xff0c;yum-util提供yum-config-manager功能&#xff0c;另外两…...

Java基础第五章、面向对象程序设计

1.package包 如果引入的不同包里面有相同的类名时&#xff0c;需要对要使用的类进行完整的限定名指定。 2.访问修饰符 子类对父类的方法重写也遵循上面的原则 一个java文件中最多只能有一个public(和文件同名)的类。 3.初始化块 //Driver.java public class Driver {private lo…...

RD电子实验记录本选用贴士A-B-C

传统的实验记录本&#xff0c;令人又爱又恨本 如何挑选电子实验室记录本&#xff08;ELN&#xff09;的品牌/服务商/供应商&#xff1f; 电子实验记录本&#xff0c;又名为ELN&#xff0c;Electronic lab notebook&#xff0c;enotebook&#xff0c;研发电子管理系统&#xf…...

Python 第 11 节课 - string 与 random 的方法

- 第 93 篇 - Date: 2025 - 04 - 26 Author: 郑龙浩/仟墨 【Python 在校课堂笔记】 Python 第 11 节课 - string 与 random 的方法 上课时间: 2025-04-14 文章目录 Python 第 11 节课 - string 与 random 的方法一 string 的方法1 s.split()2 s.find()3 s.replace()4 s.strip…...

proxychains4系统代理for linux(加速国内github下载速度,pip安装)

1.proxychains4代理安装&#xff1a; sudo apt-get install proxychains42.找到配置文件/etc/proxychains4.conf在[ProxyList]后面添加以下内容&#xff1a; socks5 127.0.0.1 10808 配置如下&#xff1a; 3.使用proxychains4(git clone)&#xff1a; proxychains4 git c…...

LLM基础之源码一

transformers 核心源码梳理 Trainer部分&#xff1a; __init__() 初始化函数&#xff1a; def __init__(xxx):if args is None:output_dir "tmp_trainer"args TrainingArguments(output_diroutput_dir) self.args argsself.compute_loss_func compute_loss_fun…...