Lambda 表达式

一、Lambda 是什么

一句话:

Lambda 表达式 = 轻量函数(匿名函数)

不需要声明名字、不需要单独写函数体,直接在代码里用。

二、C++ Lambda 基本格式

C++ 最完整语法:

capture(parameter_list) mutable noexcept -> return_type { body }

最常见精简格式:

\&(int x){ return x + 1; }

三、参数说明

部分 含义
[capture] 捕获外部变量
(parameter_list) 参数列表
mutable 允许修改捕获变量
return_type 返回类型
{ body } 实现代码

四、捕获(capture)的写法重点

捕获方式决定 Lambda 能否访问外部变量

例1:按值捕获

int a = 10;

auto f = a() { return a + 1; };

例2:按引用捕获

int a = 10;

auto f = \&a() { a++; };

f();

执行后 a == 11

例3:全部按值捕获

=() { ... }

例4:全部按引用捕获

\&() { ... }

例5:混合捕获

=,\&x(){ ... }

🧰 五、典型使用场景

① 线程回调 / 异步执行

std::thread t(\[\]{

printf("worker\n");

});

t.join();
② STL 回调(最常用)

std::vector<int> v{1,2,3,4};

std::for_each(v.begin(), v.end(), \[\](int x){

std::cout << x << " ";

});
③ 排序自定义

std::sort(v.begin(), v.end(),

\[\](int a, int b){ return a > b; });

🔧 六、底层实现

C++ Lambda 本质是:

编译器生成一个匿名类(仿函数 functor)

int a = 10;

auto f = a() { return a+1; };

等价于:

struct _Lambda {

int a;

int operator()() const {

return a+1;

}

};

所以:

  • 捕获变量 → 编译器生成成员变量

  • 调用 → 通过 operator() 执行

这一点和 std::function / function pointer 不一样。

🚩 七、常见坑

❗ 1. 捕获值不会更新原变量

int a = 10;

auto f = a(){ return a++; };

f();

printf("%d\n", a); // 输出 10(不会变)

需要引用:

auto f = \&a(){ a++; };
❗ 2. 捕获 this

类内使用很常见:

auto f = this() { this->run(); };

🚀 八、和函数指针对比

函数指针 Lambda
是否捕获外部变量 ❌ 不行 ✔ 可以
创建方式 需要函数名 无名即可
内联优化 一般
易用性

高级用法:

1️⃣ 泛型 Lambda (C++14+)

允许参数类型自动推断:

auto add = \[\](auto a, auto b){ return a + b; };

add(1, 2); // int

add(1.5, 2.2); // double

add("a"s, "b"s); // string

2️⃣ 可变参数 Lambda (C++20)

auto print = \[\](auto... args){

(std::cout << ... << args) << "\n";

};

print(1, "hello", 3.14);

3️⃣ mutable 捕获值可修改

默认按值捕获是 const 的:

int x = 10;

auto f = x() mutable {

x++;

return x;

};

f(); // 11

4️⃣ 捕获 this 指针

类内非常常见:

auto f = this { doWork(); };

如果你写:

=

类内也隐式捕获 this

但 C++20 允许捕获 this 的副本(防悬垂):

auto f = \*this { doWork(); };

等于复制整个对象避免悬空指针。


5️⃣ 初始化捕获(C++14+重要能力)

auto f = val = std::move(bigObj) {

use(val);

};

变量 val 只存在 Lambda 内

特别适合智能指针:

auto f = p = std::make_shared\(5) {

std::cout << *p;

};

甚至可以这样:

auto f = i=0() mutable {

return ++i;

};

f(); //1

f(); //2

这种行为 = 闭包(closure)状态保持

6️⃣ constexpr Lambda(C++17+)

constexpr auto sqr = \[\](int x) { return x*x; };

static_assert(sqr(5) == 25);

还能在编译期算 Fibonacci:

constexpr auto fib = \[\](int n){

if (n <= 1) return n;

return fib(n-1) + fib(n-2);

};

7️⃣ 返回类型显式指定

当需要强制返回类型:

auto f = \[\](int x) -> double {

if(x > 0) return x;

return 0.5;

};

8️⃣ Lambda + std::function

⚠ 注意性能区别:

复制代码
std::function<int(int)> f = [](int x){ return x + 1; };

会发生:

  • 类型擦除

  • 动态分配(可能)

  • 低效

推荐保留 auto

auto f = [](int x){ return x+1; };

9️⃣ Lambda 做状态机(闭包)

比如计数器:

auto counter = i = 0() mutable {

return ++i;

};

counter(); //1

counter(); //2

counter(); //3

多线程共享状态:

auto sum = total = std::atomic\(0)(int x) mutable {

total += x;

};

这就是函数式闭包的力量。

🔟 Lambda 捕获移动对象

最重要的例子:线程池任务提交

pool.push(task=std::move(task)() mutable {

task();

});

高级技巧加一条:模板 Lambda(C++20)

auto add = \[\]<typename T>(T a, T b){

return a + b;

};

底层实现补充

Lambda 本质上:

编译器生成 struct + operator()

带捕获:

复制代码
int x = 10;
auto f = [x]{ return x+1; };
等价于

struct _lambda {

int x;

int operator()() const { return x+1; }

};

🚩 性能注意点

写法 性能
auto lambda 🟢 最快
template lambda 🟢 最快
std::function 🔴 可能动态分配,慢
bind 🔴 更慢/不推荐

🧨 STL 中的高阶组合

std::sort(v.begin(), v.end(),

\[\](auto &a, auto &b){

return a.score > b.score;

}

);

过滤:

auto it = std::remove_if(v.begin(), v.end(),

\&(auto &n){ return n < 0; });

相关推荐
郝学胜_神的一滴15 小时前
CMake 034:生成器表达式:解耦构建时序、精简分支逻辑的终极利器
c++·cmake
见过夏天1 天前
C++ 基础入门完全指南
c++
用户805533698033 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
BadBadBad__AK3 天前
线段树维护区间 k 次方和
c++·数学·算法·stl
卷无止境4 天前
Eigen 库如何借助 OpenMP 加速计算
c++·后端
卷无止境4 天前
OpenMPI、MPICH 与 OpenMP:关系、核心概念与架构全解
c++·后端
郝学胜_神的一滴5 天前
CMake 30:循环语法全解|foreach_while双循环精讲、迭代技巧与实战避坑指南
c++·cmake
卷无止境7 天前
C++ 的Eigen 库全解析
c++
卷无止境7 天前
现代 C++特性大盘点:一门脱胎换骨的老语言
c++·后端
郝学胜_神的一滴7 天前
CMake 27:缓存变量的特性、语法、类型与实操全解
c++·cmake