C++4(Lambda表达式)

1.基本概念

Lambda函数,亦称为Lambda表达式、匿名函数等,是一种函数对象,Lambda函数可以让函数像普通变量一样进行赋值、传递、函数返回等操作。C++中的Lambda函数经常用来解决如下问题:

使得程序更加简洁,尤其对于一次性使用的函数。
有些库函数要求传递的参数是一个函数,但是你又不想写一个函数出来
使得函数可以自由流动,就像变量一样,这给函数式编程模式奠定了语法基础。

2.语法逻辑

2.1语法规定

在这里插入图片描述
解析:
captruelist: 外部变量列表
params list: 形参列表
mutable: 是否可以修改外部变量。
默认情况下,Lambda函数总是一个const函数,mutable可以取消其常量性。
在使用mutable时,形参列表不可省略
exception: 异常设定
return type: 返回类型
可以不需要声明返回值,此时返回类型相当于使用decltyp根据返回值推断得到
function body: 函数体

2.2 基本语法

在这里插入图片描述
在上述代码中,从左到右逐个解释:
1.Lambda函数是:a,b->int{return a+b;}
2.a和b是从外部可见作用域中捕获的变量,默认它们在Lambda函数内部是只读的。
3.()圆括号内是Lambda函数的形参列表,此处为空,但不可省略。
4.Lambda函数的形参列表一般用于跟容器类结合的时候。
5.->int 是Lambda函数的返回值类型,可以省略。
6.{}内部就是Lambda函数的具体代码实现。
7.最后面的()表示调用(执行)该表达式。

请注意,最右边的圆括号 () 是对Lambda函数调用的符号,不是Lamdba函数本身,我们可以将此Lambda 函数当做一个对象,赋值给另一个具名的函数对象,再去调用它来更清楚地看到Lambda函数的本体:

在这里插入图片描述
C语言中的函数指针调用函数的示例:
在这里插入图片描述
以引用方式捕获外部参数
上述例子捕获的 a 和 b 都是只读的,在Lambda函数内部不可修改,但如果有需要修改这些外部参数,则需要将捕获列表改为引用模式:
在这里插入图片描述
上述代码中:
捕获作用域内所有变量如果作用域内的变量较多,一个个填写到Lambda外部参数列表显然比较麻烦,此时可以用如下代码来一次性全部导入:
在这里插入图片描述

给Lambda函数传参
就像普通函数一样,可以给Lambda函数传参,比如:
需要注意的是,这个例子使用了C++17中的 if constexpr 和 std::forward,以确保在编译时进行参数数量检查和完美转发。
在这里插入图片描述
请注意,上述代码仅仅是为了讲解Lambda函数的形参列表的语法逻辑,而并不是Lambda函数的一般典型用法,因为上述例子已经违背了匿名函数的初衷 —— 将Lambda函数赋值给了一个具名函数对象sum,这么做毫无意义,如果非要定义一个具名函数的话,那么完全可以直接编写一个普通的函数 sum 来达到此功能。

上述代码之所以这么写的原因是,是需要举一个例子来说明Lambda函数的形参的传递过程,而在没有涉及STL容器及其配套算法库函数之前,我们没有用过能被自动调用的函数,因此我们需要一个语句来显式地调用函数,因此就需要一个具名的函数对象sum来承接Lambda函数的功能。

通过以下实际示例简单理解该表达式的实际应用场景:

在这里插入图片描述
在这里插入图片描述
那么,Lambda函数形参列表的典型场景是怎样的呢?这里可以举STL算法库中的最简单的一例加以说明,如果需要对STL容器及其算法库有进一步的了解,请查阅相关课件。

在这里插入图片描述
以下是提取的文字内容:


说明:

  • 上述代码中,Lambda函数是 [l(int m)(return m%2==0),基本含义是:
    • 不捕获任何外部参数
    • 接受一个 int 型参数,注意此时形参将由算法库函数 count_if() 自动传递给 Lambda函数
    • 当形参 m 为偶数时,结果为真

count_if() 是 C++ 算法库函数

  • 其基本功能是将容器指定范围内的元素,逐个地传递给 Lambda函数进行检测
  • 累计所有检测结果为真的元素,并返回这个累计数目
  • 指定的范围由半开半闭区间 [ar.begin(), arr.end()] 规定,其中的 arr.begin()arr.end() 是分别指向容器的迭代器(可看做广义指针),用来界定范围

这样一来就很清楚了,我们利用 Lambda 匿名函数逐个接收 count_if 传递过来的参数(即 int, m,因为容器 arr 中的元素类型都是 int 型整数),并判断其是否为偶数,以期达到计算容器中偶数数目的最终目的。

当然,算法库的函数所能接收的函数符(functor)不一定是 Lambda 匿名函数,Lambda 匿名函数只是函数符的其中一种形式,它们还可以是普通的函数指针,还有更常见的类函数对象,这些知识点将在 STL 容器及算法库相关章节做进一步说明。

2.3 传递 Lambda 函数

Lambda 匿名函数被设计为一种对象,这意味着可以将它们作为函数的参数、返回值,有时,那些使用了 Lambda 函数作为参数、返回值的函数,被称为高阶函数。

Lambda 表达式参数

将 Lambda 表达式作为函数参数,在上述 count_if() 求偶数数目的例子中已有体现:
在这里插入图片描述
此处,Lambda表达式 [](int m){return m%2==0;} 就做为第三个参数传递给了 count_if。
Lambda表达式返回值
对于Lambda表达式,作为函数返回值与其他普通的对象语法上没有太大区别,例如:在这里插入图片描述

浅谈函数式编程

注意,掌握了以上语法细节,并不意味着掌握了Lamba匿名函数,也不意味着掌握了函数式编程思维,Lambda函数最重要的设计目的之一,是给一种编程范式、一种思考角度提供语法方案,这种范式和思维方式就是函数式编程

举例子
给定一个字符串 “abcdefg”,要求将其翻转为 “gfedcba”,这并不是什么难题,有各种不同的解法,来
看下命令式编程思维是怎么思考的?
在这里插入图片描述

首先,如果字符串长度太短,则无需翻转,算法结束
否则,就对调首尾两个字符
最后,将中间的若干个字符翻转

那函数式编程思维会怎么解这道题呢?函数式思维的注意力主要放在数据的映射上,即设计出一个从 旧 数据向 新 数据变化的映射关系(即函数):

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值