跳到主要内容 C++ Lambda 表达式详解 | 极客日志
C++ 算法
C++ Lambda 表达式详解 C++ Lambda 表达式是 C++11 引入的核心语法糖,本质为匿名函数对象。本文详解其标准语法结构,包括捕获列表(值捕获、引用捕获、混合捕获)、mutable 修饰符、返回值推导及调用方式。重点阐述了 Lambda 在 STL 算法(如 sort、for_each)和回调函数中的高频应用场景,并补充了 C++14 泛型 Lambda 与初始化捕获特性。掌握 Lambda 有助于简化代码封装,提升开发效率且无运行时开销。
imJackJia 发布于 2026/2/7 0 浏览C++ Lambda 表达式详解
Lambda 表达式是 C++11 及以后版本的核心语法糖,本质是「匿名的函数对象(仿函数)」。它没有函数名,但能像函数一样调用,是 C++ 中简化代码、实现就地回调和逻辑封装的最优写法之一。
一、Lambda 基础语法
Lambda 的标准完整语法格式如下,中括号 []、小括号 ()、大括号 {} 是必填核心部分,其余是可选修饰:
[捕获列表](参数列表) mutable noexcept -> 返回值类型 { 函数体 };
各部分含义说明
:核心必写。指定 lambda 函数体可以访问外部作用域的哪些变量,以及以什么方式访问(值/引用)。
捕获列表
参数列表 :核心必写(无参数时可省略小括号)。支持所有普通函数的参数写法(默认参数、模板参数、值传递/引用传递等)。
mutable :可选关键字。解除「值捕获」的只读限制。
noexcept :可选关键字。声明当前 lambda 函数体不会抛出任何异常。
-> 返回值类型 :可选。编译器会自动推导返回值类型,只要 return 语句的类型唯一,通常可省略。
函数体 :核心必写。lambda 要执行的具体逻辑代码。
二、核心重点:捕获列表 捕获列表用来控制外部变量的访问规则,分「基础捕获」和「高级捕获」。
1. 空捕获 [] auto func = []() {
cout << "空捕获,不能访问任何外部变量" << endl;
};
func ();
规则:lambda 内部无法访问任何外部作用域的变量,只能用 lambda 自己的参数或局部变量。
2. 值捕获 [变量名] 或 [=]
单个值捕获 [a, b] int a = 10 , b = 20 ;
auto func = [a, b]() {
cout << "a=" << a << ", b=" << b << endl;
};
func ();
全部值捕获 [=] int a = 10 , b = 20 ;
string s = "hello lambda" ;
auto func = [=]() {
cout << a << " " << b << " " << s << endl;
};
func ();
核心规则 :值捕获的本质是「拷贝」。lambda 内部拿到的是外部变量的副本,无论外部变量后续如何修改,lambda 内部的副本都不会变;默认是只读的。
3. 引用捕获 [&变量名] 或 [&]
单个引用捕获 [&a, &b] int a = 10 , b = 20 ;
auto func = [&a, &b]() {
a++; b++;
cout << "a=" << a << ", b=" << b << endl;
};
func ();
cout << "外部 a=" << a << endl;
全部引用捕获 [&] int a = 10 , b = 20 ;
string s = "hello lambda" ;
auto func = [&]() {
a++; s += "!" ;
cout << a << " " << b << " " << s << endl;
};
func ();
cout << "外部 s=" << s << endl;
核心规则 :引用捕获的本质是「取别名」。对 lambda 内部的变量修改,会直接修改原变量。注意必须保证被引用的外部变量生命周期大于等于 lambda 的生命周期,否则会出现野引用。
4. 混合捕获 场景:需要捕获多个外部变量,一部分只读(值捕获)、一部分需要修改(引用捕获)。
int a = 10 , b = 20 , c = 30 ;
auto func1 = [=, &a]() {
a++;
cout << a << " " << b << " " << c << endl;
};
func1 ();
auto func2 = [& , b]() {
a++; c++;
cout << a << " " << b << " " << c << endl;
};
func2 ();
[=, &变量名]:优先值捕获所有,指定变量单独引用捕获。
[&, 变量名]:优先引用捕获所有,指定变量单独值捕获。
不能重复捕获:比如 [a, &a] 是语法错误。
三、关键字:mutable 修饰符
核心作用 mutable 关键字的唯一作用:解除「值捕获」的「只读限制」,允许在 lambda 内部修改「值捕获的变量副本」。
注意:只对「值捕获」生效,引用捕获本身就可以修改,加不加 mutable 都一样。
完整示例 int a = 10 ;
auto func1 = [a]() {
cout << "func1 a = " << a << endl;
};
auto func2 = [a]() mutable {
a++;
cout << "func2 a = " << a << endl;
};
func1 ();
func2 ();
cout << "外部原变量 a = " << a << endl;
关键结论 :mutable 只是让「值捕获的副本」可写,永远不会修改外部的原变量。
四、返回值的写法
1. 自动推导返回值(推荐) 只要 lambda 的函数体中,所有 return 语句的返回值类型一致,编译器会自动推导,可直接省略 -> 返回值类型。
auto add1 = []() { return 10 + 20 ; };
cout << add1 () << endl;
auto add2 = [](int x, int y) { return x + y; };
cout << add2 (5 , 6 ) << endl;
auto getStr = []() { return string ("hello lambda" ); };
cout << getStr () << endl;
2. 显式指定返回值 只有一种情况必须显式指定:函数体中有多个 return 语句,且返回值类型不同。
auto calc = [](int x, bool flag) -> double {
if (flag) {
return x;
} else {
return 3.14 * x;
}
};
cout << calc (2 , true ) << endl;
cout << calc (2 , false ) << endl;
五、Lambda 的调用方式
1. 定义后立即调用 int a = 10 , b = 20 ;
([&a, &b]() {
a++; b++;
cout << a << "," << b << endl;
})();
2. 赋值给 auto 变量,后续复用 Lambda 的类型是编译器自动生成的匿名类型,必须用 auto 关键字接收。
auto add = [](int x, int y) { return x + y; };
cout << add (1 , 2 ) << endl;
cout << add (10 , 20 ) << endl;
六、Lambda 的核心特点
本质是「匿名函数对象(仿函数)」 :lambda 不是函数,而是编译器自动生成的一个无名的类,重载了 () 运算符。
捕获列表只在「定义时」生效 :值捕获在定义时拷贝,引用捕获在定义时绑定地址。
无状态 lambda 可隐式转为函数指针 :如果捕获列表为空 [],可以直接赋值给对应签名的函数指针。
生命周期独立 :lambda 对象的生命周期和普通变量一致。
极致简洁,无额外开销 :编译后会被优化成普通的函数对象代码,没有任何运行时额外开销。
七、经典使用场景
场景 1:配合 STL 算法 STL 的很多算法都支持传入谓词,用 lambda 替代手写的仿函数。
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main () {
vector<int > vec = {3 , 1 , 4 , 1 , 5 , 9 , 2 , 6 };
sort (vec.begin (), vec.end (), [](int a, int b) { return a > b; });
for (auto x : vec) cout << x << " " ;
cout << endl;
for_each(vec.begin (), vec.end (), [](int & x) { x *= 2 ; });
for (auto x : vec) cout << x << " " ;
cout << endl;
auto it = find_if (vec.begin (), vec.end (), [](int x) { return x > 10 ; });
if (it != vec.end ()) cout << "找到:" << *it << endl;
return 0 ;
}
场景 2:作为回调函数 回调函数需要传递一段逻辑,用 lambda 可以就地封装逻辑。
void setTimer (int ms, auto callback) {
cout << "定时器启动," << ms << "ms 后执行回调..." << endl;
callback ();
}
int main () {
int count = 0 ;
setTimer (1000 , [&count]() {
count++;
cout << "回调执行,count=" << count << endl;
});
return 0 ;
}
场景 3:封装小段逻辑 如果有一段逻辑需要多次执行,但又不值得单独写一个函数,用 lambda 封装。
int main () {
int a = 10 , b = 20 , c = 30 ;
auto print = [&]() {
cout << "a=" << a << ", b=" << b << ", c=" << c << endl;
};
a++;
print ();
b += 5 ;
print ();
c *= 2 ;
print ();
return 0 ;
}
八、补充:C++14 对 Lambda 的增强
1. 支持「泛型 lambda」(参数列表用 auto) lambda 的参数可以用 auto 声明,编译器会自动推导参数类型。
auto add = [](auto x, auto y) { return x + y; };
cout << add (1 , 2 ) << endl;
cout << add (1.5 , 2.5 ) << endl;
cout << add (string ("hello" ), string (" lambda" )) << endl;
2. 支持「初始化捕获」 auto func = [n = 10 ]() {
cout << n << endl;
};
func ();
总结
Lambda 本质 :匿名函数对象(仿函数),C++11 及以上支持,无运行时开销。
核心语法 :[捕获] (参数) mutable noexcept -> 返回值 { 逻辑 };,[]、()、{} 必填。
捕获列表 :[] 空捕获;[a,b] 单个值捕获;[=] 全部值捕获;[&a,&b] 单个引用捕获;[&] 全部引用捕获;[=,&a]/[&,b] 混合捕获。
mutable :解除值捕获的只读限制,只改副本,不改原变量。
返回值 :默认自动推导,多类型 return 时显式指定。
调用方式 :立即调用 [](){}() 或 赋值给 auto 后复用 auto f=[](){};f();。
核心优势 :就地封装逻辑、简化代码、适配 STL 算法,是 C++ 开发必备技能。
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online