C++11 Lambda表达式

本文深入探讨C++11中引入的Lambda表达式,解析其语法结构,包括捕获列表、参数列表及返回类型等,并通过实例展示如何在STL库中使用Lambda表达式简化代码,提高代码可读性和效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Lambda表达式

匿名函数有函数体,但没有函数名。
匿名函数是很多高级语言都支持的概念,如lisp语言在1958年首先采用匿名函数。正因为如此,C++11也同样引入了lambda函数。
在C++11中,你可以在源码中内联一个lambda函数,这就使得创建快速的、一次性的函数变得简单了。

相同类似功能我们也可以使用函数对象或者函数指针实现:函数对象能维护状态,但语法开销大,而函数指针语法开销小,却没法保存范围内的状态。lambda表达式正是结合了两者的优点。

声明Lambda表达式

[capture list] (params list) mutable exception-> return type { function body };
[capture list] (params list) -> return type {function body};  //1
[capture list] (params list) {function body};		//2
[capture list] {function body};		//3
  • capture list:捕获外部变量列表
  • params list:形参列表
  • mutable指示符:用来说用是否可以修改捕获的变量
  • exception:异常设定
  • return type:返回类型
  • function body:函数体

标号1. 函数声明了一个const类型的表达式,此声明不可改变capture list中的捕获的值。
标号2. 函数省略了返回值,此时如果function body内含有return语句,则按return语句返回类型决定返回值类型,若无则返回值为void类型。
标号3. 函数无参数列表,意味无参函数。

简单的例子

在C++中我们对STL库中的sort()运用十分频繁,接下来就是关于他的一个例子:

//省略细节
bool compare(int a,int b){
	return a<b;
}
{
	vector<int> vec{1,0,9,5,3,3,7,8,2};
	sort(vec.begin(),vec.end(),compare);
	//在C++11之前,我们使用STL的sort函数,可以提供一个谓词函数来为sort改变其排序判断标准
}

接下来是lambda表达式的形式:

{	
	vector<int> vec{1,0,9,5,3,3,7,8,2};
	sort(lbvec.begin(), lbvec.end(), [](int a, int b) -> bool { return a < b; });  
	 // Lambda表达式
}

lambda不仅提高了代码可读性,且在例子中,这一个提供判断依据的函数是只需调用一次,在这时,lambda表达式就显示出它的“即用即扔”的特点,很适合这种不需要重复调用且运用区域单一的情景(而不是去多写一个compare的函数)。

捕获外部变量

Lambda表达式可以捕获外面变量,但需要我们提供一个谓词函数([capture list]在声明表达式最前)
类似参数传递方式:值传递、引入传递、指针传递。
在Lambda表达式中,外部变量捕获方式也类似:值捕获、引用捕获、隐式捕获

值捕获

    int a = 123;
    auto f = [a] { cout << a << endl; }; 
    f(); // 输出:123
    a = 321;
    f(); // 输出:123

值捕获和参数传递中的值传递类似,被捕获的值在Lambda表达式创建时通过值拷贝的方式传入,因此Lambda表达式函数体中不能修改该外部变量的值;同样,函数体外对于值的修改也不会改变被捕获的值。

引用捕获

    int a = 123;
    auto f = [&a] { cout << a << endl; }; 
    a = 321;
    f(); // 输出:321

引用捕获的变量使用的实际上就是该引用所绑定的对象,因此引用对象的改变会改变函数体内对该对象的引用的值。

隐式捕获

隐式捕获有两种方式,分别是
[=]:以值补获的方式捕获外部所有变量
[&]:表示以引用捕获的方式捕获外部所有变量

	int a = 123 ,b=321;
    auto df = [=] { cout << a << b << endl; };    // 值捕获
    auto rf = [&] { cout << a << b << endl; };    // 引用捕获

其他捕获方式

C++11Lambda表达式捕获外部变量形式
[ ]不捕获任何变量(无参函数)
[变量1,&变量2, …]值(引用)形式捕获指定的多个外部变量
[this]值捕获this指针
[=, &x]变量x以引用形式捕获,其余变量以传值形式捕获

Lambda表达式的参数

  • 参数列表中不能有默认参数
  • 不支持可变参数
  • 所有参数必须有参数名
### 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、付费专栏及课程。

余额充值