C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++ lambda表达式

C++中的lambda表达式简单介绍

作者:落羽的落羽

文章介绍了C++中lambda表达式的概念,作为匿名函数对象,其类型由编译器自动生成,语法包含捕捉列表、参数和返回值,支持值/引用捕捉,简化可调用对象定义,提升代码简洁性,感兴趣的朋友跟随小编一起看看吧

一、 什么是lambda表达式

C++中有“可调用对象”的概念,主要包括函数指针、仿函数、lambda表达式。lambda表达式本质是一个匿名函数对象,跟普通函数不同的是,他可以定义在函数内部

lambda表达式在语法使用层面上“没有类型”,简单来说:lambda表达式的类型是编译器即时生成的、唯一的、匿名的,程序员无法在代码中直接写出它的类型名称。lambda表达式使用时本质是被转换成一个仿函数再使用的,每个lambda表达式都会被编译器转换成一个独一无二的、匿名的类(仿函数)。即使两个lambda看起来完全一样,编译器也会为它们生成两个不同的类。所以,我们一般都是用auto或者模板参数定义的对象去接收lambda对象

二、 表达式语法

lambda表达式的语法格式是:[capture-list](parameters)->return-type {function body}

举几个栗子:

auto add = [](int x, int y){ return x + y; };

auto func = []
	{
		cout << "hello world" << endl;
	};

auto swap = [](int& a, int& b)
	{
		int tmp = a;
		a = b;
		b = tmp;
	};

非常好理解吧!

关于捕捉列表,还有一些使用的细节:

lambda表达式中默认只能使用参数列表中的变量或lambda内定义的,如果想使用外层作用域中的变量就需要进行捕捉。

lambda表达式中如果在局部域时,可以捕捉到它之前定义的变量,不能捕捉静态局部变量和全局变量,因为这两种变量本来就不需要捕捉也能在内部直接使用,lambda表达式内部可以直接使用。lambda表达式如果定义在全局位置,捕捉列表必须为空。

默认情况下,lambda捕捉列表是const属性的,也就是说传值捕捉来的对象不能被修改,在参数列表后加上修饰符mutable就可以取消其常性,但是修改还是改变的形参对象,不会影响实参。使用该修饰符后参数列表不能省略。

int x = 0;
// 捕捉列表必须为空,因为全局变量不⽤捕捉就可以⽤,没有可被捕捉的变量
auto func1 = []()
	{
		x++;
	};
int main()
{
	// 只能⽤当前lambda局部域和捕捉的对象和全局对象
	int a = 0, b = 1, c = 2, d = 3;
	auto func1 = [a, &b]
		{
			// 值捕捉的变量不能修改,引⽤捕捉的变量可以修改
			//a++;
			b++;
			int ret = a + b;
			return ret;
		};
	cout << func1() << endl;
	// 隐式值捕捉
	// ⽤了哪些变量就捕捉哪些变量
	auto func2 = [=]
		{
			int ret = a + b + c;
			return ret;
		};
	cout << func2() << endl;
	// 隐式引⽤捕捉
	// ⽤了哪些变量就捕捉哪些变量
	auto func3 = [&]
		{
			a++;
			c++;
			d++;
		};
	func3();
	cout << a << " " << b << " " << c << " " << d << endl;
	// 混合捕捉1
	auto func4 = [&, a, b]
		{
			//a++;
			//b++;
			c++;
			d++;
			return a + b + c + d;
		};
	func4();
	cout << a << " " << b << " " << c << " " << d << endl;
	// 混合捕捉1
	auto func5 = [=, &a, &b]
		{
			a++;
			b++;
			/*c++;
			d++;*/
			return a + b + c + d;
		};
		func5();
		cout << a << " " << b << " " << c << " " << d << endl;
	// 局部的静态和全局变量不能捕捉,也不需要捕捉
	static int m = 0;
	auto func6 = []
		{
			int ret = x + m;
			return ret;
		};
	// 传值捕捉本质是⼀种拷⻉,并且被const修饰了
	// mutable相当于去掉const属性,可以修改了
	// 但是修改了不会影响外⾯被捕捉的值,因为是⼀种拷⻉
	auto func7 = [=]()mutable
		{
			a++;
			b++;
			c++;
			d++;
			return a + b + c + d;
		};
	cout << func7() << endl;
	cout << a << " " << b << " " << c << " " << d << endl;
	return 0;
}

三、lambda的应用

学习lambda表达式之前,我们使用的可调用对象只有函数指针和仿函数,它们的定义都相对麻烦,使用lambda表达式去定义可调用对象,就十分简单方便了。

vector<pair<int, int>> v = { {1,2}, {3,4}, {8,3}, {5,1} };
//遇到这样的场景,假如我们想要用多种排序规则进行排序,以前是需要写不同的仿函数传给sort
/*struct Compare_first
{
	bool operator()(const pair<int, int>& p1, const pair<int, int>& p2)
	{
		return p1.first < p2.first;
	}
}; 
struct Compare_second
{
	bool operator()(const pair<int, int>& p1, const pair<int, int>& p2)
	{
		return p1.second < p2.second;
	}
};
sort(v.begin(), v.end(), Compare_first());
sort(v.begin(), v.end(), Compare_second());*/
//有了lambda表达式后,就方便许多了
sort(v.begin(), v.end(), [](const pair<int, int>& p1, const pair<int, int>& p2) {return p1.first < p2.first; });
for (auto pa : v)
{
	cout << pa.first << ":" << pa.second << " ";
}
cout << endl;
sort(v.begin(), v.end(), [](const pair<int, int>& p1, const pair<int, int>& p2) {return p1.second < p2.second; });
for (auto pa : v)
{
	cout << pa.first << ":" << pa.second << " ";
}
cout << endl;

到此这篇关于C++简单介绍lambda表达式的文章就介绍到这了,更多相关C++ lambda表达式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文