【C++进阶】模板与仿函数:C++编程中的泛型与函数式编程思想
📝个人主页🌹:Eternity._
⏩收录专栏⏪:C++ “ 登神长阶 ”
🤡往期回顾🤡:栈和队列相关知识
🌹🌹期待您的关注 🌹🌹
❀模板进阶
- 🧩<<仿函数>>
- 📕1. 仿函数的概念
- 📚2. 仿函数的用途
- 🧩<<模板>>
- 📕1. 非类型模板参数
- 📚2. 模板的特化
- ⭐函数模板特化
- ⭐类模板特化
- 🌞全特化
- 🌙偏特化
- 📜3. 模板分离编译
- 🍂模板的分离编译
- 🍁解决方法
- 📒4. 模板总结
- 🔥【优点】
- 💧【缺陷】
- 📖5. 总结
前言:在C++编程的广阔天地中,模板和仿函数是两大不可或缺的工具。模板以其强大的类型抽象能力,使得代码复用和泛型编程成为可能;而仿函数,则以其函数对象的特性,为算法和容器提供了灵活多变的操作方式。然而,这两者的深入理解和应用,往往需要程序员具备扎实的编程基础和丰富的实践经验
本文我将带领大家走进模板编程的进阶世界,探索仿函数在实际开发中的应用。我们将从模板的基本概念出发,逐步深入到模板的元编程、特化、偏特化等高级话题,同时结合仿函数的定义、使用场景 一起分析
让我们一同踏上这场关于模板进阶与仿函数应用的探索之旅吧!
🧩<<仿函数>>
📕1. 仿函数的概念
概念: 仿函数(functor)是一个编程术语,其核心概念是指通过实现一个特定的类,使得这个类的使用看上去像一个函数。
具体来说,仿函数是一个类或结构体,它重载了operator()运算符,从而使得这
个类的对象可以像函数一样被调用。
📚2. 仿函数的用途
在我们当前学习的所有知识中,仿函数的用途貌似只涉及到了在STL中的使用,比如我们刚刚了解过的std::priority_queue
,还是之前了解过的std::sort
可以通过传递仿函数作为参数来指定自定义的比较、排序、映射
等操作。这使得STL算法更加灵活和可重用。
优先级队列中的这个排序的操作其实就是通过仿函数比较出来的
仿函数在priority_queue模拟实现中的使用代码示例
(建议结合上一期内容阅读)
// 仿函数的定义
template<class T>
class Less
{
public:// 重载operator()bool operator()(const T& x, const T& y){return x < y;}
};template<class T>
class Greater
{
public:// 重载operator()bool operator()(const T& x, const T& y){return x > y;}
};// priority_queue的模板参数 -> Compare就代表调用的仿函数
template<class T, class Container = vector<T>, class Compare = Less<T>>
注意:在库里面less表示升序,greater则表示降序,默认情况下使用的时less升序
Sort算法中仿函数的使用代码示例
int main()
{vector<int> v = { 7,4,1,2,8,9,4,5 };sort(v.begin(), v.end());cout << "less: ";for (auto e : v){cout << e << " ";}cout << endl;cout << "greater: ";sort(v.begin(), v.end(),greater<int>());for (auto e : v){cout << e << " ";}cout << endl;return 0;
}
仿函数的单独使用你可以就把他想象成一个函数
template<class T>
class Less
{
public:bool operator()(const T& x, const T& y){return x < y;}
};
int main()
{Less<int> L;cout << L(1, 6) << endl;;return 0;
}
总结来说,仿函数是一种强大的编程工具,它允许开发者将功能封装在类中,并通过重载operator()运算符来使这些类的对象具有类似函数的行为。这种灵活性使得仿函数在代码复用、状态保存以及STL算法中使用等方面具有广泛的应用价值
🧩<<模板>>
📕1. 非类型模板参数
模板参数分类类型形参与非类型形参。
- 类型形参:即出现在模板参数列表中,跟在class或者typename之类的参数类型名称。
- 非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用
我们在之前学的所有模板用的基本上都是类型形参,也就是你传什么,他就用什么,而非类型形参则是相当于固定了一个模板参数的类型
类型形参
template<class T, class T>
// ... 其他待添加内容 ...
非类型形参
template<typename T, size_t N = 10>
class Array {
public: T data[N]; // ... 其他成员函数 ...
}; int main() { Array<int, 10> arr; // 创建一个大小为10的整数数组 // ... 使用arr ... return 0;
}
注意:
浮点数、类对象以及字符串
是不允许作为非类型模板参数的- 非类型的模板参数必须在编译期就能确认结果
📚2. 模板的特化
概念: 模板的特化(Template Specialization):在C++中是一种技术,它允许我们为模板的特定类型或值提供定制化的实现。这种技术对于满足特定需求或提高性能非常有用
模板特化主要可以分为两种类型:类模板特化 ,函数模板特化
⭐函数模板特化
函数模板的特化步骤:
- 必须要先有一个基础的函数模板
- 关键字template后面接一对空的尖括号<>
- 函数名后跟一对尖括号,尖括号中指定需要特化的类型
- 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误。
// 基础的函数模板 -> 函数模板,参数匹配
template<class T>
bool Less(const T& x, const T& y)
{return x < y;
}
// 函数模板特化 -> 对Less函数模板进行特化
template<>
bool Less<double>(const double& x, const double& y)
{return x < y;
}
int main()
{cout << Less(1.1, 6.6) << endl; // 调用特化之后的版本,而不走模板生成了cout << Less(1, 6) << endl;return 0;
}
注意:一般情况下如果函数模板遇到不能处理或者处理有误的类型,为了实现简单通常都是将该函数直接给
出,参数类型复杂的函数模板不建议特化!
⭐类模板特化
类模板特化(Class Template Specialization)是C++模板编程中的一种机制,它允许我们为类模板的特定类型或类型组合提供专门的定义。在默认情况下,类模板会为所有类型提供通用的实现,但有时候,我们可能希望对某些特定的类型提供不同的实现。这时,就可以使用类模板特化来实现
🌞全特化
全特化是针对类模板的所有模板参数提供专门的定义。全特化的语法与类模板的定义类似,但是需要在尖括号中指定具体的类型
类模板全特化代码示例
template<class T>
class pxt
{
public:void print() {cout << "print()" << endl;}
};// 全特化版本,针对int类型
template<>
class pxt <int>
{
public:void print() {cout << "print<int>()" << endl;}
};int main() {pxt<int> P;P.print(); // 输出 "print<int>()" pxt<double> T;T.print(); // 输出 "print()" return 0;
}
🌙偏特化
偏特化允许我们对类模板的部分模板参数提供专门的定义。这意味着我们可以为模板参数列表中的一部分参数指定具体的类型,而让其他参数保持通用
template<class T1, class T2>
class pxt
{
public:void print(){cout << "print<T1, T2>()" << endl;}
};// 偏特化版本,针对T2为int的情况
template<class T1>
class pxt <T1, int>
{
public:void print(){cout << "print<T1, int>()" << endl;}
};int main() {pxt<double, int> P;P.print(); // 输出 "print<T1, int>()" pxt<double, double> T;T.print(); // 输出 "print<T1, T2>()"return 0;
}
偏特化能将参数类型特化成不同的类型
// 两个参数偏特化为引用类型
template <typename T1, typename T2>
class Data <T1&, T2&>// 两个参数偏特化为指针类型
template <typename T1, typename T2>
class Data <T1*, T2*>
注意:
- 类模板特化不能增加新的成员变量,只能对成员函数进行特化
- 特化的优先级高于通用模板。当存在多个可用的特化版本时,编译器会选择最匹配的特化版本
- 在编写类模板特化时,要特别注意避免名称冲突和歧义
- 类模板特化在编译器进行类型推导和实例化时会被考虑,因此它们应该被定义在模板定义所在的同一命名空间内(或者在模板定义之前的某个地方)
📜3. 模板分离编译
概念: 一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式
🍂模板的分离编译
// a.h
template<class T>
T Add(const T& left, const T& right); // 声明// a.cpp
// 定义
template<class T>
T Add(const T& left, const T& right)
{return left + right;
}
// 显示实例化(不推荐)
//template
//int Add(const int& left, const int& right);// main.cpp
#include"a.h"
int main()
{Add(1, 2);Add(1.0, 2.0);return 0;
}
当程序在编译链接时,编译器找到函数模板地址的,这两个函数当时并没有实例化,所以会导致链接时报错
🍁解决方法
如果遇到模板分离编译相关的问题,常见的解决方法有两种:
- 将声明和定义放到一个文件(如“xxx.hpp”或“xxx.h”)里面。这是推荐的方法,因为它可以避免分离编译带来的潜在问题
- 在模板定义位置显式实例化。这种方法不实用,通常不推荐使用,因为它可能导致不必要的代码冗余和编译时间增加。
📒4. 模板总结
🔥【优点】
- 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
- 增强了代码的灵活性
💧【缺陷】
- 模板会导致代码膨胀问题,也会导致编译时间变长
- 出现模板编译错误时,错误信息非常凌乱,不易定位错误
📖5. 总结
当我们在编程的旅途中深入探索C++的模板和仿函数(Function Objects,也称为函数对象或仿函数对象)时,我们不禁被它们强大的灵活性和表达能力所震撼。模板和仿函数是C++标准库和许多现代编程范式中不可或缺的一部分,它们为我们提供了编写可重用、类型安全且易于维护的代码的强大工具
- 通过模板,我们可以编写出与类型无关的代码,使得代码更加通用和灵活。无论是容器类、算法还是其他高级抽象,模板都扮演着核心角色。模板进阶的学习不仅仅是理解如何编写模板代码,更重要的是理解如何设计出能够优雅地处理各种类型的模板结构和算法
- 而仿函数则为我们提供了一种以对象方式表示和操作函数行为的途径。通过重载operator(),我们可以将函数行为封装在类中,从而可以像操作普通对象一样操作函数。这种能力让我们能够在算法和数据结构中更加灵活地运用函数,同时也为我们提供了更多的控制和定制选项
最后我鼓励大家保持对模板和仿函数的学习热情,不断探索和实践它们的强大功能。通过不断的学习和实践,我们不仅能够提升自己的编程技能,还能够为C++社区的发展贡献自己的力量。让我们一起在模板和仿函数的道路上不断前行,探索编程的无限可能!
谢谢大家支持本篇到这里就结束了,祝大家天天开心!
相关文章:

【C++进阶】模板与仿函数:C++编程中的泛型与函数式编程思想
📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C “ 登神长阶 ” 🤡往期回顾🤡:栈和队列相关知识 🌹🌹期待您的关注 🌹🌹 ❀模板进阶 🧩<&…...

华安保险:核心系统分布式升级,提升保费规模处理能力2-3倍 | OceanBase企业案例
在3月20日的2024 OceanBase数据库城市行的活动中,安保险信息科技部总经理王在平发表了以“保险行业核心业务系统分布式架构实践”为主题的演讲。本文为该演讲的精彩回顾。 早在2019年,华安保险便开始与OceanBase接触,并着手进行数据库的升级…...

佐西卡在美国InfoComm 2024展会上亮相投影镜头系列
6月12日至14日,2024美国视听显示与系统集成展览会将在拉斯维加斯会议中心盛大开幕。这场北美最具影响力的视听技术盛会,将汇集全球顶尖的视听解决方案,展现专业视听电子系统集成、灯光音响等领域的最新技术动态。 在这场科技盛宴中࿰…...

【权威出版/投稿优惠】2024年智慧城市与信息化教育国际会议(SCIE 2024)
2024 International Conference on Smart Cities and Information Education 2024年智慧城市与信息化教育国际会议 【会议信息】 会议简称:SCIE 2024 大会时间:点击查看 大会地点:中国北京 会议官网:www.iacscie.com 会议邮箱&am…...
Android 应用程序 ANR 问题分析总结
ANR (Application Not Responding) 应用程序无响应。如果应用程序在UI线程被阻塞太长时间,就会出现ANR,通常出现ANR,系统会弹出一个提示提示框,让用户知道,该程序正在被阻塞,是否继续等待还是关闭。 1、AN…...

爬虫案例:建设库JS逆向
爬虫流程 1. 确定目标网址和所需内容 https://www.jiansheku.com/search/enterprise/ 只是个学习案例,所以目标就有我自己来选择,企业名称,法定代表人,注册资本,成立日期 2. 对目标网站,进行分析 动态…...
基于springboot的酒店管理系统源码数据库
时代的发展带来了巨大的生活改变,很多事务从传统手工管理转变为自动管理。自动管理是利用科技的发展开发的新型管理系统,这类管理系统可以帮助人完成基本的繁琐的反复工作。酒店是出门的必需品,无论出差还是旅游都需要酒店的服务。由于在旺季…...
Web前端开发 - 5 - JavaScript基础
JavaScript 一、JavaScript基础1. JavaScript入门2. 语句3. 数据类型4. 函数5. 对象6. 数组 一、JavaScript基础 1. JavaScript入门 <script> </script> <script type"text/javascript" src"xxx.js"> </script>//单行注释 /* 多…...
程序员之路:塑造卓越职业素养的探索与实践
序章 在这个数字时代,程序员作为技术进步的推动者,不仅需要掌握扎实的技术技能,更需具备高尚的职业素养,以应对日益复杂的行业挑战。职业素养,犹如编程中的“算法”,虽无形却决定着个人发展的效率与质量。本…...
C# Winform 在低DPI创建窗体后,在高DPI运行时,窗体会自动拉伸,导致窗体显示不全
C# Winform 在低DPI创建窗体后,在高DPI运行时,窗体会自动拉伸,导致窗体显示不全, 比如在分辨率为100% 的电脑创建C#项目,当运动到分辨率为125%的电脑运行时,后者运行的窗体会自动拉伸,窗体显示…...

JWT攻击手册(非常详细)零基础入门到精通,收藏这一篇就够了
JSON Web Token(JWT)对于渗透测试人员而言可能是一种非常吸引人的攻击途径,因为它们不仅是让你获得无限访问权限的关键,而且还被视为隐藏了通往以下特权的途径:特权升级,信息泄露,SQLiÿ…...

5.所有权
标题 一、概念二、规则三、示例3.1 变量作用域3.2 所有权的移交(深拷贝与浅拷贝)3.3 函数与所有权3.4 返回值与作用域3.5 引用的使用 四、切片(&str) 一、概念 所有权是Rust的核心特性。所有程序在运行时都必须管理它们使用计算机内存的方式。Rust的…...

RabbitMQ-工作模式(Publish模式Routing模式)
文章目录 发布/订阅(Publish/Subscribe)交换机临时队列绑定总体代码示例 路由(Routing)绑定直连交换机多重绑定发送日志订阅总体代码示例 更多相关内容可查看 发布/订阅(Publish/Subscribe) 构建一个简单的…...
【机器学习算法】期望最大化(EM)算法概述
期望最大化(EM)算法是一种迭代算法,用于在有未观测变量的情况下,求解概率模型参数的最大似然估计或最大后验估计。以下是对EM算法的原理与应用进行详细地剖析: EM算法原理 E步 - 期望计算:根据当前估计的模…...

【深度学习】数竹签演示软件系统
往期文章列表: 【YOLO深度学习系列】图像分类、物体检测、实例分割、物体追踪、姿态估计、定向边框检测演示系统【含源码】 【深度学习】物体检测/实例分割/物体追踪/姿态估计/定向边框/图像分类检测演示系统【含源码】 【深度学习】YOLOV8数据标注及模型训练方法整…...

Halcon 多相机统一坐标系
小杨说事-基于Halcon的多相机坐标系统一原理个人理解_多相机标定统一坐标系-CSDN博客 一、概述 最近在搞多相机标定等的相关问题,对于很大的场景,单个相机的视野是不够的,就必须要统一到一个坐标系下,因此我也用了4个相机&#…...
Apache Kylin:大数据分析从入门到精通
一、Kylin简介 Apache Kylin是一个分布式数据分析引擎,专为处理海量数据设计,能够在极短时间内对超大规模数据集进行OLAP(Online Analytical Processing)分析。Kylin通过预计算和高效的查询机制,为用户提供秒级的查询响应时间,支持与Hadoop、Hive、HBase等大数据平台无缝…...

SQL Server 2016导入.bak文件到数据库里面步骤
1、打开SSMS管理器 选择数据库 右键 然后点击还原数据库。 2、选择设备 然后点击三个点 找到本地bak文件,然后点击确定 3、点击确定,会自动弹出来一个成功的提示。...
WPF Frame 简单页面切换示例
原理比较简单,但是有个坑,为了使界面能够正确更新,记得使用 INotifyPropertyChanged 接口来实现属性更改通知。 <Window x:Class"PageTest.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation&…...

kafka-生产者监听器(SpringBoot整合Kafka)
文章目录 1、生产者监听器1.1、创建生产者监听器1.2、创建生产者拦截器1.3、发送消息测试1.4、使用Java代码创建主题分区副本1.5、application.yml配置----v1版1.6、屏蔽 kafka debug 日志 logback.xml1.7、引入spring-kafka依赖1.8、控制台日志 1、生产者监听器 1.1、创建生产…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程
STM32F1 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增…...

Xela矩阵三轴触觉传感器的工作原理解析与应用场景
Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知,帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量,能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度,还为机器人、医疗设备和制造业的智…...