简介
| Resources | |||||
|---|---|---|---|---|---|
| CPP | 参考手册 | ||||
| UMich | |||||
| SO | |||||
| Microsoft | |||||
为什么使用 Lambda?
Lambda 允许我们直接在使用位置编写简单的匿名函数。这样既能减少独立的小函数, 又能让相关代码集中且有条理。此外,Lambda 可以捕获周围作用域中的变量,编写 辅助函数时通常非常方便。
C++ 标准库对 Lambda 有良好支持,例如 std::sort 和 std::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}