C++11 lambda 表达
在 C++11 中,lambda 表达式是一个非常重要且强大的特性,允许在代码中定义匿名函数并立即使用它。Lambda 表达式的解析可以从语法结构、捕获列表、参数和返回类型等方面进行详细分析。
Lambda 表达式的基本语法结构
[捕获列表](参数列表) -> 返回类型 { 函数体 }
Lambda 表达式的基本语法如下:
- 捕获列表 -> 返回类型 { 函数体 }
- 捕获列表:指定外部变量的捕获方式(按值或按引用),捕获的变量可以在 lambda 内部使用。
- 参数列表:可以像普通函数一样定义 lambda 的参数。
- 返回类型:指定 lambda 函数的返回类型,可以省略,编译器会自动推断。
- 函数体:定义 lambda 的执行代码。
1. 捕获列表 (Capture List)
捕获列表是 lambda 表达式中的一个重要部分,用来捕获外部作用域中的变量。这些变量可以是按值捕获或按引用捕获,决定了 lambda 内部是否能够修改外部变量。
1.1 按值捕获
按值捕获会将外部变量的副本传递给 lambda 表达式。lambda 内部无法修改原始变量。
int x = 10;
auto lambda = [x]() { std::cout << "x inside lambda: " << x << std::endl;
};
lambda(); // 输出 "x inside lambda: 10"
1.2 按引用捕获
按引用捕获会将外部变量的引用传递给 lambda 表达式,使得 lambda 内部能够修改外部变量。
int x = 10;
auto lambda = [&x]() { x += 5; std::cout << "x inside lambda: " << x << std::endl;
};
lambda(); // 输出 "x inside lambda: 15"
std::cout << "x outside lambda: " << x << std::endl; // 输出 "x outside lambda: 15"
1.3 捕获所有变量
你可以使用 [] 捕获所有外部变量。
- [=] 按值捕获所有外部变量。
- [&] 按引用捕获所有外部变量。
int x = 10, y = 20;
auto lambda = [=]() {std::cout << "x: " << x << ", y: " << y << std::endl; // 按值捕获
};
lambda(); // 输出 "x: 10, y: 20"auto lambda2 = [&]() {x += 5;y += 10;std::cout << "x: " << x << ", y: " << y << std::endl; // 按引用捕获
};
lambda2(); // 输出 "x: 15, y: 30"
std::cout << "x: " << x << ", y: " << y << std::endl; // 输出 "x: 15, y: 30"
2. 参数列表 (Parameters List)
Lambda 表达式支持定义输入参数,类似于普通的函数。
auto add = [](int a, int b) { return a + b; };
std::cout << add(2, 3); // 输出 5
3. 返回类型 (Return Type)
Lambda 的返回类型可以省略,编译器会根据 return 语句自动推断。但如果编译器无法推断,或希望指定返回类型,则需要显式声明返回类型。
auto multiply = [](int a, int b) -> int { return a * b; };
std::cout << multiply(3, 4); // 输出 12
4. 函数体 (Function Body)
函数体部分包含 lambda 表达式的执行逻辑。你可以像普通函数一样在 lambda 中编写代码。
auto greet = []() { std::cout << "Hello, world!" << std::endl; };
greet(); // 输出 "Hello, world!"
5. 推导和类型
C++11 中的 lambda 表达式可以自动推导类型,但也允许你显式指定返回类型和参数类型。编译器通常会根据返回值推断返回类型,但如果你明确知道返回类型或有需要的情况下,可以手动指定。
5.1 推导返回类型
auto func = [](int a, int b) { return a + b; }; // 返回类型推导为 int
5.2 显式返回类型
auto func = [](int a, int b) -> double { return a / b; }; // 显式指定返回类型为 double
6. Lambda 表达式的类型
Lambda 表达式的类型是一个匿名的类类型。这个类型是由编译器自动生成的,且每个 lambda 表达式都有独特的类型。
auto lambda = [](int a, int b) { return a + b; };
lambda 是一个类型为 operator() 的对象,它的类型由编译器推断为一个匿名类。
如果你试图手动推导 lambda 的类型,可以使用 std::function 来保存它。
std::function<int(int, int)> add = [](int a, int b) { return a + b; };
7. 使用 Lambda 表达式与 STL 算法
Lambda 表达式在 C++ 中常与标准库算法(如 std::sort、std::find_if 等)配合使用,极大简化了代码。
7.1 使用 lambda 进行排序
#include <algorithm>
#include <vector>
#include <iostream>int main() {std::vector<int> vec = {5, 1, 3, 2, 4};std::sort(vec.begin(), vec.end(), [](int a, int b) { return a < b; });for (int n : vec) {std::cout << n << " "; // 输出 1 2 3 4 5}return 0;
}
7.2 使用 lambda 查找元素
#include <algorithm>
#include <vector>
#include <iostream>int main() {std::vector<int> vec = {5, 1, 3, 2, 4};auto it = std::find_if(vec.begin(), vec.end(), [](int x) { return x == 3; });if (it != vec.end()) {std::cout << "Found: " << *it << std::endl; // 输出 "Found: 3"}return 0;
}
总结
C++11 引入的 lambda 表达式使得函数式编程成为可能,并为许多编程场景(如 STL 算法等)提供了简洁的解决方案。Lambda 表达式的关键特点在于:
- 捕获外部变量:允许按值或按引用捕获外部作用域中的变量。
- 简洁性:可以定义匿名函数并在代码中直接使用,避免了传统函数定义的冗长。
- 自动推导:能够自动推导返回类型和参数类型,减少了代码量。
- 匿名类型:每个 lambda 表达式都有自己的类型,可以通过 std::function 等方式进行存储和使用。