C++11 lambda 表达式 (简单总结)

一、前言

虽然说不会lambda表达式并不影响工作赚钱,但是学会了它,在编程中确实可以增色不少。那么在C++中lambda表达式该怎么使用呢?

二、概述

C++ 11 中的 Lambda 表达式用于定义并创建匿名的函数对象,以简化编程工作。

[ capture list ] (parameters) -> return-type { method definition}
上述的这行加粗斜体,就是lambda表达式的语法形式,当然这玩意看起来十分抽象,我们不妨搞一个简单地例子来看一下。

三、简单示例

先来看这么一个简单的C++程序,无非是主程序中执行print函数,print函数中输出hello world!,那么现在就将这个程序改写为lambda表达式;

#include <iostream>

using namespace std;

void print(){
	cout << "hello world!" << endl;
}
int main(){
	print();
	cin.ignore();
	return 0;
}

如下图所示,这就是一个我们改写后的简单的lambda表达式

#include <iostream>

using namespace std;

int main(){
	auto print = []{cout << "hello world!" << endl; };
	print();
	cin.ignore();
	return 0;
}

我们专门截了个图,来看一下普通函数写法与lambda表达式的异同。
1.我们可以看到两个大括号内部,两者都是相同的,没有任何差异
2.虽然lambda表达式号称匿名函数,但是同样我们也可以利用auto推导一个函数名
3.在函数执行的写法,两者也可以做到保持一致。
在这里插入图片描述
当然lambda表达式也可以直接写为:
[]{cout << “hello world!” << endl; }();
一行搞定,这就是lambda表达式的便利之处。

#include <iostream>

using namespace std;

int main(){
	[]{cout << "hello world!" << endl; }();
	cin.ignore();
	return 0;
}

四、带参的写法

了解了,比较简单的lambda表达式,那么问题来了,如何将一个带参的函数改写为lambda表达式。

#include <iostream>
#include <string>

using namespace std;

void print(string str){
	cout << str << endl;
}
int main(){
	print("hello world!");
	cin.ignore();
	return 0;
}

一个简单的改变

#include <iostream>
#include <string>
using namespace std;

int main(){
	auto print = [](string str){cout << str << endl; };
	print("hello world!");
	cin.ignore();
	return 0;
}

如图所示,我们可以看到带参,其实也很好办,只要在[]{}中间加上(),()里面写上形参即可。
其实观察我们再最开始提到的语法形式,()这个小括号本来就是在这个位置,只是在无参的情况下,我们可以将其省略。
在这里插入图片描述

五、函数返回值

除了参数以外,一个函数还要返回值,那么返回值该怎么办呢?例如下面的代码:

#include <iostream>
#include <string>

using namespace std;

string print(string str){
	return str;
}
int main(){
	cout << print("hello world!") << endl;
	cin.ignore();
	return 0;
}

只需这样子写:

#include <iostream>
#include <string>

using namespace std;

int main(){
	auto print = [](string str)->string{return str; };
	cout << print("hello world!") << endl;
	cin.ignore();
	return 0;
}

我们来看一下区别:
无非是在{}中增加了->string罢了。
没错,->返回值类型{};这个就是带返回值的写法了。
在这里插入图片描述

六、变量捕获

lambda表达式,还有一大便利,就是它可以捕获函数体中的变量
一个简单示例:输出结果为3;

#include <iostream>

using namespace std;

int main(){
	int a = 0;
	auto print = [&a](){ int b = 3; a = b; };
	print();
	cout << a << endl;
	cin.ignore();
	return 0;
}

注:[]中相关说明:
[] 不捕获任何变量
[&] 以引用方式捕获所有变量
[=] 用值的方式捕获所有变量(可能被编译器优化为const &)
[=, &foo] 以引用捕获foo, 但其余变量都靠值捕获
[&, foo] 以值捕获foo, 但其余变量都靠引用捕获
[bar] 以值方式捕获bar; 不捕获其它变量
[this] 捕获所在类的this指针

七、mutable

还是上一个程序,做一个简单的修改,我们可以看到,在这个程序中对a的只进行了操作或者说修改,这个程序运行无误,结果输出为1;

#include <iostream>

using namespace std;

int main(){
	int a = 0;
	auto print = [&a](){ int b = 3; a++; };
	print();
	cout << a << endl;
	cin.ignore();
	return 0;
}

那么这样子写呢?不难看出,代码从&a变为了a;

#include <iostream>

using namespace std;

int main(){
	int a = 0;
	auto print = [a](){ int b = 3; a++; };
	print();
	cout << a << endl;
	cin.ignore();
	return 0;
}

大家运行一下?没错,这个代码是错误的。
因为,正常情况下,lambda表达式是不允许对这个a进行修改的,想要修改就需要加入mutable关键字。
这个时候我们可以发现输出结果为0,这是因为,我们是值捕获,而不是引用捕获,输出的还是定义a的值。

八、STL中大放异彩

无可争议,最令人感动的是,在STL这类代码的编程时,lambda表达式简直是绝配:
举例:
在没有lambda表达式的时候,有一个vector,如何遍历操作这个vector?
vector name = { “小明”, “小李”, “小王”, “小高” };
我在这里列举三种方式,当然方法肯定是不止三种的:
方法一:

	for (int i = 0; i < name.size(); i++){
		cout << name[i] << " ";
	}

方法二:

	for each (string s in name){
		cout << s << " ";
	}

方法三:

	for (string s : name){
		cout << s << " ";
	}

那么有了lambda表达式这个遍历该怎么写呢?
一行即可解决问题:

for_each (name.begin(), name.end(), [](string str){cout << str << " "; });

测试代码如下:

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

int main(){
	vector<string> name = { "小明", "小李", "小王", "小高" };
	for_each (name.begin(), name.end(), [](string str){cout << str << " "; });
	cin.ignore();
	return 0;
}

当然这个简单的示例,还不能将lambda表达式的魅力完整展现,有兴趣的朋友看完可以自己尝试一下。

九、最后

最后做一个总结吧,
看到最后,大家应该也发现了吧,其实刚开始给的形式是有那么一丢丢问题的,应该是这样的。
[capture list] (params list) 关键字-> return type {function body}

captrue list:捕获外部变量列表(选填)
params list:形参列表(可省略)
关键字:mutable,exception,attribute(可省略)
return type:返回类型(可省略)
function body:函数体

其中:

mutable说明lambda表达式体内的代码可以修改被捕获的变量,并且可以访问被捕获的对象的non-const方法。

exception说明lambda表达式是否抛出异常以及何种异常。

attribute用来声明属性。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值