C++11【包装器】

news2024/11/30 14:31:38

包装器

    • 📖1. 为什么需要包装器
    • 📖2. 如何使用包装器
    • 📖3. bind函数

📖1. 为什么需要包装器

包装器也叫做适配器,C++中的function本质是一个类模板,也是一个包装器.

为什么需要function呢?

我们来看一个例子:

ret = func(x);
//上面的func可能是函数名, 函数对象, 也有可能是lambda表达式, 这些都是可调用的类型, 如此丰富的类型, 可能会导致模板的效率低下
//例如下面这段代码

#include <iostream>

using namespace std;

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

	return 0;
}

image-20221212153936501

最终这个模板实例化出了三份.

📖2. 如何使用包装器

包装器可以很好的解决上面的问题:

std::function 在头文件 <functional>
    
//包装器原型如下
template<class T> function;

template<class Ret, class... Args>
class function<Ret(Args...)>;

模板参数说明: 
Ret: 被调用函数的返回类型
Args: 被调用函数的形参
int f(int a, int 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<int(int, int)> func1 = f;
	cout << func1(1, 2) << endl;
	
    //包装函数对象
	function<int(int, int)> func2 = Functor();
	cout << func2(1, 2) << endl;
	
    //包装lambda表达式
	function<int(int, int)> func3 = [](const int a, const int b) {return a + b; };
	cout << func3(1, 2) << endl;
	
    //包装类的成员函数(静态)
	function<int(int, int)> func4 = &Plus::plusi;
	cout << func4(1, 2) << endl;
	
    //包装类的成员函数(非静态)
	function<double(Plus, double, double)> func5 = &Plus::plusd;
	cout << func5(Plus(), 1.1, 1.2) << endl;

	return 0;
}

那么,包装器是如何解决了模板的效率低下,实例化了多份的问题呢?

#include <iostream>
#include <functional>

using namespace std;

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()
{
	// 函数
	function<double(double)> func1 = f;
	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);

	return 0;
}

image-20221212183744081

有了包装器以后,模板只实例化了一份.

📖3. bind函数

std::bind函数定义在functional头文件中,是一个函数模板,它就像一个函数包装器(适配器),接收一个可调用对象,生成一个新的可调用对象来适应原对象的参数列表.

原型如下:

template<class Fn, class... Args>
bind(Fn&& fn, Args&&... args);

template<class Ret, class Fn, class... Args>
bind(Fn&& fn, Args&&... Args);

可以将bind函数看作是一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来 “适应” 原对象的参数列表.

调用bind的一般形式:auto newCallable = bind(callable, arg_list);

其中,newCallable本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的callable的参数,当我们调用newcallable的时,newCallable会调用callable,并传给它arg_list的参数.

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

用法:

int Plus(int a, int b)
{
	return a + b;
}

class Sub
{
public:
	int sub(int a, int b)
	{
		return a - b;
	}
};

int main()
{
	//表示绑定函数Plus  参数分别由调用 func1 的第一、二个参数指定
	function<int(int, int)> func1 = bind(Plus, placeholders::_1, placeholders::_2);

	auto func2 = bind(Plus, 1, 2);
	cout << func1(1, 2) << endl;
	cout << func2() << endl;

	//绑定成员函数
	function<int(int, int)> func3 = bind(&Sub::sub, Sub(), placeholders::_1, placeholders::_2);

	//参数调换顺序
	function<int(int, int)> func4 = bind(&Sub::sub, Sub(), placeholders::_2, placeholders::_1);
	cout << func3(1, 2) << endl;
	cout << func4(1, 2) << endl;


	return 0;
}

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

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

相关文章

ant-design-vue修改input组件样式

问题场景 不得不说ant-design-vue的样式是真的难改。。。今天尝试了很多种方案&#xff0c;都无疾而终。最终&#xff0c;通过全局scss文件引入的方式解决了。 几种方案&#xff1a; 直接行内样式&#xff0c;发现部分可以&#xff0c;部分不行将style 的scoped属性去掉&#…

非线性负载的主要分类及其特性

非线性负载的主要分类 通常而言&#xff0c;由线性元件原件组成的负载称为线性负载&#xff0c;线性负载的输出与输入呈线性关系&#xff0c;典型的线性负载如电阻、电容和电感等&#xff1b;而由非线性元件构成的负载为非线性负载&#xff0c;在正弦波电压供电时会产生非正弦…

Sentinel服务流控

Sentinel通过流量控制&#xff08;flow control&#xff09;以及熔断降级来保护系统资源 QPS超过阈值直接失败 流量控制&#xff08;flow control&#xff09;&#xff0c;其原理是监控应用流量的 QPS 或并发线程数等指标&#xff0c;当达到指定的阈值时对流量进行控制&#x…

如何使用ABAQUS对新能源动力电池进行Pack分析

电池Pack的仿真&#xff0c;按照系统层次&#xff0c;可从电芯、模组、Pack和整车逐级分析。电芯主要集中于机械性能的材料拟合、激光焊接以及电-化学-热-机耦合建模&#xff0c;模组主要集中于跌落、振动以及模组冷却&#xff0c;Pack主要集中于**、冲击和振动以及Pack热管理&…

Token Merging: Your ViT But Faster

论文&#xff1a;https://arxiv.org/pdf/2210.09461.pdf 代码&#xff1a; https://github.com/facebookresearch/ToMe 这篇论文写的很棒呀&#xff0c;以摘要为例&#xff0c;第一句话指明ToMe的作用&#xff08;提高ViT-based模型的训练和推理速度&#xff09;和特色&#x…

java面试强基(21)

什么是线程和进程? 何为进程? ​ 进程是程序的一次执行过程&#xff0c;是系统运行程序的基本单位&#xff0c;因此进程是动态的。系统运行一个程序即是一个进程从创建&#xff0c;运行到消亡的过程。 ​ 在 Java 中&#xff0c;当我们启动 main 函数时其实就是启动了一个 J…

提质增效!北京筑龙助力蒙牛集团采招数智化升级

近两年&#xff0c;全球经济下行压力加剧&#xff0c;市场形势波动使得集团企业面临着很大的经营压力。随着数字经济时代的到来&#xff0c;利用数字技术重构价值链、重组业务流程&#xff0c;或创建新的生态系统平台成为集团企业数字化转型的契机。 蒙牛电子采购招标平台作为…

WEB网页设计期末作业个人主页——基于HTML+CSS制作个人简介网站

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

现实中的项目范围变更

大多数招投标或签合同的项目(TOG或TOB),范围变更是极少的,一旦发起范围变更申请,这个流程是非常复杂的,而且会有负面影响,尤其是TOG的项目。 项目范围变更,往往会引起项目金额变更,核减、增加、不变都有可能。 TOG项目的范围变更,常是因为政策变了、上级要求等不可…

(附源码)Springboot网上购物平台 毕业设计 141422

Springboot网上购物平台的开发 摘 要 随着Internet的使用越来越广泛&#xff0c;在传统的商业模式中&#xff0c;对于日常各类商品&#xff0c;人们习惯于到各种商家店铺购买。然而在快节奏的新时代中&#xff0c;人们不一定能为购买各类商品腾出时间&#xff0c;更不会耐心挑…

Docker管理工具Portainer忘记admin登录密码怎么办?

Portainer官网解决方法链接 https://docs.portainer.io/v/ce-2.11/advanced/reset-admin 炒鸡详细步骤&#xff01; 1.查看所有容器,包括未运行的 docker ps -a 2.找到Portainer对应信息 3.停止Portainer容器 docker stop portainerid 我这里就应该是 docker stop 507566…

Unity VFX图表初级到中级教程

Unity VFX图表初级到中级教程 从 Unity 学习新的视觉效果工具并开始制作一些很棒的魔法效果 课程英文名&#xff1a;Unity VFX Graph - Beginner To Intermediate 此视频教程共4.5小时&#xff0c;中英双语字幕&#xff0c;画质清晰无水印&#xff0c;源码附件全 下载地址 …

【脚本项目源码】Python制作提升成功率90%的表白神器

前言 明天就是拥抱情人节&#xff0c;情侣们会在公开的场合拥抱&#xff0c;向世人宣告你俩的爱意&#xff0c;也让这个寒冷的冬天变得格外温馨。到了年底依然能热情拥抱&#xff0c;也见证了两人情意如昔。 今天小鱼就给大家带来就是的利用Python制作表白神器&#xff0c;记…

年末消费高峰,警惕“大牌平替”的陷阱

就在眼前的双十二&#xff0c;接踵而来的圣诞跨年与春节&#xff0c;买买买的黄金时段&#xff0c;作为消费者&#xff0c;少不了要接受各式营销广告的狂轰滥炸。如今纷繁复杂的消费市场&#xff0c;大家都擦亮了眼睛追求性价比&#xff0c;如果你也曾被“五分之一价格买到大牌…

【云计算与大数据计算】分布式处理CPU多核、MPI并行计算、Hadoop、Spark的简介(超详细)

一、CPU多核和POISX Thread 为了提高任务的计算处理能力&#xff0c;下面分别从硬件和软件层面研究新的计算处理能力 在硬件设备上,CPU 技术不断发展,出现了SMP(对称多处理器)和 NUMA(非一致 性内存访问)两种高速处理的 CPU 结构 在软件层面出现了多进程和多线程编程。进程…

【王道计算机网络笔记】网络层-网络层概述和编址

文章目录IP数据报格式IP数据报分片例题IPv4地址分类的IP地址网络地址转换NAT子网划分与子网掩码无分类编址CIDR主要任务是把分组从源端传到目的端&#xff0c;为分组交换网上的不同主机提供通信服务。网络层的传输单位是数据报&#xff0c;数据报是一个比较长的数据&#xff0c…

基于51单片机的智能热水器无线WiFi控制系统proteus仿真原理图程序

功能&#xff1a; 0.本项目采用STC89C52作为单片机系统的控制MCU 1.LCD1602液晶实时显示温度阈值、当前温度和定时时间 2.支持按键和红外遥控设置温度阈值和定时时间 3.通过传感器检测&#xff0c;判定当前值是否超过设定的阈值&#xff0c;然后对相关继电器进行控制 4.支持声光…

使用DevExpress WPF主题设计器轻松创建Office 2019绿色主题(二)

DevExpress WPF拥有120个控件和库&#xff0c;将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序&#xff0c;这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 DevExpress WPF的The…

数据结构C语言版 —— 时间复杂度空间复杂度概念和计算

文章目录时间复杂度&空间复杂度1. 算法效率2. 时间复杂度1) 时间复杂度的概念2) 大O的渐近表示法3) 时间复杂度案例举例3. 空间复杂度1) 空间复杂度概念2) 计算实例时间复杂度&空间复杂度 1. 算法效率 算法效率分析一般分为两种&#xff0c;一种是时间效率&#xff0…

Unity初学者Shader Graph教程

Unity初学者Shader Graph教程 了解面向非程序员的 Unity 引擎可视化着色器编程工具的来龙去脉 课程英文名&#xff1a;Your Ultimate Guide to Shader Graph for Beginners 此视频教程共28.0小时&#xff0c;中英双语字幕&#xff0c;画质清晰无水印&#xff0c;源码附件全 …