c++中的Lambda表达式

Lambda 表达式

谓词函数: 进行一个操作时的一个临时函数,一般使用匿名函数。比如sort函数的第三个参数即传入一个谓词函数

1
std::sort(X, X+N, [](float a, float b) {return std::abs(a) < std::abs(b);});

Lambda 表达式使用一对方括号作为开始的标识,就类似于声明一个函数(也是匿名函数)

1
std::cout<<[](float f) {return std::abs(f);}(-3.5);            // 3.5

当只有一个返回值时,C++会自动判断返回值的类型而无需声明返回值的类型

我们也可以强制将返回值转换为int

1
std::cout<<[](float f) -> int {return std::abs(f);}(-3.5);     // 3

有点 JavaScript 里立即执行函数的味道了

我们可以使用auto关键字来引入Lambda表达式

1
auto lambda =[]() -> int {return val*100;};

auto关键字将Lambda表达式转换成一种类似于std::function的内部类型

1
std::function<int()> lambda = []() -> int {return val*100};

当需要接受一个double作为参数,返回int的对象时

1
std::function<int(double)>

Lambda 引入符

Lambda 表达式前面的方括号[]称为Lambda引入符,它表示其后的 Lambda 表达式以何种方式捕获变量

  • [=] 以传值的方式捕获

    1
    2
    float f0 = 1.0;
    std::cout<<[=](float f) {return f0 + std::abs(f);}(-3.5); // 4.5
  • [&] 以传引用的方式捕获

    1
    std::cout << [&](float f) {return f0 += std::abs(f);}(-3.5);    // 4.5

传值的捕获方式不允许修改外部变量,可以使用 mutabe 关键字调和(不报错,但还是不允许修改)

1
2
3
float f0 = 1.0;
std::cout<<[=](float f) mutabe {return f0 += std::abs(f);}(-3.5); // 4.5
std::cout<<'\n'<<f0<<'\n'; // 1.0

可以将传值与传引用的机制相混合:比如f0通过引用捕获,f1通过传值捕获

1
2
3
4
float f0 = 1.0f;
float f1 = 10.0f;
std::cout<<[=, &f0](float a) {return f0 += f1 + std::abs(a);}(-3.5); // 14.5
std::cout<<'\n'<<f0<<'\n'; // 14.5

总结

  • [] 不捕获任何外部变量
  • [=] 以值的形式捕获所有外部变量
  • [&] 以引用的形式捕获所有外部变量
  • [x, &y] x 以传值的形式捕获, y 以传引用的形式捕获
  • [=, &z] z 以传引用的形式捕获,其他变量则以传值的形式捕获
  • [&, x] x 以传值的形式捕获,其他变量则以传引用的形式捕获

最后,Lambda 表达式中可以直接使用 this 指针,但对[]而言则需要显式传入:

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