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

C++中模板的初级使用函数模板(刚刚接触模板概念的小白也能明白)

文章目录

  • 模板分类
  • 函数模板
  • 函数模板的原理
  • 函数模板基本语法 —— typename 以及 class
  • 简单的函数模板
  • 多类型模板参数
  • class 和 typename 的选择
  • 类模板

模板分类

模板的核心思想是让编译器在编译时生成适用于具体类型的代码,这个过程称为模板实例化。C++ 中的模板分为两种:函数模板和类模板。
在这里插入图片描述
本文对于模板的讲解仅包含模板中函数模板的部分,即初阶讲解类模板仅包含一小部分提供一些示例

函数模板

  1. 泛型编程
    如何实现一个通用的交换函数呢?
    接下来我们通过我们常见的一个简单函数进行引入:
void Swap(int& left, int& right){int temp = left;left = right;right = temp;}void Swap(double& left, double& right){double temp = left;left = right;right = temp;}void Swap(char& left, char& right){char temp = left;left = right;right = temp;}......

使用函数重载虽然可以实现,但是有一下几个不好的地方:

  1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数
  2. 代码的可维护性比较低,一个出错可能所有的重载均出错那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?

这是我们经常写的两个值交换函数,但是在我们交换不同类型数据的时候,我们就需要对这个交换函数再进行一份书写,这样就会显得整个代码程序写的非常冗余,所以在C++当中,引出了模板的这个概念

在 C++ 中,函数模板是一种可以编写泛型代码的机制。它允许你编写一个函数,而不需要预先定义具体的数据类型。函数模板可以用于处理不同类型的参数,而不需要为每个类型编写不同的函数。通过函数模板,C++ 提供了一种类型无关的编程方法。

函数模板的原理

在这里插入图片描述
在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。

函数模板基本语法 —— typename 以及 class

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

在模板参数列表中,class 和 typename 是等价的,可以互换使用。

简单的函数模板

示例:

#include <iostream>
using namespace std;template <typename T>
T add(T a, T b) {return a + b;
}int main() {cout << add(3, 4) << endl;        // 整数相加,输出 7cout << add(3.5, 4.2) << endl;    // 浮点数相加,输出 7.7return 0;
}

在这个例子中,add 函数是一个模板函数,它接受两个类型相同的参数,并返回它们的和。模板参数 T 使得这个函数能够同时处理 int、double 等多种类型。

#include <iostream>
using namespace std;template <class T>
T max_value(T a, T b) {return (a > b) ? a : b;
}int main() {cout << max_value(10, 20) << endl;         // 整数比较,输出 20cout << max_value(3.14, 2.71) << endl;     // 浮点数比较,输出 3.14return 0;
}

在这个例子中,模板参数 T 可以是任何类型,当我们调用 max_value 时,C++ 编译器会根据传递的参数自动推导 T 的类型。这个函数模板可以处理整数、浮点数等不同类型。

多类型模板参数

函数模板可以包含多个模板参数,允许不同类型的输入。例如:

#include <iostream>
using namespace std;template <typename T1, typename T2>
auto multiply(T1 a, T2 b) -> decltype(a * b) {return a * b;
}int main() {cout << multiply(10, 2.5) << endl; // 整数和浮点数相乘,输出 25.0return 0;
}
#include <iostream>
using namespace std;template <class T1, class T2>
auto add(T1 a, T2 b) -> decltype(a + b) {return a + b;
}int main() {cout << add(10, 2.5) << endl;       // 整数和浮点数相加,输出 12.5cout << add(100L, 200) << endl;     // 长整型和整型相加,输出 300return 0;
}

class 和 typename 的选择

如果你是在模板参数列表中声明类型参数,你可以自由选择 class 或 typename,两者没有任何功能上的区别。

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

类模板

除了函数模板,C++ 还支持类模板,使类可以处理不同的数据类型。下面是一个简单的类模板的例子,它实现了一个通用的容器类 Box,可以存储任何类型的数据。

格式:

template<class T1, class T2, ..., class Tn> 
class 类模板名
{// 类内成员定义
};   

示例

#include <iostream>
using namespace std;template <class T>
class Box {
private:T value;
public:Box(T v) : value(v) {}void display() const {cout << "Box contains: " << value << endl;}
};int main() {Box<int> intBox(123);           // 创建存储整数的 BoxBox<double> doubleBox(3.14);    // 创建存储浮点数的 BoxBox<string> stringBox("Hello"); // 创建存储字符串的 BoxintBox.display();      // 输出: Box contains: 123doubleBox.display();   // 输出: Box contains: 3.14stringBox.display();   // 输出: Box contains: Helloreturn 0;
}

在这个类模板中,class T 表示模板参数 T,可以是任何类型。我们可以创建不同类型的 Box 对象,比如 int, double, 或 string,每个 Box 对象会存储相应类型的数据。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 基于python+django+vue的影视推荐系统
  • 【Kubernetes】常见面试题汇总(十七)
  • 【计算机网络】第一章
  • 容器内的Nodejs应用如何获取宿主机的基础信息-系统、内存、cpu、启动时间,以及一个df -h的坑
  • 【计网】从零开始使用TCP进行socket编程 ---服务端业务模拟Xshell
  • 变脸大师:基于OpenCV与Dlib的人脸换脸技术实现
  • 掌握Spring Boot数据库集成:用JPA和Hibernate构建高效数据交互与版本控制
  • 【学习笔记】数据结构(六 ②)
  • 如何切换淘宝最新镜像源npm
  • 数字化转型中的企业蓝图构建:基于业务能力建模的全面解读与战略实施指南
  • 基于C语言+SQL Server2008实现(控制台)图书管理系统
  • 编程技巧:SQL 处理超大查询
  • 【machine learning-十-梯度下降-学习率】
  • node.js+Koa框架+MySQL实现注册登录
  • “科学突破奖”获得者连续两篇Nature,成功绘制人类主要激酶底物特异性图谱
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • Angular 响应式表单之下拉框
  • exif信息对照
  • Java到底能干嘛?
  • java概述
  • PHP那些事儿
  • storm drpc实例
  • 对话:中国为什么有前途/ 写给中国的经济学
  • 来,膜拜下android roadmap,强大的执行力
  • 力扣(LeetCode)965
  • 面试总结JavaScript篇
  • 那些年我们用过的显示性能指标
  • 如何用vue打造一个移动端音乐播放器
  • 三栏布局总结
  • 深入 Nginx 之配置篇
  • 使用agvtool更改app version/build
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • 思考 CSS 架构
  • 通过获取异步加载JS文件进度实现一个canvas环形loading图
  • 职业生涯 一个六年开发经验的女程序员的心声。
  • MiKTeX could not find the script engine ‘perl.exe‘ which is required to execute ‘latexmk‘.
  • 《码出高效》学习笔记与书中错误记录
  • 新海诚画集[秒速5センチメートル:樱花抄·春]
  • #我与Java虚拟机的故事#连载11: JVM学习之路
  • (1)无线电失控保护(二)
  • (C语言)深入理解指针2之野指针与传值与传址与assert断言
  • (NO.00004)iOS实现打砖块游戏(十二):伸缩自如,我是如意金箍棒(上)!
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (附源码)springboot 基于HTML5的个人网页的网站设计与实现 毕业设计 031623
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (十六)一篇文章学会Java的常用API
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • .aanva
  • .net core MVC 通过 Filters 过滤器拦截请求及响应内容
  • .NET Framework .NET Core与 .NET 的区别
  • .net 连接达梦数据库开发环境部署
  • .net 怎么循环得到数组里的值_关于js数组
  • @private @protected @public
  • [ linux ] linux 命令英文全称及解释
  • [383] 赎金信 js