Lambda表达式可以直接在需要调用函数的位置定义短小精悍的函数,而不需要预先定义好函数。适合短小不需要复用函数的场景
缺点:
Lamdba表达式语法比较灵活,增加了阅读代码的难度。如果我要找某个函数的调用,搜索函数名即可,但是lambda表达式往往没有名称,我要记住它的位置
难以调试:lambda表达式往往是一种匿名函数,这意味着函数名称并不明确,所以在调试中很难分清楚是哪个函数出错了。
存在捕获的性能开销:捕获变量或对象需要花费额外的时间,而这些时间开销可能会在一些精细的程序中成为问题
不适合复用的场景
原理
编译器会把一个lambda表达式生成一个匿名类的匿名对象,并在类中重载函数调用运算符,实现了一个operator()
方法
auto print = []{cout << "Hello World!" << endl; };
编译器会把上面这一句翻译为下面的代码:1
2
3
4
5
6
7
8
9
10class print_class
{
public:
void operator()(void) const
{
cout << "Hello World!" << endl;
}
};
//用构造的类创建对象,print此时就是一个函数对象
auto print = print_class();
1.捕获列表。捕获列表总是出现在Lambda函数的开始处。实际上,[]
是Lambda引出符。编译器根据它来判断接下来的代码是否是Lambda函数,捕获列表能够捕捉上下文中的变量以供Lambda函数使用。
2.参数列表。与普通函数的参数列表一致。如果不需要参数传递,则可以连同括号()
一起省略。
3.可变规则。mutable修饰符,但使用很少。默认情况下Lambda函数总是一个const函数,mutable可以取消其常量性。在使用该修饰符时,参数列表不可省略(即使参数为空)
4.异常说明。用于Lamdba表达式内部函数抛出异常,使用也很少
5.返回类型。 可以在不需要返回值的时候也可以连同符号->
一起省略。此外,在返回类型明确的情况下,也可以省略该部分,让编译器对返回类型进行推导。
6.lambda函数体。内容与普通函数一样,不过除了可以使用参数之外,还可以使用所有捕获的变量。
捕获列表
在[]
包括起来的是捕获列表,捕获列表由多个捕获项组成,并以逗号分隔。捕获列表有以下几种形式:
- []表示不捕获任何变量
1 | auto function = ([]{ |
从这个例子可以看出,Lambda表达式可以作为仿函数
[var]
表示值传递方式捕获变量var
1 | int num = 100; |
[=]
表示值传递方式捕获所有父作用域的变量(包括this)
1 | int index = 1; |
[&var]
表示引用传递捕捉变量var[&]
表示引用传递方式捕捉所有父作用域的变量(包括this)
输入参数
除了捕获列表之外,lambda还可以接受输入参数。参数列表是可选的,并且在大多数方面类似于函数的参数列表。
1 | auto function = [](int first, int second){ |
可变规格mutable和异常使用较少,不研究了。
for_each应用实例1
2
3int a[4] = {11, 2, 33, 4};
sort(a, a+4, [=](int x, int y) -> bool { return x%10 < y%10; } );
for_each(a, a+4, [=](int x) { cout << x << " ";} );
find_if应用实例1
2
3
4
5
6
7
8
9
10int x = 5;
int y = 10;
deque<int> coll = { 1, 3, 19, 5, 13, 7, 11, 2, 17 };
auto pos = find_if(coll.cbegin(), coll.cend(), [=](int i) {
return i > x && i < y;
});
if(pos != coll.end() )
cout << *pos << endl;
Lamdba表达式应用于函数指针与function1
2
3
4
5
6
7
8
9
10
11
12
13
14
using namespace std;
int main(void)
{
auto add = [](int a, int b) { return a + b; };
std::function<int(int, int)> Add = [=](int a, int b) { return a + b; };
cout << "add: " << add(1, 2) << endl;
cout << "Add: " << Add(3, 4) << endl;
return 0;
}