【C++11特性篇】玩转C++11中的包装器(function&bind)

前言

大家好吖,欢迎来到 YY 滴C++系列 ,热烈欢迎! 本章主要内容面向接触过C++的老铁
主要内容含:
在这里插入图片描述

欢迎订阅 YY滴C++专栏!更多干货持续更新!以下是传送门!

目录

  • 一.为什么需要包装器function?
  • 二.function包装器
    • 【1】function基本语法一览
    • 【2】function解决可调用对象的类型问题——>把可调用对象包装器来,存放到数组中去
  • 三.包装器,解决模板的效率低下,同一函数模板实例化多份的问题
  • 四.包装器的一个具体应用oj题:逆波兰表达式(利用map+function来解决)
  • 五.bind(绑定包装器)
    • 【1】基本概念
    • 【2】bind实现参数顺序调整的规则示意图
    • 【3】bind的一个基本应用场景:不同利率计算(引入变量rate)
    • 【4】placeholders::_1, placeholders::_2无视bind函数包装器的常量位置:按顺序1,2,3...
    • 【5】bind绑定成员函数(静态/非静态)

一.为什么需要包装器function?

  • 我们可以观察下面这段代码,我们会发现我们难以判断func( )到底是什么
  • 因为其有可能是 函数名?函数指针?函数对象(仿函数对象)?也有可能是lamber表达式对象
  • 为了方面管理这些【不同的可调用对象的类型问题】 ,我们引入了 function
ret = func(x);
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;// lambda表达式cout << useF([](double d)->double { return d / 4; }, 11.11) << endl;return 0;
}

二.function包装器

【1】function基本语法一览

std::function在头文件<functional>
// 类模板原型如下
template <class T> function;     // undefined
template <class Ret, class... Args>
class function<Ret(Args...)>;
模板参数说明:
Ret: 被调用函数的返回类型
Args…:被调用函数的形参

【2】function解决可调用对象的类型问题——>把可调用对象包装器来,存放到数组中去

  • function包装器 也叫作 适配器
  • C++中的function本质是一个 类模板
  • 在以往的学习中,面对不同的可调用对象,我们希望能把他们放到一个vector中方便调用,但是 类型不同显然做不到
  • 而function包装器就恰好解决了这个问题(可调用对象的类型问题)
  • 如在下面代码中,第一部分ret = func(x);(可能是函数名?函数指针?函数对象(仿函数对象)?也有可能是lamber表达式对象)
  • 我们 通过function语法即可成功把他们放到vector中
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;// lambda表达式cout << useF([](double d)->double { return d / 4; }, 11.11) << endl;// 可调用对象存储到容器中//vector<>// 包装器 -- 可调用对象的类型问题//function<返回值类型(参数类型)>function<double(double)> f1 = f;// 函数名function<double(double)> f2 = [](double d)->double { return d / 4; };// 函数对象function<double(double)> f3 = Functor();// lamber表达式//vector<function<double(double)>> v = { f1, f2, f3 };//写法一//我们 通过function语法即可成功把他们放到vector中 vector<function<double(double)>> v = { f, [](double d)->double { return d / 4; }, Functor() };//写法二double n = 3.3;for (auto f : v){cout << f(n++) << endl;//遍历vector,每个元素是一个包装器}return 0;
}

三.包装器,解决模板的效率低下,同一函数模板实例化多份的问题

  • 我们观察下面代码
  • count 是一个静态局部变量,它确实存储在静态存储区域。
  • 静态局部变量在程序生命周期内只被初始化一次,然后保留其值直到程序结束。因此,从理论上讲,count 应该在整个程序运行过程中保持唯一的值。然而,我们在 main 函数中使用了三个不同的函数对象(函数名、函数对象和 lambda 表达式),每个都调用了 useF 函数, 实例化了三份useF函数 ,因此count值不会增加,还是1;
    在这里插入图片描述
  • 经过包装器包装后,我们再来看这段代码:
  • 我们发现,useF函数 只被实例化成了一份 在这里插入图片描述

四.包装器的一个具体应用oj题:逆波兰表达式(利用map+function来解决)

  • 逆波兰表达式oj链接:传送门
  • 题目一览:
    在这里插入图片描述
  • 分析:我们原本用栈来完成,现在我们可以用map+function来解决
  • 改进后,用function把lambda表达式包装起来了
  • lambda相关博客传送门:【C++11特性篇】lambda表达式玩法全解
    在这里插入图片描述

五.bind(绑定包装器)

【1】基本概念

  • std::bind函数定义在头文件中,是一个 函数模板 ,它就像一个函数包装器(适配器),接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表
  • 一般主要应用于:实现参数顺序调整等操作

【2】bind实现参数顺序调整的规则示意图

  • 如图中所示:
  • 同样的rSub(10,5)通过变换bind 函数包装器 placeholders::_1, placeholders::_2,可以实现10-5&5-10
    在这里插入图片描述

【3】bind的一个基本应用场景:不同利率计算(引入变量rate)

double Plus(int a, int b, double rate)
{return (a + b) * rate;
}int main()
{function<double(int, int)> Plus1 = bind(Plus, placeholders::_1, placeholders::_2, 4.0);function<double(int, int)> Plus2 = bind(Plus, placeholders::_1, placeholders::_2, 4.2);function<double(int, int)> Plus3 = bind(Plus, placeholders::_1, placeholders::_2, 4.4);cout << Plus1(5, 3) << endl;cout << Plus2(5, 3) << endl;cout << Plus3(5, 3) << endl;return 0;
}

【4】placeholders::_1, placeholders::_2无视bind函数包装器的常量位置:按顺序1,2,3…

  • 如下图所示:
  • 即使rate参数放在bind包装器的中间,依然按照placeholders::_1,_2,_3…的顺序走
double Plus(int a, double rate,int b)
{return (a + b) * rate;
}int main()
{function<double(int, int)> Plus1 = bind(Plus, placeholders::_1,  4.0 placeholders::_2);function<double(int, int)> Plus2 = bind(Plus, placeholders::_1, 4.2,placeholders::_2);function<double(int, int)> Plus3 = bind(Plus, placeholders::_1,4.4 ,placeholders::_2);cout << Plus1(5, 3) << endl;cout << Plus2(5, 3) << endl;cout << Plus3(5, 3) << endl;return 0;
}

【5】bind绑定成员函数(静态/非静态)

主要方法分为下面三种:

  1. 对于静态成员函数,直接取类的地址即可&SubType::sub
  2. 对于非静态成员函数,在直接取类的地址的基础上&SubType::sub,法一:先实例化出一个类SubType st;,取其地址&st
  3. 在直接取类的地址的基础上&SubType::sub,法二:直接传入一个匿名对象SubType()
class SubType
{
public:static int sub(int a, int b){return a - b;}int ssub(int a, int b, int rate){return (a - b) * rate;}
};int main()
{
//对于静态成员函数function<double(int, int)> Sub1 = bind(&SubType::sub, placeholders::_1, placeholders::_2);cout << Sub1(1, 2) << endl;
//对于非静态成员函数,法一SubType st;function<double(int, int)> Sub2 = bind(&SubType::ssub, &st, placeholders::_1, placeholders::_2, 3);cout << Sub2(1, 2) << endl;
//对于非静态成员函数,法二function<double(int, int)> Sub3 = bind(&SubType::ssub, SubType(), placeholders::_1, placeholders::_2, 3);cout << Sub3(1, 2) << endl;return 0;
}

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

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

相关文章

【Earth Engine】协同Sentinel-1/2使用随机森林回归实现高分辨率相对财富(贫困)制图

目录 1 简介与摘要2 思路3 效果预览4 代码思路5 完整代码6 后记 1 简介与摘要 最近在做一些课题&#xff0c;需要使用Sentinel-1/2进行机器学习制图。 然后想着总结一下相关数据和方法&#xff0c;就花半小时写了个代码。 然后再花半小时写下这篇博客记录一下。 因为基于多次拍…

通过windows cng api 实现rsa非对称加密

参考&#xff1a; 1,使用 CNG 加密数据 - Win32 apps | Microsoft Learn 2,不记得了 &#xff08;下文通过cng api演示rsa加密&#xff0c;不做原理性介绍&#xff09; 相对于aes等对称加密算法&#xff0c;rsa加密算法不可逆性更强。非对称加密在通常情况下&#xff0c;使…

前端传输formDate格式的数据,后端不能用@RequestBody接收

写了个接口&#xff0c;跟前端对接&#xff0c;前端说怎么一直415的报错 我寻思不对啊&#xff0c;我swagger都请求成功了&#xff0c;后来发现前端一直是以formdata格式提交的数据&#xff0c;这样我其实是可以不加RequestBody的&#xff1b; 知识点&#xff1a; RequestBody…

类和对象

1 类定义&#xff1a; class ChecksumAccumulator {// class definition goes here } 你就能创建 ChecksumAccumulator 对象&#xff1a;new CheckSumAccumulator 注&#xff1a;1scala类中成员默认是public类型&#xff0c;若设为私有属性则必须加private关键字。在scala中是…

基于Springboot的留守儿童爱心网站(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的留守儿童爱心网站(有报告)。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring…

技术交底二维码的应用

二维码技术交底可以逐级落实、责任到人、有据可查、是目前最方便、实用的交底方式&#xff0c;下面我们讲解技术交底二维码的应用。 1、生成对应的技术交底二维码&#xff0c;将施工方案、技术资料、安全教育资料等内容上传到二维码里。打印出来现场粘贴&#xff0c;便于作业班…

java中线程相关的面试题

什么是线程安全&#xff0c;造成线程安全的本质是什么&#xff1f; 什么是线程安全呢&#xff1f; 咱们初步去理解话记住一句话就行&#xff1a;如果一个对象可以安全地被多个线程同时使用&#xff0c;那它就是线程安全的。 为什么并发编程会导致线程不安全&#xff1f; 可见…

用友U8CRM系统help2 任意文件读取漏洞复现

用友U8CRM系统的help2文件中接口存在任意文件读取漏洞&#xff0c;攻击者在未登录情况下即可进行漏洞利用。 1.1 漏洞级别 高危 1.2 快速检索 fofa语法&#xff1a; title"用友U8CRM"1.3 漏洞复现 该漏洞利用非常简单&#xff0c;只需构造get请求 访问该地址即可…

青少年CTF-qsnctf-A1-Misc-签到

题目环境&#xff1a; 题目难度&#xff1a;★题目描述&#xff1a;有没有可能&#xff0c;这个平台就是个题目&#xff1f; 一道杂项题 题目说的是这个平台就是题目 那么也就是说flag就在这个平台里面1.从高层次向低层次逐一排查 2.首先对平台首页进行排查进平台首页 第一种解…

HTML---浮动

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 一.常见的网页布局 二.标准文档流 标准文档流常见标签 标准文档流的组成 块级元素<div…

二叉搜索树 --- C++实现

目录 1.二叉搜索树的概念 2.二叉搜索树的操作 3. 二叉树的实现 4.二叉搜索树的应用 5. 二叉树的性能分析 6. 二叉树进阶练习题 1.二叉搜索树的概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树&#xff1a; 若它的左…

JDBC 知识点总结篇

JDBC 知识点总结篇 JDBC 接口 Java DataBase Connectivity Java数据库连接&#xff0c;由官方定义的一套操作所有关系型数据库的规则&#xff0c;即接口&#xff0c;各个数据库厂商实现该套接口 代码 // 本代码只提供一个样例&#xff0c;请根据自己实际情况修改代码 // 1.…

MyBatis笔记

Mybatis Mybatis介绍 什么是Mybatis? mybatis是支持普通SQL查询、存储过程和高级映射的优秀持久层框架。 Mybatis优点 几乎消除了JDBC代码和参数的手动设置消除结果集的检索使用XML或注解用于配置和原始映射&#xff0c;将接口和POJOs(实体类)映射成数据库中的记录。 My…

vue微乾坤子应用开发及ele组件开发时问题记录

一. 微乾坤 1. 新增page页面路由,pmi权限中心配置正常&#xff0c;跳转链接正确&#xff0c;但路由未找到403. 解决&#xff1a; 新增的配置是page类型&#xff0c;transformQianKunRoute方法转换微前端路由数据 时&#xff0c;过滤未兼容page型的路由&#xff0c; 解决 [menu,…

react中使用redux最简单最方便的方式,配合rematch简化操作,5分钟学会

react中使用状态管理的方式也很多&#xff0c;比如redux和mobx等&#xff0c;今天这一片就讲一下redux的入门到熟练使用&#xff0c;主要是要理解它redux的组成有哪些&#xff0c;到怎么创建&#xff0c;和组建中怎么使用三个问题。这里先放上官网文档&#xff0c;不理解的地方…

十一.约束(二)

约束 5.自增列:AUTO_INCREMENT5.1作用5.2关键字5.3特点和要求5.4如何指定自增约束5.5如何删除自增列5.6MySQL8.0新特性——自增变量的持久化 6.FOREIGN KEY 约束6.1作用6.2关键字6.3主表和从表/父表和子表6.4特点6.5添加外键约束6.6演示问题6.7约束等级6.8删除外键约束6.9开发场…

鸿蒙开发者工具安装及入门程序

下载工具DevEco Studio IDE 官网下载&#xff1a;HUAWEI DevEco Studio和SDK下载和升级 | HarmonyOS开发者 开发工具的安装 解压下载好的压缩包&#xff0c;一路无脑安装即可&#xff0c;安装完的使用方法类似于IDEA、WebStorm的使用&#xff0c;快捷键一致&#xff0c;默认黑…

【笔记】Spring的循环依赖

Spring的循环依赖 ObjectFactory:函数式接口&#xff0c;可以将lambda表达式作为参数放在方法的实参种&#xff0c;在方法执行的时候&#xff0c;并不会实际的调用当前lambda表达式&#xff0c;只有在调用getObject方法的时候才回去调用lambda表达式 为什么spring要用三级缓存…

常用的百兆网络变压器与RJ45网口的参考连接电路有哪些,主要注意事项在哪里呢?

Hqst华轩盛(石门盈盛)电子导读&#xff1a;一起来了解常用的百兆网络变压器与RJ45网口的参考连接电路有哪些&#xff0c;主要注意事项在哪里呢&#xff1f; 第一,常用的百兆网络变压器与RJ45网口的参考连接电路 常用百兆网络变压器与网口连接器分开为独立电子元件的分离式参考电…

TrustZone之与非安全虚拟化交互

到目前为止&#xff0c;我们在示例中忽略了非安全状态中可能存在的虚拟化程序。当存在虚拟化程序时&#xff0c;虚拟机与安全状态之间的许多通信将通过虚拟化程序进行。 例如&#xff0c;在虚拟化环境中&#xff0c;SMC用于访问固件功能和可信服务。固件功能包括诸如电源管理之…