C++中lambda的介绍和简单使用。

构成

C++11下lambda表达式完全体的构成:
[ captures ] ( params ) specifiers exception attr -> ret { body }

其中params和ret可以省略,省略返回值类型相当于返回auto类型,省略(params)相当于lambda函数不接受参数输入,对应以下几种变体:

  • [ captures ] ( params ) -> ret { body }
  • [ captures ] ( params ) { body }
  • [ captures ] { body }

captures

支持值捕获、引用捕获和隐式捕获。
值捕获和引用捕获
在变量前使用前缀=来表示值捕获,&表示引用捕获。变量在captures列表只能出现一次,当变量被一种方式隐式捕获时,显示捕获只能将其声明为另一种捕获方式。
【1】中的例子:

// 默认引用捕获
struct S2 { void f(int i); };
void S2::f(int i)
{
    [&]{};          // OK: by-reference capture default
    [&, i]{};       // OK: by-reference capture, except i is captured by copy
    [&, &i] {};     // Error: by-reference capture when by-reference is the default
    [&, this] {};   // OK, equivalent to [&]
    [&, this, i]{}; // OK, equivalent to [&, i]
}
// 默认值捕获
struct S2 { void f(int i); };
void S2::f(int i)
{
    [=]{};          // OK: by-copy capture default
    [=, &i]{};      // OK: by-copy capture, except i is captured by reference
    [=, *this]{};   // until C++17: Error: invalid syntax
                    // since c++17: OK: captures the enclosing S2 by copy
    [=, this] {};   // until C++20: Error: this when = is the default
                    // since C++20: OK, same as [=]
}

隐式捕获
上面的例子中可以看到,当捕获列表的首项为=及&时会按相应的捕获方式捕获所用的变量和this下的成员变量。另外lambda表达式可以不捕获而使用或读取一些变量,比如全局变量、静态局部变量等,具体类型可以查看参考[1]。


#include <iostream>
using namespace std;

int i = 10;
int main()
{
    static int j = 1;
    auto f = []() {cout <<"i:"<< i <<"\tj:"<< j; };
    f();
}
// out:
// i:10	j:1

params

和函数参数差不多,在C++14后不支持指定参数默认值且支持用auto声明参数。
参数名与变量名相同会隐藏所捕获的变量。

ret

返回值类型,可省略。省略后要注意不同分支下返回值类型要保持一致。

body

函数体。当变量为值捕获时,要在lambda表达式的parameter list(不可省略) 和 return type(省略或"->ret"形式)之间指定说明符为mutable才能修改变量的值,但仍是值引用。


int i = 0;
auto f = [i]() mutable {return ++i; };
cout << "i:" << i << "\tf():" << f();

// out:
// i:0     f():1

例子

在一些需要输入函数的时候就可以用lambda生成匿名函数传入,比如std中的sort、for_each等函数。

int main()
{
    using namespace std;
    vector<int> nums = { 1,2,3,4,5,6,7 };

    // 使用lambda和for_each定义一个函数用于输出vector
    auto print_vec = [](const vector<int> vec) {
        for_each(vec.begin(), vec.end(), [](int i) {cout << i << '\t'; });
    };
    print_vec(nums);
    cout << endl;

    // 引用方式修改值
    for_each(nums.begin(), nums.end(), [](int& i) { i -= 4; });
    print_vec(nums);
    cout << endl;

    // sort自定义排序
    sort(nums.begin(), nums.end(), [](int a, int b) -> bool { return abs(a) < abs(b); }); 
    print_vec(nums);
    cout << endl;
}
// out:
// 1       2       3       4       5       6       7
// -3      -2      -1      0       1       2       3
// 0       -1      1       -2      2       -3      3

参考

[1]cppreference-lambda