跟我学C++中级篇——Lambda表达式的处理

一、Lambda表达式

Lambda表达式对于了解和应用C++11以后的开发者来说,是一个很好用的语法糖。Lambda表达式的特点和应用场景对于开发者来说已经很熟悉了。在前面的分析中,将Lambda表达式简单的定义为函数对象或闭包,这样描述的目的是便于理解和学习。但从实际情况来看,它们还是有些不准确的。

二、Lambda表达式和Closure闭包

对于Lambda表达式来说,在不同的角度下分析可能表现的形式不同。比如从语法的角度来看,无捕获外部变量和有捕获外部变量的Lambda表达式来说,可能就有所不同。无捕获的可以单纯的看作是与普通函数无异的函数,而有捕获的则可以看作一个类。
那为什么前面把Lambda表达式看作一个闭包呢?闭包是函数与其捕获的外部自由变量共同组成的组合体(在前面的分析中也按离散数学中的定义描述过即通过添加最少数量的有序对,使原关系具备自反性、对称性或传递性而形成的新集合)。闭包是一个组合体,为了实现上下文的调用操作(离开lambda表达式后仍然可以操作外部变量,看下面的lifting例子),就必须分配一定的空间来处理上下文关系的内容。这但消耗了内存空间也在调用时增加了一定的开销。
lambda表达式可以认为是从语法层次上的描述,而闭包更倾向于执行时的形态。从这种情况来看,单纯无捕获变量形式的Lambda表达式不能称为闭包。这也是为什么开头提到的说法不准确的原因。也可以这样说,同一个Lambda表达式可能产生多个不同的闭包。
这里就必须提到Lambda Lifting(lambda 提升)和Lambda Dropping(lambda降级)。它们二者可以认为是互逆的,本质都是为了让编译器优化代码。Lambda Lifting,是为了将嵌套的引用了外部的自由变量的lambda表达式转化为不引用外部变量的顶函数,对C++来说,就是将相关的Lambda表达式转化为普通函数对象的技术,它可以显式的由开发者控制进行也可以由编译器内部自动实现 。
Lambda Dropping是Lambda Lifting逆操作,即将原来需要提升为独立函数对象的Lambda表达式内联或部分展开到调用上下文中的方式。

三、编译器对Lambda表达式的处理

其实在前面的std::visit分析中,就对此问题进行过简单的展开分析。在实际的编译中,当编译器发现lambda表达式后,一般来说会进行如下的处理:

  1. 创建一个匿名的函数类(闭包类型)
  2. 将捕获的变量存储为该类的成员(分别处理引用、值或隐式或混合捕获,处理方式看下面的例程)
  3. 将lambda体转换为该类的operator()方法,也就是创建一个仿函数
  4. 将匿名的函数类实例化为函数对象
  5. 调用函数对象

编译器通过上述的处理,其实是把Lambda表达式统一到了传统的编译模型。这也符合语法糖处理的风格。
但是需要说明的是,上述的处理是编译器对lambda表达式的通常处理机制。在某些情况下,如上面提到的Lambda Lifting和Lambda Dropping,其具体的处理机制可能会有一些细节上的不同。具体的来说,就是在Lambda Lifting中,会消除环境上下文及内存分配处理,优化相关操作。比如提到的lambda表达式的对象化或内联等等。

四、例程分析

可以看下面的一个简单的例子:

#include<iostream>intmain(){inta=0;intb=10;autof=[a,&b](){std::cout<<a<<","<<++b<<std::endl;};f();std::cout<<a<<","<<b<<std::endl;return0;}

编译后的代码:

#include<iostream>intmain(){inta=0;intb=10;class __lambda_5_12{public:inline/*constexpr*/voidoperator()()const{std::operator<<(std::cout.operator<<(a),",").operator<<(++b).operator<<(std::endl);}private:inta;int&b;public:__lambda_5_12(int&\_a,int&\_b):a{_a},b{_b}{}};__lambda_5_12 f=__lambda_5_12{a,b};f.operator()();std::operator<<(std::cout.operator<<(a),",").operator<<(b).operator<<(std::endl);return0;}

再看一个lambda Lifting的例子:

auto addResult = [](int v) { return [v](int x) { return x + v; }; }; auto againAdd = addResult(10); std::cout << againAdd(10); // 输出 10

看一下原来的visit中的例程的编译后的代码(编译后的代码有删减,想看全部可将其代码拷贝到cppinsights.io编译即可):

#include<iomanip>#include<iostream>#include<string>#include<type_traits>#include<variant>#include<vector>usingvalue_t=std::variant<int,long,double,std::basic_string<char>>;template<class...Ts>structoverloaded:public Ts...{using Ts::operator()...;};/* First instantiated from: insights.cpp:56 */#ifdefINSIGHTS_USE_TEMPLATEtemplate<>structoverloaded<__lambda_57_13,__lambda_58_13,__lambda_59_13>:public __lambda_57_13,public __lambda_58_13,public __lambda_59_13{using __lambda_57_13::operator();template<class type_parameter_0_0>inline/*constexpr */auto::operator()(type_parameter_0_0 arg)const{(std::cout<<arg)<<' ';}#ifdefINSIGHTS_USE_TEMPLATEtemplate<>inline/*constexpr */void::operator()<int>(intarg)const{std::operator<<(std::cout.operator<<(arg),' ');}#endif#ifdefINSIGHTS_USE_TEMPLATEtemplate<>inline/*constexpr */void::operator()<long>(longarg)const{std::operator<<(std::cout.operator<<(arg),' ');}#endif...template<class...Ts>overloaded(Ts...)->overloaded<Ts...>;/* First instantiated from: insights.cpp:56 */#ifdefINSIGHTS_USE_TEMPLATEtemplate<>overloaded(__lambda_57_13 __0,__lambda_58_13 __1,__lambda_59_13 __2)->overloaded<__lambda_57_13,__lambda_58_13,__lambda_59_13>;#endifintmain(){std::vector<std::variant<int,long,double,std::basic_string<char>>,std::allocator<std::variant<int,long,double,std::basic_string<char>>>>vec=std::vector<std::variant<int,long,double,std::basic_string<char>>,std::allocator<std::variant<int,long,double,std::basic_string<char>>>>{std::initializer_list<std::variant<int,long,double,std::basic_string<char>>>{std::variant<int,long,double,std::basic_string<char>>(10),std::variant<int,long,double,std::basic_string<char>>(15L),std::variant<int,long,double,std::basic_string<char>>(1.5),std::variant<int,long,double,std::basic_string<char>>("hello")},std::allocator<std::variant<int,long,double,std::basic_string<char>>>()};{std::vector<std::variant<int,long,double,std::basic_string<char>>,std::allocator<std::variant<int,long,double,std::basic_string<char>>>>&__range1=vec;__gnu_cxx::__normal_iterator<std::variant<int,long,double,std::basic_string<char>>*,std::vector<std::variant<int,long,double,std::basic_string<char>>,std::allocator<std::variant<int,long,double,std::basic_string<char>>>>>__begin1=__range1.begin();__gnu_cxx::__normal_iterator<std::variant<int,long,double,std::basic_string<char>>*,std::vector<std::variant<int,long,double,std::basic_string<char>>,std::allocator<std::variant<int,long,double,std::basic_string<char>>>>>__end1=__range1.end();for(;__gnu_cxx::operator!=(__begin1,__end1);__begin1.operator++()){std::variant<int,long,double,std::basic_string<char>>&v=__begin1.operator*();class __lambda_25_20{public:template<class type_parameter_0_0>inline/*constexpr */autooperator()(type_parameter_0_0&&arg)const{std::cout<<arg;}#ifdefINSIGHTS_USE_TEMPLATEtemplate<>inline/*constexpr */voidoperator()<int&>(int&arg)const{std::cout.operator<<(arg);}#endif...private:template<class type_parameter_0_0>staticinline/*constexpr */auto__invoke(type_parameter_0_0&&arg){return__lambda_25_20{}.operator()<type_parameter_0_0>(arg);}};std::visit(__lambda_25_20{},v);class __lambda_28_32{public:template<class type_parameter_0_0>inlinestd::variant<int,long,double,std::basic_string<char>>operator()(type_parameter_0_0&&arg)const{returnarg+arg;}/* First instantiated from: invoke.h:61 */#ifdefINSIGHTS_USE_TEMPLATEtemplate<>inlinestd::variant<int,long,double,std::basic_string<char>>operator()<int&>(int&arg)const{returnstd::variant<int,long,double,std::basic_string<char>>(arg+arg);}#endif/* First instantiated from: invoke.h:61 */#ifdefINSIGHTS_USE_TEMPLATEtemplate<>inlinestd::variant<int,long,double,std::basic_string<char>>operator()<long&>(long&arg)const{returnstd::variant<int,long,double,std::basic_string<char>>(arg+arg);}#endif...private:template<class type_parameter_0_0>staticinlinestd::variant<int,long,double,std::basic_string<char>>__invoke(type_parameter_0_0&&arg){return__lambda_28_32{}.operator()<type_parameter_0_0>(arg);}};std::variant<int,long,double,std::basic_string<char>>w=std::visit(__lambda_28_32{},v);std::operator<<(std::cout,". After doubling, variant holds ");class __lambda_32_20{public:template<class type_parameter_0_0>inline/*constexpr */autooperator()(type_parameter_0_0&&arg)const{using T=std::decay_t<decltype(arg)>;ifconstexpr(std::is_same_v<T,int>){(std::operator<<(std::cout,"int with value ")<<arg)<<'\n';}else/* constexpr */{ifconstexpr(std::is_same_v<T,long>){(std::operator<<(std::cout,"long with value ")<<arg)<<'\n';}else/* constexpr */{ifconstexpr(std::is_same_v<T,double>){(std::operator<<(std::cout,"double with value ")<<arg)<<'\n';}else/* constexpr */{ifconstexpr(std::is_same_v<T,std::basic_string<char>>){(std::operator<<(std::cout,"std::string with value ")<<std::quoted(arg))<<'\n';}else/* constexpr */{/* PASSED: static_assert(false, "non-exhaustive visitor!"); */;}}}}}...private:template<class type_parameter_0_0>staticinline/*constexpr */auto__invoke(type_parameter_0_0&&arg){return__lambda_32_20{}.operator()<type_parameter_0_0>(arg);}};std::visit(__lambda_32_20{},w);}}...return0;}

五、总结

掌握一个技术点,不只是需要会用,更要明白其内在的处理机制。只有内外通透,才能更加灵活的运用这个技术点去与其它的技术点融合,然后形成技术栈并最终形成技术体系。正如古人云“九层之台,起于土”。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1214751.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于YOLOv8和RepGhost的轻量化目标检测优化与性能提升

文章目录 一、为什么毕设需要RepGhost? 二、RepGhost核心原理:“训练时变强,推理时变快” 1. 幽灵特征生成 2. 重参数化多分支结构 三、实战:给YOLOv8植入RepGhost“轻量化引擎” 环境准备 1. RepGhost模块实现 2. 改造YOLOv8配置文件 3. 训练与推理 训练命令 推理命令 四、…

基于YOLOv8的多类CAM可视化在目标检测中的应用与分析

文章目录 一、为什么毕设需要CAM可视化? 二、CAM家族:不同可视化方法的特点 三、实战:在YOLOv8中实现CAM可视化 环境准备 1. 核心代码实现 2. 代码解析 四、毕设场景应用:让你的实验分析更出彩 1. 小目标检测的CAM分析 2. 改进模型的CAM对比 3. 论文中的CAM可视化呈现 五、…

基于激活函数替换和ONNX-Simplifier的ONNX模型部署性能提升指南

前言 在深度学习技术飞速发展的今天,模型部署已成为连接算法创新与实际应用的桥梁。然而,将训练好的模型高效地部署到各种硬件平台(如云端服务器、边缘设备、移动端等)上,并确保其能够以低延迟、高吞吐量运行,一直是工程师们面临的重大挑战。ONNX(Open Neural Network …

YOLOv11轻量化设计:引入变核卷积(AKConv)提升检测效率

前言 在移动端和边缘计算场景中,目标检测模型需要在精度与速度之间取得平衡。传统卷积神经网络(CNN)通过固定大小的卷积核(如33、55)提取特征,但这种静态采样方式难以适应目标的多尺度变化,且存在参数冗余问题。例如,在边缘检测等简单任务中,33卷积的9个参数可能只有…

2025气电滑环市场大排行,哪些厂家笑傲江湖?帽式导电滑环/气路滑环/导电环/过孔导电滑环/滑环,气电滑环厂家如何选

随着工业4.0与智能制造的加速推进,气电滑环作为旋转设备中实现气、电信号同步传输的核心部件,市场需求持续攀升。据行业数据显示,2025年中国气电滑环市场规模已突破35亿元,但企业间技术实力、产品稳定性及服务能力…

2025冻肉绞肉机厂口碑爆棚,这些品牌值得信赖,国内热门的绞肉机品牌电话精选国内优质品牌榜单

随着国内餐饮及食品加工行业的快速发展,冻肉绞肉机作为肉类加工的核心设备,市场需求持续攀升。据行业数据显示,2024年国内冻肉绞肉机市场规模同比增长12%,但市场集中度仍较低,中小企业占比超60%,产品同质化与质量…

导师严选2026 AI论文网站TOP10:研究生开题报告必备工具测评

导师严选2026 AI论文网站TOP10&#xff1a;研究生开题报告必备工具测评 学术写作工具测评&#xff1a;2026年研究生开题必备指南 在当前学术研究日益精细化的背景下&#xff0c;研究生群体对论文写作工具的需求也愈加多元化。从文献检索到内容生成&#xff0c;从格式规范到查重…

2026年国内可靠的不锈钢板供应商有哪些,不锈钢热轧板/不锈钢复合板/不锈钢楼梯扶手管,不锈钢板供应商哪个好

行业现状与不锈钢板核心优势 近年来,国内不锈钢板行业凭借技术迭代与产业链整合,逐步形成规模化、专业化竞争格局。不锈钢板因其耐腐蚀、高强度、易加工等特性,广泛应用于建筑装饰、石油化工、食品医疗、机械制造等…

揭晓叔丁醇钾生产企业该怎么选,江苏天泽新材料靠谱之选

本榜单依托全维度市场调研与真实行业口碑,深度筛选出五家叔丁醇钾领域标杆企业,为化工、医药、农药等行业企业选型提供客观依据,助力精准匹配适配的叔丁醇钾供应伙伴。 TOP1 推荐:江苏天泽新材料有限公司 推荐指数…

牛仔裤加工厂哪家技术强,比较靠谱的在这里

2026年服装行业消费升级趋势显著,牛仔服饰作为日常穿搭的核心品类,其加工制造的品质、工艺与定制能力直接决定品牌的市场竞争力。无论是网红直播间的爆款牛仔长裤、实体店引流的个性牛仔短裤,还是电商平台的定制弯刀…

株洲数石网络GEO优化的优势对比,和同行差距在哪?

在AI搜索浪潮席卷企业获客赛道的当下,如何让品牌在DeepSeek、豆包等主流AI平台的推荐结果中占据一席之地,成为不少企业主的核心焦虑。面对市场上鱼龙混杂的GEO营销服务商,选择一家既懂技术又懂本地生意的合作伙伴,…

2026年口碑好的AI搜索优化公司推荐,南方网通是优选

在AI技术重塑商业生态的当下,企业能否在AI搜索场景中占据优势,直接决定了品牌曝光与获客效率。面对市场上鱼龙混杂的AI搜索优化服务商,如何找到真正能解决营销获客、客户转化与办公提效痛点的伙伴?以下结合不同服务…

上海防水服务公司哪家性价比高,选对不花冤枉钱

2026年建筑行业品质升级加速,防水工程作为建筑安全与耐用性的核心屏障,已成为业主、物业及施工单位关注的焦点。无论是住宅屋顶、地下室的常规防水,还是隧道、厂房等特殊场景的疑难渗漏解决,亦或是屋顶防水防漏专用…

说说2026有名的GEO优化公司,加快科技靠谱吗?

2026年AI信源时代全面到来,GEO优化已成为企业抢占AI搜索流量、转化技术优势为市场竞争力的核心抓手。无论是AI信源矩阵搭建、技术白皮书的结构化处理,还是多语言GEO优化布局,优质服务商的专业能力直接决定企业在AI营…

AI学习笔记整理(30)—— 计算机视觉之动作识别相关算法 - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2026年值得信赖的柴油发电机服务商综合推荐

一、行业背景与市场趋势 随着全球能源结构转型与电力供应稳定性要求的不断提高,柴油发电机组作为重要的备用与应急电源,其市场需求持续增长。特别是在数据中心、高端制造业、医疗设施、大型基建项目以及应对极端天气…

springcloud Finchley 版本与 Spring Boot 2.0.x 版本兼容性说明

Finchley 版本与 Spring Boot 的兼容性 Spring Cloud ReleaseSpring Boot Version发布时间状态Finchley.SR22.0.x2018年9月已停止维护Finchley.SR12.0.x2018年8月已停止维护Finchley.RELEASE2.0.x2018年6月已停止维护 官方兼容性声明 根据 Spring Cloud 官方文档&#xff0c;…

2026年沈阳正规的新初一补习学校怎么选,双语外教/新初一补习/新初一补课/新高一补课班/补课,新初一补习老师联系方式

随着新初一升学竞争的加剧,沈阳家长对“衔接教育”的需求持续攀升。据2025年行业白皮书显示,沈阳新初一补习市场规模已突破8亿元,年增长率达15%,但机构质量参差不齐、课程体系同质化、师资流动性高等问题仍困扰着家…

任务导向人工智能应用中认知闭环切片的原理说明

一、问题提出&#xff1a;为何需要“认知闭环切片” 在当下的人工智能工程实践中&#xff0c;AI 模型已被广泛嵌入到各类任务导向系统中&#xff0c;如生产调度、质量诊断、运维决策与流程优化等。然而&#xff0c;大量实践表明&#xff0c;仅将 AI 模型作为独立的分析或预测组…

Spring Cloud Context 和 Spring Cloud Commons 包详解

Spring Cloud Context 和 Spring Cloud Commons 2.0.2 对应的 Spring Cloud 整体版本是 Finchley.SR1。 版本对应关系 Spring Cloud ContextSpring Cloud CommonsSpring Cloud 版本Spring Boot 兼容版本2.0.22.0.2Finchley.SR12.0.x2.1.02.1.0Greenwich.SR12.1.x2.2.02.2.0Ho…