PrevNext

简介

为什么使用 Lambda?

Lambda 允许我们直接在使用位置编写简单的匿名函数。这样既能减少独立的小函数, 又能让相关代码集中且有条理。此外,Lambda 可以捕获周围作用域中的变量,编写 辅助函数时通常非常方便。

C++ 标准库对 Lambda 有良好支持,例如 std::sortstd::lower_bound 都 允许传入自定义函数作为比较器。相比专门编写一个比较函数,这通常更加方便。

一般形式

Lambda 的一般形式如下:

[capture_list](parameters) -> trailing_return_type {
	// function body
}

参数、返回类型和函数体都比较直观。在算法竞赛中,通常使用以下捕获方式:

[]:不捕获局部作用域中的任何变量。

[&]:按引用捕获局部作用域中的所有变量。

[=]:按值复制局部作用域中的所有变量。

Lambda 的局部作用域是它被定义的位置,而不是它被调用的位置。

也可以逐个指定要捕获的变量,不过通常没有必要。

例如,要编写一个返回给定数字平方的函数,可以使用下面的 Lambda 表达式:

auto square = [](int x) -> long long { return (long long)x * x; };

之后可以像普通函数一样调用它。

cout << square(10) << '\n'; // prints out 100

正如自定义比较器模块所述,Lambda 也可以 用作比较器。

递归 Lambda

假设要编写一个递归的 GCD 函数,最直观的 Lambda 写法如下:

auto gcd = [](int a, int b) -> int { return b == 0 ? a : gcd(b, a % b); };

遗憾的是,这段代码无法工作,因为 Lambda 不能在自己的定义中直接引用自身。 不过有几种方法可以绕过这个限制。

使用 y_combinator

Resources
open-std
RIP Tutorial

在 C++14 中加入上述链接提供的以下代码:

namespace std {
template <class Fun> class y_combinator_result {
Fun fun_;
public:
template <class T>
explicit y_combinator_result(T &&fun) : fun_(std::forward<T>(fun)) {}
template <class... Args> decltype(auto) operator()(Args &&...args) {

之后就可以这样编写递归 Lambda:

int main() {
cout << y_combinator([](auto gcd, int a, int b) -> int {
return b == 0 ? a : gcd(b, a % b);
})(20, 30)
<< "\n"; // outputs 10
}

With std::function

使用 function<返回类型(参数类型)> 代替 auto

int main() {
function<int(int, int)> gcd = [&](int a, int b) {
return b == 0 ? a : gcd(b, a % b);
};
cout << gcd(20, 30) << '\n'; // outputs 10
}

使用泛型 Lambda

为了解决 Lambda 无法访问自身的问题,可以把 Lambda 自身作为参数传给自己。

int main() {
auto gcd = [&](int a, int b, auto &&gcd) -> int {
return b == 0 ? a : gcd(b, a % b, gcd);
};
cout << gcd(20, 30, gcd) << '\n'; // outputs 10
}

Module Progress:

PrevNext