导言
在现代 C++ 开发中,lambda 表达式(匿名函数)已经成为编写简洁高效代码的重要工具。尤其在配合 STL 算法(如for_each
)时,lambda 表达式能够消除编写命名函数或函数对象的额外开销,使代码更加紧凑直观。
一、Lambda 表达式的基本语法
lambda 表达式的完整语法结构如下:
1 2 3
| [capture](parameters) mutable noexcept -> return_type { }
|
各组成部分的含义:
[capture]
:捕获列表,定义 lambda 表达式可以访问的外部变量
(parameters)
:参数列表,与普通函数的参数列表类似
mutable
:可选修饰符,允许修改按值捕获的变量
noexcept
:可选修饰符,指定函数不会抛出异常
-> return_type
:返回类型,当函数体只有 return 语句时可省略
{}
:函数体,包含具体的执行逻辑
1.1 最简单的 Lambda 表达式
最简化的 lambda 表达式可以省略参数列表、返回类型和修饰符,仅保留捕获列表和函数体:
1 2 3 4 5 6 7 8 9 10 11
| #include <iostream>
int main() { auto hello = []{ std::cout << "Hello, Lambda!" << std::endl; }; hello(); return 0; }
|
二、捕获列表详解
捕获列表是 lambda 表达式最具特色的部分,它控制着 lambda 如何访问外部作用域中的变量。根据捕获方式的不同,可分为以下几类:
2.1 捕获列表的简化写法
C++ 提供了几种简化的捕获方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #include <iostream> #include <vector> #include <algorithm>
int main() { int x = 5, y = 10; auto by_value = [=]() { std::cout << "x = " << x << ", y = " << y << std::endl; }; auto by_ref = [&]() { x++; y++; std::cout << "x = " << x << ", y = " << y << std::endl; }; auto mixed1 = [=, &x]() { x++; std::cout << "x = " << x << ", y = " << y << std::endl; }; auto mixed2 = [&, y]() { x++; std::cout << "x = " << x << ", y = " << y << std::endl; }; by_value(); by_ref(); mixed1(); mixed2(); return 0; }
|
2.2 mutable 修饰符的作用
默认情况下,按值捕获的变量在 lambda 表达式内部是只读的,使用mutable
可以解除这一限制:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #include <iostream>
int main() { int a = 10; auto func1 = [a]() { std::cout << "a = " << a << std::endl; }; auto func2 = [a]() mutable { a++; std::cout << "内部a = " << a << std::endl; }; func1(); func2(); std::cout << "外部a = " << a << std::endl; return 0; }
|
三、与 STL 算法配合使用
lambda 表达式与 STL 算法(尤其是for_each
)配合使用时,能极大简化代码:
3.1 for_each 算法示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #include <iostream> #include <vector> #include <algorithm>
int main() { std::vector<int> numbers = {1, 2, 3, 4, 5}; std::cout << "元素列表:"; std::for_each(numbers.begin(), numbers.end(), [](int n) { std::cout << n << " "; }); std::cout << std::endl; std::for_each(numbers.begin(), numbers.end(), [](int& n) { n += 10; }); std::cout << "修改后:"; std::for_each(numbers.begin(), numbers.end(), [](int n) { std::cout << n << " "; }); std::cout << std::endl; return 0; }
|
输出结果:
1 2
| 元素列表:1 2 3 4 5 修改后:11 12 13 14 15
|
3.2 带捕获的 lambda 与算法结合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include <iostream> #include <vector> #include <algorithm>
int main() { std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int threshold = 5; int count = 0; int sum = 0; std::for_each(numbers.begin(), numbers.end(), [threshold, &count, &sum](int n) { if (n > threshold) { count++; sum += n; } }); std::cout << "大于" << threshold << "的元素有" << count << "个,"; std::cout << "它们的和是" << sum << std::endl; return 0; }
|
输出结果:
四、Lambda 表达式的返回类型
大多数情况下,lambda 表达式的返回类型可以被编译器自动推导,无需显式指定。但在某些复杂情况下(如多个 return 语句返回不同类型),需要显式指定返回类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include <iostream>
int main() { auto add = [](int a, int b) { return a + b; }; auto divide = [](double a, double b) -> double { if (b == 0) return 0; return a / b; }; std::cout << "3 + 5 = " << add(3, 5) << std::endl; std::cout << "10 / 3 = " << divide(10, 3) << std::endl; return 0; }
|
五、Lambda 表达式的实际应用场景
5.1 作为回调函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <iostream> #include <functional>
void process_data(int data, const std::function<void(int)>& callback) { int result = data * 2; callback(result); }
int main() { int value = 5; process_data(value, [](int result) { std::cout << "处理结果: " << result << std::endl; }); process_data(value, [value](int result) { std::cout << value << "的两倍是: " << result << std::endl; }); return 0; }
|
5.2 在排序算法中使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <iostream> #include <vector> #include <algorithm>
int main() { std::vector<int> numbers = {5, 2, 9, 1, 5, 6}; std::sort(numbers.begin(), numbers.end()); std::sort(numbers.begin(), numbers.end(), [](int a, int b) { return a > b; }); for (int n : numbers) { std::cout << n << " "; } std::cout << std::endl; return 0; }
|