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

C++lambda表达式

C++lambda表达式

  • 前言
  • lambda的基本语法
  • lambda的捕获列表
    • 值捕获
    • 引用捕获
    • 隐式捕获
    • 空捕获列表
    • 表达式捕获
    • 泛型 Lambda
    • 可变lambda
  • 总结

前言

  本文介绍c++ lambda的使用方法

  本专栏知识点是通过零声教育的线上课学习,进行梳理总结写下文章,对c/c++linux课程感兴趣的读者,可以点击链接 C/C++后台高级服务器课程介绍 详细查看课程的服务。

lambda的基本语法

[捕获列表](参数列表) mutable(可选) 异常属性 -> 返回类型 {
// 函数体
}

  语法规则:lambda表达式可以看成是一般函数的函数名被略去,返回值使用了一个 -> 的形式表示。唯一与普通函数不同的是增加了“捕获列表”。

  一般情况下,编译器可以自动推断出lambda表达式的返回类型,所以我们可以不指定返回类型,即:

//[捕获列表](参数列表){函数体}
int main() {
	auto Add = [](int a, int b) {
		return a + b;
	};
	std::cout << Add(1, 2) << std::endl; //输出3
	return 0;
}

  但是如果函数体内有多个return语句时,编译器无法自动推断出返回类型,此时必须指定返回类型。

lambda的捕获列表

  有时候,需要在匿名函数内使用外部变量,所以用捕获列表来传递参数。根据传递参数的行为,捕获列表可分为以下几种

值捕获

  与参数传值类似,值捕获的前提是变量可以拷贝,不同之处则在于,被捕获的变量在 lambda表达式被创建时拷贝,而非调用时才拷贝

//[捕获列表](参数列表)->返回值{函数体}
int main() {
	cout << "lambda" << endl;
	int c = 6872;
	int d = 5032;
	auto Add = [c, d](int a, int b)->int {
		cout  << "c = " << c << endl<< "d = " << d << endl;
		return a+b;
	};
	d = 20;
	std::cout << "1 + 2 = " << Add(1, 2) << std::endl;
}

引用捕获

  与引用传参类似,引用捕获保存的是引用,如果修改引用变量,则在调用lambda表达式之后,外部该变量值会发生变化。

//[捕获列表](参数列表)->返回值{函数体}
int main() {
	cout << "lambda" << endl;
	int c = 6872;
	int d = 5032;
	auto Add = [&c, &d](int a, int b)->int {
		cout  << "c = " << c << endl<< "d = " << d << endl;
		c = 68725032;
		d = c;
		return a+b;
	};
	std::cout << "1 + 2 = " << Add(1, 2) << std::endl;
	cout  << "c = " << c << endl<< "d = " << d << endl;
}

隐式捕获

  手动书写捕获列表有时候是非常复杂的,这种机械性的工作可以交给编译器来处理,这时候可以在捕获列表中写一个 &(引用捕获) 或 =(值捕获) 向编译器声明采用引用捕获或者值捕获。

//[捕获列表](参数列表)->返回值{函数体}
int main() {
	cout << "lambda" << endl;
	int c = 6872;
	int d = 5032;
	auto Add = [&](int a, int b)->int {
		cout  << "c = " << c << endl<< "d = " << d << endl;
		c = 68725032;
		d = c;
		return a+b;
	};
	std::cout << "1 + 2 = " << Add(1, 2) << std::endl;
	cout  << "c = " << c << endl<< "d = " << d << endl;
}

空捕获列表

  捕获列表’[]'中为空,表示Lambda不能使用所在函数中的变量。

//[捕获列表](参数列表)->返回值{函数体}
int main() {
	cout << "lambda" << endl;
	int c = 6872;
	int d = 5032;
	// [] 空值,不能使用外面的变量
	// [=] 传值,lambda外部的变量都能使用
	// [&] 传引用值,lambda外部的变量都能使用
	auto Add = [&](int a, int b)->int {
		cout  << "c = " << c << endl<< "d = " << d << endl;
		c = 68725032;
		d = c;
		return a+b;
	};
	std::cout << "1 + 2 = " << Add(1, 2) << std::endl;
	cout  << "c = " << c << endl<< "d = " << d << endl;
}

表达式捕获

  上面提到的值捕获、引用捕获都是已经在外层作用域声明的变量,因此这些捕获方式捕获的均为左值而不能捕获右值。

  C++14之后支持捕获右值,允许捕获的成员用任意的表达式进行初始化,被声明的捕获变量类型会根据表达式进行判断,判断方式与使用 auto 本质上是相同的

//g++ -o main main.cpp -std=c++14

#include <iostream>
#include <memory>
using namespace std;
//[捕获列表](参数列表)->返回值{函数体}
int main() {
	cout << "lambda" << endl;
	auto important = std::make_unique<int>(1);
	auto add = [v1 = 1, v2 = std::move(important)](int x, int y) -> int {
		return x + y + v1 + (*v2);
	};
	std::cout << add(3,4) << std::endl;
}

泛型 Lambda

  在C++14之前,lambda表示的形参只能指定具体的类型,没法泛型化。从 C++14 开始, Lambda 函数的形式参数可以使用 auto关键字来产生意义上的泛型:

#include <iostream>
#include <memory>
using namespace std;
//[捕获列表](参数列表)->返回值{函数体}
int main() {
	cout << "lambda" << endl;
	auto add = [](auto x, auto y) {
		return x+y;
	};
	std::cout << add(1, 2) << std::endl;
	std::cout << add(1.1, 1.2) << std::endl;
}

可变lambda

  • 采用值捕获的方式,lambda不能修改其值,如果想要修改,使用mutable修饰(这个修改只是在lambda函数体内生效,对原来的变量不生效)

  • 采用引用捕获的方式,lambda可以直接修改其值,并且对外生效

//[捕获列表](参数列表)->返回值{函数体}
int main() {
	cout << "lambda" << endl;
	int v = 5;
	// 值捕获方式,使用mutable修饰,可以改变捕获的变量值
	auto ff = [v]() mutable {
		v=100;
		return v;
	};
	auto res = ff(); // j为6
	cout<<"v="<<v<<" return="<<res;
}
lambda
v=5 return=100
int main() {
	cout << "lambda" << endl;
	int v = 5;
	// 采用引用捕获方式,可以直接修改变量值
	auto ff = [&v](){
		v=100;
		return v;
	};
	auto res = ff();
	cout<<"v="<<v<<" return="<<res;
}
lambda
v=100 return=100

总结

  1. 如果捕获列表为[&],则表示所有的外部变量都按引用传递给lambda使用;
  2. 如果捕获列表为[=],则表示所有的外部变量都按值传递给lambda使用;
  3. 匿名函数构建的时候对于按值传递的捕获列表,会立即将当前可以取到的值拷贝一份作为常数,然后将该常数作为参数传递。
捕获列表说明
[]空捕获列表,Lambda不能使用所在函数中的变量。
[names]names是一个逗号分隔的名字列表,这些名字都是Lambda所在函数的局部变量。默认情况下,这些变量会被拷贝,然后按值传递,名字前面如果使用了&,则按引用传递
[&]隐式捕获列表,Lambda体内使用的局部变量都按引用方式传递
[=]隐式捕获列表,Lanbda体内使用的局部变量都按值传递
[&,identifier_list]identifier_list是一个逗号分隔的列表,包含0个或多个来自所在函数的变量,这些变量采用值捕获的方式,其他变量则被隐式捕获,采用引用方式传递,identifier_list中的名字前面不能使用&
[=,identifier_list]identifier_list中的变量采用引用方式捕获,而被隐式捕获的变量都采用按值传递的方式捕获。identifier_list中的名字不能包含this,且这些名字面前必须使用&

相关文章:

  • 三、使用 Maven:命令行环境
  • Squid服务
  • MYSQL三M介绍
  • 大三第一周训练
  • CrossOver Linux2022虚拟机工具如何下载使用教程
  • 《uni-app》表单组件-Checkbox组件
  • PHP - AJAX 与 MySQL
  • 电线延长寿命小妙招
  • 人工神经网络文献综述,人工神经网络论文文献
  • java 带密码连接redis 单节点/集群 No reachable node in cluster报错解决
  • 如何通过UTON WALLET数字钱包创建和使用你的元宇宙身份
  • uniapp 微信小程序中授权用户手机号码
  • spring实现md5加密
  • 微信公众平台快速开发框架源码
  • DoozyUI⭐️三、DoozyUI支持的 VR SDK列表
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • 【划重点】MySQL技术内幕:InnoDB存储引擎
  • 【跃迁之路】【733天】程序员高效学习方法论探索系列(实验阶段490-2019.2.23)...
  • download使用浅析
  • echarts的各种常用效果展示
  • go语言学习初探(一)
  • mysql 数据库四种事务隔离级别
  • Swift 中的尾递归和蹦床
  • 关键词挖掘技术哪家强(一)基于node.js技术开发一个关键字查询工具
  • 汉诺塔算法
  • 使用 @font-face
  • 使用 Docker 部署 Spring Boot项目
  • 使用API自动生成工具优化前端工作流
  • 使用前端开发工具包WijmoJS - 创建自定义DropDownTree控件(包含源代码)
  • 远离DoS攻击 Windows Server 2016发布DNS政策
  • Hibernate主键生成策略及选择
  • mysql面试题分组并合并列
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (1)(1.11) SiK Radio v2(一)
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (二)斐波那契Fabonacci函数
  • (附源码)spring boot公选课在线选课系统 毕业设计 142011
  • (附源码)ssm失物招领系统 毕业设计 182317
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第3章 信息系统治理(一)
  • (十) 初识 Docker file
  • (五)网络优化与超参数选择--九五小庞
  • (转)Groupon前传:从10个月的失败作品修改,1个月找到成功
  • .describe() python_Python-Win32com-Excel
  • .libPaths()设置包加载目录
  • .NET 4 并行(多核)“.NET研究”编程系列之二 从Task开始
  • .net 调用php,php 调用.net com组件 --
  • .NET 药厂业务系统 CPU爆高分析
  • .NET 中各种混淆(Obfuscation)的含义、原理、实际效果和不同级别的差异(使用 SmartAssembly)
  • .net开源工作流引擎ccflow表单数据返回值Pop分组模式和表格模式对比
  • .Net通用分页类(存储过程分页版,可以选择页码的显示样式,且有中英选择)
  • .NET中GET与SET的用法
  • [Android]使用Retrofit进行网络请求
  • [BZOJ1008][HNOI2008]越狱
  • [C#]OpenCvSharp使用帧差法或者三帧差法检测移动物体
  • [C语言]——分支和循环(4)