C++ Lambda表达式第二篇, Lambda表达式

C++ Lambda表达式

  • Lambda 捕获
  • 含有模板参数的Lambda表达式
  • 无模板参数的Lambda表达式

Lambda 捕获

captures是零个或多个捕获的逗号分隔列表,可以选择以capture-default开头。捕获列表定义可从 lambda 函数体内访问的外部变量。唯一的捕获默认值是

  • &,变量引用方式,隐式捕获已使用的变量,存储持续时间限于Lambda表达式内
  • =,值引用方式,隐式捕获已使用的变量,存储持续时间限于Lambda表达式内。

如果存在任一捕获默认值,则当前对象 (*this)可以隐式捕获。如果隐式捕获,则始终通过引用捕获,即使捕获默认值为=。从C++20开始,当捕获默认值为 = 时,不推荐使用 *this 的隐式捕获。

captures 中单个捕获的语法是

下面展示一些 内联代码片

 - identifier                            简单的值引用捕获
 - identifier ...                        简单的值引用捕获,捕获是一个包扩展
 - identifier initializer                简单的值引用捕获,捕获包括初始化器
 - &identifier                           简单的变量引用捕获
 - &identifier...                        简单的变量引用捕获,捕获是一个包扩展
 - &identifier initializer               简单的变量引用捕获,捕获包括初始化器
 - this                                  当前对象的简单的变量引用捕获
 - *this                                 当前对象的简单的值引用捕获
 - ...identifier initializer             值引用捕获,捕获是一个包扩展, 包扩展包含初始化器
 - &...identifier initializer            变量引用捕获,捕获是一个包扩展, 包扩展包含初始化器

如果capture-default 为 &,则后续的简单捕获不能以 & 开头。

#include  <iostream>

using namespace std;

struct S2 { void f(int i, int j); };
void S2::f(int i, int j)
{
	[&] {i = i + 1;};          // OK: by-reference capture default
	cout << "i = " << i << endl;
	
//	[&, i] {i=0; j=j+1;};       // error: assignment of read-only variable ‘i’

	[&, i] {j=i+1;};
	cout << "j=" << j << endl;
	
//	[&, &i] {};      // Error: by-reference capture when by-reference is the default
	[=, &j] {j=i+1;};
	cout << "j=" << j << endl;
	
	[&, this, i] {}; // OK, equivalent to [&, i]
}


int main() {	
	S2 s1;
	s1.f(1, 2);
   cout << endl;
	
	s1.f(9, 10);
}

代码运行的屏幕输出

i = 1
j=2
j=2

i = 9
j=10
j=10

只有在块作用域或默认成员初始器中定义的 lambda 表达式,才可以有一个默认捕获或不带初始器的捕获。对于此类 lambda 表达式,其有效范围定义为一组封闭范围,这个范围包括最内层封闭函数(及其参数)。这包括嵌套的块作用域和封闭 lambda 的作用域(如果该 lambda 是嵌套的)。

任何没有初始化程序的捕获(除了 this-capture)中的 identifier,都是在 lambda 的到达范围内,使用通常的非限定名称查找来查找的。查找的结果必须是,在到达范围内声明的具有自动存储持续时间的变量,或者是其对应变量满足此类要求的结构化绑定。该实体被显式捕获。

带初始器的捕获的行为,就好像它声明,并显式捕获一个变量,这个变量使用类型说明符 auto 和相同的初始器声明。其声明区域是 lambda 表达式的主体(即,它不在其初始器设定的范围内),但不包括下列情况:

  • 如果捕获是通过值引用,则闭包对象引入的非静态数据成员,是引用该变量的另一种方式;
    换句话说,源变量实际上并不存在,并且通过 auto 进行类型推导和初始化,适用于该非静态数据成员;
  • 如果捕获是通过变量引用,则闭包对象的生命周期结束时,引用变量的生命周期也结束。

这用于通过 x = std::move(x) 等捕获,来捕获仅移动类型。
这也使得可以使用 &cr = std::as_const(x) 或类似方法,使const 引用捕获成为可能。

#include  <iostream>

using namespace std;

int x = 4;
auto y = [&r = x, x = x + 1]()->int{r += 2; return x * x;};

int main()
{
	auto val = y();
	
	cout << "x=" << x  <<  endl;
	cout << val << endl;
}
x=6
25

如果捕获表有一个默认捕获,并且未显式捕获封闭对象(如 this 或 *this),或者自动变量,或者结构化绑定;那么,它会隐式捕获实体, 该实体在一个表达式中,在potentially-evaluated表达式中命名。
该自动变量在lambda 主体中是odr-usable。结构化绑定有原子存储持续时间。

#include  <iostream>

using namespace std;

void f(int x, const int (&)[2] = {}) { cout <<"f1:" << x <<endl;}   // #1
void f(const int &x, const int (&)[1]) { cout <<"f2:" << x <<endl;} // #2
 
struct NoncopyableLiteralType
{
    constexpr explicit NoncopyableLiteralType(int n) : n_(n) {}
    NoncopyableLiteralType(const NoncopyableLiteralType&) = delete;
 
    int n_;
};
    
int main ()
{
    const int x = 17;
 
    auto l0 = []{ f(x); };           // OK: calls #1, does not capture x
    auto g0 = [](auto a) { f(x); };  // same as above
 
	auto l1 = [=]{ f(x); };          // OK: captures x (since P0588R1) and calls #1
                                     // the capture can be optimized away
	auto g1 = [=](auto a) { f(x); }; // same as above
	auto g2 = [=](auto a) {
		int selector[sizeof(a) == 1 ? 1 : 2] = {};
		f(x, selector); 					// OK: is a dependent expression, so captures x
		cout << "g2" << endl;
	};

	auto ltid = [=]{ return typeid(x).name(); };   // OK: captures x (since P0588R1)
                                     // even though x is unevaluated
                                     // the capture can be optimized away
	auto g3 = [=](auto a) {
		auto type = typeid(a + x).name();  // captures x regardless of
                        // whether a + x is an unevaluated operand
		cout << "g3: " << type << endl;
	};

	auto g4 = [&](auto a) {
		int selector[sizeof(a) == 1 ? 1 : 2] = {};
		f(x, selector); 					// OK: is a dependent expression, so captures x
		cout << "g2" << endl;
	};

	l1();
	
	g1(1);
  
	g2(1);
	g2(2);
	cout << "x id:" << ltid() << endl;
	g3(4);
	g4(1);
	 
    constexpr NoncopyableLiteralType w{42};
    auto l4 = []{ return w.n_; };      // OK: w is not odr-used, capture is unnecessary
    // auto l5 = [=]{ return w.n_; };  // error: w needs to be captured by copy
	 cout << l4() << endl;
}

f1:17
f1:17
f1:17
g2
f1:17
g2
x id:i
g3: i
f1:17
g2
42

含有模板参数的Lambda表达式

 - [captures ] front-attr (optional) (params ) specs (optional) exception (optional) back-attr (optional) trailing-type (optional) requires (optional) { body }
 - [captures ] { body }
 - [captures ] front-attr (optional) trailing-type (optional) { body }	
 - [captures ] front-attr (optional) exception back-attr (optional) trailing-type (optional) { body }	
 - [captures ] front-attr (optional) specs exception (optional) back-attr (optional) trailing-type (optional) { body }
  • captures - Lambda表达式可以拥有零个或多个逗号分隔的捕获列表,可以选择以捕获默认值开头。
    lambda 表达式可以使用变量而不捕获它,如果该变量
  • 是非局部变量或具有静态或线程局部存储持续时间(在这种情况下无法捕获该变量),或者
  • 是已使用常量表达式初始化的引用。

lambda 表达式可以读取变量的值而不捕获它,如果变量

  • 具有 const 非易失性整型或枚举类型,并且已使用常量表达式进行初始化,或者

  • 是 constexpr 并且没有可变成员。

  • tparams - 模板参数的非空逗号分隔列表,用于为通用 lambda 的模板参数提供名称。

  • t-requires - 给tparams 添加约束。
    如果 t-requires 以属性说明符序列结尾,则序列中的属性将被视为 front-attr 中的属性。

  • front-attr - 属性说明符序列适用于闭包类型的operator()。

  • params - 闭包类型的operator()的参数列表。
    它可以有一个显式的对象参数。

  • specs - 以下说明符的列表,每个说明符在每个序列中最多允许出现一次。

说明符意义
mutable允许 body 修改通过复制捕获的对象,并调用它们的非常量成员函数。如果存在显式对象参数,则无法使用。
constexpr显式指定 operator() 是 constexpr 函数。如果 operator() 满足所有 constexpr 函数要求,则即使 constexpr 不存在,operator() 也将是constexpr 。
consteval指定 operator() 是立即函数。consteval 和 constexpr 不能同时使用。
static指定 operator() 是静态成员函数。static 和 mutable 不能同时使用。如果 captures 不为空,或者存在显式对象参数,则无法使用。
  • exception - 为闭包类型的operator()提供动态异常规范,或noexcept说明符。

  • back-attr - 属性说明符序列适用于闭包(Closure)类型的operator()类型(因此不能使用noreturn属性)。

  • Trailing-type - -> ret,其中 ret 指定返回类型。

  • require - 给闭包类型的 operator() 添加约束。

  • body - 函数体。

在 body 的开头隐式定义 __func __

无模板参数的Lambda表达式

 - [captures ] <tparams > t-requires (optional) front-attr (optional) (params ) specs (optional) exception (optional) back-attr (optional) trailing-type (optional) requires (optional) { body }
 - [captures ] <tparams > t-requires (optional) { body }
 - [captures ] <tparams > t-requires (optional) front-attr (optional) trailing-type (optional) { body }	
 - [captures ] <tparams > t-requires (optional) front-attr (optional) exception back-attr (optional) trailing-type (optional) { body } 
 - [captures ] <tparams > t-requires (optional) front-attr (optional) specs exception (optional) back-attr (optional) trailing-type (optional) { body }

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Google Earth Engine(GEE)——ui.Panel添加到地图上

结果 函数 ui.root.add(widget) 将一个widget添加到根面板上。 返回根面板。 参数。 widget&#xff08;ui.Widget&#xff09;。 要添加的widget。 返回&#xff1a; ui.Panel 代码 //label var label ui.Label({ value: "text label", style: {fontSi…

java 公共字段填充

公共字段填充 1、mybatis-plus2、mybatis 使用注解加aop2.1 自定义注解2.2 自定义切面类2.3 在mapper上添加上自定义的注解 1、mybatis-plus 通过在类上使用如下的注解 TableField(fill FieldFill.INSERT) 是 MyBatis-Plus 中的注解&#xff0c;用于自动填充字段的值。MyBat…

上海外贸建站公司wordpress模板推荐

Sora索啦高端制造业wordpress主题 红色高端制造业wordpress主题&#xff0c;适合外贸企业出海建独立站的wordpress模板。 https://www.jianzhanpress.com/?p5885 Yamal外贸独立站wordpress主题 绿色的亚马尔Yamal外贸独立站wordpress模板&#xff0c;适用于外贸公司建独立站…

【HBZ】高性能zeroCopy零拷贝与普通IO差距与原理

简介 随着IO不断地发展&#xff0c;无论哪种拷贝方式&#xff0c;DMA从磁盘拷贝数据到内核缓冲区&#xff0c;都会拷贝多一些数据, 不会只拷贝用户态的指定size的数据&#xff0c;而是会将目标数据的临近数据也都拷贝到内核缓冲区&#xff0c;以便下次IO操作可以直接从内核缓冲…

【Android】自定义换肤框架05之Skinner框架集成

引入依赖 api("io.github.hellogoogle2000:android-skinner:1.0.0")初始化Skinner 在所有功能前调用即可&#xff0c;建议在Application中初始化 SkinnerKit.init(application)安装皮肤包 在应用该皮肤包前安装即可&#xff0c;建议预安装&#xff0c;或应用皮肤…

解决后端限制导致前端配置跨域仍请求失败报504的问题

文章目录 问题一、通过配置跨域方式二、直接真实接口请求三、解决方式四、后端这样做的原因 总结 问题 前端项目设置跨域proxy处理&#xff0c;接口请求不会报跨域&#xff0c;但是接口请求报了504&#xff0c;这种情况如何处理呢&#xff0c;后端又为何要这么做&#xff0c;下…

生成式AI的短板在于“Token”的存在

生成式AI模型处理文本的方式与人类不同。理解它们基于“token”的内部环境&#xff0c;可能有助于解释一些奇怪行为和固有局限性。 从小型设备上的Gemma到OpenAI领先行业的GPT-4o&#xff0c;大多数模型都是基于一种称为Transformer的架构。由于Transformer在将文本与其他类型…

前端初学java二(类、多态、接口、内部类、泛型)

目录 类 种类 Javabean类 测试类 工具类 类的初始化 构照函数 新建对象的内存图 static 继承 This Super 虚方法表 Override 修饰符权限 构造代码块 静态代码块 多态 前提 优点 缺点 示例 抽象方法 抽象类 接口 implements 继承 内部类 成员内部类…

系统化学习 H264视频编码(02) I帧 P帧 B帧 引入及相关概念解读

说明&#xff1a;我们参考黄金圈学习法&#xff08;什么是黄金圈法则?->模型 黄金圈法则&#xff0c;本文使用&#xff1a;why-what&#xff09;来学习音H264视频编码。本系列文章侧重于理解视频编码的知识体系和实践方法&#xff0c;理论方面会更多地讲清楚 音视频中概念的…

【机器学习】机器学习重塑广告营销:精准触达,高效转化的未来之路

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀目录 &#x1f4d2;1. 引言&#x1f4d9;2. 机器学习基础与广告营销的结合&#x1f9e9;机器学习在广告营销中的核心应用领域&#x1f339;用…

cf 7.7

Problem - C - Codeforces 大致意思&#xff1a; 找前缀&#xff0c;排序后使得本位之前数字和等于该位 &#xff08;以下代码超时了&#xff09; #include<bits/stdc.h> typedef long long ll;#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0) const ll …

阿里云存储应用

如何做好权限控制 小浩在梳理门户网站静态资源时&#xff0c;发现有些资源是仅内部员工可访问&#xff0c;有些资源是特定的注册客户可访问&#xff0c;还有些资源是匿名客户也可以访问。针对不同场景、不同用户&#xff0c;小浩该如何规划企业门户网站静态资源的权限控制呢&a…

MySQL第三次作业--DML语句(INSERT)

目录 一、在数据库中创建一个表student&#xff0c;用于存储学生信息 二、向student表中添加一条新记录&#xff0c;记录中id字段的值为1&#xff0c;name字段的值为"monkey"&#xff0c;grade字段的值为98.5 三、向student表中添加多条新记录&#xff1a; 2,&qu…

Docker 容器网络及其配置说明

Docker 容器网络及其配置说明 docker容器网络docker的4种网络模式bridge 模式container模式host 模式none 模式应用场景 docker 容器网络配置Linux 内核实现名称空间的创建创建 Network Namespace操作 Network Namespace 转移设备veth pair创建 veth pair实现 Network Namespac…

缓存-分布式锁-原理和基本使用

分布式锁原理和使用 自旋 public Map<String, List<Catelog2Vo>> getCatalogJsonFromDBWithRedisLock() {Boolean b redisTemplate.opsForValue().setIfAbsent(Lock, Lock, Duration.ofMinutes(1));if (!b) {int i 10;while (i > 0) {Object result redisTe…

【QT】容器类控件

目录 概述 Group Box 核心属性 Tab Widget 核心属性 核心信号 核心方法 使用示例&#xff1a; 布局管理器 垂直布局 核心属性 使用示例&#xff1a; 水平布局 核⼼属性 (和 QVBoxLayout 属性是⼀致的) 网格布局 核心属性 使用示例&#xff1a; 示例&#x…

【python】python猫眼电影数据抓取分析可视化(源码+数据集+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

安卓虚拟位置修改

随着安卓系统的不断更新&#xff0c;确保软件和应用与最新系统版本的兼容性变得日益重要。本文档旨在指导用户如何在安卓14/15系统上使用特定的功能。 2. 系统兼容性更新 2.1 支持安卓14/15&#xff1a;更新了对安卓14/15版本的支持&#xff0c;确保了软件的兼容性。 2.2 路…

Xilinx FPGA:vivado串口输入输出控制fifo中的数据

一、实验要求 实现同步FIFO回环测试&#xff0c;通过串口产生数据&#xff0c;写入到FIFO内部&#xff0c;当检测到按键信号到来&#xff0c;将FIFO里面的数据依次读出。 二、信号流向图 三、状态转换图 四、程序设计 &#xff08;1&#xff09;按键消抖模块 timescale 1ns…

批量文本编辑管理神器:一键修改多处内容,轻松转换编码,助力工作效率飞跃提升!

在信息爆炸的时代&#xff0c;文本处理已成为我们日常工作中不可或缺的一部分。无论是处理文档、整理数据还是编辑资料&#xff0c;都需要对大量的文本进行管理和修改。然而&#xff0c;传统的文本编辑方式往往效率低下&#xff0c;容易出错&#xff0c;难以满足现代工作的高效…