C++11 Lambda表达式(匿名函数)详解


使用STL时,往往会大量用到函数对象,为此要编写很多函数对象类。而有的函数对象类只用定义一个对象,而且这个对象也只使用一次,那编写这样一个函数对象就很浪费了。而且有时这定义函数对象类的地方和使用函数对象的地方很远,不方便查看。
那对于使用一次的函数对象类,能不能直接在使用它的地方定义呢?lambda就是为解决这个问题而提出的(其实在python、C#等中匿名函数已存在很久了)。使用Lambda表达式可以减少程序中函数对象类的对象,使程序更加优雅。


Lambda表达式的定义形式:
[外部变量访问方式说明符] (参数表) -> 返回值类型
{
   语句块
}

说明:“外部变量访问方式说明符”可以是=&,表示{}中用到的、定义在{}外面的变量在{}中是否允许被改变。= 表示不允许,&表示允许。当然,在{}中也可以不使用定义在外面的变量。“->返回值类型”可以省略
lambad可访问作用域内的任何动态变量,要捕获要使用的变量,可将其名称放在中括号内。如果只指定了变量名,如[z],将按值访问变量;如果在名称前加上&,如[&count],将按引用访问变量。[&]能够按引用访问所有动态变量,而[=]按值访问所有动态变量

  • 举个栗子:
[=] (int x, int y) -> bool {return x%10 < y%10; }
  • Lambda 表达式实际上就是一个函数,只是它没有名字。使用上面的Lambda表达式:
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 << " ";} );

输出的结果:
11 2 33 4

程序分析:

  • 程序第 2 行使得数组 a 按个位数从小到大排序。具体的原理是:sort 在执行过程中,需要判断两个元素 x、y 的大小时,会以 x、y 作为参数,调用 Lambda 表达式所代表的函数,并根据返回值来判断 x、y 的大小。这样,就不用专门编写一个函数对象类了。
  • 第 3 行,for_each 的第 3 个参数是一个 Lambda 表达式。for_each 执行过程中会依次以每个元素作为参数调用它,因此每个元素都被输出。
  • 再举个例子:用到外部变量的Lambda表达式的程序:
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
    int a[4] = { 1, 2, 3, 4 };
    int total = 0;
    for_each(a, a + 4, [&](int & x) { total += x; x *= 2; });
    cout << total << endl;  //输出 10
    for_each(a, a + 4, [=](int x) { cout << x << " "; });
    return 0;
}

输出结果:
10
2 4 6 8

程序分析:

  • 第 8 行,[&]表示该 Lambda 表达式中用到的外部变量 total 是传引用的,其值可以在表达式执行过程中被改变(如果使用[=],编译无法通过)。该 Lambda 表达式每次被 for_each 执行时,都将 a 中的一个元素累加到 total 上,然后将该元素加倍。

实际上,“外部变量访问方式说明符”还可以有更加复杂和灵活的用法。例如:

  • [=, &x, &y]表示外部变量 x、y 的值可以被修改,其余外部变量不能被修改;
  • [&, x, y]表示除 x、y 以外的外部变量,值都可以被修改。

参考:http://c.biancheng.net/view/433.html


补充:
匿名函数和函数的对比:
匿名函数:

[](int x){return x % 3 == 0;}

函数:

bool f3(int x){return x % 3 == 0;}

两者差别在于:
1、使用[]代替了函数名(匿名函数的由来)
2、没有声明返回类型
返回类型相当于使用decltype根据返回值推断得到。仅当lambda表达式完全由一条返回语句组成时,自动类型推断才管用,否则需要使用新增的返回类型后置语法:

[](double x)->double{int y=x;return x-y;}//return type is double

C++引入lambda的主要目的是:能够将类似于函数的表达式用作接受函数指针或函数符的函数的参数,因此典型的lambda是测试表达式或比较表达式,可编写为一条返回语句。

posted @ 2020-03-31 22:36  牛犁heart  阅读(467)  评论(0编辑  收藏  举报