lambda表达式

Lambda表达式可以直接在需要调用函数的位置定义短小精悍的函数,而不需要预先定义好函数。适合短小不需要复用函数的场景

缺点:

  1. Lamdba表达式语法比较灵活,增加了阅读代码的难度。如果我要找某个函数的调用,搜索函数名即可,但是lambda表达式往往没有名称,我要记住它的位置

  2. 难以调试:lambda表达式往往是一种匿名函数,这意味着函数名称并不明确,所以在调试中很难分清楚是哪个函数出错了。

  3. 存在捕获的性能开销:捕获变量或对象需要花费额外的时间,而这些时间开销可能会在一些精细的程序中成为问题

  4. 不适合复用的场景

原理

编译器会把一个lambda表达式生成一个匿名类的匿名对象,并在类中重载函数调用运算符,实现了一个operator()方法

auto print = []{cout << "Hello World!" << endl; };

编译器会把上面这一句翻译为下面的代码:

1
2
3
4
5
6
7
8
9
10
class 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
2
3
4
5
6
auto function = ([]{
std::cout << "Hello World!" << std::endl;
}
);

function();

从这个例子可以看出,Lambda表达式可以作为仿函数

  • [var]表示值传递方式捕获变量var
1
2
3
4
5
6
7
int num = 100;
auto function = ([num]{
std::cout << num << std::endl;
}
);

function();
  • [=]表示值传递方式捕获所有父作用域的变量(包括this)
1
2
3
4
5
6
7
8
9
int index = 1;
int num = 100;
auto function = ([=]{
std::cout << "index: "<< index << ", "
<< "num: "<< num << std::endl;
}
);

function();
  • [&var]表示引用传递捕捉变量var

  • [&]表示引用传递方式捕捉所有父作用域的变量(包括this)

输入参数

除了捕获列表之外,lambda还可以接受输入参数。参数列表是可选的,并且在大多数方面类似于函数的参数列表。

1
2
3
4
5
auto function = [](int first, int second){
return first + second;
};

function(100, 200);


可变规格mutable和异常使用较少,不研究了。


for_each应用实例

1
2
3
int 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
10
int 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表达式应用于函数指针与function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <functional>
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;
}