[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…...
恒宇信通收购神导科技,业绩V型反转、技术高度互补,能否开启增长新周期?
5月13日,恒宇信通(300965.SZ)在停牌筹划半个月后,携一份重磅资产重组预案强势复牌,开盘即收获20cm一字涨停,报收79.20元/股。根据预案,恒宇信通拟通过发行股份及支付现金的方式,收购…...
从命令行到自动化:用xrandr和shell脚本打造你的Linux多屏工作流(含常见错误排查)
从命令行到自动化:用xrandr和shell脚本打造你的Linux多屏工作流(含常见错误排查) 每天早晨,当我从笔记本单屏切换到办公室的三显示器阵列时,只需按下CtrlAltW,所有显示器就会自动按预设排列亮起——这种流畅…...
AI智能体通信基站:统一HTTP请求管理,提升开发效率与稳定性
1. 项目概述:一个为AI智能体构建的“通信基站”如果你正在开发一个AI智能体(Agent),并且需要让它与各种外部服务(比如OpenAI、Anthropic的Claude,或者任何自定义的HTTP API)进行对话,…...
Claude Code 工具提示词全拆解:AI Agent、Prompt Engineering、工具调用、上下文工程、自动化编程的底层逻辑
开篇导读很多人做 AI Agent 时,最容易盯着模型参数、系统提示词、工具数量,却忽略了一个非常关键的细节:每一个工具自己的提示词。它看起来只是一个 description 字段,实际上却在悄悄决定模型什么时候用工具、怎样用工具、不能做什…...
基于MCP协议构建AI可访问的数字基础设施安全暴露服务器
1. 项目概述:一个暴露数字基础设施的MCP服务器最近在折腾AI Agent的生态,发现一个挺有意思的项目,叫apifyforge/digital-infrastructure-exposure-mcp。光看这个名字,可能有点云里雾里,但如果你也在研究如何让AI更深入…...
从零构建轻量级爬虫框架:模块化设计与异步实现详解
1. 项目概述:从零构建一个轻量级数据爬取框架最近在做一个需要从多个公开数据源定期抓取结构化信息的小项目,一开始图省事,直接上requests加BeautifulSoup写脚本。但随着数据源增加到五六个,每个源的页面结构、反爬策略、数据清洗…...
维普AI率82%熬夜改一周只降4个点!这款软件几分钟救我一命!
维普AI率82%熬夜改一周只降4个点!这款软件几分钟救我一命! 周一早上送维普看到 82% 那一刻 3 月 17 号周一早上 9 点。导师群:「答辩前再送一次维普看 AIGC 检测,下周一早上群里发达标截图」。我赶紧上传维普「智能检测 4.0」—…...
ElevenLabs古吉拉特文语音合成失效排查手册(97.3%开发者忽略的ISO 639-2语言码陷阱)
更多请点击: https://intelliparadigm.com 第一章:ElevenLabs古吉拉特文语音合成失效的根本诱因 ElevenLabs 官方 API 文档明确标注支持 Gujarati(gu-IN)语言标识,但实际调用时持续返回 400 Bad Request 或静音音频&…...
Poppins字体技术解析:跨语言几何字体的架构设计与实战应用
Poppins字体技术解析:跨语言几何字体的架构设计与实战应用 【免费下载链接】Poppins Poppins, a Devanagari Latin family for Google Fonts. 项目地址: https://gitcode.com/gh_mirrors/po/Poppins 在全球化数字产品设计中,如何为多语言用户提供…...
ArcGIS Pro脚本工具实战:一键自动化面要素数据质检与修复流程
1. 为什么需要自动化面要素质检工具 做GIS数据处理的朋友们应该都深有体会,每次拿到一批新的面要素数据,最头疼的就是要检查各种几何错误。传统的手动检查方式有多痛苦?我给大家列几个典型场景: 检查重叠要素要用拓扑工具…...
