Lambda表达式在C++中的定义

目录

背景介绍:

Lambda表达式的定义:

Lambda结构介绍:

1. Lambda capture

2. Lambda parameter list

3. Lambda mutable

4. Lambda return type

5. Lambda 主体

Lambda 表达式小结:

Lambda 引用参考:


背景介绍:

  Lambda 表达式是从 C++ 11 开始引入并被广泛使用,在其版本和更高版本中是一种在被调用的位置或作为参数传递给函数接口的位置定义匿名函数对象即闭包的方法。

  Lambda 通常用于封装传递给异步函数或某些算法的代码,其一般是由少量代码行所编写。该文章只是简单介绍 Lambda 的一些基础知识,高阶的知识分享会在之后的文章中出现。同时,该文章我参考了一些网上的介绍加上亲身的测试和理解。如有不正确的地方,请在评论区说明。

Lambda表达式的定义:

  下面是一段伪代码,里面只是简单写了利用 lambda 作为第三个参数传递给函数和利用另外新增的函数进行调用的方法上的对比。

#include <algorithm>
#include <cmath>using namespace std;// Method 1, not use lambda
bool compareNumbers(uint8_t num1, uint_8 num2) {return num1 > num2;
}// Method 2, use lambda
// Lambda expression begins
[](uint8_t num1, uint8_t num2) {return num1 > num2;
}
// End of lambda expressionint main() {int initA = 1;uint_8 a = 10, b = 9;// Method 1sort(initA, initA + 10, compareNumbers(a, b));// Method 2sort(initA, initA + 10,[](uint8_t num1, uint8_t num2) {return num1 > num2;});
}

Lambda 的组成:

[=] () mutable throw() -> bool {int c = a + b;a = b;return c > (a + b);
}1. [=] : This is capture words.
2. () : This is parameters list (Optional)
3. mutable : This is mutable specification (Optional)
4. throw() : This is exception-specification (Optional)
5. -> bool : This is trailing-return-type (Optional)
6. {...} : This is a body of lambda

Lambda结构介绍:

1. Lambda capture

  C++ 14 中的 lambda 表达式可在其主体中引入新的变量,并可以捕获周边范围内的变量。        Lambda 以 capture 子句作为开头:

        a. 指定捕获哪些变量

        b.捕获是通过值还是通过引用进行的:

                b1. 有与号 (&) 前缀的变量将通过引用进行访问

                b2. 没有该前缀的变量将通过值进行访问。

        c. 空 capture 子句 [ ] 表示 lambda 的主体不访问封闭范围中的变量。

  可以使用默认捕获模式来指示如何捕获 Lambda 体中引用的任何外部变量,使用默认捕获时,只有 lambda 体中所提及的变量才会被捕获:

  a. [&] 表示通过引用捕获引用的所有变量,而 [=] 表示通过值捕获它们。

  可以使用默认捕获模式,然后为特定变量显式指定相反的模式。 例如,如果 lambda 体通过引用访问外部变量 tot 并通过值访问外部变量 foo1,则以下 capture 子句等效:

[&, foo1]
[=, &tot]
[&tot, foo1]
[foo1, &tot]

  this 和标识符在 capture 中出现的次数不能超过一次。接下来的伪代码片段会提示一些内容(该部分参考微软提供的资料):

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

   下面这一部分代码和说明是参考C++官网资料:

If the capture-default is &, subsequent simple captures must not begin with &:struct S2 { void f(int i); };void S2::f(int i)
{[&] {};          // OK: by-reference capture default[&, i] {};       // OK: by-reference capture, except i is captured by copy[&, &i] {};      // Error: by-reference capture when by-reference is the default[&, this] {};    // OK, equivalent to [&][&, this, i] {}; // OK, equivalent to [&, i]
}// ...If the capture-default is =, subsequent simple captures must begin with & or be *this (since C++17) or this (since C++20):struct S2 { void f(int i); };void S2::f(int i) {[=] {};        // OK: by-copy capture default[=, &i] {};    // OK: by-copy capture, except i is captured by reference[=, *this] {}; // until C++17: Error: invalid syntax// since C++17: OK: captures the enclosing S2 by copy[=, this] {};  // until C++20: Error: this when = is the default// since C++20: OK, same as [=]
}// ...Any capture may appear only once, and its name must be different from any parameter name:struct S2 { void f(int i); };void S2::f(int i)
{[i, i] {};        // Error: i repeated[this, *this] {}; // Error: "this" repeated (C++17)[i] (int i) {};   // Error: parameter and capture have the same name
}

  当然还有些捕获后跟省略号的做法,这是一个包扩展,比如可变参数模板

template<class... Args>void foo(Args... args) {auto x = [args...] { return g(args...); };x();
}

  如果要访问对封闭类中的成员变量和成员函数,需要将 this 指针传递给 capture,这样将会获得访问的权限。

  当采用多线程的 lambda 表达式时,需要注意几点:

  a. 引用捕获会跟随外部变量的更新,但是值捕获是不会的

  b. 引用捕获修改时,外部变量的值会更新,同样,值捕获是不会的。

  c. 引用捕获会引入生存周期,而值捕获不会。

  C++ 14中引入通用捕获,即可以在 capture 中引入和初始化新变量,无需将这些变量存于 lambda 的闭包范围之内。有个比较不错的特性,即初始化可以以任意表达式表示,并且可以根据生成的类型推导新变量的类型,可以平行理解为 auto 关键字。

pString = make_unique<string>("Hello world!");auto pp = [p = move(pString)](){// use p};
2. Lambda parameter list

  Lambda 表达式是可以接收输入参数的,同时参数列表在 Lambda 中是可选的,有点类似于函数接口中的参数列表。(下方伪代码只是示例)

auto test = [] (uint_8 i, uint_8 j) {return i * j;
}

  C++ 14 可以使用 auto 关键字作为类型说明符,即当使用了 auto 关键字后编译器会将函数调用的运算符创建为模板,从而参数列表中定义为 auto 的实例都等效于对应的参数类型。

auto test = [] (auto i, auto j) {return i * j;
}

  当你不进行传参操作时,你可以省略掉 "()",因为参数列表是可选择的,其它的可选项基本上是一个道理的。

auto test = [] {return false;
}
3. Lambda mutable

  简单来说,利用mutable,Lambda 体可以修改通过值捕获的变量。

#include <iostream>int main() {int a = 1, b = 1, c = 1;auto foo1 = [a, &b, &c]() mutable {auto foo2 = [a, b, &c]() mutable {a = 2;b = 2;c = 2;};a = 3;b = 3;c = 3;foo2();};
}

  注意: mutable可以允许修改副本,而不能修改原始项。

4. Lambda return type

  在没有特别指定类型,如 trailing-return-type 的情况下,通常是无需 auto 关键字就可以自动推导 Lambda 表达式的返回类型。(trailing-return-type 实际上类似于普通函数接口的返回类型,只是它必须跟在参数列表的后面,且必须在返回类型前面包含 trailing-return-type 关键字 ->

auto test = [] (uint8_t i, uint8_t j) -> bool {return i > j;
}

  假设 Lambda 未提示返回值的情况下,如果包含有返回语句,则编译器将会自动推导出表达式的返回类型,即 return-type。否则,将会被推导为 void

// OK: return type is uint8_t
auto test1 = [] (uint8_t i) {return i * i;
};// ERROR: return type is void, deducing
auto test2 = [] {return {1, 2, 3}; // return type from braced-init-list isn't valid
};

  跟大多数函数接口一样,Lambda 可以再生成 Lambda 来作为其返回值。类似于上述 Lambda mutable 中代码所体现的 foo1 和 foo2。

5. Lambda 主体

  Lambda 体是一个复合语句,可以包含类似于函数接口中所允许的任意内容,比如一下的变量类型皆可访问:

    a. 参数

    b. 本地变量

    c. 类成员参数,需要捕获 this

    d. 当前封闭范围内所声明的变量

    e. 全局变量

  其实上述很多代码段已经展示了 Lambda 的主体,如果需要参考的话,基础的可以按照上面的结构来对比使用,这样可以减少很多问题。

auto foo = [](int n){std::function<int(int, int, int)> ff = [&](int n, int a, int b){return n ? ff(n - 1, a + b, a) : b;};return ff(n, 0, 1);};

Lambda 表达式小结:

  综上,我只是根据已有的一些资料结合自己的理解对 Lambda 表达式进行了一个基本的介绍。其中也有很多没有涉及到的部分,比如 noexcept 异常规范,constexpr 关键字对 Lambda 的修饰等,这些没有涉及到的部分有些是我还没来得及整理的,有些是我也没有遇到过的,所以暂时就不进行补充说明了。这篇文章主要着重于帮助大家理解最基本的 Lambda 结构和如何正确使用,这样可以减少代码问题的发生。

Lambda 引用参考:

  Lambda expressions (since C++11) - cppreference.com

  上述链接里面有非常清楚的介绍,也包括一些高级的用法,有兴趣的小伙伴不妨试试去看看。

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

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

相关文章

短视频平台的那些事

短视频平台的那些事 文章目录 短视频平台的那些事1. 前言2. 概览介绍3. 业务框架4. 关键技术能力4.1 视频处理4.1.1 FFMPEG技术 4.2 视频安全&#xff0c;合规4.2.1 视频安全审核4.2.2 视频MD5校验4.2.3 视频AI指纹 4.3 视频内容理解4.3.1 视频分类4.3.2 视频标签4.3.3 视频质量…

windows docker desktop配置加速地址

目录 为什么常见加速地址在docker desktop上配置 为什么 https://hub.docker.com 是官方的镜像仓库地址&#xff0c;但是它的服务器地址是在国外&#xff0c;有时候访问和下载的速度差强人意。不过好在&#xff0c;我们可以进行远程仓库的设置&#xff0c;将仓库镜像地址设置为…

ChatGPT 背后包含了哪些技术?

ChatGPT 是由OpenAI开发的一款基于GPT-3&#xff08;Generative Pre-trained Transformer 3&#xff09;的人工智能语言模型。这个模型是使用多种编程语言和技术组合编写的。 首先&#xff0c;ChatGPT 使用了 Python 作为主要的编程语言。Python 是一种流行的高级编程语言&…

Prometheus集成consul[被监控对象开启basic认证]

1&#xff0c;被监控对象开启basic认证 具体操作这里不再详细细讲。 2&#xff0c;将被监控对象注册到consul 由于被监控对象开启了basic认证&#xff0c;注册到consul后显示&#xff1a;401 Unauthorized Output: Unauthorized&#xff0c;不能够正常健康检查。 3&#xff0c…

AI绘画-Stable Diffusion笔记

软件&#xff1a;Stable Diffusion 视频教程来自 https://www.bilibili.com/video/BV1As4y127HW/?spm_id_from333.337.search-card.all.click 提示词 提示词类别 内容型提示词 人物主题特征&#xff1a; 服饰穿搭&#xff1a;white dress 发型发色&#xff1a;blonde hair,l…

TensorFlow案例学习:对服装图像进行分类

前言 官方为我们提供了一个 对服装图像进行分类 的案例&#xff0c;方便我们快速学习 学习 预处理数据 案例中有下面这段代码 # 预处理数据&#xff0c;检查训练集中的第一个图像可以看到像素值处于0~255之间 plt.figure() # 创建图像窗口 plt.imshow(train_images[0]) # …

【基于STM32OpenCV的车载机器人的抓取控制软件设计】

这里写自定义目录标题 本科优秀毕业论文《基于STM32&OpenCV的车载机器人的抓取控制软件设计》摘要:Abstract:前 言1方案设计与论证2机器人硬件电路设计3机器人软件设计4系统主要功能测试5 结 论参考文献本科优秀毕业论文《基于STM32&OpenCV的车载机器人的抓取控制软件…

开发过程教学——交友小程序

交友小程序 1. 我的基本信息2. 我的人脉2.1 我的关注2.2 我的粉丝 3. 我的视频4. 我的相册 特别注意&#xff1a;由于小程序分包限制2M以内&#xff0c;所以要注意图片和视频的处理。 1. 我的基本信息 数据库表&#xff1a; 我的基本信息我的登录退出记录我的登录状态&#x…

云计算:常用微服务框架

目录 一、理论 1.Java微服务框架 2.Go微服务框架 3.Python微服务框架 4.Node.js微服务框架 5..Net微服务框架 一、理论 1.Java微服务框架 Spring Cloud&#xff1a;最早最成熟&#xff0c;Java开源微服务框架方案 SpringBoot&#xff1a;全新框架&#xff0c;设计目的是…

Godot 官方2D游戏笔记(1):导入动画资源和添加节点

文章目录 前言2D官方游戏案例资源下载项目配置添加角色节点模拟运行移动根节点 结束 Godot专栏地址 前言 Godot 官方给了我们2D游戏和3D游戏的案例&#xff0c;不过如果是独立开发者只用考虑2D游戏就可以了&#xff0c;因为2D游戏纯粹&#xff0c;我们只需要关注游戏的玩法即可…

蓝桥杯---第二讲---二分与前缀和

文章目录 前言Ⅰ. 数的范围0x00 算法思路0x00 代码书写 Ⅱ. 数的三次方根0x00 算法思路0x01代码书写 Ⅲ. 前缀和0x00 算法思路0x01 代码书写 Ⅳ. 子矩阵的和0x00 算法思路0x01 代码书写 Ⅴ. 机器人跳跃问题0x00 算法思路0x01 代码书写 Ⅵ. 四平方和0x00 算法思路0x01 代码书写 …

SpringCloud学习笔记-注册微服务到Eureka注册中心

目录 1.在该Module的pom文件中引入eureka依赖2.在该module的src/main/resources/application.yml配置文件3.启动对应的微服务4.查看微服务是否启动成功 假如我有一个微服务名字叫user-service,我需要把它注册到Eureka注册中心,则具体步骤如下: 1.在该Module的pom文件中引入eure…

Flink的处理函数——processFunction

目录 一、处理函数概述 二、Process函数分类——8个 &#xff08;1&#xff09;ProcessFunction &#xff08;2&#xff09;KeyedProcessFunction &#xff08;3&#xff09;ProcessWindowFunction &#xff08;4&#xff09;ProcessAllWindowFunction &#xff…

真香!Jenkins 主从模式解决问题So Easy~

01.Jenkins 能干什么 Jenkins 是一个开源软件项目&#xff0c;是基于 Java 开发的一种持续集成工具&#xff0c;用于监控持续重复的工作&#xff0c;旨在提供一个开放易用的软件平台&#xff0c;使软件项目可以进行持续集成。 中文官网&#xff1a;https://jenkins.io/zh/ 0…

好消息:用 vue3+layui 共同铸造我们新的项目

前言&#xff1a; layui这个框架不知道多少人还在关注着&#xff0c;记得第一次接触它是在18年&#xff0c;后来随着vue&#xff0c;react的盛行&#xff0c;jquerylayui的模式受到了特别大的冲击&#xff0c;后来作者都放弃维护他的官方网站&#xff0c;转而在github/gitee上做…

SLAM从入门到精通(ROS和底盘Stm32的关系)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 学过Ros的同学&#xff0c;一般对subscribe、publish、话题、服务这些内容都比较熟悉。如果再熟悉一点的话&#xff0c;还会知道slam、move_base、…

NLP - 数据预处理 - 文本按句子进行切分

NLP - 数据预处理 - 文本按句子进行切分 文章目录 NLP - 数据预处理 - 文本按句子进行切分一、前言二、环境配置1、安装nltk库2、下载punkt分句器 三、运行程序四、额外补充 一、前言 在学习对数据训练的预处理的时候遇到了一个问题&#xff0c;就是如何将文本按句子切分&#…

LeetCode:买卖股票 系列 含冷冻期、含手续费(C++)

目录 309. 买卖股票的最佳时机含冷冻期 714. 买卖股票的最佳时机含手续费 买卖股票的最佳时机 Ⅰ、Ⅱ、Ⅲ、Ⅳ 的解析&#xff0c;在如下的上一篇博文中&#xff1a; LeetCode&#xff1a;买卖股票的最佳时机 系列Ⅰ、Ⅱ、Ⅲ、Ⅳ、含冷冻期&#xff08;C&#xff09;_Cosmos…

ChainForge:衡量Prompt性能和模型稳健性的GUI工具包

ChainForge是一个用于构建评估逻辑来衡量模型选择&#xff0c;提示模板和执行生成过程的GUI工具包。ChainForge可以安装在本地&#xff0c;也可以从chrome浏览器运行。 ChainForge可以通过聊天节点对多个对话可以使用不同的llm并行运行。可以对聊天消息进行模板化&#xff0c;并…

基于复旦微JFM7K325T FPGA的高性能PCIe总线数据预处理载板(100%国产化)

PCIE711是一款基于PCIE总线架构的高性能数据预处理FMC载板&#xff0c;板卡采用复旦微的JFM7K325T FPGA作为实时处理器&#xff0c;实现各个接口之间的互联。该板卡可以实现100%国产化。 板卡具有1个FMC&#xff08;HPC&#xff09;接口&#xff0c;1路PCIe x8主机接口&#x…