c14 lambda表达式
·
在 C++ 中,lambda 表达式(匿名函数)是一种便捷的函数定义方式,允许在需要函数的地方直接编写代码块,无需单独定义函数或函数对象。它是 C++11 引入的重要特性,广泛用于简化代码(尤其是配合 STL 算法)。
一、lambda 表达式的基本语法
lambda 表达式的基本格式如下:
[capture-list](parameter-list) mutable noexcept -> return-type {
// 函数体
}
各部分含义:
capture-list(捕获列表):指定外部变量如何被 lambda 内部访问(如按值捕获、按引用捕获)。parameter-list(参数列表):与普通函数的参数列表相同(可省略,若为空可连同()一起省略)。mutable:可选,允许在 lambda 内部修改按值捕获的变量(默认不可修改)。noexcept:可选,指定 lambda 不会抛出异常。-> return-type(返回类型):可选,若函数体只有return语句或无返回值,可省略(编译器自动推导)。- 函数体:lambda 要执行的代码。
二、最简单的 lambda 示例
最简化的 lambda 可以没有参数、捕获列表和返回类型:
#include <iostream>
int main() {
// 无参数、无捕获的lambda
auto hello = [] {
std::cout << "Hello, Lambda!" << std::endl;
};
hello(); // 调用lambda,输出:Hello, Lambda!
return 0;
}
三、核心组成部分详解
1. 捕获列表(capture-list):访问外部变量
lambda 可以通过捕获列表访问定义它的作用域中的变量,主要有以下几种捕获方式:
| 捕获方式 | 含义 | 示例 |
|---|---|---|
[] | 不捕获任何外部变量 | - |
[var] | 按值捕获var(复制一份,内部不可修改,除非用mutable) | [x] { return x * 2; } |
[&var] | 按引用捕获var(可修改原变量) | [&x] { x++; } |
[=] | 按值捕获所有用到的外部变量 | [=] { return x + y; } |
[&] | 按引用捕获所有用到的外部变量 | [&] { x++; y++; } |
[=, &var] | 除var按引用捕获外,其余按值捕获 | [=, &x] { x++; return y; } |
[&, var] | 除var按值捕获外,其余按引用捕获 | [&, x] { y++; return x; } |
示例:
#include <iostream>
int main() {
int a = 10, b = 20;
// 按值捕获a,按引用捕获b
auto func = [a, &b] {
// a = 30; // 错误:按值捕获的变量默认不可修改
b = 30; // 正确:按引用捕获的变量可修改
return a + b;
};
std::cout << func() << std::endl; // 输出:10 + 30 = 40
std::cout << "b = " << b << std::endl; // 输出:30(原变量被修改)
return 0;
}
若要修改按值捕获的变量,需加mutable:
auto func = [a]() mutable {
a = 30; // 允许修改(仅修改副本,不影响原变量)
return a;
};
2. 参数列表与返回类型
lambda 的参数列表与普通函数一致,支持类型推导(C++14 起)、默认参数等:
// 带参数和返回类型的lambda
auto add = [](int x, int y) -> int {
return x + y;
};
std::cout << add(2, 3) << std::endl; // 输出5
// C++14起支持参数类型自动推导(auto)
auto multiply = [](auto x, auto y) {
return x * y;
};
std::cout << multiply(2.5, 4) << std::endl; // 输出10.0
四、lambda 的典型应用场景
1. 作为 STL 算法的回调函数
lambda 最常用的场景是配合 STL 算法(如sort、for_each),简化代码:
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> nums = {3, 1, 4, 1, 5};
// 用lambda作为排序的比较函数(降序)
std::sort(nums.begin(), nums.end(), [](int a, int b) {
return a > b; // 从大到小排序
});
// 用lambda遍历容器
std::for_each(nums.begin(), nums.end(), [](int num) {
std::cout << num << " "; // 输出:5 4 3 1 1
});
return 0;
}
2. 简化函数对象(仿函数)
在需要临时函数对象的场景(如线程、异步操作),lambda 比自定义仿函数更简洁:
#include <thread>
#include <iostream>
int main() {
int count = 0;
// 用lambda创建线程(捕获count的引用)
std::thread t([&count]() {
for (int i = 0; i < 1000000; ++i) {
count++;
}
});
t.join();
std::cout << "count = " << count << std::endl; // 输出:1000000
return 0;
}
3. 捕获上下文的临时逻辑
lambda 可以捕获当前作用域的变量,实现依赖上下文的临时逻辑:
#include <iostream>
#include <functional>
// 返回一个依赖于参数x的lambda
std::function<int(int)> makeAdder(int x) {
return [x](int y) { // 捕获x
return x + y;
};
}
int main() {
auto add5 = makeAdder(5);
auto add10 = makeAdder(10);
std::cout << add5(3) << std::endl; // 输出:8
std::cout << add10(3) << std::endl; // 输出:13
return 0;
}
五、lambda 的本质
lambda 表达式在编译时会被转换为匿名的函数对象( functor,一种重载了operator()的类),捕获的变量会成为该类的成员变量。因此,lambda 的大小取决于捕获变量的大小(无捕获的 lambda 大小为 1,类似空类)。
例如,以下 lambda:
int x = 10;
auto func = [x](int y) { return x + y; };
编译器会生成类似这样的类:
class LambdaFunc {
private:
int x; // 捕获的变量
public:
LambdaFunc(int x_) : x(x_) {} // 构造函数初始化捕获的变量
int operator()(int y) const { // 重载()运算符
return x + y;
}
};
auto func = LambdaFunc(x);
六、注意事项
- 捕获列表的生命周期:按引用捕获的变量必须在 lambda 调用时仍有效,否则会导致悬空引用(如捕获局部变量后,在变量销毁后调用 lambda)。
mutable的影响:仅允许修改按值捕获的副本,不影响原变量。- 与
std::function结合:lambda 可赋值给std::function(需包含<functional>),用于存储或传递匿名函数。
总结
lambda 表达式是 C++ 中简化代码的强大工具,核心优势在于:
- 可以在需要函数的地方直接定义,避免编写独立函数或仿函数。
- 灵活的捕获机制,可访问外部变量。
- 与 STL 算法、线程等特性无缝配合,大幅提升代码可读性和开发效率。
掌握 lambda 是编写现代 C++ 代码的必备技能,尤其在泛型编程和异步编程中应用广泛。
更多推荐



所有评论(0)