C++11 -- 包装器

文章目录

  • function包装器
    • function包装器的概念
    • function的运用
    • function实例化
    • 使用function解决逆波兰表达式
  • bind包装器
    • bind包装器相关介绍
    • bind绑定函数固定参数

function包装器

function包装器的概念

function包装器,也叫做适配器,它的本质是一个类模板.
例如:

1 template< class R, class... Args >
2 class function< R (Args...)>

说明
( 1 ) :R是被调用函数的返回类型 Args…是被调用的函数的形参,本质上是一个参数包.

( 2 ): function是类模板,只有成员函数,没有数据成员。

function的运用

function包装器可以对普通函数,函数对象,lambda表达式,类中的成员函数进行包装,以下针对各类函数进行包装调用以及相关注意事项如下:

double f(double a, double b)
{return a + b;
}
struct Functor
{
public:int operator()(int a, int b){return a + b;}
};
class Plus
{
public:static int Plusi(int a, int b)         //静态成员函数{return a + b;}double Plusd(double a, double b)      //成员函数{return a + b;}
};
int main()
{//包装函数指针function<double(double, double)> funcf = f;  //传递函数名cout << funcf(1.1, 2.2) << endl;//包装仿函数function<int(int, int)> funcFunctor = Functor();//传递仿函数对象cout << funcFunctor(11, 22) << endl;//包装lambda表达式function<int(int, int)> funcLmd = [](int a, int b) {return a + b;}; //传递匿名对象cout << funcLmd(11, 22) << endl;//静态成员函数function<int(int, int)> funcPlusi = Plus::Plusi;  //标明类域,传递函数名.cout << funcPlusi(11, 22) << endl;//非静态成员函数function<double(Plus, double, double)> funcPlusd = &Plus::Plusd; //增加&,标明类域,传递函数名.cout << funcPlusd(Plus(),3.3,4.4)<< endl;        //因为类的成员函数需要对象的调用,所以必须传递额外传递一个对象.                        return 0;
}

function实例化

包装器可以解决模板实例化多份而造成的效率低下的问题.
例如:

  • 在useF模板中,有两个参数,第一个参数可以接收各种函数类型,第二个参数可以接收各种信息.
  • useF函数模板中的定义了一个静态变量,如果实例化出多分useF函数模板,静态变量count也将不是同一个变量.

代码如下:

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;
}

运行结果如下:

  • 由此可见,在这里由于我们对useF函数模板的第一个参数T传递了三种不同类型的函数,进而导致useF函数模板在编译阶段实例化出了三份,因为静态变量为三个不同的变量.
  • 在使用三种不同函数作为实参传递并调用useF函数模板,实际上是分别调用了一次不同的useF函数,进而导致useF函数中的静态变量不是同一个,所以count只增加了一次.
  • 但是由于我们所传的三种函数类型的返回值数据类型和形参数据类型是一样的,在执行useF函数中,其他数据类型也相同,所以根本就没必要实例化三份useF函数.
    在这里插入图片描述
    所以,包装器可以解决因为该情况而导致模板实例化多份造成效率低下的问题.
int main()
{//函数名function<double(double)> func1 = func;cout << useF(func1, 11.11) << endl;//函数对象function<double(double)> func2 = Functor();cout << useF(func2, 11.11) << endl;//lambda表达式function<double(double)> func3 = [](double d)->double {return d / 4; };cout << useF(func3, 11.11) << endl;return 0;
}

运行效果如下:

  • 由于useF类模板中的静态变量相同,由此可以判断经过function包装过后,useF函数模板只实例化出了一份,这极大地提高了函数模板的效率.
  • 当我们传递三种不同的函数类型并进行调用时,实际上就是调用了三次同一个useF函数,对静态变量count累加了三次.
    在这里插入图片描述

使用function解决逆波兰表达式

bind包装器

bind的本质是一个函数模板,它就像一个函数包装器(适配器),可以接收一个可调用对象的,从而生成一个新的可调用对象来"适应"原对象的参数列表.

bind包装器相关介绍

bind原型如下:

// 原型如下:
template <class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);
// with return type (2) 
template <class Ret, class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);

注意:
( 1 ): fn 指的是需要包装的对象.

( 2 ): args…对应的是给定fn函数中的参数.

调用bind的一般形式如下:

auto newCallable = bind(callable,arg_list);

( 1 ) callable: 需要包装的对象…

( 2 ) newCallable: 生成的一个新的可调用对象.

( 3 ) arg_list: arg_list是一个逗号分隔的参数列表,对应给定的callable的参数.当我们调用newCallable时,newCallable会调用callable,并将arg_list参数列表传给callable中.

注意:
arg_list中的参数可能包含形如_n的名字,其中n是一个整数,这些参数是“占位符”,表示newCallable的参数,它们占据了传递给newCallable的参数的“位置”。例如: _1为newCallable的第一个参数,_2为第二个参数,以此类推.

bind绑定函数固定参数

为什么要使用bind绑定固定参数呢?

因为使用bind绑定固定参数后,可以通过bind包装后生成新的形参较少的对象来调用原来的对象.

例如:
在以下例子中,对于成员函数来说,要通过bind包装新生成的对象调用,因为成员函数需要对象才能调用,所以我们要比全局成员函数要额外多传递一个参数,但是当我们使用包装器bind同时包装全局成员函数和普通成员函数时,那么包装器此时根本无法判断接收参数的具体个数.
在这里插入图片描述
代码如下:

int Plus(int a, int b)
{return a / b;
}}
class Sub
{
public:int sub(int a, int b){return a - b;}
};
int main()
{function< int(int, int)> funcPlus = Plus;function< int(int, int)>funcSub = bind(&Sub::sub, Sub(), _1, _2);map<string, function<int(int, int)>> funcMap ={{"+",Plus},{"-",bind(&Sub::sub,Sub(),_1,_2) }};cout << funcSub(2, 1) << endl;cout << funcMap["-"](2, 1) << endl;
}
  • 将成员函中要接收三个参数经过bind适配器绑定后,在定义时只需要在&Sub::sub后面直接传递的一个sub()匿名对象进行该参数绑定,然后在以后的调用时,只需要传递对应的函数所需要的形参就可以了.
  • 这样也完美的解决了bind同时包装类的成员函数和全局函数接收参数不匹配的问题.
    在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt赋能python:Python中撤销的快捷键

Python中撤销的快捷键 在编程中&#xff0c;我们经常需要进行调试&#xff0c;不可避免地会出现一些错误&#xff0c;这时候撤销 (Undo) 功能就显得尤为重要。在 Python 中&#xff0c;我们可以使用一些快捷键来快速撤销&#xff0c;本文将会介绍这些快捷键的使用以及使用它们…

chatgpt赋能python:Python中的构造函数

Python 中的构造函数 Python 是一门广泛应用于各种应用领域的高级编程语言&#xff0c;它支持不同的编程范式&#xff0c;包括面向对象编程。在面向对象编程中&#xff0c;构造函数是一个重要的概念。本文将介绍 Python 中的构造函数&#xff0c;并介绍如何使用它们来创建对象…

淘宝店铺老店标识怎么显示 怎么淘宝老店标识申请

我们在很多时候都喜欢去一个淘宝开的时间比较长的店铺去购买商品&#xff0c;因为这样的店铺可能在信誉度这一块会更加能够让人信服&#xff0c;因为一个店铺能开这么久&#xff0c;肯定还是证明这个店铺拥有一定的实力。淘宝店铺老店标识怎么显示 怎么淘宝老店标识申请 在回答…

22-0001 淘宝店铺搜索界面

淘宝店铺搜索界面 1.元素2.过程2.1 搜索界面的网页源码2.2 通过Chrome控制台获取sellerid2.3 搜索链接2.4 控制台 3.总结 1.元素 获取店铺搜索界面每个店铺的’sellerid’ 备注&#xff1a;通过sellerid可以在下面链接中获取买家秀的图片&#xff0c;也可以使用相关软件进行下…

淘宝开店指南——店铺设置篇

目录 店铺基本设置店铺装修手机店铺装修PC 店铺装修 保证金管理客服&#xff08;子账号&#xff09;管理创建子账号修改子账号权限 店铺基本设置 通过千牛主账号工作台左侧点击【店铺】->选择【店铺信息进入】。 设置链接&#xff1a;点击访问 可设置内容&#xff1a; 个…

淘宝/天猫API:seller_info-获得淘宝店铺详情

万邦淘宝/天猫获得淘宝店铺详情 API 返回值说明 seller_info-获得淘宝店铺详情 onebound.taobao.seller_info 公共参数 请求地址: https://console.open.onebound.cn/console/?ipony 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;…

SpringCloud Alibaba Seata 工作机制

SpringCloud Alibaba Seata Seata 工作机制 说明 之所以放在后面说工作机制是因为如果一开始就说的话理解困难 所以我们有了前面的列子和说明我们在结合本节内容会收获的多理解相对容易点 分布式事务过程分析 Seata 分布式事务处理过程-ID三组件模型 debug 梳理: 术语 先…

ShardingSphere笔记(三):自定义分片算法 — 按月分表·真·自动建表

ShardingSphere笔记&#xff08;二&#xff09;&#xff1a;自定义分片算法 — 按月分表真自动建表 文章目录 ShardingSphere笔记&#xff08;二&#xff09;&#xff1a;自定义分片算法 — 按月分表真自动建表一、 前言二、 Springboot 的动态数据库三、 实现我们自己的动态数…

如何创建springboot项目

SpringBoot 优点 可快速构建spring应用直接嵌入tomcat、jetty、undenrtow服务器&#xff08;无须部署war文件&#xff09;提供依赖启动器&#xff08;starter&#xff09;简化构建配置极大程度的自动化配置Spring和第三方库提供生产就绪功能&#xff0c;例如指标监控检测、外部…

函数(C语言程序设计)

目录 一、函数定义 二、函数调用 三、递归函数 四、局部变量和全局变量 一、函数定义 1、无参函数的定义 类型名 函数名&#xff08;&#xff09; /*函数首部*/ { 函数体 } 或 类型名 函数名&#xff08;void&#xff09; /*函数首部*/ { 函数体 } void类型的函数不…

因为修改系统设置导致edge浏览器打不开的最快解决办法

设置&#xff0d;应用&#xff0d;应用与功能&#xff0c;然后找到Microsoft edge点击修改进行修复&#x1f917;

Microsoft Edge打不开了怎么办

相信许多小伙伴都遇到过win10自带浏览器microsoft edge打不开的问题吧&#xff0c;接下来我就教大家怎么做 1.首先&#xff0c;右键单击开始菜单 2.之后单击设置&#xff0c;进入设置。 3.之后分别找到应用-Microsoft Edge&#xff0c;之后单击修改&#xff0c;之后等待修复就…

edge浏览器打不开,有网络能正常上网,但是edge浏览器无法浏览

在edge浏览器设置中&#xff0c;隐私功能往下找到服务提供商 我的是选择的第二个&#xff0c;自己提供服务供应商&#xff0c;后面打不开了 如果是自己填的服务提供商&#xff0c;直接点击第一个&#xff0c;或者直接点击关闭。 速度嘎嘎快

Edge浏览器打不开任何网页!!!

错误代码: STATUS_INVALID_IMAGE_HASH 1、电脑搜索注册表 win键&#xff0c;然后输入“注册表” 2、增加项 找到路径&#xff1a;“计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge” 没有Edge的&#xff0c;直接在Microsoft下新建一个Edge文件夹 在Edge下&#…

windows11,打不开IE浏览器,自动跳转到edge浏览器

目前的 暂时解决办法是&#xff0c; 1. 打开 Edge浏览器&#xff0c;--设置 2. 点击左上角 设置--默认浏览器 3. Internet Explorer模式页面--添加 ‘自己需要IE浏览器打开的网址’&#xff0c;然后 就会在 Edge中&#xff0c;再次打开网址尝试&#xff1b;(次模式 会保…

Windows11更新后打不开Edge浏览器解决办法

前几天吐槽win11更新版本后打不开Microsoft Edge浏览器了&#xff0c;特别影响我使用&#xff0c;然后找网上方法&#xff0c;大多让去设置里 修复&#xff0c;就这样&#xff0c;然而没什么卵用&#xff0c;这应该是win11新版本的bug了。 后来看到b站博主 https://b23.tv/QKUh…

微软浏览器Edge打不开怎么办

ctrl shift esc 打开任务管理器 点击窗口内&#xff0c;使其获得焦点&#xff0c;然后切换到英文输入法&#xff0c;输入m(因为edge全称是m开头&#xff0c;这样可以快速找到) 右键&#xff0c;关闭所有edge有关程序&#xff0c;然后进入此目录 C:\Users\&#xff08;你的用…

Microsoft Edge浏览器不兼容解决办法

Microsoft Edge浏览器不兼容解决办法 报错代码&#xff1a;STATUS_INVALID_IMAGE_HASH 步骤 1、按win R键&#xff0c;打开运行命令框。 2、输入 regedit &#xff0c;打开注册表编辑器 3、注册表编辑器窗口中&#xff0c;依次展开到以下路径&#xff1a; HKEY_LOCAL_MACHIN…

Microsoft Edge 嗯...无法访问此页面解决办法

目录 【问题描述】 嗯...无法访问此页面&#xff0c;短短半年遇到两次这个问题&#xff0c;具体如下图所示。 【解决步骤】 1.设置 2.高级设置 3.打开代理设置 4.开启 自动检测设置 &#xff08;初始如图&#xff1a;处于关闭状态&#xff09; 5.恢复正常 【问题描述】…

Win11重置后edge打不开了?

最近有用户发现电脑升级Win11系统&#xff0c;edge浏览器老是出现一些问题&#xff0c;比如edge打不开&#xff0c;无法启动&#xff0c;这该怎么办&#xff1f;针对这一问题&#xff0c;小编给大家带来了详细的解决方法&#xff0c;操作非常简单&#xff0c;快来试试&#xff…