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
上述链接里面有非常清楚的介绍,也包括一些高级的用法,有兴趣的小伙伴不妨试试去看看。
相关文章:
Lambda表达式在C++中的定义
目录 背景介绍: Lambda表达式的定义: Lambda结构介绍: 1. Lambda capture 2. Lambda parameter list 3. Lambda mutable 4. Lambda return type 5. Lambda 主体 Lambda 表达式小结: Lambda 引用参考: 背景介…...

sheng的学习笔记-【中文】【吴恩达课后测验】Course 1 - 神经网络和深度学习 - 第二周测验
课程1_第2周_测验题 目录:目录 第一题 1.神经元计算什么? A. 【 】神经元计算激活函数后,再计算线性函数(zWxb) B. 【 】神经元计算一个线性函数(zWxb),然后接一个激活函数…...
前端代码格式化规范总结
在日常开发过程中,经常会碰到代码格式化不一致的问题,还要就是 js 代码语法错误等没有及时发行改正,下面就介绍一下如何使用eslint、prettier、husky、lint-staged、commitizen来规范代码格式和提高代码质量的方法。 目录 准备工作代码检测代…...

Windows10打开应用总是会弹出提示窗口的解决方法
用户们在Windows10电脑中打开应用程序,遇到了总是会弹出提示窗口的烦人问题。这样的情况会干扰到用户的正常操作,给用户带来不好的操作体验,接下来小编给大家详细介绍关闭这个提示窗口的方法,让大家可以在Windows10电脑中舒心操作…...

易点易动固定资产管理系统: 帮助您应对2023年年终固定资产大盘点
作为一名企业的行政人员,我们都了解年终固定资产盘点对于企业来说至关重要。然而,面对众多资产、复杂的流程和繁琐的记录工作,往往会令人感到头疼不已。为了帮助您应对2023年的年终固定资产大盘点,我们推荐易点易动固定资产管理系…...

OpenGLES:绘制一个混色旋转的3D立方体
效果展示 混色旋转的3D立方体 一.概述 之前关于OpenGLES实战开发的博文,不论是实现相机滤镜还是绘制图形,都是在2D纬度 这篇博文开始,将会使用OpenGLES进入3D世界 本篇博文会实现一个颜色渐变、旋转的3D立方体 动态3D图形的绘制…...

Maven(4)-利用intellij idea创建maven 多模块项目
本文通过一个例子来介绍利用maven来构建一个多模块的jave项目。开发工具:intellij idea。 一、项目结构 multi-module-project是主工程,里面包含两个模块(Module): web-app是应用层,用于界面展示ÿ…...

8年测试老鸟,性能测试-数据库连接池问题定位/分析,一篇打通...
目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 1、环境准备 1&a…...

【Sentinel】Sentinel原码分析
本文内容来自【黑马】Sentinel从使用到源码解读笔记,做了部分修改和补充 目录 Sentinel 基本概念 基本流程 Node Entry 定义资源的两种方式 使用try-catch定义资源 使用注解标记资源 基于注解标记资源的实现原理 Context 什么是Context Context的初始化 …...

计算机竞赛 题目:基于深度学习的人脸表情识别 - 卷积神经网络 竞赛项目 代码
文章目录 0 简介1 项目说明2 数据集介绍:3 思路分析及代码实现3.1 数据可视化3.2 数据分离3.3 数据可视化3.4 在pytorch下创建数据集3.4.1 创建data-label对照表3.4.2 重写Dataset类3.4.3 数据集的使用 4 网络模型搭建4.1 训练模型4.2 模型的保存与加载 5 相关源码6…...
基于aarch64分析kernel源码 五:idle进程(0号进程)
一、参考 linux — 0号进程,1号进程,2号进程 - 流水灯 - 博客园 (cnblogs.com) Linux0号进程,1号进程,2号进程_0号进程和1号进程-CSDN博客 二、idle进程的创建流程 start_kernel --> arch_call_rest_init --> rest_init…...

【Linux】 vi / vim 使用
天天用vim 或者vi 。看着大佬用的很6 。我们却用的很少。今天咱们一起系统学习一下。 vi / vim 发展史 vi 是一款由加州大学伯克利分校,Bill Joy研究开发的文本编辑器。 vim Vim是一个类似于Vi的高度可定制的文本编辑器,在Vi的基础上改进和增加了很多…...

Leetcode hot 100之双指针(快慢指针、滑动窗口)
目录 数组 有序的平方仍有序 删除/覆盖元素 移动零:交换slow和fast 滑动窗口:最短的连续子串(r可行解->l--最短解) 最小长度的子数组 求和:sort、l i 1, r len - 1 三数之和abctarget 四数之和abcdtarg…...

Bridge Champ助力我国桥牌阔步亚运, Web3游戏为传统项目注入创新活力
本届杭州亚运会,中国桥牌队表现杰出,共斩获1金1银1铜佳绩,其中女子团体夺得冠军,混合团体获得亚军。这充分展现了我国桥牌的实力,也彰显了桥牌作为亚运会体育竞技项目的影响力。与此同时,Web3游戏Bridge Champ为传统桥牌项目带来创新模式,将有望推动桥牌运动在亚运舞台上焕发新…...

云原生微服务 第六章 Spring Cloud中使用OpenFeign
系列文章目录 第一章 Java线程池技术应用 第二章 CountDownLatch和Semaphone的应用 第三章 Spring Cloud 简介 第四章 Spring Cloud Netflix 之 Eureka 第五章 Spring Cloud Netflix 之 Ribbon 第六章 Spring Cloud 之 OpenFeign 文章目录 系列文章目录前言1、OpenFeign的实现…...
uniapp-vue3 抖音小程序开发(上线项目开源)
最近公司临时接一个项目来接手别人的流量,项目比较小,时间比较赶。 需求:一个答题小程序,通过答题来实现性格测算和分析。 之前开发过支付宝小程序和微信小程序,这次是首次开发抖音小程序,老板要求只能下…...

基于微信小程序的个人健康数据管理平台设计与实现(源码+lw+部署文档+讲解等)
文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…...

真香!Jenkins 主从模式解决问题So Easy~
01.Jenkins 能干什么 Jenkins 是一个开源软件项目,是基于 Java 开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件项目可以进行持续集成。 中文官网:https://jenkins.io/zh/ 0…...

Win10系统打开组策略编辑器的两种方法
组策略编辑器是Win10电脑中很实用的工具,它可以帮助用户管理和设置计算机的安全性、网络连接、软件安装等各种策略。但是,很多新手用户不知道打开Win10电脑中组策略编辑器的方法步骤,下面小编给大家介绍两种简单的方法,帮助打开快…...
git 的行结束符
CR (Carriage Return) 表示<回车>LF (Line Feed) 表示<换行> 1. 不同系统的行结束符 系统名称行结束符意义释义git line endings选项DOS / Windows\r\nCRLF‘\r’是使光标移动到行首 ’\n’是使光标下移一行Windows-styleMacOS\rCRreturnAs-isUNIX / Linux\nLFne…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
uniapp 实现腾讯云IM群文件上传下载功能
UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中,群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS,在uniapp中实现: 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...
Windows 下端口占用排查与释放全攻略
Windows 下端口占用排查与释放全攻略 在开发和运维过程中,经常会遇到端口被占用的问题(如 8080、3306 等常用端口)。本文将详细介绍如何通过命令行和图形化界面快速定位并释放被占用的端口,帮助你高效解决此类问题。 一、准…...