Lambda表达式

语法定义

[capture] (parameters) mutable -> return-type {statement}
  • [capture]:捕捉列表。[]lambda表达式的引出符。lambda表达式可以自由访问全局变量和static变量,但对于局部变量和成员变量需要捕捉变量支持。capture描述了上下文可以供函数体使用的变量及其使用方式(值传递或引用传递)。[capture]有以下几种基本形式:
表达式意义
[var]值传递方式捕捉var变量
[=]值传递方式捕捉lambda表达式所在函数位置可以访问到的所有局部变量,和lambda表达式所在类的所有成员变量
[&var]引用传递方式捕捉var变量
[&]引用传递方式捕捉lambda表达式所在函数位置可以访问到的所有局部变量,和lambda表达式所在类的所有成员变量
[this]值传递方式捕捉lambda表达式所在类的所有成员变量

此外,还可以组合上面的基本形式,来按更复杂的形式捕捉变量,例如:

表达式意义
[=, &a, &b]按引用传递方式捕捉变量a、b,其他变量按值传递方式捕捉
[&, a, this]按值传递方式捕捉变量a和类成员变量,按引用传递方式捕捉其他变量

但是,组合方式中,同种传递方式中不能存在包含关系:

表达式意义
[=, a]=和a都是按值传递,且=包含了a
[&, &this]&和this都是按引用传递,且&包含了&this
  • (parameters):参数列表,如果不需要传递参数可省略。
  • mutable:修饰符。默认情况下,按值传递方式捕捉的变量(注意不是参数列表中的传参)是const,不可对其进行修改,mutable修饰符可以取消其常量性。当使用了mutable修饰符时,参数列表不可省略。
  • ->return-type:返回类型,不需要返回值时可省略。
  • {statement}:函数体。

lambda表达式是函数对象的语法糖
lambda表达式的本质是函数对象。现阶段,编译器通常把lambda表达式转换为一个函数对象
在这里插入图片描述
值传递和引用传递
捕捉列表中值传递的变量,其传递的值在lambda表达式定义时已经确定;而引用传递的变量,其传递的值等于lambda函数调用时的值。这可以用lambda表达式到函数对象的转换来解析。

int i = 10;

auto by_val_lambda = [=] { return i + 1; };
auto by_ref_lambda = [&] { return i + 1; };

cout << "by_val_lambda: " << by_val_lambda() << endl;
cout << "by_ref_lambda: " << by_ref_lambda() << endl;

i++;

cout << "by_val_lambda: " << by_val_lambda() << endl;
cout << "by_ref_lambda: " << by_ref_lambda() << endl;

运行结果

by_val_lambda: 11
by_ref_lambda: 11
by_val_lambda: 11
by_ref_lambda: 12

lambda表达式的常量性
前面说到,lambda表达式的本质是函数对象,更准确地说应该是operator()为常成员函数的函数对象(默认情况),捕捉列表的参数对应函数对象的成员变量。而常成员函数不能修改任何非静态成员变量,所以默认情况下lambda不能修改捕捉列表中按值传递的变量。而按引用传递的变量可以在lambda中修改,因为并没有改变引用本身,而是改变了引用指向的对象。
mutable修饰符可以移除lambda的常量性。

lambda表达式和普通函数在STL中的应用
STL中部分算法可以通过回调函数指定内部实现,但是函数签名是固定的。普通函数和STL算法搭配使用时,普通函数无法获取到额外的信息,而lambda可以通过捕捉列表来实现这一需求:

// 利用for_each算法输出vector中大于ubound的值
void above_fun(int i, int ubound)
{
	if (i > ubound)
		cout << i << endl;
}

int main()
{
	vector<int> vec = { 1, 2, 3, 4, 5, 6 };
	
	int ubound = 3;
	auto above_lambda = [ubound](int i) {
		if (i > ubound)
			cout << i << endl;
	};
	
	for_each(vec.begin(), vec.end(), above_lambda);
	
	// 函数签名不匹配for_each第三参数,不能使用for_each算法
	for (auto iter = vec.begin(); iter != vec.end(); iter++)
		above_fun(*iter, ubound);
}

lambda表达式相对于普通函数,在STL算法中的使用更加灵活,适用性更广。而且lambda表达式默认内联,相比普通函数更高效。

实际上,可以利用STL提供的函数适配器来改变函数可调用对象的参数个数。也就是,above_fun函数通过函数适配器,可以搭配for_each算法使用,但是代码通常比较晦涩:

for_each(vec.begin(), vec.end(), bind(above_fun, _1, ubound));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值