[c++11(二)]Lambda表达式和Function包装器及bind函数
1.前言
Lambda表达式着重解决的是在某种场景下使用仿函数困难的问题,而function着重解决的是函数指针的问题,它能够将其简单化。
本章重点:
本章将着重讲解lambda表达式的规则和使用场景,以及function的使用场景及bind函数的相关使用方法。
2.为什么要有Lambda表达式
在C++98中,对自定义类型进行排序时,需要自己写仿函数,并传递给sort库函数
但是如果每次要按照自定义类型的不同成员变量进行排序的话,就要写很多个仿
函数,十分的不方便,于是C++11给出了一个新玩法:
struct Goods
{
string _name; // 名字
double _price; // 价格
int _evaluate; // 评价
Goods(const char* str, double price, int evaluate):_name(str), _price(price), _evaluate(evaluate)
{}
};
vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠萝", 1.5, 4 } };
sort(v.begin(), v.end(), [](Goods g1, Goods g2)->bool
{return g1._price < g2._price; });//按照价格升序
sort(v.begin(), v.end(), [](Goods g1, Goods g2)->bool
{return g1._price > g2._price; });//按照价格降序
sort(v.begin(), v.end(), [](Goods g1, Goods g2)->bool
{return g1._evaluate < g2._evaluate; });//按照评价升序
sort(v.begin(), v.end(), [](Goods g1, Goods g2)->bool
{return g1._evaluate > g2._evaluate; });//按照评价降序
后面那一坨就完美的代替了仿函数。他其实就是传说中的lambda表达式
上述代码具体分析如下:

3.Lambda表达式的语法
lambda 表达式书写格式: [capture-list] (parameters) mutable -> return-type { statement}
注意:在 lambda 函数定义中, 参数列表和返回值类型都是可选部分 ,而捕捉列表和函数体可以为空 。因此 C++11 中 最简单的 lambda 函数为: []{} ; 该 lambda 函数不能做任何事情。
int main()
{// 最简单的lambda表达式, 该lambda表达式没有任何意义[]{}; // 省略参数列表和返回值类型,返回值类型由编译器推导为intint a = 3, b = 4;[=]{return a + 3; }; // 省略了返回值类型,无返回值类型auto fun1 = [&](int c){b = a + c; }; fun1(10)cout<<a<<" "<<b<<endl;// 各部分都很完善的lambda函数auto fun2 = [=, &b](int c)->int{return b += a+ c; }; cout<<fun2(10)<<endl;// 复制捕捉xint x = 10;auto add_x = [x](int a) mutable { x *= 2; return a + x; }; cout << add_x(10) << endl; return 0;
}
通过上述例子可以看出, lambda 表达式实际上可以理解为无名函数,该函数无法直接调用,如果想要直接调用,可借助 auto 将其赋值给一个变量。
4.Lambda表达式的捕捉列表
lambda表达式的捕捉列表[ ]可以捕捉父作用域的变量供自己使用。
规则如下:

#include <iostream>
#include <vector>
#include <algorithm>int main() {int x = 10;int y = 20;std::vector<int> v = {1, 2, 3, 4, 5};// 混合捕获std::vector<int> filtered;std::copy_if(v.begin(), v.end() [x, &y](int z) { return z > x && z < y; });// 输出过滤后的结果for (int n : filtered) {std::cout << n << " ";}std::cout << std::endl;return 0;
}
在这个例子中,[x, &y] 捕获 x 的值和 y 的引用。
注意:

lambda表达式之间不能相互赋值,即使看起来类型是相同的。
lambda表达式的使用方法和仿函数非常相似,实际在底层编译器对于lambda表达式的处理方式完全就是按照函数对象的方式处理的即:如果定义了一个lambda表达式,
编译器会自动生成一个类,在该类中重载了operator()
mutable关键字详解:
由于lambda表达式是具有常属性的,所以在通常的情况下是无法被修改的,因此在C++14中引入了mutable关键字,可以用于Lambda表达式中,以允许Lambda表达式修改捕获的变量。
例:
#include <iostream>int main() {int x = 10;auto lambda = [=]() mutable { ++x; }; // 值捕获,允许修改lambda();std::cout << x << std::endl; // 输出: 10return 0;
}
分析:为什么这里用了mutable之后,输出还是10呢?
简单理解就是:类比函数传参,你在这里传的只是x的副本,并不是真正的x,所以外部的x并没有被修改。
mutable关键字的作用是允许 Lambda 表达式修改通过值捕获的变量。然而,值捕获的本质是复制外部变量的值到 Lambda 表达式的内部环境,
5.function包装器
ret = func(x);
// 上面func可能是什么呢?那么func可能是函数名?函数指针?函数对象(仿函数对象)?
//也有可能是lamber表达式对象?所以这些都是可调用的类型!如此丰富的类型
//可能会导致模板的效率低下!
template<class F, class T>
T useF(F f, T x)
{static int count = 0;cout << "count:" << ++count << endl;cout << "count:" << &count << endl;return f(x);
}
double f(double i)
{return i / 2;
}
struct Functor
{double operator()(double d){return d / 3;}
};
int main()
{
// 函数名cout << useF(f, 11.11) << endl;// 函数对象cout << useF(Functor(), 11.11) << endl;// lamber表达式cout << useF([](double d)->double{ return d/4; }, 11.11) << endl;return 0;
}
这样的话一份useF就实例化出了三份代码,这样就比较low了。
那么如果用function的话,那么就可以提高效率了。
Function函数的使用方法:

第一个int表示返回值,()里面的int表示参数的类型。
回到上述要解决的问题,解决方式如下:
#include <functional>
template<class F, class T>
T useF(F f, T x)
{static int count = 0;cout << "count:" << ++count << endl;cout << "count:" << &count << endl;return f(x);
}
double f(double i)
{return i / 2;
}
struct Functor
{double operator()(double d){return d / 3;}
};int main()
{// 函数名std::function<double(double)> func1 = f;cout << useF(func1, 11.11) << endl;// 函数对象std::function<double(double)> func2 = Functor();cout << useF(func2, 11.11) << endl;// lamber表达式std::function<double(double)> func3 = [](double d)->double{ return d /
4; };cout << useF(func3, 11.11) << endl;return 0;
}
6.function包装器的使用场景
例如:1.可以存储在容器中,使得可以动态地管理和调用函数。
#include <iostream>
#include <vector>
#include <functional>int main() {std::vector<std::function<void()>> functions;functions.push_back([]() { std::cout << "Function 1" << std::endl; });functions.push_back([]() { std::cout << "Function 2" << std::endl; });for (auto& func : functions) {func();}return 0;
}
在这个例子中,functions 容器存储了多个 std::function<void()> 类型的函数,并在运行时依次调用这些函数。
在操作系统中,不同的线程要执行不同的函数的话,那么就可以用这种方式 来进行封装并且调用函数。
2.函数适配器
std::function 可以用于创建函数适配器,使得可以将不同类型的函数适配为统一的接口。
#include <iostream>
#include <functional>void functionA(int x) {std::cout << "Function A called with " << x << std::endl;
}void functionB(double x) {std::cout << "Function B called with " << x << std::endl;
}int main() {std::function<void(int)> adapterA = functionA;std::function<void(double)> adapterB = functionB;adapterA(10);adapterB(3.14);return 0;
}
在这个例子中,
adapterA和adapterB分别适配了不同类型的功能函数,使得它们可以统一调用。
7.bind函数
// 原型如下:
template <class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);
// with return type (2)
template <class Ret, class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args); std::placeholders 占位符 std::placeholders 提供占位符 _1, _2, _3 等,用于表示函数调用时的参数位置。 #include <iostream>
#include <functional>void print(int a, int b) {std::cout << "a: " << a << ", b: " << b << std::endl;
}int main() {auto bound_func = std::bind(print, std::placeholders::_2, std::placeholders::_1);bound_func(20, 10); // 输出: a: 10, b: 20return 0;
}
在这个例子中,std::bind 将 print 函数的参数位置交换了,使得 _2 即func里面的第二个参数作为print的第一个参数,_1 即func里面的第一个参数作为第二个参数传递给 print 函数。
简单总结一下:
std::bind是 C++ 标准库中的一个函数模板,用于绑定函数和对象,以便创建新的可调用对象。std::bind可以用于创建适配器,将函数、成员函数、甚至是函数对象绑定到特定的参数,从而生成新的可调用对象。
8.bind函数的使用场景
1. 绑定带有默认参数的成员函数
#include <iostream>
#include <functional>class MyClass {
public:void print(int a, int b = 0) {std::cout << "a: " << a << ", b: " << b << std::endl;}void bindAndCall() {// 使用 std::bind 绑定成员函数和 this 指针auto bound_func = std::bind(&MyClass::print, this, std::placeholders::_1, 20);// 调用绑定后的函数bound_func(10); // 输出: a: 10, b: 20}
};int main() {MyClass obj;obj.bindAndCall();return 0;
}
2.绑定函数对象
#include <iostream>
#include <functional>class PrintFunc {
public:void operator()(int a, int b) {std::cout << "a: " << a << ", b: " << b << std::endl;}
};int main() {PrintFunc pf;auto bound_func = std::bind(pf, std::placeholders::_1, 20);bound_func(10); // 输出: a: 10, b: 20return 0;
}
9.总结
lambda表达式和function包装器以及bind函数到这就讲解完毕了。
相关文章:
[c++11(二)]Lambda表达式和Function包装器及bind函数
1.前言 Lambda表达式着重解决的是在某种场景下使用仿函数困难的问题,而function着重解决的是函数指针的问题,它能够将其简单化。 本章重点: 本章将着重讲解lambda表达式的规则和使用场景,以及function的使用场景及bind函数的相关使…...
基于字节大模型的论文翻译(含免费源码)
基于字节大模型的论文翻译 源代码: 👏 star ✨ https://github.com/boots-coder/LLM-application 展示 项目简介 本项目是一个基于大语言模型(Large Language Model, LLM)的论文阅读与翻译辅助工具。它通过用户界面(…...
Mysql语法之DQL查询的多行函数
Mysql的多行函数和分组 目录 Mysql的多行函数和分组多行函数概念常用的多行函数 数据分组概念语法where和having的区别 语句关键字及执行顺序语句关键字执行顺序 实际操作基本语句格式和多行操作筛选语句格式 多行函数 概念 不管函数处理多少条,只返回一条记录&…...
OpenSSL 心脏滴血漏洞(CVE-2014-0160)
OpenSSL 心脏滴血漏洞(CVE-2014-0160) Openssl简介: 该漏洞在国内被译为"OpenSSL心脏出血漏洞”,因其破坏性之大和影响的范围之广,堪称网络安全里程碑事件。 OpenSSL心脏滴血漏洞的大概原理是OpenSSL在2年前引入了心跳(hearbea0机制来维特TS链接的…...
监控视频汇聚融合云平台一站式解决视频资源管理痛点
随着5G技术的广泛应用,各领域都在通信技术加持下通过海量终端设备收集了大量视频、图像等物联网数据,并通过人工智能、大数据、视频监控等技术方式来让我们的世界更安全、更高效。然而,随着数字化建设和生产经营管理活动的长期开展࿰…...
ElasticSearch 数据同步
1、同步调用 操作步骤: 管理系统新增酒店数据添加到数据库调用 ES 更新文档接口,同步数据库的数据到 ES 文档 流程图: 特点: 优点:实现简单,粗暴缺点:业务耦合度高 2、异步消息通知 操作步骤…...
MyBatis-Plus中isNull与SQL语法详解:处理空值的正确姿势
目录 前言1. 探讨2. 基本知识3. 总结 前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF 基本的Java知识推荐阅读: java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全&#x…...
RabbitMQ个人理解与基本使用
目录 一. 作用: 二. RabbitMQ的5中队列模式: 1. 简单模式 2. Work模式 3. 发布/订阅模式 4. 路由模式 5. 主题模式 三. 消息持久化: 消息过期时间 ACK应答 四. 同步接收和异步接收: 应用场景 五. 基本使用 ÿ…...
Python球球大作战
系列文章 序号直达链接表白系列1Python制作一个无法拒绝的表白界面2Python满屏飘字表白代码3Python无限弹窗满屏表白代码4Python李峋同款可写字版跳动的爱心5Python流星雨代码6Python漂浮爱心代码7Python爱心光波代码8Python普通的玫瑰花代码9Python炫酷的玫瑰花代码10Python多…...
入侵他人电脑,实现远程控制(待补充)
待补充 在获取他人无线网网络密码后,进一步的操作是实现入侵他人电脑,这一步需要获取对方的IP地址并需要制作自己的代码工具自动化的开启或者打开对方的远程访问权限。 1、获取IP地址(通过伪造的网页、伪造的Windows窗口、hook,信…...
数据分析实战—IMDB电影数据分析
1.实战内容 1.加载数据到movies_df,输出前5行,输出movies_df.info(),movies_df.describe() # (1)加载数据集,输出前5行 #导入库 import pandas as pd import numpy as np import matplotlib import matplotlib.pyplo…...
Google guava 最佳实践 学习指南之08 `BiMap`(双向映射)
guava 最佳实践 学习指南 Google Guava 库中的 BiMap(双向映射)是一种特殊的映射类型,它维护了映射的反向视图,并确保不存在重复值,且始终可以安全地使用值获取对应的键。以下是关于 Guava BiMap 的一些介绍和用法&am…...
【设计模式】空接口
(空)接口的用法总结 接口用于定义某个类的特定能力或特性。在工作流或任务管理系统中,接口可以帮助标识哪些任务可以在特定阶段执行。通过实现这些接口,任务类可以被标识为在相应的阶段可以执行,从而在验证和执行逻辑…...
Grad-CAM-解释CNN决策过程的可视化技术
Grad-CAM(Gradient-weighted Class Activation Mapping)是一种用于解释卷积神经网络(CNN)决策过程的可视化技术。其核心思想是通过计算分类分数相对于网络确定的卷积特征的梯度,来识别图像中哪些部分对分类结果最为重要…...
前后端学习中本周遇到的内容
一、RequiresPermissions注解 例如: RequiresPermissions("demo:staff:save") void saveStaff(); 权限控制,要求含有demo:staff:save的权限才能执行方法saveStaff()。 二、遇到的细节问题 在进行增删改查时,发送http请求时&…...
基于海思soc的智能产品开发(巧用mcu芯片)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 对于开发车规级嵌入式软件的同学来说,socmcu这样的组合,他们并不陌生。但是传统的工业领域,比如发动机、医疗或…...
批量DWG文件转dxf(CAD图转dxf)——c#插件实现
此插件可将指定文件夹及子文件夹下的dwg文件批量转为dxf文件。 (使用方法:命令行输入 “netload” 加载插件,然后输入“dwg2dxf”运行,选择文件夹即可。) 生成dxf在此新建的文件夹路径下,包含子文件夹内的…...
flask flask-socketio创建一个网页聊天应用
应用所需环境: python 3.11.11 其他 只需要通过这个命令即可 pip install flask3.1.0 Flask-SocketIO5.4.1 -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple 最好是用conda创建一个新的虚拟环境来验证 完整的pip list如下 Package Version ----…...
使用CNN模型训练图片识别(键盘,椅子,眼镜,水杯,鼠标)
首先是环境: 我是在Anaconda3中的Jupyter Notebook (tensorflow)中进行训练,环境各位自行安装 数据集: 本次数据集五个类型(键盘,椅子,眼镜,水杯,鼠标)我收集了每个接近两…...
Gitlab 数据备份全攻略:命令、方法与注意事项
文章目录 1、备份命令2、备份目录名称说明3、手工备份配置文件3.1 备份配置文件3.2 备份ssh文件 4、备份注意事项4.1 停止puma和sicdekiq组件4.2 copy策略需要更多磁盘空间 5、数据备份方法5.1 docker命令备份5.2 kubectl命令备份5.3 参数说明5.4、选择性备份5.5、非tar备份5.6…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门 执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
