【C++11】lambda 表达式

一. 为什么要有 lambda 表达式?

在 C++98 中,如果想要对一个数据集合中的元素进行排序,可以使用 std::sort 方法。如果待排序元素为自定义类型,此时需要用户自定义排序时的比较规则:
在这里插入图片描述

后面人们开始觉得上面的写法太复杂了:

  • 如果每次比较的逻辑不一样,就要去分别实现多个仿函数
  • 仿函数命名不规范的话(比如:Cpmpare1、Compare2 这样的),会给编程者带来了极大的不便。因此,在 C++11 语法中引入了 lambda 表达式。

二. 什么是 lambda 表达式?

1. 概述

下面是 lambda 表达式各个部分的说明:

在这里插入图片描述

  • [capture-list] : 捕捉列表。该列表总是出现在 lambda 表达式的开始位置,它是 lambda 表达式的标识。编译器根据 [ ] 来判断接下来的代码是否为 lambda 表达式,捕捉列表能够捕捉上文作用区中的变量供 lambda 表达式使用。
  • (parameters):参数列表。与普通函数的参数列表一致(可以指定参数是传值还是传引用,或者是否是 const),如果不需要参数传递,则可以连同括号一起省略。
  • mutable:默认情况下,lambda 表达式的捕捉列表中,传值捕捉到的值都是 const 属性的,使用 mutable 可以取消这些传值捕捉对象的 const 量性。注意使用该修饰符时,参数列表不可省略。
  • ->returntype:返回值类型。用追踪返回类型形式声明表达式的返回值类型,没有返回值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型自动进行推导。
  • {statement}:函数体。在该函数体内,除了可以使用参数列表中提供的形参外,还可以使用捕捉列表中,所有捕获到的变量。

注意: 在 lambda 表达式中,参数列表和返回值类型都可以省略不写,而捕捉列表和函数体可以为空,但不能省略不写。因此 C++11 中最简单的 lambda 表达式为:[]{}; 该 lambda 表达式不能做任何事情。

如果我们将 lambda 表达式写全,那便是如下的样子:

在这里插入图片描述

接下来,我们分别来看看,组成 lambda 表达式的这几个部分

参数列表 — ( )

示例:使用普通函数和 lambda 表达式,各自实现一个两数相加的功能:
在这里插入图片描述
可以看到,两者在使用上是没有区别的

有时,我们的 lambda 表达式不需要传入参数,此时连 ( ) 都可以省略掉:
在这里插入图片描述

捕捉列表 — [ ]

lambda 表达式和函数有一个区别是:函数先是在全局域中定义,然后到局部中去使用;而 lambda 表达式,它的定义和使用都在局部中,这个时候 lambda 表达式旁定然会存在着许多局部变量

int main()
{
   
	//函数体里有大量局部变量
	int a = 10;
	char c = 20;
 
	//lambda 表达式就定义在这些局部变量周围
	auto lambda_func = []() {
   };
}

为了方便获得他们,lambda 表达式里便引入了一个新的参数列表——捕捉列表,它专门用来捕捉所属局部域中的其它参数,比如:

int main
### C++11 Lambda表达式使用教程 #### 定义与基本语法 C++11引入了lambda表达式这一强大特性,使得开发者能够更加便捷地定义和创建匿名函数。这种新的功能不仅简化了代码编写过程,还提升了程序的功能性和执行效率[^1]。 Lambda表达式的通用形式如下: ```cpp [capture](parameters)->return_type { body } ``` 其中`capture`表示捕获列表,用于指定如何访问外部作用域中的变量;`parameters`代表参数列表;`->return_type`可选部分用来显式声明返回类型;最后是函数体`body`[^2]。 #### 捕获列表详解 捕获列表允许lambda表达式获取其所在环境内的局部变量或全局变量。常见的几种方式包括但不限于按值传递(`[var]`)、按引用传递(` [&var] `),以及默认全部按值/引用捕获(` [= ] / [&] `)[^3]。 ##### 示例:按值捕获 当采用按值的方式捕获时,意味着会复制一份原始数据供内部逻辑操作而不影响原值。 ```cpp #include <iostream> using namespace std; int main(){ int value = 42; auto func_by_value = [value]() { cout << "Value captured by copy: " << value << endl; }; ++value; // 修改外界的value func_by_value(); // 输出的是未修改前的数值 } ``` ##### 示例:按引用捕获 相反地,如果选择了按引用的形式,则任何对于被捕获变量的操作都会直接影响到实际存在的那个实例。 ```cpp #include <iostream> using namespace std; int main(){ int ref_val = 88; auto modify_ref = [&ref_val]() mutable{ ++ref_val; cout << "Modified reference-captured variable to : " << ref_val << endl; }; modify_ref(); } ``` #### 实际应用场景举例 考虑这样一个场景——我们需要交换两个整型数的位置而无需借助额外的空间开销。此时可以巧妙运用带有适当捕获机制的lambda表达式来完成任务[^5]。 ```cpp void swapTwoNumbers(int &num1, int &num2){ auto swapper = [&](int &a, int &b){ int temp=a;a=b;b=temp; }; swapper(num1,num2); } // 或者更为简洁的做法直接在lambda体内处理 auto direct_swap=[&](int &x,int &y){swap(x,y);} direct_swap(a,b); ``` #### 关于赋值行为的重要注意事项 值得注意的一点在于,尽管可以通过拷贝构造的方式来生成另一个具有相同行为的新对象,但是不同lambda表达式之间不允许互相赋值,即便它们看起来拥有完全一致的结构和语义[^4]。 ```cpp auto hello_world_1=[](){std::cout<<"Hello World"<<std::endl;}; auto hello_world_2=[](){std::cout<<"Hello World"<<std::endl;}; // 下面这行会导致编译错误 //hello_world_1=hello_world_2; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值