【C++初阶(九)】C++模版(初阶)----函数模版与类模版
本专栏内容为:C++学习专栏,分为初阶和进阶两部分。 通过本专栏的深入学习,你可以了解并掌握C++。
💓博主csdn个人主页:小小unicorn
⏩专栏分类:C++
🚚代码仓库:小小unicorn的代码仓库🚚
🌹🌹🌹关注我带你学习编程知识
C++模版(初阶)
- 泛型编程
- 函数模版
- 函数模版的概念
- 函数模版的格式
- 函数模版的原理
- 函数模版的实例化
- 隐式实例化
- 显式实例化
- 函数模版的匹配原则
- 类摸版
- 类模版的定义方式
- 类模版的实例化
泛型编程
回顾一下:如果让你编写一个函数,用于对两个数的交换。在C语言中,我们会用到以下这样:
// 交换两个整型
void Swapi(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
// 交换两个双精度浮点型
void Swapd(double* p1, double* p2)
{double tmp = *p1;*p1 = *p2;*p2 = tmp;
}
但是C语言不支持函数重载,所以用于交换不同类型变量的函数的函数名是不能相同的,并且传参形式必须是址传递,不能是值传递。
而在学习了C++的函数重载和引用后,我们又会用如下方法实现两个数的交换:
// 交换两个整型
void Swap(int& x, int& y)
{int tmp = x;x = y;y = tmp;
}
// 交换两个双精度浮点型
void Swap(double& x, double& y)
{double tmp = x;x = y;y = tmp;
}
C++的函数重载使得用于交换不同类型变量的函数可以拥有相同的函数名,并且传参使用引用传参,使得代码看起来不那么晦涩难懂。
使用函数重载虽然可以实现,但是有一下几个不好的地方:
- 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函
数 - 代码的可维护性比较低,一个出错可能所有的重载均出错
那我们能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成相应的代码呢?
跟浇筑原理一样:如果在C++中,也能够存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件
(即生成具体类型的代码),那将会节省许多头发。
巧的是前人早已将树栽好,我们只需在此乘凉。
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

函数模版
函数模版的概念
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
函数模版的格式
template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表){}
举个例子:
template<typename T>
void Swap(T& x, T& y)
{T tmp = x;x = y;y = tmp;
}
注意:typename是用来定义模板参数关键字,也可以使用class(但是切记:不能使用struct代替class)
函数模版的原理
那么函数模板的底层原理是什么呢?大家都知道,瓦特改良蒸汽机,人类开始了工业革命,解放了生产力。机器生产淘汰掉了很多手工产品。其本质就是将重复的工作交给了机器去完成。
有人给出了论调:懒人创造世界!


懒不是傻懒,如果你想少干,就要想出懒的方法。要懒出风格,懒出境界。
函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器

在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。(编译器:终究是我一个人承担了所有)
函数模版的实例化
用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化
隐式实例化
隐式实例化:让编译器根据实参推演模板参数的实际类型:
例如:
template<typename T>
T Add(const T& x, const T& y)
{return x + y;
}
int main()
{int a = 10, b = 20;int c = Add(a, b); //编译器根据实参a和b推演出模板参数为int类型cout << c << endl;return 0;
}

特别注意:使用模板时,编译器一般不会进行类型转换操作。所以,以下代码将不能通过编译:
int a = 10;
double b = 1.1;
int c = Add(a, b);
因为在编译期间,编译器根据实参推演模板参数的实际类型时,根据实参a将T推演为int,根据实参b将T推演为double,但是模板参数列表中只有一个T,编译器无法确定此处应该将T确定为int还是double。
此时,我们有两种处理方式,第一种就是我们在传参时将b强制转换为int类型,第二种就是使用下面说到的显示实例化。
显式实例化
显示实例化:在函数名后的<>中指定模板参数的实际类型
例如:
template<typename T>
T Add(const T& x, const T& y)
{return x + y;
}
int main()
{int a = 10;double b = 1.1;int c = Add<int>(a, b); //指定模板参数的实际类型为intcout << c << endl;return 0;
}

注意:使用显示实例化时,如果传入的参数类型与模板参数类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功,则编译器将会报错。
函数模版的匹配原则
一、一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
例如:
//专门用于int类型加法的非模板函数
int Add(const int& x, const int& y)
{return x + y;
}
//通用类型加法的函数模板
template<typename T>
T Add(const T& x, const T& y)
{return x + y;
}
int main()
{int a = 10, b = 20;int c = Add(a, b); //调用非模板函数,编译器不需要实例化int d = Add<int>(a, b); //调用编译器实例化的Add函数return 0;
}

二、对于非模板函数和同名的函数模板,如果其他条件都相同,在调用时会优先调用非模板函数,而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数,那么选择模板
//专门用于int类型加法的非模板函数
int Add(const int& x, const int& y)
{return x + y;
}
//通用类型加法的函数模板
template<typename T1, typename T2>
T1 Add(const T1& x, const T2& y)
{return x + y;
}
int main()
{int a = Add(10, 20); //与非模板函数完全匹配,不需要函数模板实例化int b = Add(2.2, 2); //函数模板可以生成更加匹配的版本,编译器会根据实参生成更加匹配的Add函数return 0;
}

三、模板函数不允许自动类型转换,但普通函数可以进行自动类型转换
template<typename T>
T Add(const T& x, const T& y)
{return x + y;
}
int main()
{int a = Add(2, 2.2); //模板函数不允许自动类型转换,不能通过编译return 0;
}
因为模板函数不允许自动类型转换,所以不会将2自动转换为2.0,或是将2.2自动转换为2。

类摸版
类模版的定义方式
template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
例如:
template<class T>
class Score
{
public:void Print(){cout << "数学:" << _Math << endl;cout << "语文:" << _Chinese << endl;cout << "英语:" << _English << endl;}
private:T _Math;T _Chinese;T _English;
};
注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。
template<class T>
class Score
{
public:void Print();
private:T _Math;T _Chinese;T _English;
};
//类模板中的成员函数在类外定义,需要加模板参数列表
template<class T>
void Score<T>::Print()
{cout << "数学:" << _Math << endl;cout << "语文:" << _Chinese << endl;cout << "英语:" << _English << endl;
}
除此之外,类模板不支持分离编译,即声明在xxx.h文件中,而定义却在xxx.cpp文件中。
类模版的实例化
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后面根<>,然后将实例化的类型放在<>中即可。
//Score不是真正的类,Score<int>和Score<double>才是真正的类Score<int> s1;Score<double> s2;
注意:类模板名字不是真正的类,而实例化的结果才是真正的类。
相关文章:
【C++初阶(九)】C++模版(初阶)----函数模版与类模版
本专栏内容为:C学习专栏,分为初阶和进阶两部分。 通过本专栏的深入学习,你可以了解并掌握C。 💓博主csdn个人主页:小小unicorn ⏩专栏分类:C 🚚代码仓库:小小unicorn的代码仓库&…...
Permission denied
Permission denied:权限被拒绝,没有访问文件的权限。 查询对文件的权限: ls -l 文件名称 r为可读权限,w为可写权限,x为可执行权限。 授权文件rwx,可读可写可执行权限: chmod 777 文件名称 如…...
轻松学会电脑如何录制音频
随手录音,保留证据以便后续出现问题进行判定,或者保存会议音频记录方便后续根据录音内容整理自己会议记录不足之处等等;越来越多的地方需要用到录音,那么在电脑上该如何进行音频录制呢?特别是使用比较广泛的Windows电脑…...
react antd,echarts全景视图
1.公告滚动,40s更新一次 2.echarts图标 左右轮播 60s更新一次 3.table 表格 import { useState, useEffect } from react;import Slider from react-slick; import slick-carousel/slick/slick-theme.css; import slick-carousel/slick/slick.css;import Layout fro…...
GD32 支持IAP的bootloader开发,使用串口通过Ymodem协议传输固件(附代码)
资料下载: https://download.csdn.net/download/wouderw/88714985 一、概述 关于IAP的原理和Ymodem协议,本文不做任何论述,本文只论述bootloader如何使用串口通过Ymodem协议接收升级程序并进行IAP升级,以及bootloader和主程序两个工程的配置…...
【C#】知识点实践序列之UrlEncode在线URL网址编码、解码
欢迎来到《小5讲堂》,大家好,我是全栈小5。 这是2024年第8篇文章,此篇文章是C#知识点实践序列文章, 博主能力有限,理解水平有限,若有不对之处望指正! 地址编码大家应该比较经常遇到和使用到&…...
泽攸科技完全自主研制的电子束光刻机取得阶段性成果
国产电子束光刻机实现自主可控,是实现我国集成电路产业链自主可控的重要一环。近日,泽攸科技联合松山湖材料实验室开展的全自主电子束光刻机整机的开发与产业化项目取得重大进展,成功研制出电子束光刻系统,实现了电子束光刻机整机…...
上篇 | CDP应用篇之兴趣标签的3种破圈玩法
谈到客户洞察,在这个以客户为中心、以数据为驱动的客户经营时代,贯通数据,联动CDP客户数据平台、SCRM、会员、营销一站式的客户洞察解决方案,成为了头部房企们的万千宠爱。其中关于人群兴趣标签的破圈玩法,我们结合过往…...
智能的核心依然是哲学的三个基本问题
智能的发展与哲学的三个基本问题密切相关,作为一个复杂领域,智能涉及到人类认知和行为的模拟与复制,因而也会涉及到哲学的核心问题。 存在论:智能的存在论问题涉及到什么是智能以及智能系统的本质。这包括对于意识、思维和自主性的…...
用python实现提取word中的所有图片
你可以使用python-docx库来处理word文件,然后遍历文件中的所有形状,找到图片。 首先,你需要安装python-docx库。在命令行中输入以下命令进行安装: 复制代码 pip install python-docx 然后,你可以使用以下代码提取wo…...
CoTracker 环境配置与ORB 特征点提取结合实现视频特征点追踪
CoTracker 环境配置&与ORB 特征点提取结合实现视频特征点追踪 文章目录 CoTracker 环境配置&与ORB 特征点提取结合实现视频特征点追踪Step1:配置 CoTracker 环境Step2:运行官方的例程Step3:结合 ORB 特征点提取结果展示: …...
10000000000 大瓜背后的真相(附 PDD 算法真题)
10 个亿的大事? 京东诉阿里强迫商家「二选一」,京东胜诉,获阿里赔偿 10 亿。 很多小伙伴见到公主号开创了锐评时事板块,当天就在后台留言问我看法。 先说结论:这是一则「媒体影响力」远大于「实际意义」的报道。 首先&…...
python爬虫,简单的requests的get请求,百度搜索实例
1、百度搜索实例 import requests url https://www.baidu.com/s? # key_word 迪丽热巴 key_word input(输入搜索内容:) headers {User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537…...
UNION 和 UNION ALL
概述 UNION 和 UNION ALL 都是 SQL 中用于将多个 SELECT 语句的结果合并成一个结果集的操作符。它们都适用于需要将多个表或查询结果合并在一起的情况。但是它们的行为略有不同。 区别 UNION 和 UNION ALL 的区别在于,UNION 会将结果集合并成一个不含重复行的结果…...
NPS 内网穿透安装
NPS 内网穿透安装 NPS 内网穿透安装服务端搭建SSH配置流程 NPS 内网穿透安装 NPS分为服务端和客户端,对应的不同操作系统软件可以在GitHub RELEASES自行选择下载。 服务端搭建 由于个人非企业级使用,为了方便直接使用docker安装 1.docker运行 (注意…...
【C++学习笔记】C++多值返回写法
C不像python可以轻易地处理多值返回问题,处理使用指针或者引用将需要返回的值通过参数带出来,还有几种特殊的方式。 引用自:https://mp.weixin.qq.com/s/VEvUxpcJPsxT9kL7-zLTxg 1. Tuple tie 通过使用std::tie,我们可以将tuple…...
读取带有梯度的张量的具体的值
问题:存在一个带有梯度的张量tensor_example,怎么读取它具体的值 方法:可以使用 .detach().cpu().numpy() 的组合。这样可以在保留值的同时,将张量从计算图中分离(detach)并移动到 CPU 上。 示例…...
【分布式微服务专题】SpringSecurity快速入门
目录 前言阅读对象阅读导航前置知识笔记正文一、Spring Security介绍1.1 什么是Spring Security1.2 它是干什么的1.3 Spring Security和Shiro比较 二、快速开始2.1 用户认证2.1.1 设置用户名2.1.1.1 基于application.yml配置文件2.1.1.2 基于Java Config配置方式 2.1.2 设置加密…...
EasyRecovery2024永久免费版电脑数据恢复软件
EasyRecovery是一款操作安全、价格便宜、用户自主操作的非破坏性的只读应用程序,它不会往源驱上写任何东西,也不会对源驱做任何改变。它支持从各种各样的存储介质恢复删除或者丢失的文件,其支持的媒体介质包括:硬盘驱动器、光驱、…...
iphone 苹果 IOS 越狱详细图文保姆级教程非常简单
现在随着各个工具的升级,越狱的难度也是越来越低,还记得 iphone 4 的时候我越狱还是花钱请别人搞得,现在只要你的机型支持越狱,下个工具点一点就可以了,非常简单 目前来说整个越狱过程中,寻找合适机型是最…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
实战三:开发网页端界面完成黑白视频转为彩色视频
一、需求描述 设计一个简单的视频上色应用,用户可以通过网页界面上传黑白视频,系统会自动将其转换为彩色视频。整个过程对用户来说非常简单直观,不需要了解技术细节。 效果图 二、实现思路 总体思路: 用户通过Gradio界面上…...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...
