[C++] Lambda表达式
参考自:https://www.cnblogs.com/jimodetiantang/p/9016826.html
1.概述
Lambda是c++11中引入的特性,为创建函数提供一种新的方式,用于定义和创建匿名的函数,以简化编程工作。
关于Lambda需要知道:
-
Lambda 函数可以引用在它之外声明的变量. 这些变量的集合叫做一个闭包. 闭包被定义在 Lambda 表达式声明中的方括号 [] 内。编译器为每个Lambda函数生成唯一闭包。
-
Lambda函数不会降低性能,它的性能和普通的函数一样
2.Lambda语法
Lambda完整语法如下所示:
[ capture ] ( params ) mutable exception attribute -> ret { body }
2-1 capture字句
capture字句是在[]内的内容,是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义 Lambda 为止时 Lambda 所在作用范围内可见的局部变量(包括 Lambda 所在类的 this)。有以下形式:
- 空。没有任何函数对象参数。
- =。函数体内可以使用 Lambda 所在范围内所有可见的局部变量(包括 Lambda 所在类的 this),并且是值传递方式(相
当于编译器自动为我们按值传递了所有局部变量)。 - &。函数体内可以使用 Lambda 所在范围内所有可见的局部变量(包括 Lambda 所在类的 this),并且是引用传递方式
(相当于是编译器自动为我们按引用传递了所有局部变量)。 - this。函数体内可以使用 Lambda 所在类中的成员变量。
- a。将 a 按值进行传递。按值进行传递时,函数体内不能修改传递进来的 a 的拷贝,因为默认情况下函数是 const 的,要
修改传递进来的拷贝,可以添加 mutable 修饰符。 - &a。将 a 按引用进行传递。
- a,&b。将 a 按值传递,b 按引用进行传递。
- =,&a,&b。除 a 和 b 按引用进行传递外,其他参数都按值进行传递。
- &,a,b。除 a 和 b 按值进行传递外,其他参数都按引用进行传递。
定义在闭包中的lambda用[]捕获来自调用它的外部的变量, 例如,如果 lambda 体通过引用访问外部变量 total
并通过值访问外部变量 factor
,则以下 capture 子句等效:
[&total, factor] [factor, &total] [&, factor] [factor, &] [=, &total] [&total, =]
在 C++14 中,可在 Capture 子句中引入并初始化新的变量,而无需使这些变量存在于 lambda 函数的封闭范围内。 初始化可以任何任意表达式表示;且将从该表达式生成的类型推导新变量的类型。 此功能的一个好处是,在 C++14 中,可从周边范围捕获只移动的变量(例如 std::unique_ptr)并在 lambda 中使用它们。例:
1 pNums = make_unique<vector<int>>(nums); 2 //... 3 auto a = [ptr = move(pNums)]() 4 { 5 // use ptr 6 };
这里注意,当以[=]方式进行捕捉时,传递到Lambda中的值视为常量,只会初始化一次,下例可以演示该情况。
1 int main() 2 { 3 int i = 10; 4 auto f = [=]() { 5 std::cout<< i << std::endl; 6 }; 7 f(); 8 i++; 9 f(); 10 }
即使i在第2次使用时已进行过一次自加,输出仍然为10。
2-2 参数列表
标识重载的 () 操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如: (a, b))和按引用 (如: (&a, &b)) 两种方式进行传递。
在C++ 14,如果参数类型是泛型,则可以使用 auto 关键字作为类型说明符。 这将告知编译器将函数调用运算符创建为模板。 参数列表中的每个 auto 实例等效于一个不同的类型参数。
2-3 mutable声明
这部分可以省略。
按值传递函数对象参数时,加上 mutable 修饰符后,可以修改传递进来的拷贝(注意是能修改拷贝,而不是值本身)。
2-4 exception声明
这部分可以省略。
exception 声明用于指定函数抛出的异常,如抛出整数类型的异常,可以使用 throw(int)。
可以使用 noexcept
异常规范来指示 lambda 表达式不会引发任何异常。
2-5 返回类型
标识函数返回值的类型,当返回值为 void,或者函数体中只有一处 return 的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。
2-6 函数体
标识函数的实现,这部分不能省略,但函数体可以为空。
普通函数和 lambda 表达式的主体均可访问以下变量类型:
-
从封闭范围捕获变量,如前所述。
-
参数
-
本地声明变量
-
类数据成员(在类中声明时)并被捕获
-
具有静态存储持续时间的任何变量(例如,全局变量)
3.Lambda和std::function
可以利用lambda对std::function进行赋值,赋值时编译器会检查两者的参数类型和返回类型,类型不一致时编译器会优先尝试类型的转换,不能转换的情况会编译错误。
示例如下:
1 #include <iostream> 2 #include <string> 3 #include <functional> 4 using namespace std; 5 6 7 double global_f(int n) { 8 cout << "global_f()" << endl; 9 return static_cast<double>(n++); 10 } 11 12 int main() { 13 std::function<double(int)> f; 14 cout << "sizeof(f) == " << sizeof(f) << endl; 15 16 int n = 10; 17 f = global_f; 18 cout << f(n) << endl; 19 20 f = [](double n)->double { 21 cout << "Lambda" << endl; 22 return static_cast<double>(n++); 23 }; 24 cout << f(n) << endl; 25 26 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具