当前位置: 首页 > news >正文

7.3 lambda函数

一、语法

1.基础语法

[capture](paramLists) mutable ->retunType{statement}
  • capture。捕获列表,用于捕获前文的变量供lambda函数中使用,可省略。
  • (paramLists)。参数列表,可省略。
  • mutable。lambda表达式默认具有常量性,可以通过mutable取消常量性,可省略。
  • returnType。函数返回类型,可省略。
  • statement。函数体,可省略。

结合上述可省略的内容,C++11中最简单的lambda表达式可以是(虽然没有实际意义):

[]{}

2.捕获列表

lambda函数的与普通函数最大的区别在于可以捕获前文的局部变量(仅仅对于局部而言,如果是全局lambda函数则不支持)。而捕获的方式有:

  • [var]表示值传递方式捕获变量var
  • [=]表示值传递方式捕获父作用域所有变量(包括this)
  • [&var]表示引用传递方式捕获变量var
  • [&]表示引用传递方式捕获父作用域所有变量(包括this)
  • [this]表示值传递方式捕获变量this

而由于捕获列表支持多个值(用,分隔),因此可以进行组合:

  • [=,&a,&b]表示引用传递捕获a,b,值传递捕获其他内容。
  • [&,a,this]表示值传递捕获a,this,引用传递捕获其他内容。

需要注意的是,捕获列表不能重复,如

[=,a,b]或者[&,&a,&b]等都是重复捕获(以相同的传递方式捕获同一个变量)。

3.基础使用

lambda函数通常用于局部作用域作为局部[匿名]函数。

        extern int z;extern float c;void Calc(int& , int, float &, float);void TestCalc() {int x, y = 3;float a, b = 4.0;int success = 0;auto validate = [&]() -> bool{if ((x == y + z) && (a == b + c))return 1;elsereturn 0;};Calc(x, y, a, b);success += validate();y = 1024;b = 1e13;Calc(x, y, a, b);success += validate();}// 编译选项:g++ -c -std=c++11 7-3-7.cpp

而在有时会通过auto为lambda函数命名,使其获得自说明性。

与普通函数相比lambda有如下优势:

  • 支持直接在函数内创建,作用域外释放,而不用额外创建一个函数。
  • 能够直接捕获所有局部变量,而普通函数则需要额外传递。
  • lambda函数默认内联,在较多次调用时性能比普通函数好。
  • lambda函数的设计更简单,不需要考虑参数传递等问题

二、关于lambda的一些实验与讨论

1.捕获参数的传递方式

lambda函数中不同的捕获传递方式会造成不同的结果,对于值传递,则在传递的值在编译期就确定了,无法被修改,而对于引用传递则可以同步lambda函数外的修改。

        #include <iostream>using namespace std;int main() {int j = 12;auto by_val_lambda = [=] { return j + 1;};auto by_ref_lambda = [&] { return j + 1;};cout << "by_val_lambda: " << by_val_lambda() << endl;cout << "by_ref_lambda: " << by_ref_lambda() << endl;j++;cout << "by_val_lambda: " << by_val_lambda() << endl;cout << "by_ref_lambda: " << by_ref_lambda() << endl;}

运行结果:

        by_val_lambda: 13by_ref_lambda: 13by_val_lambda: 13by_ref_lambda: 14

2.与函数指针的关系

lambda函数与函数指针看起来很相似,但是实际上却不是函数指针,它是一种称为"闭包"(closure)的类。

这种类型支持向函数指针转换,前提是:

  • lambda函数不捕获任何变量
  • 函数指针的原型与lambda一致(参数,返回值都完全一致)
        int main() {int girls = 3, boys = 4;auto totalChild = [](int x, int y)->int{ return x + y; };typedef int (*allChild)(int x, int y);typedef int (*oneChild)(int x);allChild p;p = totalChild;oneChild q;q = totalChild;      // 编译失败,参数必须一致decltype(totalChild) allPeople = totalChild;   // 需通过decltype获得lambda的类型decltype(totalChild) totalPeople = p;       // 编译失败,指针无法转换为lambdareturn 0;}// 编译选项:g++ -std=c++11 7-3-10.cpp

此外,不支持函数指针向lambda转换

3.常量性与mutable

前面提到对于值传递的捕获参数具有常量性无法被修改,而想要打破这一限制,可以加上mutable关键字。(注意虽然可以修改,但仍然不影响父作用域变量)

#include <iostream>
int main() {int val=0;// 编译失败, 在const的lambda中修改常量//auto const_val_lambda = [=]() { val = 3; };// 非const的lambda,可以修改常量数据auto mutable_val_lambda = [=]() mutable { val = 3; };mutable_val_lambda();std::cout << val << std::endl;// 依然是const的lambda,不过没有改动引用本身auto const_ref_lambda = [&] { val = 4; };const_ref_lambda();std::cout << val << std::endl;// 依然是const的lambda,通过参数传递valauto const_param_lambda = [&](int v) { v = 5; };const_param_lambda(val);std::cout << val << std::endl;return 0;
}

而对于引用传递方式,则表示lambda捕获的参数引用了父作用域的变量,一边修改都会同步到另一边。

三、lambda与STL

前面说到,lambda对C++11最大的贡献,或者说是改变,应该在STL库中。这主要体现于STL算法更加容易,也更加容易学习了(可读性更高)。

下面将以for_each为例,讲述lambda带来的便捷。

#include <vector>
#include <algorithm>
using namespace std;
vector<int> nums;
vector<int> largeNums;
const int ubound = 10;
inline void LargeNumsFunc(int i){if (i > ubound)largeNums.push_back(i);
}
void Above() {// 传统的for循环for (auto itr = nums.begin(); itr != nums.end(); ++itr) {if (*itr >= ubound)largeNums.push_back(*itr);}// 使用函数指针for_each(nums.begin(), nums.end(), LargeNumsFunc);// 使用lambda函数和算法for_eachfor_each(nums.begin(), nums.end(), [=](int i){if (i > ubound)largeNums.push_back(i);});
}
编译选项: g++ 7-3-13.cpp -c -std=c++11

这是通过基础for循环、for_each和lambda实现查找大于某个值的功能。相比for循环而言,for_each只需要关心数据起始点,并将每个元素作用到指定的操作上即可,在效率、正确性、可维护性上都具有一定优势。

而lambda较for_each而言,首先其函数内容会直接放在调用处,可阅读性更高(当然,有时也会被分离出来并命名,但通常不会太远);其次使用函数指针很可能导致编译器不对其进行inline优化(inline对编译器而言并非强制),在循环次数较多的时候,内联的lambda和没有能够内联的函数指针可能存在着巨大的性能差别。

此外相较于仿函数(不论是自己实现还是内置仿函数),lambda也依旧存在着不小的优势。

#include <vector>
#include <algorithm>
using namespace std;
vector<int> nums;
vector<int> largeNums;
class LNums{
public:
LNums(int u): ubound(u){}
void operator () (int i) const
{if (i > ubound)largeNums.push_back(i);
}
private:
int ubound;
};
void Above(int ubound) {// 传统的for循环for (auto itr = nums.begin(); itr != nums.end(); ++itr) {if (*itr >= ubound)largeNums.push_back(*itr);}// 使用仿函数for_each(nums.begin(), nums.end(), LNums(ubound));// 使用lambda函数和算法for_eachfor_each(nums.begin(), nums.end(), [=](int i){if (i > ubound)largeNums.push_back(i);});
}

对于自己实现的仿函数,很直观的,lambda更加简洁。

而当面对更加复杂的场景时,lambda显得更加有优势:

#include <vector>
#include <algorithm>
using namespace std;
extern vector<int> nums;
void TwoCond(int low, int high) {// 传统的for循环for (auto i = nums.begin(); i != nums.end(); i++)if (*i >= low && *i < high) break;// 利用了3个内置的仿函数,以及非标准的compose2find_if(nums.begin(), nums.end(),compose2(logical_and<bool>(),bind2nd(less<int>(), high),bind2nd(greater_equal<int>(), low)));// 使用lambda函数find_if(nums.begin(), nums.end(), [=](int i) {return i >= low && i < high;});
}

这里我们需找到vector nums中第一个值介于[low, high)间的元素,可以看到内置仿函数变得异常复杂。

相关文章:

7.3 lambda函数

一、语法 1.基础语法 [capture](paramLists) mutable ->retunType{statement} capture。捕获列表&#xff0c;用于捕获前文的变量供lambda函数中使用&#xff0c;可省略。(paramLists)。参数列表&#xff0c;可省略。mutable。lambda表达式默认具有常量性&#xff0c;可以…...

dcoker-compose一键部署EFAK —— 筑梦之路

简介 EFAK&#xff08;Eagle For Apache Kafka&#xff0c;以前称为 Kafka Eagle&#xff09;是一款由国内公司开源的Kafka集群监控系统&#xff0c;可以用来监视kafka集群的broker状态、Topic信息、IO、内存、consumer线程、偏移量等信息&#xff0c;并进行可视化图表展示。独…...

音视频:Ubuntu下安装 FFmpeg 5.0.X

1.安装相关依赖 首可选一&#xff1a; sudo apt-get update sudo apt-get install build-essential autoconf automake libtool pkg-config \libavcodec-dev libavformat-dev libavutil-dev \libswscale-dev libresample-dev libavdevice-dev \libopus-dev libvpx-dev libx2…...

【LSM tree 】Log-structured merge-tree 一种分层、有序、面向磁盘的数据结构

文章目录 前言基本原理读写流程写流程读流程 写放大、读放大和空间放大优化 前言 LSM Tree 全称是Log-structured merge-tree, 是一种分层&#xff0c;有序&#xff0c;面向磁盘的数据结构。其核心原理是磁盘批量顺序写比随机写性能高很多&#xff0c;可以通过围绕这一原理进行…...

配置OSPF与BFD联动示例

定义 双向转发检测BFD&#xff08;Bidirectional Forwarding Detection&#xff09;是一种用于检测转发引擎之间通信故障的检测机制。 BFD对两个系统间的、同一路径上的同一种数据协议的连通性进行检测&#xff0c;这条路径可以是物理链路或逻辑链路&#xff0c;包括隧道。 …...

01到底应该怎么理解“平均负载”

1、如何了解系统的负载情况&#xff1f; 每次发现系统变慢时&#xff0c; 我们通常做的第⼀件事&#xff0c; 就是执⾏top或者uptime命令&#xff0c; 来了解系统的负载情况。 ⽐如像下⾯这样&#xff0c; 我在命令⾏⾥输⼊了uptime命令&#xff0c; 系统也随即给出了结果。 …...

jmeter,动态参数之随机数、随机日期

通过函数助手&#xff0c;执行以下配置&#xff1a; 执行后的结果树&#xff1a; 数据库中也成功添加了数据&#xff0c;对应字段是随机值&#xff1a;...

uniApp常见知识点-问题答案

1、uniApp中如何进行页面跳转&#xff1f; 答案&#xff1a;可以使用 uni.navigateTo、uni.redirectTo 和 uni.reLaunch 等方法进行页面跳转。其中&#xff0c;uni.navigateTo可以实现页面的普通跳转&#xff0c; uni.redirectTo可以实现页面的重定向跳转&#xff0c; uni.reL…...

云原生基础入门概念

文章目录 发现宝藏云原生的概念云原生的关键技术为何选择云原生&#xff1f;云原生的实际应用好书推荐 发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【宝藏入口】。 云原生的概念 当谈及现…...

一个 tomcat 下如何部署多个项目?附详细步骤

一个tomcat下如何部署多个项目&#xff1f;Linux跟windows系统下的步骤都差不多&#xff0c;以下linux系统下部署为例。windows系统下部署同理。 1 不修改端口&#xff0c;部署多个项目 清楚tomcat目录结构的应该都知道&#xff0c;项目包是放在webapps目录下的&#xff0c;那…...

pycharm强制让terminal停止执行的快捷键

CtrlC即可...

MFC(Microsoft Foundation Classes)中 MessageBox

在MFC&#xff08;Microsoft Foundation Classes&#xff09;中&#xff0c;MessageBox是一个常用的对话框类&#xff0c;用于显示消息框并与用户进行交互。MessageBox类提供了多种用法和选项&#xff0c;以下是一些常见的用法和示例说明&#xff1a; 显示简单的消息框&#x…...

如何让.NET应用使用更大的内存

我一直在思考为何Redis这种应用就能独占那么大的内存空间而我开发的应用为何只有4GB大小左右&#xff0c;在此基础上也问了一些大佬&#xff0c;最终还是验证下自己的猜测。 操作系统限制 主要为32位操作系统和64位操作系统。 每个进程自身还分为了用户进程空间和内核进程空…...

【从零开始学习JVM | 第九篇】了解 常见垃圾回收器

前言&#xff1a; 垃圾回收器&#xff08;Garbage Collector&#xff09;是现代编程语言中的一项重要技术&#xff0c;它提供了自动内存管理的机制&#xff0c;极大地简化了开发人员对内存分配和释放的繁琐工作。通过垃圾回收器&#xff0c;我们能够更高效地利用计算机的内存资…...

Wordle 游戏实现 - 使用 C++ Qt

标题&#xff1a;Wordle 游戏实现 - 使用 C Qt 摘要&#xff1a; Wordle 是一款文字猜词游戏&#xff0c;玩家需要根据给定的单词猜出正确的答案&#xff0c;并在限定的次数内完成。本文介绍了使用 C 和 Qt 框架实现 Wordle 游戏的基本思路和部分代码示例。 引言&#xff1a;…...

Python 爬虫开发完整环境部署,爬虫核心框架安装

Python 爬虫开发完整环境部署 前言&#xff1a; ​ 关于本篇笔记&#xff0c;参考书籍为 《Python 爬虫开发实战3 》 笔记做出来的一方原因是为了自己对 Python 爬虫加深认知&#xff0c;一方面也想为大家解决在爬虫技术区的一些问题&#xff0c;本篇文章所使用的环境为&#x…...

汽车标定技术(十三)--标定概念再详解

目录 1.概述 2.基于Flash的标定 3.基于RAM的标定 4.AUTOSAR基于指针标定概念 5.小结 1.概述 最近有朋友问到是否用overlay标定完数据就直接写在Flash中&#xff0c;其实不然&#xff0c;是需要关闭overlay然后通过XCP Program指令集或者UDS刷进Flash。 从这里看出&#…...

PostgreSQL常用命令

数据库版本 :9.6.6 注意 :PostgreSQL中的不同类型的权限有 SELECT,INSERT,UPDATE,DELETE,TRUNCATE,REFERENCES,TRIGGER,CREATE,CONNECT,TEMPORARY,EXECUTE 和 USAGE。 1. 登录PG数据库 以管理员身份 postgres 登陆,然后通过 #psql -U postgres #sudo -i -u postgres …...

使用python脚本部署k8s集群

1.环境规划&#xff1a; 节点IP地址操作系统配置脚本运行节点192.168.174.5centos7.92G2核server192.168.174.150centos7.92G2核client1192.168.174.151centos7.92G2核client2192.168.174.152centos7.92G2 2.运行准备&#xff1a; yum install -y python python-pip pip in…...

【C语言】操作符详解(四):结构成员访问操作符

目录 结构成员访问操作符 结构体 结构体的声明 结构体变量的定义和初始化 结构成员访问操作符 结构体成员的直接访问 结构体成员的间接访问 结构成员访问操作符 结构体 ⭐C语言已经提供了内置类型&#xff0c;如: char、short、int、long、float、double等&#xff0c;但…...

【算法】二分法

1、二分法 1.1 二分法原理 每次将查找的范围缩小一半&#xff0c;直到最后找到记录或者找不到记录返回。 要求&#xff1a;采用二分法查找时&#xff0c;数据需是排好序的。 1.2二分法思路 判断某个数是否在数组中存在&#xff08;例&#xff1a;判断3是否在数组中存在&#…...

2023.12.18 JAVA学习day03,while与for循环

目录 0.switch 判断语句 一.for循环 1.简单练习 2.使用for循环计算1-100求和, 以及偶数求和 3.进阶练习,配合键盘录入与判断使用循环 二.while循环 三种格式的区别&#xff1a; 0.switch 判断语句 switch (表达式) { case 1: 语句体1; break; case …...

使用Pytorch从零开始构建StyleGAN2

这篇博文是关于 StyleGAN2 的&#xff0c;来自论文Analyzing and Improving the Image Quality of StyleGAN&#xff0c;我们将使用 PyTorch 对其进行干净、简单且可读的实现&#xff0c;并尝试尽可能地还原原始论文。 如果您没有阅读 StyleGAN2 论文。或者不知道它是如何工作…...

C++ Qt 开发:ListWidget列表框组件

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍ListWidget列表框组件的常用方法及灵活运用。…...

手机天线市场分析:预计2029年将达到576亿美元

手机天线&#xff0c;即手机上用于接收信号的设备&#xff0c;旧式手机有外凸式天线&#xff0c;新式手机多数已隐藏在机身内。这类天线主要都在手机内部&#xff0c;手机外观上看不到里面的东西。 手机天线主要就内置及外置天线两种&#xff0c;内置天线客观上必然比外置天线弱…...

FPGA引脚分配的问题

今天在做一个FPGA的实验时&#xff0c;在引脚分配时失败了&#xff0c;出现了如下报错&#xff1a; 我当时分配的引脚是PIN_AE19&#xff0c;然而奇怪的是我之前并未分配这个引脚&#xff0c;我使用的开发工具是Quartus II 9.1 Web Edition&#xff0c;算个老版本了。 有的网站…...

面试经典150题(27-28)

leetcode 150道题 计划花两个月时候刷完&#xff0c;今天&#xff08;第十三天&#xff09;完成了2道(27-28)150&#xff1a; 今天这两道是真的汗流浃背&#xff01;&#xff01;&#xff01; 27.&#xff08;209. 长度最小的子数组&#xff09;题目描述&#xff1a; 给定一…...

计算机图形学头歌合集(题集附解)

目录 CG1-v1.0-点和直线的绘制 第1关&#xff1a;OpenGL点的绘制 第2关&#xff1a;OpenGL简单图形绘制 第3关&#xff1a;OpenGL直线绘制 第4关&#xff1a;0<1直线绘制-dda算法<> 第5关&#xff1a;0<1直线绘制-中点算法<> 第6关&#xff1a;一般直线绘…...

MacBook Air提供了丰富多彩的截图选项,大到整个屏幕,小到具体的区域

本指南将带你了解在MacBook Air笔记本电脑上进行屏幕截图的各种方法。它涵盖了所有用于截屏的键盘快捷键,还包括如何启动MacBook Air屏幕录制和更改屏幕截图设置的信息。 如何在MacBook Air上进行屏幕截图 在MacBook上进行整个屏幕截图的最快、最简单的方法是使用command+sh…...

【CMU 15-445】Lecture 12: Query Execution I 学习笔记

Query Execution I Processing ModelsIterator ModelMaterialization ModelVectorization Model Access MethodsSequential ScanIndex Scan Modification QueriesHalloween Problem 本节课主要介绍SQL语句执行的相关机制。 Processing Models 首先是处理模型&#xff0c;它定义…...

wordpress过滤/推广软件排行榜前十名

最近遇到的连接问题我准备从重构的几个程序&#xff08;redis和mysql&#xff09;长连接和短连接&#xff0c;以及连接池和单连接等问题用几篇博客来总结下。 这个问题的具体发生在java原生程序和mysql的交互中。心得和上一篇一样&#xff0c;不过没用好也有对连接池的不熟悉的…...

资阳的网站建设/seo的目的是什么

参考资料&#xff1a; 基于Qt的P2P局域网聊天及文件传送软件设计 http://bbs.csdn.net/topics/390386771 分享qtffmpegsdl播放视频。 ffmpeg各种项目 https://trac.ffmpeg.org/wiki/Projects http://blog.sina.com.cn/s/blog_554f7c9501015vqx.html 用qt开发ffmpeg应用gui。…...

网站建设沧州/网页制作app

1、简介与下载 Anaconda 本质上是一个软件发行版&#xff0c;包含了 conda、Python 等 180 多个科学包及其依赖项。 简单来说&#xff0c;就是安装了Annaconda&#xff0c;就安装了python、conda和一般可能用到的numpy、scipy、pandas等等常见的科学计算包&#xff0c;而无需…...

网站的按钮怎么做的/贴吧推广

如何在Linux文件系统里面找到非UTF-8编码的文件名的文件或者文件夹&#xff1f; - 乐维UP如何在Linux文件系统里面找到非UTF-8编码的文件名的文件或者文件夹&#xff1f;0孟庆磊&#xff0c;乐维程序员在Linux系统中&#xff0c;如Ubuntu&#xff0c;经常会发现一些文件的文件名…...

网站上可以做直播吗/网络推广与优化

这里阅读的php版本为PHP-7.1.0 RC3&#xff0c;阅读代码的平台为linux ZTS 我们会看到文章中有很多地方是: #ifdef ZTS # define CG(v) ZEND_TSRMG(compiler_globals_id, zend_compiler_globals *, v) #else # define CG(v) (compiler_globals.v) extern ZEND_API struct _zend…...

郑州市建设委员会网站/域名查询网入口

http://blog.csdn.net/u013093547/article/details/53584591 今天在拷贝对象的时候&#xff0c;看着代码实在是有点烦&#xff0c;一堆一样的代码&#xff0c;还是找找有没有直接反射拷贝不同对象相同属性的值 百度了一下&#xff0c;结果第二个博客就是&#xff0c;地址就是最…...