Bootstrap

C++新特性12_ Lambda 表达式/匿名函数捕获列表[]及应用(捕获列表可以起到传递外部数据的作用;传递方式:值捕获、引用捕获、隐式捕获;容器for_each遍历中嵌入匿名函数)

本篇将会介绍Lambda 表达式中的捕获列表。

捕获列表
所谓捕获列表,其实可以理解为参数的一种类型,lambda 表达式内部函数体在默认情况下是不能够使用函数体外部的变量的,这时候捕获列表可以起到传递外部数据的作用。 根据传递的行为,捕获列表也分为以下几种:

C++新特性12_ Lambda 表达式/匿名函数捕获列表[]及应用

1. 值捕获

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


#include <iostream>
using namespace std;


int main() {
	
	int t = 10;

	//按值捕获,捕获的是声明匿名函数时,捕获列表参数的值
	 auto f=[t]() mutable{
		 cout << t << endl;
		 return t;
	};

	t = 11;

	f();

}

在这里插入图片描述

2. 引用捕获

与引用传参类似,引用捕获保存的是引用,值会发生变化。

#include <iostream>
using namespace std;

int main() {

	//按引用捕获
	int t = 10;
	//此处只是一个声明,还未调用
	auto f2 = [&t]() mutable {
		cout << t << endl;
		t = 13;
		return t;
	};

	t = 11;

	f2();

	cout << t << endl;

}

运行结果:
在这里插入图片描述

3. 隐式捕获

手动书写捕获列表有时候是非常复杂的,这种机械性的工作可以交给编译器来处理,这时候可以在捕获列表中写一个 &= 向编译器声明采用 引用捕获或者值捕获.
总结一下,捕获提供了 Lambda 表达式对外部值进行使用的功能,捕获列表的最常用的四种形式可以是:
(1)[] 空捕获列表;
(2)[name1, name2, …] 捕获一系列变量;
(3)[&] 引用捕获, 让编译器自行推导捕获列表;
(4)[=] 值捕获, 让编译器执行推导应用列表;

//捕获列表
	int a = 1;
	int b = 2;

	//按值捕获所有变量
	[=]() {
		cout << a << "+" << b << endl;
	}();

	//按引用捕获所有变量
	[&]() {
		cout << a++ << "+" << b++ << endl;
	}();

	//按值和引用捕获所有变量
	[a,&b]() {
		cout << a<< "+" << b<<endl;
	}();

4. 容器for_each遍历中嵌入Lambda 表达式

利用stl中迭代写法for_each进行动态数组内元素奇偶数的判断。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

//应用举例
int main()
{
	//常规方法
	//判断哪些是奇数,哪些是偶数
	vector<int>v = {1,2,3,4,5};
	for (int i=0;i<v.size();i++)
	{
		if (v[i] % 2 == 0)
		{
			cout << v[i] << "是偶数" << endl;

		}
		else {
			cout << v[i] << "是奇数" << endl;
		}
	}

	//高阶写法,for_each,stl中提供的迭代的写法
	//起始,结尾,每遍历一次执行的匿名函数
	//每一次调用就会将值传给n
	for_each(v.begin(), v.end(), [](int n) {
		if (n % 2 == 0)
		{
			cout << n << "是偶数" << endl;

		}
		else {
			cout << n << "是奇数" << endl;
		}
	});
	return 0;
	
	//未能实现,时间问题后期再研究:迭代器中auto不能用于参数所以失败(20230609)
	//利用迭代器iterator进行遍历,并应用匿名函数
	//for (auto it : v)
	for (auto it = v.begin(); it != v.end(); it++)
	{
		[&](int n) {
			if (n % 2 == 0)
			{
				cout << n << "是偶数" << endl;

			}
			else {
				cout << n << "是奇数" << endl;
			}
		};
	}

上面的明显存在问题,为什么不直接使用以下迭代方式遍历,用Lambda表达式很多余
for (auto it = v.begin(); it != v.end(); it++)
	{
		if (*it % 2 == 0)
		{
			cout << *it << "是偶数" << endl;

		}
		else {
			cout << *it << "是奇数" << endl;
		}
	}

	
}

迭代器:C++新特性03_迭代器iterator及类型推导auto

5.学习视频地址: Lambda 表达式/匿名函数捕获列表及应用

6.学习笔记:Lambda 表达式/匿名函数捕获列表及应用笔记

;