C++STL---<functional>
C++标准库中的 <functional> 库是一个强大的工具集,它提供了用于处理函数对象、函数绑定、函数包装等功能的设施,极大地增强了代码的灵活性和可复用性。
1. 函数对象(Functors)
函数对象,也被称作仿函数,是重载了 () 运算符的类的实例。其使用方式与普通函数调用类似,但函数对象可以携带状态,这使得它比普通函数更加灵活。
#include <iostream>// 定义一个函数对象类
class Adder {
public:int operator()(int a, int b) const {return a + b;}
};int main() {Adder adder;int result = adder(3, 4);std::cout << "3 + 4 = " << result << std::endl;return 0;
}
- 原理:在
Adder类中,重载了()运算符,该运算符接受两个int类型的参数并返回它们的和。Adder类的对象adder就可以像函数一样被调用,当调用adder(3, 4)时,实际上是调用了Adder类的operator()方法。 - 优点:函数对象可以包含成员变量,这些成员变量可以在对象创建时进行初始化,并且在多次调用
operator()时保持状态,这是普通函数无法做到的。
2. std::function
std::function 是一个通用的多态函数包装器,它可以存储、复制和调用任何可调用对象,包括普通函数、函数指针、成员函数指针、函数对象和 lambda 表达式等。
#include <iostream>
#include <functional>// 普通函数
int add(int a, int b) {return a + b;
}int main() {// 使用 std::function 包装普通函数std::function<int(int, int)> func = add;int result = func(3, 4);std::cout << "3 + 4 = " << result << std::endl;// 包装 lambda 表达式std::function<int(int, int)> lambdaFunc = [](int a, int b) { return a * b; };result = lambdaFunc(3, 4);std::cout << "3 * 4 = " << result << std::endl;return 0;
}
- 模板参数:
std::function<int(int, int)>中的模板参数指定了可调用对象的签名,即接受两个int类型的参数并返回一个int类型的结果。 - 包装过程:当将普通函数
add或 lambda 表达式赋值给std::function对象时,std::function会内部存储该可调用对象,并提供统一的调用接口。当调用func(3, 4)或lambdaFunc(3, 4)时,std::function会根据存储的可调用对象进行相应的调用。 - 用途:
std::function常用于实现回调机制,例如在事件处理、多线程编程等场景中,通过std::function可以方便地传递和调用不同类型的可调用对象。
3. std::bind
std::bind 用于创建一个新的可调用对象,它将一个可调用对象和其部分或全部参数绑定在一起,允许进行部分参数绑定和参数重排。
#include <iostream>
#include <functional>// 普通函数
int add(int a, int b) {return a + b;
}int main() {// 使用 std::bind 绑定 add 函数的第一个参数为 3auto add3 = std::bind(add, 3, std::placeholders::_1);int result = add3(4);std::cout << "3 + 4 = " << result << std::endl;// 参数重排auto sub = [](int a, int b) { return a - b; };auto reversedSub = std::bind(sub, std::placeholders::_2, std::placeholders::_1);result = reversedSub(3, 4);std::cout << "4 - 3 = " << result << std::endl;return 0;
}
- 部分参数绑定:在
std::bind(add, 3, std::placeholders::_1)中,add是要绑定的可调用对象,3是第一个参数,std::placeholders::_1是一个占位符,表示新可调用对象的第一个参数。add3是一个新的可调用对象,当调用add3(4)时,实际上是调用add(3, 4)。 - 参数重排:在
std::bind(sub, std::placeholders::_2, std::placeholders::_1)中,通过占位符的顺序交换了sub函数的参数顺序。当调用reversedSub(3, 4)时,实际上是调用sub(4, 3)。 - 用途:
std::bind可以用于简化函数调用,特别是在需要固定部分参数的情况下,或者在需要对参数顺序进行调整的情况下。
4. std::mem_fn
std::mem_fn 用于创建一个可调用对象,该对象可以调用类的成员函数。它可以处理成员函数指针,使得调用成员函数更加方便。
#include <iostream>
#include <functional>class MyClass {
public:void print() const {std::cout << "Hello, World!" << std::endl;}int add(int a, int b) const {return a + b;}
};int main() {MyClass obj;// 使用 std::mem_fn 包装成员函数auto printFunc = std::mem_fn(&MyClass::print);printFunc(obj);auto addFunc = std::mem_fn(&MyClass::add);int result = addFunc(obj, 3, 4);std::cout << "3 + 4 = " << result << std::endl;return 0;
}
- 成员函数指针:
&MyClass::print和&MyClass::add是成员函数指针,它们指向MyClass类的print和add成员函数。 - 包装过程:
std::mem_fn接受成员函数指针作为参数,返回一个可调用对象。当调用printFunc(obj)时,std::mem_fn会将obj作为调用print成员函数的对象,从而实现成员函数的调用。同样,addFunc(obj, 3, 4)会调用obj的add成员函数,并传递3和4作为参数。 - 用途:
std::mem_fn使得成员函数的调用可以像普通函数调用一样方便,特别是在需要将成员函数作为参数传递给其他函数时非常有用。
5. 预定义的函数对象
<functional> 库提供了一系列预定义的函数对象,用于常见的操作,如算术运算、比较运算等。
算术运算
#include <iostream>
#include <functional>int main() {std::plus<int> add;int result = add(3, 4);std::cout << "3 + 4 = " << result << std::endl;std::minus<int> sub;result = sub(4, 3);std::cout << "4 - 3 = " << result << std::endl;return 0;
}
std::plus:std::plus<int>是一个预定义的函数对象,它重载了()运算符,用于执行两个int类型数的加法运算。当调用add(3, 4)时,实际上是调用了std::plus<int>的operator()方法,返回3 + 4的结果。std::minus:std::minus<int>用于执行两个int类型数的减法运算,其原理与std::plus类似。
比较运算
#include <iostream>
#include <functional>int main() {std::greater<int> greater;bool isGreater = greater(4, 3);std::cout << "4 > 3: " << (isGreater ? "true" : "false") << std::endl;std::less<int> less;isGreater = less(4, 3);std::cout << "4 < 3: " << (isGreater ? "true" : "false") << std::endl;return 0;
}
std::greater:std::greater<int>用于比较两个int类型数的大小,返回true表示第一个参数大于第二个参数。当调用greater(4, 3)时,返回true。std::less:std::less<int>用于比较两个int类型数的大小,返回true表示第一个参数小于第二个参数。当调用less(4, 3)时,返回false。
6. std::ref 和 std::cref
std::ref 和 std::cref 用于创建引用包装器,当需要将引用传递给 std::bind 或其他需要按值传递参数的地方时非常有用。
#include <iostream>
#include <functional>void increment(int& num) {++num;
}int main() {int num = 3;auto func = std::bind(increment, std::ref(num));func();std::cout << "num = " << num << std::endl;return 0;
}
std::ref:std::ref(num)创建了一个对num的引用包装器。在std::bind(increment, std::ref(num))中,由于increment函数接受一个引用参数,使用std::ref可以确保传递给increment的是num的引用,而不是num的副本。当调用func()时,increment函数会修改num的值。std::cref:std::cref与std::ref类似,但它创建的是一个常量引用包装器,用于传递常量引用。
7. std::hash
std::hash 是一个模板类,用于生成对象的哈希值,常用于实现哈希表等数据结构。
#include <iostream>
#include <functional>int main() {std::hash<int> hasher;int num = 3;std::size_t hashValue = hasher(num);std::cout << "Hash value of " << num << " is " << hashValue << std::endl;return 0;
}
- 哈希函数:
std::hash<int>是一个针对int类型的哈希函数模板类,它重载了()运算符,接受一个int类型的参数并返回一个std::size_t类型的哈希值。当调用hasher(num)时,会根据num的值生成一个对应的哈希值。 - 用途:在实现哈希表、哈希集合等数据结构时,
std::hash可以方便地为元素生成哈希值,从而实现快速的查找和插入操作。
8. std::not_fn (C++17 起)
std::not_fn 用于创建一个新的可调用对象,该对象返回原可调用对象结果的逻辑非。
#include <iostream>
#include <functional>
#include <algorithm>
#include <vector>bool isEven(int num) {return num % 2 == 0;
}int main() {std::vector<int> numbers = {1, 2, 3, 4, 5};auto isOdd = std::not_fn(isEven);auto oddCount = std::count_if(numbers.begin(), numbers.end(), isOdd);std::cout << "Number of odd numbers: " << oddCount << std::endl;return 0;
}
- 逻辑非操作:
std::not_fn(isEven)创建了一个新的可调用对象isOdd,当调用isOdd时,它会调用isEven并返回其结果的逻辑非。在std::count_if中使用isOdd可以统计numbers向量中奇数的个数。 - 用途:
std::not_fn可以方便地反转一个布尔函数的逻辑,避免手动编写反转逻辑的代码。
总结
<functional> 库提供了丰富的工具来处理函数对象和函数调用,通过这些工具可以提高代码的灵活性和可维护性。合理使用这些工具可以让代码更加简洁和高效,特别是在实现回调机制、函数绑定、成员函数调用等场景中发挥重要作用。
相关文章:
C++STL---<functional>
C标准库中的 <functional> 库是一个强大的工具集,它提供了用于处理函数对象、函数绑定、函数包装等功能的设施,极大地增强了代码的灵活性和可复用性。 1. 函数对象(Functors) 函数对象,也被称作仿函数…...
java详细笔记总结持续完善
一.Java开发环境的搭建 1. 单位换算 1TB 1024GB 1GB 1024MB 1MB 1024KB 1KB 1024Byte (字节) 1Byte 8 bit(位) 注意:一个字节占8位 2. DOS命令 DOS : Disk Operation System 磁盘操作系统 即用于操作本地磁盘的系统 命令操作符号盘符切换命令盘符名:查看当前文…...
图解AUTOSAR_SWS_CANInterface
AUTOSAR CAN接口详解文档 基于AUTOSAR标准的CAN通信接口模块架构与工作原理 目录 1. AUTOSAR CAN接口概述2. CAN接口架构 2.1 模块定位与组成2.2 内部组件结构2.3 接口关系3. CAN消息传输流程 3.1 消息发送流程3.2 消息接收流程4. CAN控制器模式管理 4.1 状态定义4.2 状态转换4…...
wsl2的centos7安装jdk17、maven
JDK安装 查询系统中的jdk rpm -qa | grep java按照查询的结果,删除对应版本 yum -y remove java-1.7.0-openjdk*检查是否删除 java -version 下载JDK17 JDK17,下载之后存到wsl目录下(看你自己)然后一键安装 sudo rpm -ivh jd…...
乐鑫ESP-Mesh-Lite方案,启明云端乐鑫代理商,创新组网拓展智能应用边界
在当今智能化浪潮的背景下,智能家居、智能农业、能源管理等领域对设备组网的需求日益增长。然而,传统的Wi-Fi组网方式常常受限于设备数量、路由器位置以及网络覆盖范围等因素,难以满足复杂场景下的多样化需求。 一方面,需要支持更…...
ISIS【路由协议讲解】-通俗易懂!
IS-IS的背景 IS-IS最初是国际标准化组织ISO为它的无连接网络协议CLNP(ConnectionLess Network Protocol)设计的一种动态路由协议。随着TCP/IP协议的流行,为了提供对IP路由的支持,IETF在相关标准中对IS-IS进行了扩充和修改…...
FastPillars:一种易于部署的基于支柱的 3D 探测器
FastPillars:一种易于部署的基于支柱的 3D 探测器Report issue for preceding element Sifan Zhou 1 , Zhi Tian 2 , Xiangxiang Chu 2 , Xinyu Zhang 2 , Bo Zhang 2 , Xiaobo Lu11{}^{1}start_FLOATSUPERSCRIPT 1 end_FLOATSUPERSCRIPT11footnotemark: 1 Chengji…...
Vitis HLS 学习笔记--块级控制(IDE 2024.1 + 执行模式 + 默认接口实现)
目录 1. 简介 2. 默认接口实现 2.1 执行模式 2.2 接口范式 2.2.1 存储器 2.2.2 串流 2.3.3 寄存器 2.3 Vitis Kernel Flow 2.3.1 默认的协议 2.3.2 vadd 代码 2.3.3 查看报告 2.4 Vivado IP Flow 2.4.1 默认的协议 2.4.2 vadd 代码 2.4.3 查看报告 3. 测试与波…...
红宝书第二十一讲:详解JavaScript的模块化(CommonJS与ES Modules)
红宝书第二十一讲:详解JavaScript的模块化(CommonJS与ES Modules) 资料取自《JavaScript高级程序设计(第5版)》。 查看总目录:红宝书学习大纲 一、模块化的意义:分而治之 模块化解决代码依赖混…...
github 页面超时解决方法
github 页面超时解决方法 每次好不容易找到github项目代码之后,满心欢喜打开却是个无法访问,心顿时又凉了半截,现在有方法可以访问github啦 快来学习 打开浏览器插件(Edge浏览器) 搜索iLink插件 并安装 打开插件 填…...
前端 vue 项目上线前操作
目录 一、打包分析 二、CDN加速 三、项目部署 1. 打包部署 2. nginx 解决 history 刷新 404 问题 3. nginx配置代理解决生产环境跨域问题 一、打包分析 项目编写完成后,就需要部署到服务器上供他人访问。但是在此之前,我们可以先预览项目的体积大…...
矩阵对角化→实对称矩阵的对角化→实对称半正定矩阵的对角化
上篇:特征值→相似矩阵→矩阵对角化(特征值分解) 实对称矩阵正交对角化 实对称矩阵是指满足 A A T \bm A \bm A^{\mathsf {T}} AAT的矩阵,其中 A T \bm A^{\mathsf T} AT是 A \bm A A的转置矩阵。对称矩阵的特征值均为实数。实…...
vue: easy-cron扩展-更友好地显示表达式
我们一个批处理调度系统里要用到cron表达式,于是就在网上找到一个现成的组件easy-cron,采用后发现,它的配置界面还是很直观的,但显示时直接显示cron表达式,这对业务人员很不友好,所以,我们就扩展…...
移动零+复写零+快乐数+盛最多水的容器+有效三角形的个数
前言 2025.3.31,今天开始每日五道算法题,今天的算法题如标题! 双指针算法 在做今天的算法题之前,先来介绍一下今天会用到的算法! 双指针算法分为了两种常见的形式:对撞指针和快慢指针! 对撞…...
Linux中常用的文件管理命令
一、文件和目录的建立 文件 touch命令 单一文件的创建 当按下回车后我们就可以在桌面获得一个名字叫file的文件 [rootlocalhost Desktop]# touch file 同步文件访问时间和文件修改时间 由上两图可知touch file这个命令还可以把文件访问时间和文件修改时间变成touch file命…...
Root Cause Analysis in Microservice Using Neural Granger Causal Discovery
Root Cause Analysis in Microservice Using Neural Granger Causal Discovery 出处:AAAI 24 摘要 近年来,微服务因其可扩展性、可维护性和灵活性而在 IT 运营中得到广泛采用。然而,由于微服务中的复杂关系,当面临系统故障时,站点可靠性工程师 (SRE) 很难查明根本原…...
学习笔记—数据结构—二叉树(链式)
目录 二叉树(链式) 概念 结构 初始化 遍历 前序遍历 中序遍历 后序遍历 层序遍历 结点个数 叶子结点个数 第k层结点个数 深度/高度 查找值为x的结点 销毁 判断是否为完整二叉树 总结 头文件Tree.h Tree.c 测试文件test.c 补充文件Qu…...
微前端 - 以无界为例
一、微前端核心概念 微前端是一种将单体前端应用拆分为多个独立子应用的架构模式,每个子应用可独立开发、部署和运行,具备以下特点: 技术栈无关性:允许主应用和子应用使用不同框架(如 React Vue)。独立部…...
DIskgenius使用说明
文章目录 一、概述1. 软件简介2. 系统要求 二、核心功能1. 分区管理(1) 查看磁盘分区(2) 创建与删除分区(3) 调整分区大小(4) 格式化分区 2. 数据恢复(1) 恢复已删除文件(2) 恢复丢失分区(3) 恢复误格式化分区 3. 磁盘复制(1) 克隆磁盘(2) 磁盘镜像 4. 文件操作(1) 文件复制与移…...
深入理解指针5
sizeof和strlen的对比 sizeof的功能 **sizeof是**** 操作符****,用来**** 计算****变量或类型或数组所占**** 内存空间大小****,**** 单位是字节,****他不管内存里是什么数据** int main() {printf("%zd\n", sizeof(char));p…...
一文详解QT环境搭建:Windows使用CLion配置QT开发环境
在当今的软件开发领域,跨平台应用的需求日益增长,Qt作为一款流行的C图形用户界面库,因其强大的功能和易用性而备受开发者青睐。与此同时,CLion作为一款专为C/C打造的强大IDE,提供了丰富的特性和高效的编码体验。本文将…...
NE 综合实验3:基于 IP 配置、链路聚合、VLAN 管理、路由协议及安全认证的企业网络互联与外网访问技术实现(H3C)
综合实验3 实验拓扑 设备名称接口IP地址R1Ser_1/0与Ser_2/0做捆绑MP202.100.1.1/24G0/0202.100.2.1/24R2Ser_1/0与Ser_2/0做捆绑MP202.100.1.2/24G0/0172.16.2.1/24G0/1172.16.1.1/24G0/2172.16.5.1/24R3G5/0202.100.2.2/24G0/0172.16.2.2/24G0/1172.16.3.1/24G0/2172.16.7.1/…...
Ground Truth(真实标注数据):机器学习中的“真相”基准
Ground Truth:机器学习中的“真相”基准 文章目录 Ground Truth:机器学习中的“真相”基准引言什么是Ground Truth?Ground Truth的重要性1. 模型训练的基础2. 模型评估的标准3. 模型改进的指导 获取Ground Truth的方法1. 人工标注2. 众包标注…...
双重token自动续期解决方案
Token自动续期实现方案详解 Token自动续期是提升用户体验和保障系统安全的关键机制,其核心在于无感刷新和安全可控。以下从原理、实现方案、安全措施和最佳实践四个维度展开说明: 一、核心原理:双Token机制 Token自动续期通常采用 Access …...
我与数学建模之启程
下面的时间线就是从我的大二上开始 9月开学就迎来了本科阶段最重要的数学建模竞赛——国赛,这个比赛一般是在9月的第二周开始。 2021年国赛是我第一次参加国赛,在报名前我还在纠结队友,后来经学长推荐找了另外两个学长。其实第一次国赛没啥…...
多段圆弧拟合离散点实现切线连续
使用多段圆弧来拟合一个由离散点组成的曲线,并且保证切线连续。也就是说,生成的每一段圆弧之间在连接点处必须有一阶导数连续,也就是切线方向相同。 点集分割 确保每个段的终点是下一段的起点,相邻段共享连接点,避免连接点位于数…...
烧结银:解锁金刚石超强散热潜力
烧结银:解锁金刚石超强散热潜力 在材料科学与热管理领域,金刚石凭借超高的热导率,被誉为 “散热之王”,然而,受限于其特殊的性质,金刚石在实际应用中难以充分发挥散热优势。而烧结银AS9335的出现&#x…...
【蓝桥杯】第十四届C++B组省赛
⭐️个人主页:小羊 ⭐️所属专栏:蓝桥杯 很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~ 目录 试题A:日期统计试题B:01串的熵试题C:冶炼金属试题D:飞机降落试题E:接…...
企业级海外网络专线行业应用案例及服务商推荐
在全球化业务快速发展的今天,传统网络技术已难以满足企业需求。越来越多企业开始选择新型海外专线解决方案,其中基于SD-WAN技术的企业级海外网络专线备受关注。这类服务不仅能保障跨国数据传输,还能根据业务需求灵活调整网络配置。接下来我们…...
阿里云服务器安装docker以及mysql数据库
(1) 官方下载路径 官方下载地址: Index of linux/static/stable/x86_64/阿里云镜像地址: https://mirrors.aliyun.com/docker-ce/下载最新的 Docker 二进制文件:wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.23.tgz登录到阿里云服务…...
