C++ Lambda 表达式是 C++11 引入的一个强大功能,允许你定义内联的匿名函数对象(也称为“Lambda 表达式”),使得代码更加简洁、灵活和易于维护。Lambda 表达式可以用在许多场景中,尤其是当你需要传递一个小的匿名函数到标准库算法或其他函数时。

1. 基本语法

Lambda 表达式的基本语法如下:

1
[捕获列表](参数列表) -> 返回类型 { 函数体 }

各部分说明:

  • 捕获列表:决定 Lambda 函数是否可以访问外部作用域的变量,及如何访问它们(值捕获、引用捕获等)。
  • 参数列表:定义 Lambda 函数的参数,就像普通的函数一样。
  • 返回类型:指定 Lambda 表达式返回值的类型,如果省略,编译器会自动推导。
  • 函数体:Lambda 函数的实现部分。

2. 示例代码

2.1 简单的 Lambda 表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

int main() {
// 定义一个简单的 Lambda 表达式
auto greet = []() {
std::cout << "Hello, Lambda!" << std::endl;
};

// 调用 Lambda
greet();

return 0;
}

输出:

1
Hello, Lambda!

这里的 []() 表示一个没有参数并且没有捕获任何外部变量的 Lambda 函数。

2.2 带参数的 Lambda 表达式

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

int main() {
// 带参数的 Lambda 表达式
auto add = [](int a, int b) -> int {
return a + b;
};

std::cout << "Sum: " << add(5, 3) << std::endl; // 输出:Sum: 8

return 0;
}

在这个例子中,add 是一个带有两个 int 类型参数的 Lambda 表达式,返回两个整数的和。

2.3 捕获外部变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>

int main() {
int x = 5;
int y = 10;

// 捕获外部变量
auto sum = [x, y]() -> int {
return x + y;
};

std::cout << "Sum: " << sum() << std::endl; // 输出:Sum: 15

return 0;
}

[x, y] 表示捕获 x 和 y,并按值捕获它们。如果你希望按引用捕获它们,可以使用 & 符号。

1
2
3
auto sum = [&x, &y]() -> int {
return x + y;
};

2.4 捕获所有外部变量

  • [=] 捕获所有外部变量,按值捕获。
  • [&] 捕获所有外部变量,按引用捕获。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>

int main() {
int a = 1, b = 2;

// 捕获所有变量,按值
auto sum_by_value = [=]() -> int {
return a + b;
};

// 捕获所有变量,按引用
auto sum_by_ref = [&]() -> int {
a = 10; // 修改 a 的值
return a + b;
};

std::cout << "Sum by value: " << sum_by_value() << std::endl; // 输出:Sum by value: 3
std::cout << "Sum by ref: " << sum_by_ref() << std::endl; // 输出:Sum by ref: 12
std::cout << "Modified a: " << a << std::endl; // 输出:Modified a: 10

return 0;
}

3. 返回类型的推导

C++11 中,Lambda 表达式的返回类型可以由编译器自动推导。你也可以显式地指定返回类型。

1
2
auto add = [](int a, int b) -> int { return a + b; };  // 显式指定返回类型
auto add = [](int a, int b) { return a + b; }; // 自动推导返回类型

如果 Lambda 函数有返回值,编译器会自动推导出返回类型。

如果你明确知道返回类型,最好显式地指定它,避免潜在的错误。

4. Lambda 表达式与标准库

Lambda 表达式常用于 C++ 标准库算法中,如 std::sortstd::for_eachstd::transform 等。

4.1 示例:std::for_each 与 Lambda

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};

// 使用 Lambda 遍历并打印每个元素
std::for_each(nums.begin(), nums.end(), [](int n) {
std::cout << n << " ";
});

return 0;
}

输出:

1
1 2 3 4 5

4.2 示例:std::sort 与 Lambda

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
std::vector<int> nums = {5, 2, 8, 1, 3};

// 使用 Lambda 对数组进行排序
std::sort(nums.begin(), nums.end(), [](int a, int b) {
return a < b; // 升序排序
});

for (int num : nums) {
std::cout << num << " ";
}

return 0;
}

输出:

1
1 2 3 5 8

5. 捕获列表的更多技巧

5.1 捕获所有变量并按引用捕获

1
2
3
4
5
6
7
int x = 5, y = 10;
auto f = [&]() {
x++; // x 被按引用捕获,修改其值
y++; // y 被按引用捕获,修改其值
};
f();
std::cout << "x: " << x << ", y: " << y << std::endl; // 输出:x: 6, y: 11

5.2 捕获 this 指针(在类的成员函数中)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class MyClass {
public:
int value;
MyClass(int v) : value(v) {}

void printValue() {
auto lambda = [this]() { // 捕获 this 指针
std::cout << "Value: " << value << std::endl;
};
lambda();
}
};

int main() {
MyClass obj(42);
obj.printValue(); // 输出:Value: 42
}

6. 总结

Lambda 表达式提供了一种在函数内定义匿名函数的方式,可以捕获外部作用域的变量,具有高度的灵活性。它广泛应用于 C++11 及更高版本的标准库算法中,并且能够让代码更加简洁、可读和易于维护。

  • 捕获外部变量:可以按值或引用捕获外部变量。
  • 简洁的语法:允许在函数内部定义小型匿名函数。
  • 与标准库配合使用:特别适用于像 std::sortstd::for_each 等算法。