在 C++ 中,Lambda 表达式是一种轻量级的函数对象(或匿名函数),可以在代码中定义并直接使用。它是从 C++11 引入的功能,常用于需要定义短小函数的场景,比如多线程、STL 算法或回调函数中。


1. Lambda 表达式的基本语法

1
2
3
[捕获列表](参数列表) -> 返回类型 {
函数体
};
  • **捕获列表**:定义 lambda 可以捕获哪些变量,以及如何捕获(按值或按引用)。
  • **参数列表**:和普通函数类似,定义函数的参数。
  • **返回类型**:可选,通常由编译器自动推断。
  • **函数体**:函数的逻辑部分。

2. Lambda 表达式的基本示例

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

int main() {
// 最简单的 Lambda
auto lambda = [] {
std::cout << "Hello, Lambda!" << std::endl;
};
lambda(); // 调用 lambda

// 带参数的 Lambda
auto add = [](int a, int b) {
return a + b;
};
std::cout << "Sum: " << add(5, 3) << std::endl;

return 0;
}

输出

1
2
Hello, Lambda!
Sum: 8

3. 捕获列表

Lambda 可以通过 捕获列表 访问外部变量。捕获列表控制外部变量的作用域和捕获方式。

(1) 按值捕获

  • Lambda 会复制外部变量的值。
  • 外部变量的值在 Lambda 定义时捕获,不受后续修改影响。
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

int main() {
int x = 10;
auto byValue = [x] {
std::cout << "Captured by value: " << x << std::endl;
};

x = 20; // 修改外部变量
byValue(); // 输出仍然是 10

return 0;
}

输出

1
Captured by value: 10

(2) 按引用捕获

  • Lambda 捕获外部变量的引用,因此可以修改外部变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>

int main() {
int x = 10;
auto byReference = [&x] {
x += 10;
std::cout << "Captured by reference: " << x << std::endl;
};

byReference(); // 修改了 x
std::cout << "Modified x: " << x << std::endl;

return 0;
}

输出

1
2
Captured by reference: 20
Modified x: 20

(3) 捕获所有变量

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

int main() {
int x = 10, y = 20;

auto captureAllByValue = [=] {
std::cout << "x: " << x << ", y: " << y << std::endl;
};

auto captureAllByReference = [&] {
x += 5;
y += 5;
std::cout << "Modified x: " << x << ", y: " << y << std::endl;
};

captureAllByValue(); // 按值捕获,不影响外部变量
captureAllByReference(); // 按引用捕获,修改外部变量

return 0;
}

输出

1
2
x: 10, y: 20
Modified x: 15, y: 25

4. Lambda 的返回类型

(1) 自动推断返回类型

  • 如果函数体只有一条 return 语句,返回类型会自动推断。
    1
    2
    3
    auto multiply = [](int a, int b) {
    return a * b; // 自动推断为 int
    };

(2) 显式指定返回类型

  • 如果返回类型不能自动推断,可以显式指定。
    1
    2
    3
    auto divide = [](int a, int b) -> double {
    return (double)a / b;
    };

5. Lambda 在 STL 中的使用

Lambda 通常用作回调函数,尤其在 STL 算法中非常常见。

(1) 用于 std::sort

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
8 5 3 2 1

(2) 用于 std::for_each

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};

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

return 0;
}

输出

1
1 2 3 4 5

6. 带状态的 Lambda

  • Lambda 本质是一个函数对象,因此它可以存储状态。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>

int main() {
int counter = 0;

auto increment = [counter]() mutable {
return ++counter; // 由于捕获的是值,必须加 `mutable` 才能修改
};

std::cout << increment() << std::endl; // 输出 1
std::cout << increment() << std::endl; // 输出 2

return 0;
}

输出

1
2
1
2

总结

  • Lambda 表达式是一种简洁的方式定义匿名函数,非常适合短小的逻辑。
  • 捕获列表允许访问外部变量,通过值或引用捕获,甚至可以捕获所有变量。
  • 在现代 C++ 中,Lambda 经常用于 STL 算法、多线程、回调等场景,是高效编写代码的重要工具。