浅谈C++的模板—— 这一篇就够了

今天我们来谈谈C++中有关于模板的知识😊😊😊,对于C++模板来说,我们首先得了解以下几个术语

  • 函数模板
  • 模板函数
  • 模板实例化
  • 模板特例化
  • 模板的实参推演
  • 模板的非类型参数
  • 非模板函数
  • 类模板
  • 模板类
  • 选择性实例化

下面,我们将对这几个有关于模板的术语进行详述的论述

浅谈C++的模板—— 这一篇就够了

    • 一、函数模板
    • 二、模板实例化、实参推演、非模板函数
    • 三、模板特例化、非类型参数
    • 四、类模板、模板类、选择性实例化
    • 五、模板代码的使用方法

一、函数模板

函数模板是一种通用的函数定义,可以用来表示一类相似的函数。它可以使用泛型编程技术来编写通用的代码,使得函数能够适应不同的数据类型。通过在函数体中使用模板参数,可以实现对不同数据类型进行相同的操作,具体使用方式如下代码:

template<typename T>
返回类型 函数名(参数列表)
{ //函数体
}

其中,template 是关键字,也可以用 class 代替,用于声明一个函数模板,<typename T> 是模板参数列表,可以在其中指定一个或多个类型参数,用于指定将要使用的数据类型,T 是类型参数的名称,可以根据需要自定义。

📢📢📢需要注意:函数模板定义仅仅只是模板的声明,不是实际的函数定义,实际的函数定义是在函数模板被实例化时,根据具体的模板参数生成的,编译时由于参数类型不确定,编译器是不会对它进行编译的

优点:

  • 提高代码的重用性和可维护性,减少代码冗余。它可以通过一次定义和实现,实现对多种数据类型的支持。

缺点:

  • 函数模板会增加编译时间,并且对于复杂的模板参数,可能存在性能损失的问题。因此,在使用函数模板时需要权衡其优缺点,并选择合适的方式来应用。

使用函数模板时,可以通过显示实例化或隐式实例化来生成具体函数

  • 显示实例化是指在编译时将模板参数替换为具体的类型或值,即compare<指定的类型>(各种参数)
  • 隐式实例化是在调用函数时由编译器自动推断参数类型,即compare(各种参数)

二、模板实例化、实参推演、非模板函数

模板实例化: 指编译器根据特定的类型参数将函数模板生成一个具体的函数或者类的过程
实参推演: 在函数调用过程中,根据函数参数的类型和传递给函数的实际参数的值推断出函数模板参数或自动推导模式类型的过程
非模板函数: 没有使用template<...>

下面给出一段代码:

template<typename T>  //定义一个模板参数列表 typename/class也可以
bool compare(T a, T b) //compare是一个函数模板
{cout << "template compare" << endl;return a > b;
}//template<typename T>
//bool compare<int>(int a, int b)
//{
//	cout << "template compare" << endl;
//	return a > b;
//}int main()
{compare<int>(10, 20);return 0;
}

当主函数执行到compare函数的调用点时,编译器会根据用户指定的类型,从原函数模板实例化出来一个函数代码,也就是代码中被注释的模板函数,供主函数正常使用

但是在这里,我们会有个疑问:如若我们不指定对应的类型<T>呢 ?

template<typename T>
.... compare bool compare(const char* a, const char* b)
{
... //非模板函数  -》  普通函数
}int main()
{compare(10, 40.2);  //编译器会找不到对应的模板参数列别,报错compare<int>(10.5, 20.6); //指定参数int,强制转化(显示)//没有指定参数列表,自动推导出 const char*,但存在非模板函数的对应函数定义,直接使用非模板函数compare("aaa", "bbb");return 0;
}

三、模板特例化、非类型参数

当我们给上述的函数模板传入的类型为 const char*(这里仅作演示,其他类型某些也可以),准备让它实例化一个模板函数用于字符串的比较时,经过程序的执行,会直接比较内存地址的大小,并不是我们想要的字符串比较,即处理逻辑有误,此时我们就需要针对原函数模板,额外提供一个const char*类型的特例化版本,以独立的完成正常的处理逻辑,代码如下

// 模板的非类型参数
template<typename T, int SIZE>
void func(T *a){}  //针对函数模板,提供const char* 类型的特例化版本
template<>  
bool compare<const char*>(const char* a, const char* b>
{cout << "compare<const char*>" << endl;return strcmp(a, b) > 0;
}

此时当程序再次想要使用对应的传入参数为const char* 的模板函数时,编译器会直接找到模板的特例化版本,执行正确的字符串比较处理逻辑

四、类模板、模板类、选择性实例化

C++类模板: 根据不同的数据类型生成具体的类
模板类: 通过类模板创建的具体类实例
选择性实例化: 在编译时只生成使用过的具体类实例,而不生成未使用的实例

下面给出实现栈的代码:

#include<iostream>
using namespace std;
//类模板进行选择性实例化   ->  模板类  template<typename T = int>
class SeqStack  //模板名称 + 类型参数列表 = 类名称
{
public://构造函数、析构函数可以不加<T>SeqStack(int size = 10) :_pstack(new T[size]), _top(0), _size(size){cout << this << "SeqStack()" << endl;}~SeqStack()  {cout << this << "~SeqStack()" << endl;delete[]_pstack;_pstack = nullptr;}SeqStack(const SeqStack<T>& stack)   //拷贝构造:_top(stack._top), _size(stack._size){_pstack = new T[_size];for (int i = 0; i < _top; i++){_pstack[i] = stack._pstack[i];}}SeqStack<T>& operator=(const SeqStack<T>& stack)  //赋值重载{if (&stack == this) return *this; delete[] _pstack;_top = stack._top;_size = stack._size;_pstack = new T[_size];for (int i = 0; i < _top; i++){_pstack[i] = stack._pstack[i];}}void push(const T& val);void pop(){	if (empty()) return;--_top;}T top() const{if (empty())throw "stack is empty !!!"; return _pstack[_top - 1];}bool full() const { return _top == _size; }bool empty() const { return _top == 0; }private:int* _pstack;int _top;int _size;void expand(){T* Ptmp = new T[_size * 2];for (int i = 0; i < _top; i++){Ptmp[i] = _pstack[i];}delete[]_pstack;_pstack = Ptmp;_size *= 2;}
};template<typename T>
void SeqStack<T>::push(const T& val)  //类外定义类模板的成员方法
{if (full()) expand();_pstack[_top++] = val;
}int main()
{//类模板的选择性实例化SeqStack<int> s(10);s.push(10);s.pop();SeqStack<> s1(10); //使用默认模板类型参数return 0;
}

五、模板代码的使用方法

一般来说,模板的定义常常是放在头文件中的,因为模板的实现需要在编译时进行,并非在链接时。当我们在源文件中包含头文件时,编译器会将头文件的内容复制到源文件中,根据需要实例化模板

但是如果我们在源文件中直接进行模板的声明而不是使用头文件,那么编译器将无法找到模板定义的实现,导致链接错误
在这里插入图片描述

  • 模板代码不能在一个文件中定义,在另一个文件使用的
  • 在模板代码被调用之前,必须能够找到模板定义的位置,才能进行正常的实例化

如果直接在定义文件中声明,告诉编译器,就能直接指定类型的模板实例化,但是不推荐!!!

在这里插入图片描述


🌻🌻🌻以上就是有关浅谈C++的模板—— 这一篇就够了的内容,如果聪明的你浏览到这篇文章并觉得文章内容对你有帮助,请不吝动动手指,给博主一个小小的赞和收藏 🌻🌻🌻

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/752805.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在Visual Studio中调试 .NET源代码

前言 在我们日常开发过程中常常会使用到很多其他封装好的第三方类库&#xff08;NuGet依赖项&#xff09;或者是.NET框架中自带的库。如果可以设置断点并在NuGet依赖项或框架本身上使用调试器的所有功能&#xff0c;那么我们的源码调试体验和生产效率会得到大大的提升。今天我…

数据分析 | Matplotlib

Matplotlib 是 Python 中常用的 2D 绘图库&#xff0c;它能轻松地将数据进行可视化&#xff0c;作出精美的图表。 绘制折线图&#xff1a; import matplotlib.pyplot as plt #时间 x[周一,周二,周三,周四,周五,周六,周日] #能量值 y[61,72,66,79,80,88,85] # 用来设置字体样式…

vulnhub ---- Dr4g0n b4ll

文章目录 网段扫描隐藏目录隐写尝试通过ssh连接提权路径劫持 网段扫描 nmap -sn 命令用于执行主机存活扫描&#xff0c;仅检测目标网络中的活动主机&#xff0c;而不进行端口扫描。 ┌──(root㉿kali)-[~/Downloads] └─# nmap -sn 10.10.10.0/24 …

计算机网络——物理层(宽带接入技术)

计算机网络——物理层&#xff08;宽带接入技术&#xff09; 什么是宽带有线带宽接入xDSLADSL 技术ADSL 的大部分组成 光纤同轴混合网&#xff08;HFC 网&#xff09;机顶盒与电缆调制解调器&#xff08;set-top box&#xff09; FTTx 技术光配线网 ODN (Optical Distribution …

nginx 基本使用、借助 nginx 和 mkcert 实现本地 https://localhost 测试。

CSDN 如何将资源设置为免费&#xff1f; 安装和基本使用 进入 nginx 官网 下载 Mainline version 版本 解压到一个你喜欢的位置&#xff0c;比如解压到 C: 目录 不管配不配置环境变量&#xff0c;对 nginx 的所有操作都应该在对应文件夹中 基本命令的使用&#xff1a; cd …

性能测试 事务 -- HPE Virtual User Generator -Web -HTTP/HTML

软件介绍 Virtual User Generator &#xff0c;记录用户流程并创建一个自动化性能测试脚本 Controller&#xff0c;单一控制点&#xff0c;轻松、有效地控制所有Vuser&#xff0c;执行期间监控场景性能 Analysis&#xff0c;生成性能测试报告&#xff0c;以图表形式呈现。 操…

2024图表分析网页模版大数据可视化大屏电子沙盘合集包含金融行业智慧大厅智慧交通智慧门店智慧物流智慧小区

2024图表分析网页模版大数据可视化大屏电子沙盘合集包含金融行业智慧大厅智慧交通智慧门店智慧物流智慧小区 项目介绍&#xff1a; 图表分析网页模版 大数据可视化大屏电子沙盘合集&#xff0c;项目基于html/css/js&#xff0c;包含行业&#xff1a; 智慧政务 智慧社区 金融行…

mysql 更新时,旧值与新值相同会怎么做?

文章目录 1 问题描述2 验证2.1 验证猜想12.2 验证猜想2 3 结论4 mysql 为什么这么设计呢&#xff1f; 1 问题描述 创建一张表t&#xff0c;插入一行数据 mysql> CREATE TABLE t ( id int(11) NOT NULL primary key auto_increment, a int(11) DEFAULT NULL ) ENGINEInnoDB…

第111讲:Mycat实践指南:固定Hash算法分片下的水平分表详解

文章目录 1.固定Hash算法分片的概念1.1.固定Hash算法的概念1.2.固定Hash算法是如何将数据路由到分片节点的 2.使用固定Hash算法分片对某张表进行水平拆分2.1.在所有的分片节点中创建表结构2.2.配置Mycat实现固定Hash算法分片的水平分表2.2.1.配置Schema配置文件2.2.2.配置Rule分…

unityprotobuf自动生成C#

Release Protocol Buffers v3.19.4 protocolbuffers/protobuf GitHub 导入Source code 里面的 csharp/src/Google.Protobuf 进入Unity 拷贝其他版本的 System.Runtime.CompilerServices.Unsafe进入工程 使用protoc-3.19.4-win32 里面的exe去编译proto文件为C# using Sys…

MybatisPlus-Generator自定义模版生成CRUD、DTO、VO、Convert等

个人博客&#xff1a;无奈何杨&#xff08;wnhyang&#xff09; 个人语雀&#xff1a;wnhyang 共享语雀&#xff1a;在线知识共享 Github&#xff1a;wnhyang - Overview 简介 如标题所言&#xff0c;本篇文章介绍如何使用MybatisPlus-Generator自定义模版生成CRUD、DTO、V…

Redis实战——查询缓存缓存穿透、雪崩、击穿

目录 为什么要使用缓存缓存的作用缓存的成本如何使用缓存缓存模型和思路缓存更新策略数据库和缓存不一致解决方案数据库和缓存不一致采用什么方案对比删除缓存与更新缓存如何保证缓存与数据库的操作同时成功/同时失败先操作缓存还是先操作数据库&#xff1f; 实现商铺缓存与数据…

Tensorflow笔记(二):激活函数、优化器等、神经网络模型实现(商品销量预测)

import tensorflow as tf import numpy as np from tqdm import tqdm# ----------------------------- tensor常用函数2 ----------------------------------- a tf.constant([1, 2, 3, 1, 2]) b tf.constant([0, 1, 3, 4, 5]) c tf.where(tf.greater(a, b), a, b) # 若a&g…

Linux下的多线程编程:原理、工具及应用(4)

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;Flower of Life—陽花 0:34━━━━━━️&#x1f49f;──────── 4:46 &#x1f504; ◀️ ⏸ ▶️ ☰ …

RuoYi-Vue开源项目2-前端登录验证码生成过程分析

前端登录验证码实现过程 生成过程分析 生成过程分析 验证码的生成过程简单概括为&#xff1a;前端登录页面加载时&#xff0c;向后端发送一个请求&#xff0c;返回验证码图片给前端页面展示 前端页面加载触发代码&#xff1a; import { getCodeImg } from "/api/login&q…

Spring6--基础概念

1. 概述 1.1. Spring是什么 Spring 是一套广泛应用于 Java 企业级应用开发领域的轻量级开源框架&#xff0c;由 Rod Johnson 创立&#xff0c;旨在显著降低 Java 企业应用的复杂性&#xff0c;缩短开发周期&#xff0c;并提升开发效率。Spring 不仅适用于服务器端开发&#x…

三个案例,带你看懂智能时代支撑降本增效的底层逻辑

2003年&#xff0c;“神舟五号”成功登上太空&#xff0c;2007年&#xff0c;乔布斯初代苹果发布会&#xff0c;2016年“天宫二号”与“神州十一号”自动交会对接成功&#xff0c;2022年ChatGPT横空出市。 科技发展速度令人惊叹&#xff0c;一不留神就步入了下一个科技时代&am…

【vue elementUI】el-select和弹出框el-option样式调整,::v-deep失效

组件自带样式&#xff1a; 修改后样式&#xff1a; 注意修改弹出框样式需要修改一个属性&#xff1a; 此属性默认值为true&#xff0c;此时可以看到弹出框是放在外面的&#xff0c;没有在el-select里面。此时设置弹窗样式会不生效&#xff0c;::v-deep无效。 需要将此属性改为f…

JavaScript练手小技巧:数字反转时钟

样式基于博主的这篇文章&#xff1a; CSS3技巧38&#xff1a;3D 翻转数字效果-CSDN博客 既然可以实现翻转数字了&#xff0c;肯定就可以跟 JS 相结合去完成一些数字展示效果。 比如&#xff0c;数字反转时钟。 为了方便&#xff0c;所有 HTML 数字根据时间动态生成。因此&a…

vue3 element plus 上传下载

文章目录 上传下载 上传 /* html */ <el-upload v-model"fileId" class"avatar-uploader" ref"exampleUploadRef" :file-list"fileList" :show-file-list"false" action"/ys-three-year/ThreeReport/uploadFile&q…