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

C++模板初阶

C++模板初阶

  • 泛型编程
  • 函数模板
    • 概念
    • 函数模板格式
    • 函数模板原理
    • 函数模板的实例化
    • 模板参数的匹配原则
  • 类模板
    • 类模板的定义格式
    • 类模板的实例化

泛型编程

我们前面学习了C++的函数重载功能,那么我们如何实现一个通用的交换函数呢,比如:我传入int就是交换int,传入double就进行double类型的交换……

void Swap( int& a,  int& b)
{int temp = a;a = b;b = temp;
}
void Swap(double& a, double& b)
{double temp = a;a = b;b = temp;
}
void Swap(char& a, char& b)
{char temp = a;a = b;b = temp;
}
void Swap(int*& a, int*& b)
{int* temp = a;a = b;b = temp;
}

我们可以发现尽管有了函数重载的技术,但是我们还是避免不了所有问题;我们很难写出一个通用的Swap函数,如果我们每增加一个新类型,我们就得重新写一个Swap函数,很麻烦!那么有没有什么办法让我只写一份通用的代码,所有类型都可以用呢?当然有!对于C语言的这种不足,C++在此基础上提出了泛型编程的概念:就是对于一些所有类型都可通用的代码,比如Swap这种我们在写具体实现的时候可以假装我们的数据类型是通用的,然后在对其进行处理,当我们在调用该函数的时候,编译器会自动推演出数据的具体类型,这就好比我们在写方程一样,我们先假设未知数,将未知数先当成已知,最后在解出未知数!这里自动推演数据类型的过程就相当于在解方程!

这个编写通用代码的过程就是在造模子通过给这个模子传递不同的参数类型,来确定具体的数据类型,从而获得具体类型对应的代码,生成具体类型代码的过程是由编译器来帮助我们完成的,我们无需在自己手动写了;

在C++中模板是泛型编程的基础
模板又分为:函数模板、类模板;
在这里插入图片描述

函数模板

概念

函数模板代表了一个函数家族,该函数模板与类型无关,在使用参数时,由编译器根据所传参数类型自动推演函数参数的具体类型,由此产生特定类型的函数版本,这个过程,被称为实例化;

函数模板格式

template<class 类型参数名1,class 类型参数名2,…… >
返回类型 函数名(参数列表)

或者
template<typename 类型参数名1,typename 类型参数名2……>;
返回类型 函数名(参数列表)

注意:typename是用来定义模板参数的关键字,class也可以,但是struct不可以;

实例:写一个通用的交换函数:

template <typename T>
void Swap(T& a, T& b)
{T tmp = a;a = b;b = tmp;
}

在这里插入图片描述

函数模板原理

么如何解决上面的问题呢?大家都知道,瓦特改良蒸汽机,人类开始了工业革命,解放了生产力。机器生产淘汰掉了很多手工产品。本质是什么,重复的工作交给了机器去完成。有人给出了论调:懒人创造世界。
在这里插入图片描述

函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器;

函数模板的实例化

用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化;

1、隐式实例化
在这里插入图片描述
上述Add的调用,就是隐式实例化,编译器会根据我们传递给Add的参数自动推演出类型参数的具体类型,以此来生成具体类型的交换函数来给我们用;
当然我们不能乱传递参数类型,比如:Add(a,x);
在这里插入图片描述
编译器在调用该Add函数的时候,根据左参数类型先推演出类型参数T为int类型,然后又根据有参数类型推演出类型参数T为double类型,那么参数类型到底具体为那个类型?这就会让编译器陷入歧义,编译器也就会报错,Add函数也就无法正确实例化!类型参数,会根据以第一次推演出的结果作为默认类型,与auto在一排的用法差不多,但是模板无法完成参数的隐式转换!
那如果我们就是要调用Add(a,x);函数应该怎么办?
有两种解决办法:
1、强转a,或强转x,就是将a,x的类型转换成一致的;
2、显示实例化;
2、显示实例化:
就是明确指定类型参数的具体类型,不需要编译器再根据参数类型自动推演了;明确指定参数的具体类型过后,编译器就会自动生成具体函数,来供调用处使用!
比如上述的Add(a,x)
我们像这样做:Add<int>(a,x);显示的指定类型参数为int,编译器就会自动生成参数类型为int的Add函数:
在这里插入图片描述
如果类型不匹配编译器会自动尝试隐式转换!无法完成完成隐式类型转换的编译器直接报错;
这里的隐式类型转换与上面隐式调用的类型转换不一样,这里使明确规定了类型参数的具体类型,也就是先生成了具体函数,才有的隐式类型转换;上面是根据参数类型推演类型参数的具体类型,然后再生成匹配的函数,参数不匹配,无法生成具体函数,怎么能进行隐式转换呢?

模板参数的匹配原则

1、非模板函数与函数模板同名,同时函数模板还可以实例化成非模板函数,编译器会优先调用非模板函数
在这里插入图片描述
为什么会出现这种情况呢?
编译器是很聪明的,如果我们去调用函数模板时,编译器会首先根据参数类型推演出类型参数的具体类型,然后实例化出具体的Add函数来调用,你看啊,现在我明明有现成的Add函数可以用,那么我们为什么还要去实例化,再调用呢?这不是脱了裤子放屁,多此一举嘛!
那如果我们非要调用模板实例化出来的Add函数,该怎么办呢?
当然是显示调用:
在这里插入图片描述
2、对于非模板函数与同名函数模板,其他条件都相同,但是非模板函数的参数类型与调用处的类型不一样,编译器会根据函数模板实例化出最匹配的函数来调用:
在这里插入图片描述
3、对于隐式实例化函数模板,不会发生隐式类型转换;对于显示实例化函数模板,可以发生隐式类型转换;

类模板

类模板的定义格式

template<class T1,class T2,class T3,……>
class 类模板名
{
//类成员定义;
};

比如现在我们写一个栈类模板:

template <class T>
class Stack
{Stack(){int capacity = 4;_a = new T[capacity];_top = 0;_capacity = capacity;}~Stack(){delete[] _a;_top = _capacity = 0;}
private:T* _a;int _top;int _capacity;
};

类模板中的成员函数全是模板函数
然后注意此时的Stack不是具体的类,而是编译器根据被实例化的类型生成具体类的模具;
同时类模板的成员函数也可以实现在类内声明,类外定义;
只不过与我们平时写的具体的类的定义方式不太一样:
比如现在我在类内声明构造函数,类外定义构造函数:
在这里插入图片描述
这样我们既能定义基本数据类型为double的栈,也可以定义基本数据类型为int的栈了:
在这里插入图片描述
这时候或许会有读者说,我用typedef也能做到类型替换啊,可是typedef不能做到Stack<int>与Stack<double>两种栈同时存在啊,如果想要这两个栈同时存在,我们就只能再重新定义一个栈,这样很是麻烦!
同时不建议类模板的声明与函数定义分离!

类模板的实例化

类模板的实例化与函数模板的实例化不同,类模板实例化只能通过显示实例化,不能隐式实例化:
在这里插入图片描述

相关文章:

C++模板初阶

C模板初阶泛型编程函数模板概念函数模板格式函数模板原理函数模板的实例化模板参数的匹配原则类模板类模板的定义格式类模板的实例化泛型编程 我们前面学习了C的函数重载功能&#xff0c;那么我们如何实现一个通用的交换函数呢&#xff0c;比如:我传入int就是交换int&#xff…...

文献阅读:Scaling Instruction-Finetuned Language Models

文献阅读&#xff1a;Scaling Instruction-Finetuned Language Models 1. 文章简介2. 实验 1. 数据集 & 模型 1. 数据集考察2. 使用模型 2. scale up对模型效果的影响3. CoT对模型效果的影响4. 不同模型下Flan的影响5. 开放接口人工标注指标 3. 结论 文献链接&#xff1a;…...

gpt草稿

ChatgptWhatChatGPT&#xff08;全名&#xff1a;Chat Generative Pre-trained Transformer [2]&#xff09;是由OpenAI开发的一个人工智能聊天机器人程序&#xff0c;于2022年11月推出。该程序使用基于GPT-3.5架构的大型语言模型并通过强化学习进行训练。ChatGPT里面有两个词&…...

mysal第三次作业

1、显示所有职工的基本信息。 2、查询所有职工所属部门的部门号&#xff0c;不显示重复的部门号。 3、求出所有职工的人数。 4、列出最高工和最低工资。 5、列出职工的平均工资和总工资。 6、创建一个只有职工号、姓名和参加工作的新表&#xff0c;名为工作日期表…...

分页和mmap

文章目录一、内存分页1、基本概念2、分页机制下&#xff0c;虚拟地址和物理地址是如何映射的&#xff1f;3、快表(TLB)二、mmap基本原理和分类一、内存分页 1、基本概念 CPU并不是直接访问物理内存地址&#xff0c;而是通过虚拟地址空间来间接的访问物理内存地址。 页&#x…...

C++之异常处理

异常异常是面向对象语言处理错误的一种方式。当一个函数出现自己无法处理的错误时&#xff0c;可以抛出异常&#xff0c;然后输的直接或者间接调用者处理这个错误。语法捕获全部的异常try {//可能抛出异常的代码//throw异常对象 } catch(...) {//不管什么异常&#xff0c;都在这…...

牛客寒假集训营6 E 阿宁的生成树

E-阿宁的生成树_2023牛客寒假算法基础集训营6 (nowcoder.com)开始慢慢补牛牛的题题意&#xff1a;最小生成树质数距离思路&#xff1a;最小生成树一共就两种算法&#xff0c;我们考虑Prim的过程初始连通块是1&#xff0c;然后考虑拿1和其他的结点连边当j-i<k时边权是gcd&…...

嵌入式C基础知识(10)

C语言如何实现一个频繁使用短小函数&#xff0c;C如何实现&#xff1f;C语言可以使用宏定义实现一个短小函数&#xff0c;如下面例子所示。但是宏定义语句不会进行检查&#xff0c;并且对书写格式有过分的讲究。比如MAX和括号之间不能有空格&#xff0c;每个参数都要放在括号里…...

TC3xx FlexRay™ 协议控制器 (E-Ray)-01

1 FlexRay™ 协议控制器 (E-Ray) E-Ray IP 模块根据为汽车应用开发的 FlexRay™ 协议规范 v2.1 执行通信【performs communication according to the FlexRay™ 1) protocol specification v2.1】。使用最大指定时钟&#xff0c;比特率可以编程为高达 10 Mbit/s 的值。连接到物…...

优劣解距离法TOPSIS——清风老师

TOPSIS法是一种常用的综合评价方法&#xff0c;能充分利用原始数据的信息&#xff0c;其结果能精确地反映各评价方案之间的差距。 基本过程为先将原始数据矩阵统一指标类型&#xff08;一般正向化处理&#xff09;得到正向化的矩阵&#xff0c;再对正向化的矩阵进行标准化处理…...

【Unity3D】Shader常量、变量、结构体、函数

1 源码路径 Unity Shader 常量、变量、结构体、函数一般可以在 Unity Editor 安装目录下面的【Editor\Data\CGIncludes\UnityShader】目录下查看源码&#xff0c;主要源码文件如下&#xff1a; UnityCG.cgincUnityShaderUtilities.cgincUnityShaderVariables.cginc 2 Shader 常…...

LeetCode 刷题系列 -- 496. 下一个更大元素 I

nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。给你两个 没有重复元素 的数组 nums1 和 nums2 &#xff0c;下标从 0 开始计数&#xff0c;其中nums1 是 nums2 的子集。对于每个 0 < i < nums1.length &#xff0c;找出满…...

Docker 搭建本地私有仓库

一、搭建本地私有仓库有时候使用Docker Hub这样的公共仓库可能不方便&#xff0c;这种情况下用户可以使用registry创建一个本地仓库供私人使用&#xff0c;这点跟Maven的管理类似。使用私有仓库有许多优点&#xff1a;1&#xff09;节省网络带宽&#xff0c;针对于每个镜像不用…...

XML中的CDATA且mybatis中特殊字符转义

如果想看如果CDATA在mybatis的xml文件中使用的可以直接跳转。 CDATA1 XML中的CDATA1.1 为什么叫CDATA1.2 CDATA在XML中的语法1.3 CDATA在XML中的例子1.4 CDATA规则2 Mybatis中的CDATA2.1 Mybatis中使用XML转义序列转义2.2 Mybatis中使用CDATA转义2.3 mybatis中使用CDATA需注意的…...

位运算 | 1356. 根据数字二进制下 1 的数目排序

LeetCode 1356. 根据数字二进制下 1 的数目排序 给你一个整数数组 arr 。请你将数组中的元素按照其二进制表示中数字 1 的数目升序排序。如果存在多个数字二进制中 1 的数目相同&#xff0c;则必须将它们按照数值大小升序排列。 文章讲解https://www.programmercarl.com/1356.%…...

React Hooks之useState详解

1. 什么是Hooks&#xff1f; React官方简介&#xff1a;Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。 本文中讲解的useState就是React中的其中一个Hook。 2. useState useState 通过在函数组件里调用它来满足给组件添…...

选购交换机的参数依据和主要的参数指标详解

如何选购交换机&#xff1f;用什么交换机&#xff1f;在选购交换机时交换机的优劣无疑十分的重要&#xff0c;而交换机的优劣要从总体构架、性能和功能三方面入手。交换机选购时。性能方面除了要满足RFC2544建议的基本标准&#xff0c;即吞吐量、时延、丢包率外&#xff0c;随着…...

Connext DDS属性配置参考大全(1)

介绍属性QoS策略存储名称/值(字符串)对,可用于配置Connext DDS的某些参数,这些参数未通过正式的QoS策略公开。 属性QoS策略存储实体的名称/值对。名称和值都是字符串。在核心库用户手册的“Property QosPolicy(DDS Extension)”部分中找到有关RTI Connext DDS属性QoS的更…...

Docker安全

容器的安全性问题的根源在于容器和宿主机共享内核。如果容器里的应用导致Linux内核崩溃&#xff0c;那么整个系统可能都会崩溃。 与虚拟机是不同的&#xff0c;虚拟机并没有与主机共享内核&#xff0c;虚拟机崩溃一般不会导致宿主机崩溃 一、Docker 容器与虚拟机的区别 1、隔…...

刷题记录:牛客NC20279[SCOI2010]序列操作

传送门:牛客 题目描述: lxhgww最近收到了一个01序列&#xff0c;序列里面包含了n个数&#xff0c;这些数要么是0&#xff0c;要么是1&#xff0c;现在对于这个序列有五种变换操作和询问操作&#xff1a; 0 a b 把[a, b]区间内的所有数全变成0 1 a b 把[a, b]区间内的所有数全…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...