lambda函数

参考:C++ 函数 | 菜鸟教程 (runoob.com)

Lambda 函数与表达式

C++11 提供了对匿名函数的支持,称为 Lambda 函数(也叫 Lambda 表达式)。
Lambda 表达式把函数看作对象。Lambda 表达式可以像对象一样使用,比如可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值。
Lambda 表达式本质上与函数声明非常类似。Lambda 表达式具体形式如下:

[capture](parameters)->return-type{body}

例如:

[](int x, int y){ return x < y ; }

如果没有返回值可以表示为:

[capture](parameters){body}

例如:

[]{ ++global_x; } 

在一个更为复杂的例子中,返回类型可以被明确的指定如下:

[](int x, int y) -> int { int z = x + y; return z + x; }

本例中,一个临时的参数 z 被创建用来存储中间结果。如同一般的函数,z 的值不会保留到下一次该不具名函数再次被调用时。
如果 lambda 函数没有传回值(例如 void),其返回类型可被完全忽略。
在Lambda表达式内可以访问当前作用域的变量,这是Lambda表达式的闭包(Closure)行为。 与JavaScript闭包不同,C++变量传递有传值和传引用的区别。可以通过前面的[]来指定:

[]      // 沒有定义任何变量。使用未定义变量会引发错误。
[x, &y] // x以传值方式传入(默认),y以引用方式传入。
[&]     // 任何被使用到的外部变量都隐式地以 引用 方式加以引用。
[=]     // 任何被使用到的外部变量都隐式地以 传值 方式加以引用。
[&, x]  // x显式地以传值方式加以引用。其余变量以引用方式加以引用。
[=, &z] // z显式地以引用方式加以引用。其余变量以传值方式加以引用。

另外有一点需要注意。对于[=]或[&]的形式,lambda 表达式可以直接使用 this 指针。但是,对于[]的形式,如果要使用 this 指针,必须显式传入:

[this]() { this->someFunc(); }();

例子

1、未定义变量时不可以使用外部变量

#include <iostream>
using namespace std;
 
int main()
{
    int i = 1024;
    auto func = [] { cout << i; };
    func();
}  // 结果报错,因为未指定默认捕获模式

正确的如下,[=]传值引入外部变量:

#include <iostream>
using namespace std;
 
int main()
{
    int i = 1024;
    cout << "i:" << &i << endl;//输出i的地址
    auto func = [=]{  // [=] 表明将外部的所有变量拷贝一份到该Lambda函数内部
        cout << "i:" << &i << endl;
        cout << i;
    };
    func();
}

输出为

i:0x7ff7bfeff13c
i:0x7ff7bfeff138

这表明传值引用为拷贝原有变量到新的内存地址
2、引用捕获

#include <iostream>
using namespace std;
 
int main()
{
    int i = 1024;
    cout << "i:" << i << endl;
    cout << "i:" << &i << endl;
    auto fun1 = [&]{
        cout << "i:" << &i << endl;
        i++;
    };
    fun1();
    cout << "i:" << i << endl;
}

结果为:

i:1024
&i:0x7ff7bfeff13c
&i:0x7ff7bfeff13c
i:1025

这表明引用变量仍为外部原变量,改变

3、复制并引用捕获

#include <iostream>
using namespace std;
 
int main()
{
    int i = 1024, j = 2048;
 
    cout << "i:" << &i << endl;
    cout << "j:" << &j << endl;
 
    auto fun1 = [=, &i]{ // 默认拷贝外部所有变量,但引用变量 i
        cout << "i:" << &i << endl;
        cout << "j:" << &j << endl;
    };
    fun1();
}

4、指定引用或复制

#include <iostream>
using namespace std;
 
int main()
{
    int i = 1024, j = 2048;
 
    cout << "outside i value:" << i << " addr:" << &i << endl;
 
    auto fun1 = [i]{
        cout << "inside  i value:" << i << " addr:" << &i << endl;
        // cout << j << endl; // j 未捕获
    };
    fun1();
}

5、捕获this指针

#include <iostream>
using namespace std;
 
class test
{
public:
    void hello() {
        cout << "test hello!n";
    };
    void lambda() {
        auto fun = [this]{ // 捕获了 this 指针
            this->hello(); // 这里 this 调用的就是 class test 的对象了
        };
        fun();
    }
};
 
int main()
{
    test t;
    t.lambda();
}