【C++11(二)】lambda表达式以及function包装器

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:C++从入门到精通⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学习C++
  🔝🔝


在这里插入图片描述

C++11

  • 1. 前言
  • 2. lambda表达式的提出
  • 3. lambda表达式的语法
  • 4. lambda表达式的捕捉列表
  • 5. function包装器
  • 6. function包装器使用场景
  • 7. decltype关键字用法
  • 8. 可变参数模板讲解
  • 9. 总结

1. 前言

C++11新增了lambda表达式来解决
特定场景下使用仿函数很麻烦的问题
而function包装器则将C语言中复杂的
函数指针问题给简单化了!

本章重点:

本篇文章着重讲解lambda表达式
的语法使用方法和实用场景以及
function包装器的语法使用以及如何
用包装器一次性搞定函数指针,仿函数
和lambda表达式,最后简单讲解关键字
decltype的使用方法和可变模板参数


2. lambda表达式的提出

在C++98中,对自定义类型进行排序时,
需要自己写仿函数,并传递给sort库函数
但是如果每次要按照自定义类型的不同
成员变量进行排序的话,就要写很多个仿
函数,十分的不方便,C++11给出了一个新玩法:

struct Goods
{
string _name;  // 名字
double _price; // 价格
int _evaluate; // 评价
Goods(const char* str, double price, int evaluate):_name(str), _price(price), _evaluate(evaluate)
{}
};
vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠萝", 1.5, 4 } };
sort(v.begin(), v.end(), [](Goods g1, Goods g2)->bool
{return g1._price < g2._price; });//按照价格升序
sort(v.begin(), v.end(), [](Goods g1, Goods g2)->bool
{return g1._price > g2._price; });//按照价格降序
sort(v.begin(), v.end(), [](Goods g1, Goods g2)->bool
{return g1._evaluate < g2._evaluate; });//按照评价升序
sort(v.begin(), v.end(), [](Goods g1, Goods g2)->bool
{return g1._evaluate > g2._evaluate; });//按照评价降序

看不懂没关系,现在你只需要知道这种
写法可以代替完美去写仿函数即可.

它的大概意思请看下图:

在这里插入图片描述


3. lambda表达式的语法

书写格式:

A=捕捉列表, B=参数列表, C=返回值
`[A] (B)-> C {函数体}

lambda表达式各部分说明:

  • 捕捉列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda表达式,捕捉列表能够捕捉上下文中的变量供lambda函数使用

  • 参数列表,与普通函数的参数列表一致,如果不需要传递参数,则可以连同()一起省略

  • 返回值类型,没有返回值时此部分可省略,返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。

  • 函数体,在该函数体内,除了可以使用其参数外,还能使用捕捉列表中的变量

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

事实上,可以把lambda表达式看作一个
class类,被捕捉或定义的变量可以看作
是类中的成员变量,但是lambda表达式
有一个特性是它默认有const属性,相当于
这个类的所有成员变量都是const修饰的
,无法被修改,要想修改它,要在返回值前加
上一个关键字: mutable

利用lambda表达式实现一个swap函数:

int x = 3;
int y = 5;
auto myswap = [](int& x,int&y)mutable->void
{int tmp = x;x = y;y = tmp;
};
myswap(x,y);

实际上lambda表达式的返回值是一个函数对象
在sort中传参正是要一个函数对象,而在这里需要
的是用函数对象来充当一个函数,也就是使用(x,y)


4. lambda表达式的捕捉列表

lambda表达式的捕捉列表[ ]可以
捕捉父作用域的变量供自己使用

下面请看它的捕捉规则:

首先捕捉分为值捕捉和引用捕捉

在这里插入图片描述

int a = 10;
char* b = "xxxxxxxxxxx"
vector<double> v{1.11,2.22};
auto it = [a,&b,c]()->bool{return b+="abcd";};
//以值传递的方式捕捉a和c,引用捕捉b

在这里插入图片描述
在这里插入图片描述

其实可以发现,lambda表达式的使用
方法和仿函数及其相似实际在底层
编译器对于lambda表达式的处理方式
完全就是按照函数对象的方式处理的
即:如果定义了一个lambda表达式,
编译器会自动生成一个类,
在该类中重载了operator()


5. function包装器

C++中的function本质是一个类模板
也是一个包装器,请看下面的代码:

ret = func(x);
// 上面func可能是什么呢?那么func可能是函数名?函数指针?函数对象(仿函数对象)?
//也有可能是lamber表达式对象?所以这些都是可调用的类型!如此丰富的类型
//可能会导致模板的效率低下!
template<class F, class T>
T useF(F f, T x)
{static int count = 0;cout << "count:" << ++count << endl;cout << "count:" << &count << endl;return f(x);
}
double f(double i)
{return i / 2;
}
struct Functor
{double operator()(double d){return d / 3;}
};
int main()
{
// 函数名cout << useF(f, 11.11) << endl;// 函数对象cout << useF(Functor(), 11.11) << endl;// lamber表达式cout << useF([](double d)->double{ return d/4; }, 11.11) << endl;return 0;
}

我们会发现useF函数模板实例化了三份
但是不管func是什么东西,都可以用
function来定义,这也就提高了效率

function包装器的使用方法:

在这里插入图片描述
第一个int代表返回值类型
括号里面用逗号分割的是参数类型


6. function包装器使用场景

function的使用场景非常多,博主
结合了自己学习操作系统的编码
经验来给大家做几个分享:

  1. 创建线程时用function:

在Linux下创建线程时,我们使用
pthread_create函数时要传入此
线程要调用的线程函数对象,这里
配合function使用起来非常方便

pthread_t tid;
pthread_create(&tid,nullptr,[](void* args)->void*
{//函数体
},nullptr);
  1. 线程池内部的处理方法用function

在编写线程池时,每一个线程被创建
出来可能会执行不同的任务,也就是
执行不同的函数,但所有函数的参数
与返回值都一样,这是就可以使用一个
数组保存函数方法,而数组中的元素
类型就是function定义的对象类型!

//func_t是一种函数类型,此类型的函数的返回值和参数都是int
typedef function<int(int,int)> func_t;
//将不同的函数方法插入到数组中,使用时去数组找!
vector<func_t> Task;

这里旨在告诉大家,function的使用场景
很多,即使你现在还没有接触过它,你也
应该掌握它!!!


7. decltype关键字用法

关键字decltype可以将变量的
类型声明为表达式指定的类型

使用场景以及用法:

// decltype的一些使用使用场景
template<class T1, class T2>
void F(T1 t1, T2 t2)
{decltype(t1 * t2) ret;cout << typeid(ret).name() << endl;
}
int main()
{
const int x = 1;
double y = 2.2;
decltype(x * y) ret; // ret的类型是double
decltype(&x) p;      // p的类型是int*
cout << typeid(ret).name() << endl;
cout << typeid(p).name() << endl;
F(1, 'a');
return 0;
}

你可能会觉得decltype关键字很鸡肋
因为有auto可以自动推导类型了,还要
decltype干啥?不错!auto固然好用,但是
有些场景下你想要一个具体的类型时,
比如vector的元素类型时,你不能用auto

decltype([](int x)->int{return 2*x+10;}) it;

8. 可变参数模板讲解

下面是一个基本可变参数的函数模板

// Args是一个模板参数包,args是一个函数形参参数包
// 声明一个参数包Args...args,这个参数包中可以包含0到任意个模板参数。
template <class ...Args>
void ShowList(Args... args)
{}

上面的参数args前面有省略号,所以它就是一个可变模版参数,我们把带省略号的参数称为“参数包”,它里面包含0~N(N>=0)个模版参数。我们无法直接获取参数包args中的每个参数的,只能通过展开参数包的方式来获取参数包中的每个参数,这是使用可变模版参数的一个主要特点,也是最大的难点,即如何展开可变模版参数。由于语法不支持使用args[i]这样方式获取可变参数,所以我们的用一些奇招来一一获取参数包的值

递归函数的方式展开参数包:

// 递归终止函数
template <class T>
void ShowList(const T& t)
{cout << t << endl;
}
// 展开函数
template <class T, class ...Args>
void ShowList(T value, Args... args)
{cout << value <<" ";ShowList(args...);
}
int main()
{ShowList(1);ShowList(1, 'A');ShowList(1, 'A', std::string("sort"));return 0;
}

对于可变模板参数的认知到这儿就差不多了
这属于是了解认知的范畴,下次看见了不会懵逼


9. 总结

本篇文章介绍了两个C++11十分
常用的内容,lambda表达式和包装器
function是需要同学们掌握并且能熟练
编写的,后面的decltype和可变模板参数
属于了解内容,保证你下次看见这个的
时候不会懵逼


🔎 下期预告:智能指针详解🔍

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

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

相关文章

Python之html2text,清晰解读HTML内容!

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;我是彭涛&#xff0c;今天为大家分享 Python之html2text&#xff0c;清晰解读HTML内容&#xff0c;全文3900字&#xff0c;阅读大约10分钟。 HTML是Web开发中常见的标记语言&#xff0c;但有时我们需要将HTML内容…

数据结构算法-归并排序

引言 小明和小森是超市的货架管理人员&#xff0c;他们每天都要确保货架上的商品摆放整齐、有序。一天&#xff0c;他们发现一个货架上的商品有些混乱&#xff0c;需要尽快进行补货。由于该货架上的商品种类繁多&#xff0c;不同种类的商品之间还要考虑价格、销量等因素&#…

Volumetric Lights 2 HDRP

高清晰度渲染管道,包括先进的新功能,如半透明阴影图和直接灯光投射加上许多改进。 插件是一个快速,灵活和伟大的前瞻性光散射解决方案的高清晰度渲染管道。只需点击几下,即可改善场景中的照明视觉效果。 兼容: 点光源 聚光灯 碟形灯 矩形灯 通过覆盖摄像机周围大面积区域的…

算法通关村第二关—K个一组反转(黄金)

K个一组翻转链表 题目介绍 LeetCode25.给你一个链表&#xff0c;每k个节点一组进行翻转&#xff0c;请你返回翻转后的链表。k是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是k的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。进阶&#xff1…

Android Init系统:引领设备启动的先锋

Android Init系统&#xff1a;引领设备启动的先锋 引言 Init系统是一个操作系统启动的必要组件&#xff0c;负责在启动时初始化所有系统资源、服务和应用程序。在Android设备中&#xff0c;Init系统起到了至关重要的作用&#xff0c;它是启动过程中的第一个进程&#xff0c;负…

题目:谈判(蓝桥OJ 545)

题目描述&#xff1a; 解题思路&#xff1a; 本题采用贪心的思想&#xff0c;与蓝桥的合并果子题思路一样。可以使用优先对列&#xff0c;输入进去后自动排序。将两个最小的合并再放入对列中&#xff0c;并将值加入到ans&#xff0c;最终结果即ans。如下图&#xff1a;xy为4&a…

kyuubi整合flink yarn session mode

目录 概述配置flink 配置kyuubi 配置kyuubi-defaults.confkyuubi-env.shhive 验证启动kyuubibeeline 连接使用hive catlogsql测试 结束 概述 flink 版本 1.17.1、kyuubi 1.8.0、hive 3.1.3、paimon 0.5 整合过程中&#xff0c;需要注意对应的版本。 注意以上版本 配置 ky…

JavaScript面向对象编程的奥秘揭秘:掌握核心概念与设计模式

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;JavaScript篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来JavaScript篇专栏内容:JavaScript-面向对象 目录 什么是面向对象&#xff1f; 类与对象的主要区别 创建…

ambari 开启hdfs回收站机制

hdfs回收站类似于我们常用的windows中的回收站&#xff0c;被删除的文件会被暂时存储于此&#xff0c;和回收站相关的参数有两个&#xff1a; fs.trash.interval&#xff1a;默认值为0 代表禁用回收站&#xff0c;其他值为回收站保存文件时间&#xff0c;单位为分钟 fs.trash…

【Vue第2章】Vue组件化编程

目录 2.1 模块与组件、模块化与组件化 2.1.1 模块 2.1.2 组件 2.1.3 模块化 2.1.4 组件化 2.2 非单文件组件 2.3.1 代码 2.3.1.1 基本使用 2.3.1.2 几个注意点 2.3.1.3 组件的嵌套 2.3.1.4 VueComponent 2.3.1.5 一个重要的内置关系 2.3 单文件组件 2.3.1 一个.v…

2024年网络安全行业前景和技术自学

很多人不知道网络安全发展前景好吗&#xff1f;学习网络安全能做什么&#xff1f;今天为大家解答下 先说结论&#xff0c;网络安全的前景必然是超级好的 作为一个有丰富Web安全攻防、渗透领域老工程师&#xff0c;之前也写了不少网络安全技术相关的文章&#xff0c;不少读者朋…

基于Java OpenCV实现图像透视变换,图片自动摆正

如题&#xff0c;效果图如下&#xff1a; 稍后上源码。

【MATLAB源码-第96期】基于simulink的光伏逆变器仿真,光伏,boost,逆变器(IGBT)。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 1. 光伏单元&#xff08;PV Cell&#xff09; 工作原理&#xff1a;光伏单元通过光电效应将太阳光转换为直流电。它们的输出取决于光照强度、单元温度和负载条件。Simulink建模&#xff1a;在Simulink中&#xff0c;光伏单元…

字符函数和字符串函数

✨ 猪巴戒&#xff1a;个人主页✨ 所属专栏&#xff1a;《C语言进阶》 &#x1f388;跟着猪巴戒&#xff0c;一起学习C语言&#x1f388; 前言 C语言中对字符和字符串的处理很是频繁&#xff0c;但是C语言本身是没有字符串类型的&#xff0c;字符串通常放在常量字符串中或者字…

实战演练 | 在 Navicat 中格式化日期和时间

Navicat 支持团队收到来自用户常问的一个问题是&#xff0c;如何将网格和表单视图中的日期和时间进行格式化。其实这个很简单。今天&#xff0c;我们将介绍在 Navicat Premium 中进行全局修改日期和时间格式的步骤。 如果你想边学边用&#xff0c;欢迎点击 这里 下载免费全功能…

C# 图解教程 第5版 —— 第16章 接口

文章目录 16.1 什么是接口16.2 声明接口16.3 实现接口16.4 接口是引用类型16.5 接口和 as 运算符16.6 实现多个接口16.7 实现具有重复成员的接口16.8 多个接口的引用&#xff08;*&#xff09;16.9 派生成员作为实现&#xff08;*&#xff09;16.10 显示接口成员实现16.11 接口…

浅谈基于泛在电力物联网的综合能源管控平台设计及硬件选型

贾丽丽 安科瑞电气股份有限公司 上海嘉定 201801 摘要&#xff1a;城区内一般都具有错综复杂的能源系统&#xff0c;且大部分能耗都集中于城区的各企、事业单位中。基于泛在电力物联网的综合能源管控平台将城区内从能源产生到能源消耗的整体流动情况采用大屏清晰展示&#xff…

小航助学题库白名单竞赛考级蓝桥杯等考scratch(15级)(含题库教师学生账号)

需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09; 需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09;

串口程序(1)-接收多个字节程序设计

数据寄存器 关键的标志位 通过该宏定义可以开启对应的串口中断&#xff0c;之前用该宏定义代替标准库函数USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //使能接收中断 HAL库程序 1.串口发送程序 HAL库串口发送一个/一组数据是很简单的&#xff0c;可以直接调用HAL_UART…

互联网Java工程师面试题·Spring Cloud篇

目录 1、什么是 Spring Cloud&#xff1f; 2、使用 Spring Cloud 有什么优势&#xff1f; 3、服务注册和发现是什么意思&#xff1f;Spring Cloud 如何实现&#xff1f; 4、负载平衡的意义什么&#xff1f; 5、什么是 Hystrix&#xff1f;它如何实现容错&#xff1f; 6、什么是…