当前位置: 首页 > 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]区间内的所有数全…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

鸿蒙(HarmonyOS5)实现跳一跳小游戏

下面我将介绍如何使用鸿蒙的ArkUI框架&#xff0c;实现一个简单的跳一跳小游戏。 1. 项目结构 src/main/ets/ ├── MainAbility │ ├── pages │ │ ├── Index.ets // 主页面 │ │ └── GamePage.ets // 游戏页面 │ └── model │ …...

macOS 终端智能代理检测

&#x1f9e0; 终端智能代理检测&#xff1a;自动判断是否需要设置代理访问 GitHub 在开发中&#xff0c;使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新&#xff0c;例如&#xff1a; fatal: unable to access https://github.com/ohmyzsh/oh…...

MySQL体系架构解析(三):MySQL目录与启动配置全解析

MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录&#xff0c;这个目录下存放着许多可执行文件。与其他系统的可执行文件类似&#xff0c;这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中&#xff0c;用…...

渗透实战PortSwigger Labs指南:自定义标签XSS和SVG XSS利用

阻止除自定义标签之外的所有标签 先输入一些标签测试&#xff0c;说是全部标签都被禁了 除了自定义的 自定义<my-tag onmouseoveralert(xss)> <my-tag idx onfocusalert(document.cookie) tabindex1> onfocus 当元素获得焦点时&#xff08;如通过点击或键盘导航&…...