C++模板

研究:同样的C++模板在多个cpp里出现,编译器是否要重复生成? 2023年就要过去,马上要跨如2024年。祝大家在新的一年,有个好收成。一直以来不是很确定:同样的的模板,在各个cpp分别出现,编译器要实现几份?研究一下。 阅读详情

C++ Templates 模板全套知识点详解

一、基础概念:模板、函数模板 / 类模板

1. 什么是模板

模板是C++泛型编程核心,把类型/常量做成参数,一份代码适配多种数据类型,避免重复写 int/float/string 版本的重复代码。
本质:编译器根据传入参数,自动生成对应类型的函数/类代码(代码生成机制)。

2. 函数模板(通用函数)

语法:template<参数列表> + 普通函数

// T 是类型参数,代表任意类型
template<typename T>
T max(T a, T b) {
    return a > b ? a : b;
}

// 调用
max(1, 2);    // T=int
max(3.14, 2.5); // T=double

typename 和 class 在模板参数里完全等价:template<class T> 效果一样。

3. 类模板(通用容器/数据结构)

语法:template<参数列表> + 类定义

template<typename T>
class Vector {
private:
    T* data;
public:
    void push_back(T val);
    T get(int idx);
};

// 使用
Vector<int> vi;    // 存储int的数组
Vector<string> vs;  // 存储字符串的数组

二、模板的实例化、模板函数 / 模板类

1. 模板本身≠可执行代码

template<...> 只是蓝图/图纸,不会生成机器码;只有用到具体类型时,编译器才会生成实体代码,这个过程叫实例化。

2. 模板函数

函数模板实例化后,生成的具体类型函数称为模板函数:

template<typename T> void func(T) {}

func(10);   // 实例化 void func<int>(int) → 模板函数
func(3.14); // 实例化 void func<double>(double) → 另一个模板函数

3. 模板类

类模板实例化后得到的具体类叫模板类:

template<typename T> class Box {};
Box<int> b1;  // 实例化得到 Box<int> 模板类
Box<string> b2; // Box<string> 另一个独立类

4. 两种实例化方式

  1. 隐式实例化(自动推演):上面调用 max(1,2),编译器自动推导出 T=int,自动生成代码。
  2. 显式实例化:手动指定类型,强制生成代码
    template int max<int>(int, int); // 显式实例化int版本max
    template class Vector<double>;   // 显式实例化Vector<double>
    

三、模板实参的推演(函数模板专属)

只针对函数模板,编译器自动从函数入参推导模板参数T,不用手动写 <int>。

1. 基础推演

template<typename T> void print(T x) {}
print(99);    // 实参int → T=int
print("abc"); // 实参const char[4] → T=const char*

2. 推演限制场景(无法自动推演,必须显式指定)

模板参数只出现在返回值,不出现在函数形参时,推演失效:

template<typename T> T create() { return T(); }
create<int>(); // 必须手动写<int>,没有入参无法推T

3. 推演匹配规则

  • 数组实参 → 推演为指针;
  • const/引用会参与推演;
  • 自动忽略顶层const(底层const保留)。

四、模板的类型参数 / 非类型参数

模板尖括号 <> 里分两种参数:类型参数、非类型参数。

1. 类型参数(最常用)

用 typename/class 修饰,代表一种数据类型(int、string、自定义类等)

template<typename T, class U> // T、U都是类型参数
void swap(T& a, U& b) {}

2. 非类型参数(常量参数)

不是类型,是编译期常量值,支持整数、指针、引用、枚举等,必须是编译期确定的值。
语法:直接写类型+参数名,不加 typename

// N是非类型参数,编译期常量整数
template<int N>
class Array {
private:
    int buf[N]; // 固定大小数组,大小由N指定
};

Array<10> arr1;  // N=10
Array<256> arr2; // N=256
限制:
  • 不能传变量:int n=5; Array<n> x; 报错,n是运行期变量;
  • C++17前非类型参数不能是浮点数、类对象。

五、模板的特化 / 特例化(Specialization)

通用模板对所有类型一套逻辑;特化为某一类/某一个类型单独重写一套逻辑,分全特化、偏特化。

1. 全特化(完全特化)

给模板所有参数指定固定值,针对单一类型单独实现。
示例:通用Vector,单独给 bool 类型特殊优化

// 通用类模板
template<typename T>
class Vector { /* 通用实现 */ };

// bool类型全特化版本
template<> // 尖括号空,所有参数都指定死了
class Vector<bool> {
    // 单独优化:用bit存储bool,节省内存
};

函数模板全特化:

template<typename T> void show(T x) { cout << x; }
template<> void show<string>(string s) { cout << "字符串:" << s; }

2. 偏特化(部分特化,仅类模板支持)

只固定一部分模板参数,剩余参数依然泛型。
示例:模板有T、N两个参数,只固定N=64,T任意

template<typename T, int N> class Buffer {};

// 偏特化:N固定64,T仍可变
template<typename T>
class Buffer<T, 64> {
    // N=64专属逻辑
};

特化优先级

调用时优先匹配特化版本,没有特化才走通用基础模板。

六、模板函数和非模板函数的重载

C++允许同时存在:同名普通函数 + 函数模板,构成重载,编译器有固定匹配优先级:

  1. 优先匹配完全匹配的普通非模板函数(优先级最高);
  2. 无匹配普通函数,再用函数模板推演实例化;
  3. 模板推演有多个候选,选最匹配的。

代码示例

// 普通非模板函数
void max(int a, int b) {
    cout << "普通int版本";
    return a > b ? a : b;
}

// 函数模板
template<typename T>
T max(T a, T b) {
    cout << "模板泛型版本";
    return a > b ? a : b;
}

max(1, 2);      // 匹配普通int函数,不走模板
max(3.1, 2.9);  // 无匹配普通函数,调用模板double版本
max("a", "b");  // 调用模板const char*版本

手动强制走模板

就算有普通函数,想强制使用模板版本,加空尖括号:

max<>(1, 2); // 强制触发模板推演,调用模板int版本

整体知识脉络总结

  1. 模板分两大分支:函数模板、类模板;
  2. 模板只是蓝图,使用时触发实例化生成实体(模板函数/模板类);
  3. 模板参数两类:类型参数(代表类型)、非类型参数(编译期常量);
  4. 函数独有:模板实参自动推演;
  5. 特化:给特定类型定制专属逻辑,分全特化、偏特化;
  6. 重载规则:普通函数 > 模板函数,可共存重载。

需要我把以上知识点整理一份可直接编译的完整综合示例代码吗?

在VisualStudio添加CPP模板 创建一个模板项目:导出模板:自定义模板内容:重新导入模板: 重启 Visual Studio,您的模板将出现在新建项目的模板列表中。 方法 2:使用代码片段(Code Snippets) 打开代码片段管理器:添加自定义代码片段: 使用代码片段: 在 文件中,输入快捷键 ,然后按 键,注释模板将自动插入。 方法 3:直接修改默认模板 找到默认模板文件: 修改模板:保存并重启 Visual Studio: 阅读详情

相关推荐

RedPanda-CPP项目模板:打造高效C/C++开发工作流

在C/C++开发中,项目初始化与工程配置是开发者常面临的基础挑战。其核心原理在于通过预定义的文件结构和配置脚本,自动化完成目录创建、构建系统配置和编译选项设置。这项技术的价值在于将重复性劳动固化为可复用的模板,显著提升开发效率并降低配置错误。在实际应用场景中,无论是快速启动控制台应用、构建静态库,还是开发带图形界面的Qt程序,一个设计良好的项目模板都能让开发者从繁琐的配置中解放,直接聚焦核心逻辑编写。本文以RedPanda-CPP为例,深入解析如何利用其模板机制,结合CMake构建系统和现代C++工程实践,

weixin_34221073的博客 503

C++学习15:C++模板的参数

C++模板的参数

2920

深度学习、图像分类入门,从VGG16卷积神经网络开始

刚开始接触深度学习、卷积神经网络的时候非常懵逼,不知道从何入手,我觉得应该有一个进阶的过程,也就是说,理应有一些基本概念作为奠基石,让你有底气去完全理解一个庞大的卷积神经网络: 本文思路: 一、我认为学习卷积神经网络必须知道的几个概念: 1、卷积过程:   我们经常说卷积神经网络卷积神经网络,到底什么才是卷积?网络层卷积过程到底怎么实现?我们在这里借鉴了另一位博客大牛的动态图来给大

Errors_In_Life的博客 16万+

C++类模板参数

C++类模板参数

Jasmine-Lily的博客 2376

Multisim仿真电路:(十二)MOS管缓启动电路设计与优化

本文详细介绍了基于Multisim的MOS管缓启动电路设计与优化方法。通过分析米勒平台效应,探讨RC参数选择、多级设计和有源电路等技巧,有效抑制冲击电流并优化开关损耗。文章结合仿真实例,提供实用的设计策略和实际应用注意事项,帮助工程师提升电源管理系统的可靠性。

pytorch8learner的博客 237

XY2-100协议解析

1.XY2-100包括四路信号 : SENDCK(时钟信号)、SYNC(同步信号)、CHANNELX(X通道)、CHANNELY(Y通道)

qq_38360574的博客 9535

【C++ 泛型编程 中级篇】深度解析C++:类型模板参数与非类型模板参数

C++模板(C++ Templates)是C++编程中一种强大的工具,它允许程序员编写在类型或值上参数化的代码。这种技术的灵感来源于人类的"抽象思维"能力——我们总是倾向于通过识别和归纳共同特征来理解和分类世界。 想象一下,你正在编写一个函数来交换两个整数的值。很快,你可能会意识到这个函数也可以用来交换两个浮点数或甚至两个自定义类型的对象。但是,如果没有模板,你需要为每种类型都写一个交换函数。这显然是冗余的,因为交换两个元素的逻辑在所有类型之间是相同的。

探索C++编程的奥秘,分享深入的技术见解和实践,旨在激发读者创造力与解决问题的思维。 792

Proxmox VE(PVE)与UPS联动配置:实现智能断电保护方案

本文详细介绍了为Proxmox VE (PVE)服务器配置UPS智能断电保护的完整方案。通过安装和配置apcupsd软件,实现PVE与UPS的联动,可在市电中断、电池电量不足时自动触发安全关机流程,有效保护虚拟机数据与服务连续性。文章涵盖了硬件选择、软件配置、策略设定及实战测试指南,并扩展了网络共享UPS的高级应用。

python9snake的博客 511

C++:模板

在这个例子中,multiply(3, 4) 直接使用了默认的模板参数 T = int,而 multiply<double> 明确指定了模板参数。因为p1的地址小于p2,但是我们想比较的是p1和p2指向的日期。非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。类类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称。函数可以接受任意类型的参数,只要这两个参数的类型相同。模板参数分 类类型参数与非类型参数。定义了一个模板,其中。

2303_80078385的博客 740

SAP系统从ECC升级至S/4 HANA的实现路径及项目过程

从SAP ECC升级到 S/4 HANA,通常是一个复杂的转型过程,涉及到企业资源规划系统的全面现代化

saplakes的博客 2905

o型圈沟槽设计_O型密封圈——详细选型过程及步骤

一、密封圈常用材料二、密封圈常用密封形式密封圈分为活塞密封,活塞杆密封,端面密封,旋转密封。三、O型密封圈的选型规则O型密封圈的尺寸图径向安装O型圈选型(静态和动态运动)活塞杆密封选择适当规格的O形圈时,应该保证其外径(d1+2*d2)至少等于或者大于沟槽外径d6;当选择的O形圈直径d1大于250 mm时, O形圈外径将不能超过沟槽外径的3%;当选择的O形圈直径d1小于250mm时, O形圈外径将...

weixin_39856630的博客 2万+

全面总结C++类模板使用的基础知识

✨引言 建立一个通用类,类中的成员数据类型可以不具体确定,先用一个虚拟的类型来代表示例: 先使用template关键字声明类模板,接着创建Person类,属性name和age用虚拟类型T1和T2声明,这就是最简单的类模板定义。示例: 可以看到第一行代码T2的后面指定了类型为整型,所以创建类模板对象的时候可以省略T2数据类型的指定,但是切记 :在不给参数列表最后一个虚拟类型指定数据类型的情况下是无法做到参数列表含有默认参数的。 类模板中的成员

叶落秋白的博客 3293

吃透工业通信:C#工控机实现Modbus、OPC UA、Profinet、EtherCAT协议全适配

本文介绍了基于C#的工业通信协议全适配方案,采用分层架构设计实现Modbus、OPC UA、Profinet和EtherCAT四种主流协议的统一管理。核心包括:1)三层架构(应用层、抽象层、协议层)降低耦合;2)定义统一通信接口IIndustrialCommunication;3)工厂模式创建不同协议实例;4)以Modbus TCP为例展示具体实现。该方案经过实际项目验证,可简化多协议设备管理,提升工业自动化系统的开发效率。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 725

【C++】模板进阶---cpp模板的深入探索

模板参数分类类型形参与非类型形参。 类型形参,即出现在模板参数列表中,跟在class或者typename之类的参数类型名称。 非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。

专注于前后端学习 1235

AUTOSAR进阶图解==>AUTOSAR_SWS_COM

AUTOSAR COM模块是AUTOSAR通信堆栈的核心组件,提供信号导向的通信服务。该模块位于通信服务层,连接RTE与PDU Router,主要功能包括信号封装/提取、传输模式管理、信号路由、超时监控和字节序转换等。COM模块架构分为应用层、通信服务层和通信抽象层,包含信号管理、I-PDU处理、传输模式管理等组件。其配置结构包括顶层容器、I-PDU组、I-PDU和信号等多层次配置对象,支持丰富的参数设置。模块采用严格的状态管理机制,包括模块状态和I-PDU组状态转换,确保通信可靠性。

一名留德华的,康德的信徒的,专注于汽车电子领域的博客 1245

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

黑马C++笔记——模板(CPP)

C++模板的常见操作

感觉画质不如...原神的博客 988

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

C++ 在.h文件中声明,在.cpp文件中定义 模板函数和模板类

C++ 需要模板函数的定义和声明要放在一起,这样才能根据调用需要选择编译具体的实例。如果我们需要多种实例,每个实例要编译一次,就需要编译多次。在模板函数实现妥当以后,当我们在其它文件中使用某些模板函数的时候,基本所有实例都会被重新编译。如果每次编译时间过长,势必会停滞我们的思维,拖长开发进度。所以在模板函数实现妥当以后,我们希望他只编译一次,在非当前模块被修改时,他也不会被重新编译。这篇博客就是介绍

Expressing Youself Using Code 1万+

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

【C++】简单理解CPP模板

了解模板的概念,函数模板与类模板,以及它们的基础用法

DEXTERFUTIAN的博客 702

c++ 模板的实现位置讨论(.h cpp)

本文,仅针对模板函数的写的位置做讨论(记录)。          首先,c++的模板是要有调用,才会被编译的。  因为本身函数要被编译成具体的参数,函数名,返回值类型的一条函数记录(个人理解),记录在函数表中, 而模板本身就是一个泛型, 只有被调用的时候才会产生一个具体的函数记录。  比如        template Class TestC { Public:        

mincheat的专栏 1025

【CPP】CPP的模板(前篇)

模板是分割C和C++的重要的分水线,决定了C语言注定不能取代C++设计模板一般咱称作为泛型编程,泛型编程即通过数据类型编写代码,使得同一段代码能够不断复用,提高了代码的复用性模板一般分为函数模板类模板public:,_size(0),_capa(n){}~Stack()_size = 0;_capa = 0;"

2302_79981653的博客 1603

【CPP杂货篇】C++模板(超详细)

函数模板代表了一个函数家族,该函数模板与类型无关,在使用时才被参数化,根据实参类型产生函数的特定类型版本。定义格式:class 类模板名// 类内成员定义模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生增强了代码的灵活性模板会导致代码膨胀问题,也会导致编译时间变长出现模板编译错误时,错误信息非常凌乱,不易定位错误。

2302_78684687的博客 862

RedPanda-CPP项目模板使用技巧:快速创建专业C/C++工程

RedPanda-CPP是一款基于Qt开发的轻量级C/C++集成开发环境(IDE),它提供了丰富的项目模板功能,帮助开发者快速搭建专业的C/C++工程。本文将详细介绍如何充分利用RedPanda-CPP的项目模板,提升开发效率,让你轻松创建规范的C/C++项目。 ## 为什么使用项目模板? 项目模板是RedPanda-CPP的核心功能之一,它能够: - 提供标准化的项目结构,确保代码组织一致性

gitblog_01423的博客 883

CPP模板编程

语法形式如下:多个参数用逗号分隔。template <typename t1,typename t2,...... > 返回值类型 函数名(参数列表){//函数体template <class t1,class t2,......> 返回值类型 函数名(参数列表){//函数体template关键字表示这是一个模板定义。typename T声明了一个类型参数T,表示函数可以接受任何类型作为此参数。模板定义中 <> 里的内容即模板参数列表,不能为空t1 : t2;

qq_59805046的博客 1137

c++详解模板泛型编程,详解类模板的实现为什么不能放在cpp文件

泛型编程是一种编程范式,它允许程序员编写与类型无关的代码,从而在编译期确定具体的类型。我们通过模板编写一个函数可以让编译器,自动生成对应类型的实现,这大大减少了重复代码的出现,还提高了代码的可维护性和可扩展性,很重要的一点是模板有特性。

z3363的博客 1067

Cpp-Templates-2ed完全指南:从C++11到C++20的终极模板编程教程

C++模板是C++11至C++20标准中最复杂也最强大的特性之一,是构建高性能基础设施库不可或缺的技术。本教程将带你从基础到进阶,全面掌握现代C++模板编程的核心技术与最佳实践。 ## 为什么模板是C++开发者的必备技能 🚀 模板作为C++的元编程基础,允许开发者编写与类型无关的通用代码,在保持类型安全的同时实现代码复用。无论是STL标准库、Boost库,还是现代C++基础设施,模板技术都扮

gitblog_00195的博客 683

cpp之模板

这里只针对模板对于一些数组或者类作为参数的情况,函数模板无法正确运行了;我们可以运用以前学过的运算符重载,不过那会显得非常麻烦,所以这里就有了函数模板的重载,即提供一个具体化的模板。如果是全局函数在类内实现友元函数那么直接实现就可以了,但是如果是在类外实现友元函数,我们需要提前让编译器知道全局函数的存在。,这和之前的默认函数参数规则是一样的,不过要注意的是如果我们全部使用了默认参数也要在调用时写上空列表即。不仅要告知编译器模板参数的存在,还要告知其不为普通函数的类外实现,而是函数模板的类外实现。

2303_80883523的博客 1509
上一篇: 结构体对齐
下一篇: C++ 类编译器默认生成的十大特殊成员函数
越甲八千
博客等级 码龄11年 2959粉丝 553原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值