前言

在Cpp11以前,为了把函数当作对象调用,可以使用C中的函数指针类型,也可以使用Cpp98的仿函数。

但二者都不是很好用,函数指针 return_type (*name)(parameters)的长相就令人望而却步,仿函数将一个函数重载为一个类的operator()的方式又沉重麻烦。

C++11中做出了(抄Python的)更灵活、轻便的lambda表达式。

lambda表达式

lambda表达式 是一个 匿名函数对象,本质上是一个对象。

语法格式

[capture_list](parameters)->return_type
{};

由捕捉列表、参数列表、返回值、函数体四大部分构成。

捕捉列表用于捕捉此前出现过的变量,后三大部分就是函数正常的定义理解。(如果函数无参且无返回值,可以省略这两大部分,但是捕捉列表和函数体不可省略)

捕捉列表 

由于lambda本质是一个对象,在写出lambda表达式时,就在创建一个对象。

捕捉列表中捕捉的值,就是构造函数的参数,用于初始化成员变量,以供函数体中直接使用。

捕捉的规则如下:

【1】捕捉某变量的值

int a = 1, b = 2;
auto afun = [a](){cout << a << endl;
}
auto abfun = [a, b](int x, int y){cout << a + b << endl;
}

此时,捕捉a、b值,相当于拷贝a、b的值,lambda中的a、b和外面的变量a、b是两个东西。

且lambda内部不能修改捕捉的变量值,会报错。(硬要修改就要了解mutable关键字)

【2】捕捉某变量的引用

要捕捉变量引用,就在捕捉列表中,变量前加上一个&。

int a = 0;
auto af = [&a](){a++;cout<< a << endl;
};

此时的变量a就是内外统一的了,允许修改了。 

【3】捕捉所有变量的值

int a = 0, b = 1, c = 2, d = 3;auto all_fun = [=]{           //捕捉所有要用到的变量值cout << a+b+c+d << endl;
};auto all_fun = [=, &a]{       //在=后指定需要引用的变量a++;cout << a+b+c+d << endl;
};

前者用 = 表示 捕捉所有要用到的变量值;后者在 = 后指定需要引用的变量。

【4】捕捉所有变量的引用

int a = 0, b = 1, c = 2, d = 3;auto r_fun_1 = [&]{a++;b++;c++;
};
auto r_fun_2 = [&, a]{b++;c++;d++;
};

用&表示捕获所有被使用的变量的引用;后者指定捕获某变量的值。

补充

【1】全局变量不需要捕捉,也不能。

【2】返回值可以不写,函数体内部返回值时,编译器会自己推。但建议写,为了代码的可读性。

【3】使用auto可以推导lambda的类型,这个类型由编译器决定,MSVC用uuid来保证不同的lambda有不同的类型。这样匿名函数对象就可以被引用了,延长了生命周期,可以直接作为一个函数使用。(模板也能推)

应用场景

在使用算法库中的sort排序时,有时想要按照特殊的要求进行排序,就要传仿函数对象。

现在,我们可以直接传lambda匿名函数对象即可,轻便易读。可以替换仿函数的大部分使用。

包装器

function和bind都在<functional>头文件中。

function类模板

template <class T> function;     // undefinedtemplate <class Ret, class... Args> class function<Ret(Args...)>;

 function包装器一般用于包装返回值、参数列表的函数对象。包装前进行特化即可。

用函数的返回值和参数类型进行特化:Ret是前者类型,可变参数包Args是后者。

int pf(int a, int b)
{return a + b;
}struct Functor
{int operator()(int a, int b){return a - b;}
};int main()
{auto lf = [](int a, int b) { return a * b; };function<int(int, int)> f1 = &pf; //函数名也行,也是函数指针function<int(int, int)> f2 = lf;function<int(int, int)> f3 = Functor();vector<function<int(int, int)>> funcs = { f1, f2, f3 };//非静态成员函数                       function<int(Functor*, int, int)> f4 = &Functor::operator();function<int(Functor&&, int, int)> f5 = &Functor::operator();Functor f1_obj;f4(&f1_obj, 5, 6);f5(Functor(), 5, 6);return 0;
}

通过上例可见,用function包装了函数指针,lambda函数对象,仿函数对象。 

 这样统一了他们的类型,最后竟能放在一个容器里。

特殊的地方在于下面的非静态成员函数的包装。由于成员函数有一个隐式的参数--this指针,所以其特化类型与上面不同,但既可以传引用,也可以传指针。

在调用时,也要手动传入对象的指针或者对象。

这个就需要回顾类和对象重载运算符 .* 和 ->* 的知识点。但对比一下,可以看出,函数指针真的不方便,不如包装器好用。

	typedef int(Functor::*PF)(int, int);PF pf = &Functor::operator(); //成员函数指针必须加&才能取到//int(Functor::*)(int, int) p = &Functor::operator();//cpp不允许这样写和用函数指针类型Functor f;(f.*pf)(5, 6);Functor* p = &f;(p->*pf)(5, 6);

bind函数模板

在了解了function的包装类型后,bind的作用就不太一样。

bind主要用于函数的参数个数或位置调整。需要结合placeholders命名空间中的_1、_2、...、_n的占位符使用。

template <class Fn, class... Args>/* unspecified */ bind (Fn&& fn, Args&&... args);template <class Ret, class Fn, class... Args>/* unspecified */ bind (Fn&& fn, Args&&... args);

 使用:把要调整的函数的包装后的对象传给bind,使用占位符进行调整。

调整参数位置

using namespace placeholders;
int main()
{auto fun = [](int a, int b) { return a + b*10; };auto newFun = bind(fun, _2, _1);cout << fun(3, 4) << endl;     //43cout << newFun(3, 4) << endl;  //34return 0;
}

bind中的占位符用来确定实参的位置,根据实参所在位置从左往右确定_1、_2等等。然后bind再将对应占位符的值传给原本的函数。以实现参数位置的调整。

调整参数个数

通过确定某个位置的值,以达到少传参数、调整参数个数的目的。

auto newFun_4 = bind(fun, _1, 4);cout << newFun_2(3) << endl;  // 3 + 4 * 10;

强调:占位符指的是实参的位置。。。不要搞混了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/86470.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/86470.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/86470.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【国产化-K8s】混合架构的 K8s + KubeSphere 部署指南

本文由 KubeSphere 社区贡献者 天行1st 编写。本文为作者实践总结。本文记录了在信创环境中基于混合架构&#xff08;x86 与 ARM64&#xff09;部署 Kubernetes 和 KubeSphere 的实践过程&#xff0c;覆盖多种国产 CPU 和操作系统&#xff0c;具有一定的参考价值。 环境涉及软…

利用python实现NBA数据可视化

大家好&#xff0c;今天我们利用python爬取NBA球星每年的比赛数据并进行可视化展示。主要用到三个模块&#xff1a;xpath、matplotlib。其中xpth负责爬取网站上的信息。Matplotlib是Python开发人员常用的Python绘图库&#xff0c;可以用来绘制各种2D图形&#xff0c;具有绘图质…

基于 SpringBoot+JSP 的医疗预约与诊断系统设计与实现

摘要 本研究针对传统医疗预约与诊断流程中存在的效率低下、信息不透明、患者等待时间长等问题&#xff0c;设计并实现了一个基于 SpringBootJSP 的医疗预约与诊断系统。系统采用 B/S 架构&#xff0c;整合了用户管理、科室管理、医生排班、预约挂号、在线问诊、检查检验、诊断…

2025.6.27总结

最近工作又开始内耗了&#xff0c;一位同事的转岗直接让我破防了&#xff0c;明明他工作干得很不错&#xff0c;会得又多&#xff0c;性格又好&#xff0c;我还经常请教他业务上的问题。我和他的关系并不算太好&#xff0c;但他加入其他部门&#xff0c;竟然让我有些不舍&#…

详解HashMap底层原理

核心数据结构&#xff1a;数组 链表 / 红黑树 HashMap 的底层核心是一个 Node<K,V>[] table 数组&#xff08;通常称为 桶数组 或 哈希桶数组&#xff09;。这个数组的每个元素称为一个 桶。 Node<K,V> (链表节点)&#xff1a; 这是存储键值对的基本单位&#xf…

历史项目依赖库Bugfix技巧-类覆盖

在项目维护过程中&#xff0c;我们可能会遇到历史项目依赖的第三方库出现BUG而需要修复的情况&#xff0c;而这些第三方库可能来源于公司自主开发或开源项目&#xff0c;但由于各种原因&#xff0c;这些库可能已无人维护。 此时&#xff0c;解决这个问题有三个办法 1、基于源…

多模态大型语言模型最新综述

多模态大型语言模型&#xff08;Multimodal Large Language Models&#xff0c;MLLMs&#xff09;已迅速发展&#xff0c;超越了文本生成的范畴&#xff0c;如今能够覆盖图像、音乐、视频、人类动作以及三维物体等多种输出模态。它们通过在统一架构下将语言与其他感知模态整合&…

使用ASIO的协程实现高并发服务器

使用ASIO的协程实现高并发服务器 在 C 网络编程领域&#xff0c;Asio 库提供了两种主要的异步编程范式&#xff1a;传统的回调模式和基于协程的现代模式&#xff0c;传统的回调模式大家都很清楚&#xff0c;这里不多做介绍&#xff0c;本文主要介绍基于协程的模式&#xff0c;…

OpenCV——轮廓检测

轮廓检测 一、轮廓检测二、轮廓的层级三、轮廓的特征3.1、轮廓面积3.2、轮廓周长3.3、边界矩形3.4、最小外接圆3.5、近似轮廓3.6、凸包 一、轮廓检测 轮廓可以简单的描述为具有相同颜色或灰度的连续点连在一起的一条曲线&#xff0c;轮廓通畅会显示出图像中物体的形状。关于轮…

高等概率论题解-心得笔记【15】

文章目录 拓扑参考文献 拓扑 参考文献 《测度论基础与高等概率论》

Windows 10关闭自动更新功能

Windows 10关闭自动更新功能&#xff0c;大家是不是经常用下面的几个步骤&#xff1a; 1、禁用Windows Update服务&#xff1b; 2、在组策略里关闭Win10自动更新相关服务&#xff1b; 3、禁用任务计划里边的Win10自动更新&#xff1b; 4、在注册表中关闭Win10自动更新&…

[Meetily后端框架] 配置指南 | 后端API网关 | API文档体系

链接: https://github.com/Zackriya-Solutions/meeting-minutes docs&#xff1a;会议纪要管理系统 本项目是一个专门用于**处理会议记录**的后端系统。 系统接收会议文本内容&#xff0c;利用先进的AI模型自动识别关键信息&#xff0c;包括行动项、决策内容以及截止期限。 处…

Flink2.0 配置 historyserver

Flink2.0 配置 historyserver 主要是去修改config.yaml配置文件 主要修改的点有两个 网上很多文档都是写的只配置一个 都是坑啊 historyserver :历史服务器 运行 Flink job 的集群一旦停止(例如yarn模式&#xff0c;程序一旦停止&#xff0c;集群也就关闭了)&#xff0c;只能去…

LLM的训练过程

一般而言&#xff0c;训练一个完整的 LLM 需要经过图1中的三个阶段——Pretrain、SFT 和 RLHF。 1.预训练 Pretrain&#xff0c;即预训练&#xff0c;是训练 LLM 最核心也是工程量最大的第一步。LLM 的预训练和传统预训练模型非常类似&#xff0c;同样是使用海量无监督文本对随…

用 AI + Canvas 生成图形、动画与图表

摘要 随着人工智能&#xff08;AI&#xff09;技术与 Web 可视化的结合&#xff0c;前端开发者可以通过自然语言生成复杂的图表、动画和交互式画布&#xff0c;极大地提升了开发效率和用户体验。本文作为《AI 前端&#xff1a;构建智能化 Web 应用的未来》专栏的第七篇&#…

SQL Server for Linux 如何实现高可用架构

关键词&#xff1a;SQL Server for Linux、高可用、读写分离、动态扩容、Always On、可用性组 &#x1f4cb; 文章目录 前言&#xff1a;Linux上的SQL Server不再是梦高可用架构设计 Always On 可用性组故障转移集群实例 读写分离架构 可用性组读写分离应用层读写分离 动态扩…

【51单片机流水灯控制4种造型,按下1,2,3,4时,数码管对应显示键号,同时流水灯对应四种造型】2022-6-1

缘由流水灯控制4种造型&#xff0c;按下1,2,3,4时&#xff0c;数码管对应显示键号&#xff0c;同时流水灯对应四种造型-编程语言-CSDN问答 #include "REG52.h" unsigned char code smgduan[]{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5…

设计模式 - 工厂方法

工厂方法是一种设计模式&#xff0c;对工厂制造方法进行接口规范化&#xff0c;允许子类工厂决定具体知道哪类产品的实例&#xff0c;最终降低系统耦合&#xff0c;使系统的可维护性、可扩展性等得到提升。 一、工厂的多元化与专业化 要实例化对象&#xff0c;就得用到关键词“…

数据应该如何组织,才能让Excel“读懂”?

前言&#xff1a;如果你希望Excel能“读懂”你的数据&#xff0c;就得学会让排序、筛选、数据透视表、函数等这些功能为我们服务。 假设你在和一个非常聪明但有点“死板”的机器人&#xff08;Excel&#xff09;对话&#xff0c;你必须用它能理解的语言来组织信息。 “一维表”…

js防止重复提交的3种解决方案

防止 javascript 重复点击和提交的关键方法有三种&#xff1a;1. 禁用按钮法&#xff0c;点击后立即禁用按钮并更改文本提示&#xff0c;请求完成后恢复&#xff1b;2. 节流函数&#xff08;throttle&#xff09;&#xff0c;限制函数在设定时间间隔内仅执行一次&#xff0c;适…