C++笔记之lambda表达式

news2024/11/15 13:51:01

在这里插入图片描述

引言

Lambda表达式是从C++ 11版本引入的特性,利用它可以很方便的定义匿名函数对象,通常作为回调函数来使用。大家会经常拿它和函数指针,函数符放在一起比较,很多场合下,它们三者都可以替换着用。

语法

[ captures ] ( params ) specs requires (optional) {body}

上面是完整的Lambda表达式结构,从左到右分别是:

  • capture–捕获列表
  • params–参数列表
  • specification列表-- 可选部分,这块部分主要由变量说明符、异常、返回类型等组成
  • requires – C++20 版本开始增加的
  • body-- 函数体

关于specification和requires部分的详细描述可以参考:https://en.cppreference.com/w/cpp/language/lambda

我们平时的开发工作可能不会基于C++20版本,一般都是C++17及以下,所以就先记录一下,平时开发所接触的Lambda表达式。哪些新版本增加的相关特性就暂不讨论。

常见的Lambda表达式语法:

图片引自 微软C++课程

结构描述:

  1. 捕获列表,可以捕获外部变量
  2. 形参列表 (可选)
  3. 变量说明符(可选)属于specification列表,用来表示可以修改值捕获的变量,后面会详细说明
  4. exception (可选)属于specification列表,用来表示是否会有异常
  5. 返回类型 (可选)
  6. 函数体

从上面的结构描述,我们能看到,最简洁的lambda表达式应该是这样:

[]{}

我们常用的lambda表达式有以下几种:

[capture list]{body}
[capture list](params){body}
[capture list](params)->return type {body}

捕获列表

lambda表达式有两种捕获其作用域外部变量的方式,一种是值捕获,一种是引用捕获。

值捕获
#include <iostream>
using namespace std;
int main(int argc, char **argv) {
  int a = 100;
  auto test = [a]() mutable {
    a++;
    cout << "inside, a:" << a << endl;
  };
  test();
  cout << "outsize, a:" << a << endl;
  return 0;
}

输出结果:

inside, a:101
outsize, a:100

值捕获的情况下,如果需要某个特地的外部变量,那么直接在捕获列表里面写相应的变量名即可,如果想要值捕获所以外部变量,可使用如下形式:

[=]

上面的例子中有mutable,这个关键字的作用是运行lambda内部可以修改值捕获的变量,默认情况下,值捕获的变量是只读的。

引用捕获
#include <iostream>
using namespace std;
int main(int argc, char **argv) {
  int a = 100;
  auto test = [&a]() {
    a++;
    cout << "inside, a:" << a << endl;
  };
  test();
  cout << "outsize, a:" << a << endl;
  return 0;
}

输出结果:

inside, a:101
outsize, a:101

引用捕获外部变量的话,需要在变量名前加上**&,如果想要以引用捕获的方式访问所以外部变量,可以使用:[&]**

注意,这里我们移除了mutable关键字。

值捕获&引用捕获

因为是捕获列表嘛,所以当然可以互相组合搭配了,不然怎么能达到列表的定义呢。例如,我们想要以值捕获的方式捕获factor变量,以引用捕获的方式捕获total变量,那么可以用如下的方式:

[&total, factor]
[factor, &total]
[&, factor]
[=, &total]

以上面第一个方式举个例子:

#include <iostream>
using namespace std;
int main(int argc, char **argv) {
  int total = 100;
  float factor = 0.2f;
  auto test = [&total, factor]() mutable {
    factor = 0.5f;
    total = static_cast<int>(total * factor);
    cout << "inside, total:" << total << ", factor:" << factor << endl;
  };
  test();
  cout << "outsize, total:" << total << ",factor:" << factor << endl;
  return 0;
}

输出结果:

inside, total:50, factor:0.5
outsize, total:50,factor:0.2

在两种捕获方式互相搭配的使用过程中,需要注意一点的是,当捕获列表中已经使用了**&来捕获所以外部变量,就不能再使用&变量名**,捕获指定变量了,同理,值捕获也是这样。例如:

struct S { void f(int i); };

void S::f(int i) {
    [&, i]{};      // OK
    [&, &i]{};     // ERROR: i preceded by & when & is the default
    [=, this]{};   // ERROR: this when = is the default
    [=, *this]{ }; // OK: captures this by value. See below.
    [i, i]{};      // ERROR: i repeated
}
注意

上面的例子中,访问外部的变量,都必须通过捕获列表“处理”一下,内部才能访问,其实还有一些情况是不需要捕获,lambda就能访问的。例如:

  • 当lambda要访问的变量是全局的或者静态(static)的,可以直接使用
  • Thread Local 变量
  • constant expression 并且没有mutable成员 (只读)
  • const修饰的non-volatile int型字面量 或者 由constant expression初始化的枚举类型 (只读)

下面举一些例子:

#include <iostream>
using namespace std;
int total = 100;
int main(int argc, char **argv) {
  static float factor = 0.2f;
  auto test = []() {
    factor = 0.5f;
    total = static_cast<int>(total * factor);
    cout << "inside,global total:" << total << ", static factor:" << factor
         << endl;
  };
  test();
  cout << "outsize,global total:" << total << ", static factor:" << factor
       << endl;
  return 0;
}

输出结果:

inside,global total:50, static factor:0.5
outsize,global total:50, static factor:0.5
#include <iostream>
#include <thread>
using namespace std;
int main(int argc, char **argv) {
  const int x = 1024;
  enum TYPE { kTypeApp = 0, kTypeUser };
  auto test = []() {
    cout << "type:" << kTypeUser << endl;
    cout << "x:" << x << endl;
  };
  test();
  return 0;
}

输出结果:

type:1
x:1024

参数列表&返回类型

lambda除了通过捕获列表的方式访问外部变量,也可以通过传递参数来与外界交流。跟普通函数没啥区别,这个没啥好说的。需要知道的是lambda支持它的参数也可以是lambda表示式。

返回类型跟普通函数差别也不大,同样需要注意的是,跟参数列表一样,也是支持返回lambda表达式的。同时,如果不指定返回类型的话,那么可以用auto关键字接收返回结果,自动推导结果。

#include <functional>
#include <iostream>
using namespace std;
int main() {
  auto addtwointegers = [](int x) -> function<int(int)> {
    return [=](int y) { return x + y; };
  };

  auto higherorder = [](const function<int(int)>& f, int z) {
    return f(z) * 2;
  };

  auto answer = higherorder(addtwointegers(7), 8);

  cout << answer << endl;
}

输出结果:

30

lambda嵌套

lambda表达式内部还可以创建lambda表达式,套娃的感觉🪆。

#include <iostream>
using namespace std;
int main()
{
    int ret = [](int x) { return [](int y) { return y * 2; }(x) + 3; }(5);
    cout << ret << endl;
}

输出结果:

13

参考

https://learn.microsoft.com/en-us/cpp/cpp/examples-of-lambda-expressions?view=msvc-170

https://en.cppreference.com/w/cpp/language/lambda

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

javaScript基础面试题 ---宏任务微任务

宏任务微任务一、为什么JS是单线程语言&#xff1f;二、JS是单线程&#xff0c;怎样执行异步代码&#xff1f;1、JS是单线程语言 2、JS代码执行流程&#xff0c;同步执行完&#xff0c;再进行事件循环&#xff08;微任务、宏任务&#xff09; 3、清空所有的微任务&#xff0c;再…

机器学习100天(四十):040 线性支持向量机-公式推导

《机器学习100天》完整目录:目录 机器学习 100 天,今天讲的是:线性支持向量机-公式推导! 首先来看这样一个问题,在二维平面上需要找到一条直线划分正类和负类。 我们找到了 A、B、C 三条直线。这三条直线都能正确分类所有训练样本。但是,哪条直线最好呢?直观上来看,我…

代码随想录算法训练营第六天|242.有效的字母异位词 、349. 两个数组的交集 、 202. 快乐数、1. 两数之和

当我们遇到了要快速判断一个元素是否出现集合里的时候&#xff0c;就要考虑哈希法。哈希法是牺牲了空间换取了时间&#xff0c;要使用额外的数组&#xff0c;set或者是map来存放数据&#xff0c;才能实现快速的查找。当我们要使用集合来解决哈希问题的时候&#xff0c;优先使用…

【SpringCloud】SpringCloud教程之Nacos实战(1)

目录Nacos是什么&#xff1f;一.Nacos下载二.安装Nacos三.Nacos原理四.Nacos快速入门五.Nacos服务多级存储模式六.Nacos根据集群设置负载均衡1.根据同集群优先访问2.根据权重配置负载均衡七.Nacos的环境隔离八.Nacos和Eureka的区别前提&#xff1a;以订单服务和用户服务为例&am…

【C++基础入门】数组、函数

一&#xff1a;数组 1.1 概述 所谓数组&#xff0c;就是一个集合&#xff0c;里面存放了相同类型的数据元素 特点1&#xff1a; 数组中的每个数据元素都是相同的数据类型 特点2&#xff1a; 数组是由连续的内存位置组成的 1.2 一维数组 1.2.1 一维数组定义方式 一维数组…

世界那么大,你哪都别去了,来我带你了解CSS3 (二)

文章目录‍❤️‍&#x1f525;CSS文档流‍❤️‍&#x1f525;CSS浮动‍❤️‍&#x1f525;CSS定位‍❤️‍&#x1f525;CSS媒体查询‍❤️‍&#x1f525;CSS文档流 文档流是文档中可显示对象在排列时所占用的位置/空间。 例如&#xff1a;块元素自上而下摆放&#xff0c;内…

第一章---Pytorch快速入门---第一节---张量及运算

目录 1.1张量的数据类型 1.2 张量的生成 1.3 张量操作 1.4 张量的计算 一、张量 在高等数学中&#xff0c;单独的一个数是标量&#xff0c;而有序排列的一组数字是一个向量&#xff08;例如一个数组&#xff09;&#xff0c;向量组可以构成矩阵。向量是一维的&#xff0c;而…

Java——腐烂的橘子

题目链接 leetcode在线oj题——腐烂的橘子 题目描述 在给定的 m x n 网格 grid 中&#xff0c;每个单元格可以有以下三个值之一&#xff1a; 值 0 代表空单元格&#xff1b;值 1 代表新鲜橘子&#xff1b;值 2 代表腐烂的橘子。 每分钟&#xff0c;腐烂的橘子 周围 4 个方…

Python数据分析案例19——上市银行财务指标对比

我代码栏目都是针对基础的python数据分析人群&#xff0c;比如想写个本科毕业论文&#xff0c;课程论文&#xff0c;做个简单的案例分析等。过去写的案例可能使用了过多的机器学习和深度学习方法&#xff0c;文科的同学看不懂&#xff0c;可能他们仅仅只想用python做个回归或者…

Method breakpoints may dramatically slow down debugging 解决方案

项目无法启动了 简单介绍一下事情的过程&#xff1a;昨天在进行代码调试的时候&#xff0c;代码部分处理完成之后&#xff0c;启动debug模式的热部署准备测试一下逻辑&#xff0c;结果左下角提示我热部署失败&#xff0c;需要重新启动Tomcat才能再次调试&#xff0c;所以只得重…

spring之refresh流程-Java八股面试(六)

系列文章目录 第一章 ArrayList-Java八股面试(一) 第二章 HashMap-Java八股面试(二) 第三章 单例模式-Java八股面试(三) 第四章 线程池和Volatile关键字-Java八股面试(四) 第五章ConcurrentHashMap-Java八股面试(五) 动态每日更新算法题&#xff0c;想要学习的可以关注一下…

css中重难点整理(vertical-align)

一、vertical-align 在学习vertical-align的时候&#xff0c;可能会很困惑。即使网上有一大推文章讲veitical-align,感觉看完好像懂了&#xff0c;等自己布局的时候用到vertical-align的时候好像对它又很陌生。这就是我在布局的时候遇到的问题。 本来vertical-align就很不好理…

Spring——配置文件实现IOC和DI入门案例

现在先如图创建如下的Maven项目&#xff0c;在业务层和数据层分别写上对应的接口和实现类 在BookServiceImpl中创建一个BookDaoImpl对象&#xff0c;并调用里面的save()方法。 在测试类里面new一个bookservice的实现类&#xff0c;调用save()方法 输出如下图所示 要使用IOC容…

安全开发基础 -- DAST,SAST,IAST简单介绍

安全开发基础-- DAST&#xff0c;SAST&#xff0c;IAST 简介 DAST 动态应用程序安全测试&#xff08;Dynamic Application Security Testing&#xff09;技术在测试或运行阶段分析应用程序的动态运行状态。它模拟黑客行为对应用程序进行动态攻击&#xff0c;分析应用程序的反…

Windows 10 - Django + simpleui项目实战 - 详细总结 导入导出-权限修改-修改登录界面-数据库优化-js触发事件失效奇葩问题

目录对django框架的内置功能的修改导入导出模块超级用户权限修改了解修改登录界面方法安装mysqlclient 性能优化&#xff0c;比pymysql模块更好报错 django.db.utils.OperationalError: (2026, SSL connection error: unknown error number)静态文件管理js问题 - onchange 和 o…

微信小程序搭建流程

一、申请微信开发者账号虽然开发微信小程序可以使用工具提供的测试号&#xff0c;但是测试号提供的功能极为有限&#xff0c;而且使用测试号开发的微信小程序不能上架发布。因此说我们想要开发一个可以上架的微信小程序&#xff0c;首先必须要申请微信开发者账号。大家尽可放心…

2023年总结的web前端学习路线分享(学习导读)

如果你打开了这篇文章&#xff0c;说明你是有兴趣想了解前端的这个行业的&#xff0c;以下是博主2023年总结的一些web前端的学习分享路线&#xff0c;如果你也想从事前端或者有这方面的想法的&#xff0c;请接着往下看&#xff01; 前端发展前景 前端入门 巩固基础 前端工程…

深度学习J1周-ResNet50算法实战与解析_鸟类识别(CNN)

&#x1f368; 本文为[&#x1f517;365天深度学习训练营]内部限免文章&#xff08;版权归 *K同学啊* 所有&#xff09; &#x1f356; 作者&#xff1a;[K同学啊] 本周任务&#xff1a; ●1.请根据本文 TensorFlow 代码&#xff08;训练营内部阅读&#xff09;&#xff0c;编写…

EasyExcel3.x文件导入SpringBoot2

引入依赖<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.3</version></dependency>简单导出以导出用户信息为例&#xff0c;接下来手把手教大家如何使用EasyExcel实现导出功能&a…

华为OD机试题,用 Java 解【数字涂色】问题

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典使用说明 参加华为od机试,一定要注意不…