【C++干货铺】C++11新特性——lambda表达式 | 包装器

=========================================================================

个人主页点击直达:小白不是程序媛

C++系列专栏:C++干货铺

代码仓库:Gitee

=========================================================================

目录

C++98中的排序

lambda表达式

lambda表达式语法

表达式中的各部分说明

lambda表达式的使用

基本的使用

[var]值传递捕捉变量var 

​编辑 [&var]引用传递捕捉变量var | [&]引用传递捕获所有变量

[this]值传递捕获当前的this指针 | [=]值传递捕获所有变量

包装器

bind


C++98中的排序

在C++98中,如果我们想要对一个集合中的数据元素进行排序时,可以使用库中的std::sort方法。

int main()
{int arr[10] = { 9,4,2,3,5,6,7,8,1,0 };//默认排序是升序sort(arr, arr + sizeof(arr) / sizeof(arr[0]));// 如果需要降序,需要改变元素的比较规则std::sort(arr, arr + sizeof(arr) / sizeof(arr[0]), greater<int>());return 0;
}

但是排序的元素是自定义类型呢?需要用户自己定义排序时候的比较规则;

但是对于一个自定义类型来说比较的逻辑可能有很多种;每要使用一个逻辑比较,就要实现一个algorithm算法,重新写一个类,这就意味着要实现很多类;特别是有些相容类的命名,这很令人头疼,因此在C++11的语法中出现了lambda表达式。


lambda表达式

lambda表达式语法

书写格式:[ capture-list ]( parameters )mutable -> return-type { statement }

表达式中的各部分说明

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

注意:

在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为
空。因此C++11中最简单的lambda函数为:[]{}; 该lambda函数不能做任何事情。


lambda表达式的使用

在使用lambda表达式之前我们还要对捕获列表进行说明

捕捉列表描述了上下文中那些数据可以被lambda使用,以及使用的方式传值还是传引用。

  • [var]:表示值传递方式捕捉变量var
  • [=]:表示值传递方式捕获所有父作用域中的变量(包括this)
  • [&var]:表示引用传递捕捉变量var
  • [&]:表示引用传递捕捉所有父作用域中的变量(包括this)
  • [this]:表示值传递方式捕捉当前的this指针

注意:

a. 父作用域指包含lambda函数的语句块
b. 语法上捕捉列表可由多个捕捉项组成,并以逗号分割。
          比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量
                     [&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量
c. 捕捉列表不允许变量重复传递,否则就会导致编译错误。
        比如:[=, a]:=已经以值传递方式捕捉了所有变量,捕捉a重复

d. 在块作用域以外的lambda函数捕捉列表必须为空。

e. 在块作用域中的lambda函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者
非局部变量都会导致编译报错。

f. lambda表达式之间不能相互赋值,即使看起来类型相同

基本的使用

int main()
{//最简单的lambda表达式//该表达式没有任何意义[] {};// 省略参数列表和返回值类型,返回值类型由编译器推导为intint a = 3, b = 4;[=] {return a + 3; };// 省略了返回值类型,无返回值类型auto fun1 = [&](int c) {b = a + c; };fun1(10);cout << a << " " << b << endl;//各部分都很完善的lambda表达式。auto f1 = [&](int x, int y)->int {cout << x + y << endl; return 0; };f1(a,b);//cout << typeid(f1).name() << endl;return 0;
}

[var]值传递捕捉变量var 

int main()
{int x = 1, y = -1;//表示值传递方式捕捉变量var//捕捉的值可以使用但是不可以修改,要想修改的话需要加上mutable//修改的也只在lambda表达式作用域内有效cout << &x << endl << &y << endl;cout << x << " " << y << endl;auto f2 = [x, y]() mutable {cout << &x << endl << &y << endl;int tmp = x;x = y;y = tmp;cout << x << " " << y << endl;};f2();cout << x << " " << y << endl;return 0;
}

 [&var]引用传递捕捉变量var | [&]引用传递捕获所有变量

int main()
{//表示引用传递捕捉变量varint x = 1, y = -1;cout << x << " " << y << endl;cout << &x << endl << &y << endl;auto f1 = [&x, &y]() {cout << &x << endl << &y << endl;int tmp = x;x = y;y = tmp;};f1();cout << x << " " << y << endl;//引用传递捕捉所有父作用域中的变量auto f2 = [&](){int tmp = x;x = y;y = tmp;};f2();cout << x << " " << y << endl;return 0;
}

 

[this]值传递捕获当前的this指针 | [=]值传递捕获所有变量

class Test
{
public:void Func(){auto f1 = [this]() {cout << a << endl << b << endl;};f1();auto f2 = [=](){cout << a << endl << b << endl;};f2();}
public:int a = 1;int b = -1;
};
int main()
{Test t;t.Func();return 0;
}

通过上述例子可以看出,lambda表达式实际上可以理解为无名函数,该函数无法直接调
用,如果想要直接调用,可借助auto将其赋值给一个变量。


包装器

std::function 类模板函数是一个通用的可调用对象的包装器,它用简单的、统一的方式处理可调用对象。使用包装器之前需要包含头文件:#include<functional>

#include<functional>
int Print1(int x ,int y)
{cout << "这是一个普通函数调用" << endl;return x + y;
}
class Print2
{
public:double operator()(double x, double y){cout << "这是一个仿函数调用" << endl;return x + y;}
};
class Printf
{
public:static int Print3(char x , char y){cout << "这是类内的一个静态函数调用" << endl;return x - y;}void Print4(){cout << "这个类内的一个普通函数调用" << endl;}
};
int main()
{//普通函数包装function<int(int, int)> p1 = Print1;p1(1, -1);//lambda表达式包装function<int(int, int)> L = [](int x, int y) {return x + y;};L(1, 1);//仿函数包装//匿名对象包装function<double(double, double)> p2 = Print2();p2(1.0, -1.0);//创建对象包装Print2 P;function<double(double, double)> p3 = P;p3(1.0, 1.0);//类内静态函数包装//类内的静态函数是没有this指针的//可以写 & 也可以不写&function<int(char, char)> p4 = Printf::Print3;p4('a', 'a');function<int(char, char)> p44 = &Printf::Print3;p44('b', 'b');//类内非静态函数包装//类内的非静态函数是含有this指针的//因此包装时候函数参数是要有能代表this指针的东西 类指针,类名function<void(Printf*)> p5 = &Printf::Print4;//使用时也必须创建一个新对象使用。Printf Pf;p5(&Pf);function<void(Printf)> p6 = &Printf::Print4;p6(Printf());return 0;
}

bind

std::bind函数定义在头文件中,是一个函数模板,它就像一个函数包装器(适配器),接受一个可
调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。一般而
言,我们用它可以把一个原本接收N个参数的函数fn,通过绑定一些参数,返回一个接收M个(M
可以大于N,但这么做没什么意义)参数的新函数。同时,使用std::bind函数还可以实现参数顺
序调整等操作。

int Sub(int x, int y)
{return x - y;
}
int main()
{cout << Sub(10, 5) << endl;//调整参数顺序function<int(int, int)> S = bind(Sub, placeholders::_2, placeholders::_1);cout << S(10, 5) << endl;//调整参数顺序,有些参数可以bind时写死function<int(int)> S1 = bind(Sub, 10,placeholders::_1);cout << S1(5) << endl;return 0;
}

今天给大家分享介绍了C++中常用特性包括lambda表达式、包装器、bind。如果觉得文章还不错的话,可以三连支持一下,个人主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是我前进的动力! 

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

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

相关文章

【C语言编程之旅 6】刷题篇-for循环

第1题 解析 思路&#xff1a; 两个循环进行控制 外层循环控制打印多少行 内部循环控制每行打印多少个表达式以及表达式内容&#xff0c; 比较简单&#xff0c;具体参考代码 #include <stdio.h> int main() {int i 0;//控制行数for(i1; i<9; i){//打印每一行内容&am…

JUC并发编程知识点总结

JMM Java内存模型规定所有的变量都存储在主内存中&#xff0c;包括实例变量&#xff0c;静态变量&#xff0c;但是不包括局部变量和方法参数。每个线程都有自己的工作内存&#xff0c;线程的工作内存保存了该线程用到的变量和主内存的副本拷贝&#xff0c;线程对变量的操作都在…

手把手教你如何搭建性能测试环境

前言 在进行性能则试前&#xff0c;需要完成性能测试的搭建工作&#xff0c;一般包括硬件环境、软件环境及网络环境&#xff0c;可以要求配置和开发工程师协助完成&#xff0c;但是作为一个优秀性能测试工程师&#xff0c;这也是你的必备技能之一。 性能测试环境与功能测试环…

常用排序算法总结(直接插入排序、选择排序、冒泡排序、堆排序、快速排序、希尔排序、归并排序)

目录 一. 直接插入排序 二:选择排序 三:冒泡排序 四.堆排序 五:希尔排序 六:快速排序(递归与非递归) 七.归并排序(递归与非递归) 一. 直接插入排序 &#x1f31f;排序思路 直接插入排序的基本原理是将一条记录插入到已排好的有序表中&#xff0c;从而得到一个新的、记录…

【白皮书下载】GPU计算在汽车中的应用

驾驶舱域控制器 (CDC) 是汽车 GPU 的传统应用领域。在这里&#xff0c;它可以驱动仪表板上的图形&#xff0c;与车辆保持高度响应和直观的用户界面&#xff0c;甚至为乘客提供游戏体验。随着车辆屏幕数量的增加和分辨率的提高&#xff0c;对汽车 GPU 在 CDC 中进行图形处理的需…

Spark On Hive配置测试及分布式SQL ThriftServer配置

文章目录 Spark On Hive的原理及配置配置步骤在代码中集成Spark On Hive Spark分布式SQL执行原理及配置配置步骤在代码中集成Spark JDBC ThriftServer 总结 Spark On Hive的原理及配置 Spark本身是一个执行引擎&#xff0c;而没有管理metadate的能力&#xff0c;当我们在执行S…

Jenkins环境配置篇-更换插件源

作为持续集成的利器 Jenkins 已经得到了广泛地应用&#xff0c;仅仅作为一个工具&#xff0c;Jenkins 已然有了 自己的生态圈&#xff0c;支持其的 plugin 更是超过 1300。在实际中如何使用以及如何更好地使用 jenkins&#xff0c;一直是大家在实践并讨论的。本系列文章将会从如…

Beego之Beego快速入门

1、beego快速入门 1.1 新建项目 新建一个项目&#xff1a; [rootzsx src]# bee new quickstart 2023/02/19 15:55:50.370 [D] init global config instance failed. If you do not use this, just ignore it. open conf/app.conf: no such file or directory 2023/02/19 1…

接口自动化框架搭建-写在前面

从今天开始&#xff0c;我将带领大家一起学习接口自动化框架的搭建&#xff0c;在学习之前&#xff0c;我们先了解搭建一个接口自动化框架需要具备哪些知识&#xff0c;应该做哪些准备工作 测试开发工程师的入门条件 近几年比较流行测试开发岗位&#xff0c;很多小伙伴都不知…

消息队列介绍

什么是 MQ MQ(message queue)&#xff0c;本质是个队列&#xff0c;FIFO 先入先出&#xff0c;只不过队列中存放的内容是 message 而已&#xff0c;还是一种跨进程的通信机制&#xff0c;用于上下游传递消息。在互联网架构中&#xff0c;MQ 是一种非常常 见的上下游“逻辑解耦…

SpringBoot 项目中后端实现跨域的5种方式!!!

文章目录 SpringBoot 项目中后端实现跨域的5种方式&#xff01;&#xff01;&#xff01;一、为什么会出现跨域问题二、什么是跨域三、非同源限制四、Java后端 实现 CORS 跨域请求的方式1、返回新的 CorsFilter(全局跨域)2、重写 WebMvcConfigurer(全局跨域)3、使用注解 (局部跨…

实战纪实 | 某配送平台zabbix 未授权访问 + 弱口令

本文由掌控安全学院 - 17828147368 投稿 找到一个某src的子站&#xff0c;通过信息收集插件wappalyzer&#xff0c;发现ZABBIX-监控系统&#xff1a; 使用谷歌搜索历史漏洞&#xff1a;zabbix漏洞 通过目录扫描扫描到后台&#xff0c;谷歌搜索一下有没有默认弱口令 成功进去了…

LeetCode:206. 反转链表

力扣链接 算法思想&#xff1a;由于单链表是单向的&#xff0c;想要对当前元素进行操作&#xff0c;需找到前一个元素。本题利用双指针&#xff0c;初始pre指针指向NULL&#xff0c;cur指针指向head.再对局部翻转之前&#xff0c;先把下一个结点存到temp指针中。当进行完如下代…

构建中国人自己的私人GPT

创作不易&#xff0c;请大家多鼓励支持。 在现实生活中&#xff0c;很多人的资料是不愿意公布在互联网上的&#xff0c;但是我们又要使用人工智能的能力帮我们处理文件、做决策、执行命令那怎么办呢&#xff1f;于是我们构建自己或公司的私人GPT变得非常重要。 先看效果 他的…

YOLOv8全网首发:新一代高效可形变卷积DCNv4如何做二次创新?高效结合SPPF

💡💡💡本文独家改进:DCNv4更快收敛、更高速度、更高性能,与YOLOv8 SPPF高效结合 收录 YOLOv8原创自研 https://blog.csdn.net/m0_63774211/category_12511737.html?spm=1001.2014.3001.5482 💡💡💡全网独家首发创新(原创),适合paper !!! 💡💡💡…

视频水平翻转,开启创意之旅

想象一下&#xff0c;一段普通的视频在瞬间被水平翻转&#xff0c;画面中的一切仿佛被镜子所反射&#xff0c;给人一种惊艳而又奇妙的感受。在这个充满无限可能的数字时代&#xff0c;我们不应被传统的视觉效果所束缚&#xff0c;尝试运用水平翻转技术&#xff0c;为你的作品注…

pytest文档内置fixture的request详情

前言 request 是 pytest 的内置 fixture &#xff0c; "为请求对象提供对请求测试上下文的访问权&#xff0c;并且在fixture被间接参数化的情况下具有可选的“param”属性。"这是官方文档对request的描述&#xff0c;可参考的文档不多。 一、FixtureRequest Fixtur…

Spring Bean 生命周期的执行流程?

一、问题解析 Spring 生命周期全过程大致分为五个阶段&#xff1a;创建前准备阶段、创建实例阶段、依赖注入阶段、容器缓存阶段和销毁实例阶段。 这张是 Spring Bean 生命周期完整流程图&#xff0c;其中对每个阶段的具体操作做了详细介绍&#xff1a; &#xff08;把这张图按…

【Linux】Linux进程间通信(四)

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;Linux &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【Linux】…

Lua 快速入门 · 教程笔记

Lua语言快速入门 教程笔记 前言1. Lua 语言介绍2. Lua 语言基础之基本语法声明变量声明方法使用 if - else使用 for使用 while 3. Lua 语言基础之表4. Lua 语言基础之数组插入元素移除元素获取表的长度全局表 5. Lua 语言面向对象之复制表的方式面向对象实现继承和重写父类方法…