C++学习之lambda表达式

2023-11-08

一、基本概念

  1. C++11 引入了lambda表达式,这个特性的最普遍应用,就是配合泛型算法。泛型算法,采用了迭代器操作,从而使得各种不同的容器能使用一套算法。泛型算法允许我们定制自己的操作,即传递一个可调用对象,lambda其实也是一个可调用对象

  2. 匿名函数:是指一类无需定义函数名称的函数,普遍存在多种编程语言中
  3. lambda表达式存储时必须用function模板或auto

           好处:   1)随时定义使用短小精悍的函数

                        2)可用lambda语法来创造匿名函数并操作,让函数成为“First Class function”

          lambda表达式表示了一个可调用的单元代码,与函数类似,具有一个返回类型,一个参数列表,一个函数体,不同之处在于,还有一个捕获参数列表。

 

          各部分的含义如下:

         ①捕获列表,=表示传值捕获,&表示引用捕获

               1)全局变量、静态变量不用显示写在外部变量列表中,可直接在lambda表达式中读写

               2)传值捕获的外部变量是一个副本,默认情况下在lambda表达式中是只读的,若想修改该副本,需要在lambda表达式上添加mutable关键字  如:auto a2 = [Value](int x) mutable {Value++;};

               3)在类的非静态成员函数中定义的lambda表达式可以通过捕捉this指针,来访问对象的成员变量和成员函数

               4)c++14中增加广义捕获(Generalized capture):即在捕获子句中增加并初始化新的变量,该变量不需要在lambda表达式所处的闭包域中存在;

         ②参数列表

         ③可变动规则,在进行传值捕获时用到

         ④例外指定

         ⑤返回值类型

         ⑥函数体

二、lambda表达式的基本构成

lambda表达式表示了一个可调用的单元代码,与函数类似,具有一个返回类型,一个参数列表,一个函数体,不同之处在于,还有一个捕获参数列表。

[](int a, int b)->bool{return a > b; }

需要注意的是,返回类型必须使用尾置返回。参数列表和返回类型都是可以忽略的,但是捕获列表和函数体必须保留。个人猜想,省略了捕获列表和函数体可能会使得编译器无法判断类型。

lambda既然是个可调用对象,那么它的调用方法也与一般的函数对象一致:

 

class Increase
{
public:
    void operator()(int& val){++val;}
};
int main()
{
    int i = 1, j = 1;
    auto f = [](int& j){ ++j; };//等价于Increase
    f(j);//1
    Increase Inc;
    Inc(i);//2
}//1与2等价

三、捕获

捕获可以说是lambda最难理解的部分。所谓捕获,指的是允许lambda使用它所在函数中的局部变量。对于函数外的变量以及函数内的static变量,无需进行捕获即可直接使用。

捕获有两种方式,一种是值捕获,另外一种是引用捕获。

static i=1;
int j=1;
auto f1 = [&j]()->int{ ++j; return j; };//引用捕获
auto f2 = [j](){return j; };//值捕获
auto f3 = [](){return i; }//静态变量无需捕获

引用捕获,实际上就是引用了一个局部变量。既然是引用,就要注意引用存在的问题。必须确保引用的变量在整个lambda执行的周期内都是存在的,并且为一个正确的值。

值捕获,相当于函数参数值传递的过程。因此,必须保证捕获的量是可拷贝的。此外,针对捕获的值为指针或者引用类型,也存在确保对象依然存在的问题。

因此,应对尽量减少捕获,避免潜在的问题。可能的话,尽量避免捕获指针或者引用。

四、隐式捕获

隐式捕获是一种简略的方法,下面举个例子来说明一下:

int i = 1, j = 1;
auto f = [=, &j](){return i + (++j); };

前面“=”或者“&”说明默认捕获的类型,如果有需要显示捕获的另外一种类型,在后面单独列出即可。

五、修改捕获量的值

auto f2 = [j](){return ++j; };//error,因为这是个右值
auto f4 = [j]()mutable{return ++j; };//正确

值捕获是无法修改变量值的,加一个mutable即可

六、返回类型

前面的例子中我们可以看到,我们没有显示说明返回类型,也得到了正确的结果。不过,默认的规则如下

1、如果仅有return ,那么根据return 的类型确定返回类型。

2、如果除了return 还有别的语句,那么返回void。

所以,不仅有return语句时,尽量要自己显示说明返回类型。

七、lambda表达式的本质

我们知道,定义了调用运算符的对象,可以称为函数对象,即这个对象可以像函数一样被调用,行为类似函数。

与lambda一样,函数对象同样可以作为泛型算法的自定义操作:

class Bigger//1
{
public:
    bool operator()(int a, int b){ return a > b; }
};
bool bigger(int a, int b){ return a > b; }
int main()
{
    vector<int> vec{ 2, 0, 1, 3, 3, 0, 1, 9, 7, 7 };
    sort(vec.begin(), vec.end(), [](int a, int b)->bool{return a > b; });//2
    sort(vec.begin(), vec.end(), bigger);
    sort(vec.begin(), vec.end(), Bigger());
}

 

上面的例子中,分别用了lambda表达式、函数指针、函数对象来进行了排序,结果是相同的。

事实上,lambda表达式就是一个函数对象。当编写了一个lambda表达式的时候,编译器将该表达式翻译成一个未命名类的未命名对象。

lambda表达式产生的类中会有一个重载的函数调用运算符。如果没有捕获任何变量,如上面我们定义的lambda(1)和函数对象(2),其实是完全相同的。

如果lambda采用引用捕获的方式,那么该变量其实不是lambda对象的成员,所以无需进行额外操作。

如果采用值捕获,那么就相当于在对象内部创建了自己的成员,因此需要增加一部分内容:

class F
{
public:
    F(int n) :num(n){}
    int operator()(){ return num; }
private:
    int num;
};
int num = 100;
auto f = [num](){return num; };//等价于F

 

即增加了一个用捕获的值进行构造的构造函数。

lambda表达式产生的类,不含有默认构造函数、赋值运算符和默认析构函数,其他成员由需要捕获的类型确定。


 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++学习之lambda表达式 的相关文章

随机推荐

  • Handler 细节分析

    Handler 常见问题分析 1 Handler 机制中涉及到那些类 各自的功能是什么 2 有哪些发送消息的方法 3 MessageQueue 中的 Message 是有序的吗 排序的依据是什么 4 Message when 是指的是什么
  • 使用KVM虚拟机安装Linux

    KVM虚拟系统管理器 基于内核的虚拟机 Kernel based Virtual Machine 简称KVM 是一种内建于 Linux 中的开源虚拟化技术 具体而言 KVM 可帮助你将 Linux 转变为虚拟机监控程序 使主机计算机能够运行
  • vue做色带

    项目中需要用到色带去设置定量的栅格图层在geoserver显示的样式 记录一下 将下拉框选项设置为图片 渐变颜色 每个选项对应两个颜色 将两个颜色传递到后端即可 样式如下图所示 下拉框结构
  • 【Linux

    目录 一 概述 二 test 命令 2 1 test 命令 2 2 方括号测试条件 2 3 test 命令和测试条件可以判断的 3 类条件 2 3 1 数值比较 2 3 2 字符串比较 三 复合条件测试 四 if then 的高级特性 五
  • 谷歌浏览器单独下载插件文件crx到本地的方法步骤

    描述 谷歌浏览器单独下载插件文件crx到本地的方法步骤 步骤 打开网站 搜索插件名称 https www crx4chrome com 进入详情页 点击Download crx file from Crx4Chrome crx文件已经下载到
  • stm32 mbed入门教程(一)mbed IDE与第一个程序

    mbed os是一个简化编写的架构 与其类似的还有Arduino生态环境 是一种大幅度的减少编程要求 快速达到用户需求的一套开发架构 而mbed ide 及其一整套在线编程 拷贝式下载方法 则是这一套架构的开发平台及其执行方法 这一篇将介绍
  • 如何通过cmd找文件

    在学习的过程中 老师要找丢在各个角落的文件 这次主要找得是C盘里面的my ini文件 如果不知道在哪个盘 就每个盘改一下C变成D dir C my ini s b cmd里面的运行结果 找不到的结果
  • 搜索回溯算法—全排列 II(leetcode 47)

    题目描述 给定一个可包含重复数字的序列 nums 按任意顺序 返回所有不重复的全排列 示例 1 输入 nums 1 1 2 输出 1 1 2 1 2 1 2 1 1 示例 2 输入 nums 1 2 3 输出 1 2 3 1 3 2 2 1
  • background

    设计网页的背景图片 在一个div元素中设置多个背景图像 并指定他们的位置 body background 00ff00 url smiley gif no repeat fixed center 00ff00 指定背景的颜色 url smi
  • CAM(Class Activation Mapping)通俗篇

    在Learning Deep Features for Discriminative Localization这篇文章中 作者提出了CNN网络除了具有很强的图片处理 分类能力 同时还能够针对图片中的关键部分进行定位 这个过程被称为Class
  • 无公网IP,公网SSH可远程访问家中的树莓派

    文章目录 前言 如何通过 SSH 连接到树莓派 步骤1 在 Raspberry Pi 上启用 SSH 步骤2 查找树莓派的 IP 地址 步骤3 SSH 到你的树莓派 步骤 4 在任何地点访问家中的树莓派 4 1 安装 Cpolar内网穿透
  • cuda第一次计算耗时_MNN 1.1.0发布:几何计算/TensorRT,CUDA后端/ASR模型支持/ARM CPU和GPU性能再提升/MNN工作台...

    一 框架通用性 1 1 几何计算 几何计算是本次发布中大规模的框架重构 它将大部分算子的计算过程中与硬件后端无关部分 形状计算和几何计算 剥离出来 极大地降低了异构后端算子实现的成本 基于几何计算 MNN重写了目前所有的硬件后端 由于引入几
  • PCB板的过孔工艺--塞孔

    PCB板厂常用的塞孔方法有 1 油墨塞孔 用挡墨网来完成客户要求的过孔塞孔 2 铝片塞孔 钻出须塞孔的铝片 制成网版来进行塞孔 3 树脂塞孔 利用树脂将孔塞住 树脂塞孔的好处 1 多层板BGA上的过孔塞孔 采用树脂塞孔能缩小孔与孔间距 解决
  • vscode编写前端提升效率的三个必不可缺的插件以及使用方法

    直接官网下载这个软件就行 没什么操作的 这里面有新建文件夹 你可以自己去建一个文件夹 然后点击那个小 号 就可以新建一个文件 比如说demo01 html 后面的html是你需要自己手动输入的 第一个插件 就是这个她可以让你改动开始标签的时
  • docker学习第三章之commit提交镜像

    文章目录 前言 一 commit命令 二 案例使用步骤 1 拉一个Tomcat镜像 2 交互模式启动刚拉取的镜像同时暴露8086端口 3 重新打开一个窗口进入容器内 4 创建一个test txt文件 5 用commit命令提交镜像 6 查看
  • 区块链的数据结构和数据存储

    区块链的数据结构和数据存储 一 区块链是什么 1 1 公链 1 2 联盟链 1 3 私链 二 公链BTC和联盟链长什么样 2 1 共性 2 2 特性 三 区块链为什么安全 防篡改 四 区块链可以做什么 4 1 货币发行 比特币 4 2 证明
  • 基于微信小程序的办公用品销售系统设计和实现(源码+lw+部署文档+讲解等)

    前言 博主介绍 全网粉丝10W CSDN特邀作者 博客专家 CSDN新星计划导师 全栈领域优质创作者 博客之星 掘金 华为云 阿里云 InfoQ等平台优质作者 专注于Java 小程序技术领域和毕业项目实战 精彩专栏 推荐订阅 2023 20
  • Matlab笔记

    这里写自定义目录标题 Matlab笔记 统计矩阵中非0元素的个数 Matlab笔记 统计矩阵中非0元素的个数 sum sum A 0
  • WebBrowser控件使用详解

    WebBrowser控件使用详解 方法 说明 GoBack 相当于 IE的 后退 按钮 使你在当前历史列表中后退一项 GoForward 相当于IE的 前进 按钮 使你在当前历史列表中前进一项 GoHome 相当于IE的 主页 按钮 连接用
  • C++学习之lambda表达式

    一 基本概念 C 11 引入了lambda表达式 这个特性的最普遍应用 就是配合泛型算法 泛型算法 采用了迭代器操作 从而使得各种不同的容器能使用一套算法 泛型算法允许我们定制自己的操作 即传递一个可调用对象 lambda其实也是一个可调用