[C++11#47] (四) function包装器 | bind 函数包装器 | 结合使用

news2024/9/24 7:22:11

目录

一. function包装器

1. 在题解上

 2.bind 绑定

1.调整参数顺序

2.对类中函数的包装方法


一. function包装器

function包装器也叫作适配器。C++中的function本质是一个类模板,也是一个包装器。 那么我们来看看,我们为什么需要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函数模板实例化了三份。

如何实现对函数传参的三种统一模板化调用?包装器

解决了:模板调用函数的效率低下,实例化多份的问题

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(function<double(double)>(f), 11.11) << endl;

	// 函数对象
	Functor  ft;
	cout << useF(function<double(double)>(ft), 11.11) << endl;

	// lamber表达式
	cout << useF(function<double(double)>([](double d)->double { return d / 4; }), 11.11) << endl;

	return 0;
}

实现了对象对 同类型 的不同函数处理的便捷调用,再也不用创建多个了,实现了优化

1. 在题解上

以150. 逆波兰表达式求值为例

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> _st;
        map<string,function<int(int,int)>> opFuncMap = 
        {
            {"+",[](int x,int y)->int{return x+y;}},
            {"-",[](int x,int y)->int{return x-y;}},
            {"*",[](int x,int y)->int{return x*y;}},
            {"/",[](int x,int y)->int{return x/y;}},
            //这里还可以添加%其他东西,还是很好用的

        };

        for(auto& str : tokens)
        {
            if(opFuncMap.count(str) == 0)
            {
                _st.push(stoi(str));
            }
            else
            {
                int right=_st.top();
                _st.pop();
                int left=_st.top();
                _st.pop();

                _st.push(opFuncMap[str](left,right));
            }
        }
        return _st.top();
    }
};

 2.bind 绑定

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

使用

  • bind,第一个参数传的是可调用对象
  • placeholders

placeholders是一个命名空间,里面定义了很多_1,_2,_3等等,这些东西是一个占位对象。绑定后如果需要自己传参数,_1代表要传的第一个参数,_2代表要传的第二个参数

可以结合如下代码理解:

1.调整参数顺序

例如说调用银行的不同利率

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

double PPlus(int a, double rate, int b)
{
	return  rate*(a + b);
}
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;

    //PPlus    
    function<double(int, int)> PPlus1 = bind(PPlus, placeholders::_1, 4.0, placeholders::_2);
	function<double(int, int)> PPlus2 = bind(PPlus, placeholders::_1, 4.2, placeholders::_2);
	cout << PPlus1(5, 3) << endl;
	cout << PPlus2(5, 3) << endl;

}
  • 注意:对 PPlus 而言,是 _1,_2 不是 _2,_3
  • 重申:_1代表要传的第一个参数,_2代表要传的第二个参数
  • 打印:

2.对类中函数的包装方法

两种写法:

  1. Sub st; bind(&Sub::sub,&st, ..)
  2. bind(&Sub::sub, Sub(), ..)

取函数地址后,再传个对象/对象的指针

class Sub
{
public:
	int sub(int a, int b)
	{
		return a - b * x;
	}
private:
	int x = 20;
};


int main()
{
	//绑定固定参数
	//类成员函数多了一个参数,每次调用都需要在前面传一个对象然后才能调用
	function<int(Sub, int, int)> func4 = &Sub::sub;
	cout << func4(Sub(), 10, 20) << endl;
	

	function<int(int, int)> func5 = bind(&Sub::sub, Sub(), placeholders::_1, placeholders::_2);
	cout << func5(10, 20) << endl;

	return 0;
}

Bind 此处的调用的内部:还是一个 operate()的仿函数,相当于对类函数的提取

sum:

function 是想对各种可调用对象函数指针、函数对象,lambda进行适配包装给一个统一的类型

bind 是对可调用的对象的参数进行包装绑定,然后调整,绑死。

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

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

相关文章

[数据集][目标检测]机油泄漏检测数据集VOC+YOLO格式43张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;43 标注数量(xml文件个数)&#xff1a;43 标注数量(txt文件个数)&#xff1a;43 标注类别数…

基于SSM的献血管理系统设计与实现(论文+源码)_kaic

摘 要 近年来&#xff0c;随着科技的飞速发展&#xff0c;在全球经济一体化的大背景下&#xff0c;我们面临着巨大的挑战&#xff0c;互联网技术将进一步提高社会综合发展的效率和速度&#xff0c;而且也会涉及到各个领域。献血管理系统在网络背景下有着无法忽视的作用&#x…

Xilinx FPGA 原语解析(三):OBUFDS差分输出缓冲器(示例源码及仿真)

目录 前言&#xff1a; 一、原语使用说明 二、原语实例化代码模版 三、使用示例 1.设计文件代码 2.仿真文件代码 3.仿真结果 前言&#xff1a; 主要参考 Xilinx 官方文档《Xilinx 7 Series FPGA and Zynq-7000 All Programmable SoC Libraries Guide for HDL Designs》…

网络工程师学习笔记——局域网和城域网(二)

快速以太网 快速以太网&#xff08;&#xff18;&#xff10;&#xff12;.&#xff13;&#xff55; &#xff11;&#xff10;&#xff10;&#xff2d;&#xff42;&#xff50;&#xff53;&#xff09; 其中多模光纤的芯线直径为&#xff16;&#xff12;.&#xff15;…

跟李沐学AI:循环神经网络RNN

循环神经网络 循环神经网络&#xff08;recurrent neural networks&#xff0c;RNNs&#xff09; 是具有隐状态的神经网络。RNN 具有隐状态&#xff08;hidden state&#xff09;的原因在于它需要一种机制来存储之前输入的信息&#xff0c;以便于处理当前输入时能够考虑之前的…

Linux教程8:文本编辑命令vi

一、文本编辑命令介绍 vi&#xff08;Visual Interface&#xff09;是一种广泛使用的文本编辑器&#xff0c;特别是在Unix和类Unix系统&#xff08;如Linux&#xff09;中。尽管现代系统通常提供了更现代的文本编辑器&#xff08;如vim&#xff0c;它是vi的增强版本&#xff0…

vue axios发送post请求跨域解决

跨越解决有两种方案&#xff0c;后端解决&#xff0c;前端解决。后端解决参考Django跨域解决-CSDN博客 该方法之前试着可以的&#xff0c;但是复制到其他电脑上报错&#xff0c;所以改用前端解决 1、main.js做增加如下配置 import axios from axios Vue.prototype.$axios a…

Spring1~~~

快速入门 javaBean规范要有set方法&#xff0c;底层反射赋值 <!-- id表示在该java对象在spring容器中的id--><bean class"spring.bean.Monster" id"monster01"><property name"Id" value"100"/><property nam…

Unity数据持久化 之 向文件流读写(详细Plus版)

本文仅作笔记学习和分享&#xff0c;不用做任何商业用途 本文包括但不限于unity官方手册&#xff0c;unity唐老狮等教程知识&#xff0c;如有不足还请斧正​​ 在 Unity 手册中&#xff0c;FileStream 并没有单独的详细介绍&#xff0c;因为它是 .NET 框架的一部分&#xff0c;…

已经存在的项目如何变成git的一个repository

已经存在的项目如何被git管理 背景&#xff1a; 有一套代码很敏感&#xff0c;可能动不动就要不能正常工作(硬件开发常事)&#xff0c;那改动一下下就要有个记录&#xff0c;就决定用git管理 已经有了服务里里docker里运行的gitbucket,已经有了开发用的电脑上的git客户端&…

c++ websocket简单讲解

只做简单讲解。 一.定义和原理 WebSocket 是从 HTML5 开始⽀持的⼀种⽹⻚端和服务端保持⻓连接的消息推送机制&#xff0c;传统的 web 程序都是属于 "⼀问⼀答" 的形式&#xff0c;即客⼾端给服务器发送了⼀个 HTTP 请求&#xff0c;服务器给客⼾端返回⼀个 HTTP 响…

亿发进销存一体化解决方案:多终端无缝协同,赋能企业全业务-上

亿发软件凭借对产品、市场、业务的深入理解&#xff0c;在进销存基础上进行了延伸&#xff0c;推出多终端、一体化的“进销存管理系统”多元产品矩阵。在技术上实现电脑端、手机端、PDA端、零售端、商家版以及小程序商城的多终端无缝对接。各个端口间的数据可以互通互联&#x…

Prometheus Blackbox监控网站

Blackbox Exporter简介 blackbox_exporter 是 Prometheus 拿来对 http/https、tcp、icmp、dns、进行的黑盒监控工具&#xff0c;也就是从服务、主机等外部进行探测&#xff0c;来查看服务、主机等是否可用。 Blackbox Exporter 默认端口是 9115&#xff0c; 安装1 wget htt…

模电-三极管2

学习资料&#xff1a; 12-放大电路的分析方法_4K_哔哩哔哩_bilibili 如何向老奶奶解释数据库 如何向幼儿解释能量守恒 内容有误&#xff0c;无法保证一定正确&#xff0c;请各自深入学习 大学的知识连贯性很强&#xff0c;没有前面的基础&#xff0c;无法对后面的知识进行&a…

2023 ICPC 江西省赛K. Split

K. Split time limit per test: 3 seconds memory limit per test: 512 megabytes You are given a positive integer n and a non-increasing sequence ai of length n , satisfying ∀i∈[1,n−1],. Then, you are given a positive integer m, which represents the tot…

新版英语教材变化,强调应用与素养并重

随着新学期的到来&#xff0c;2024年新版义务教育英语教材正式在全国范围内投入使用&#xff0c;这一变化不仅在教育界引起了广泛关注&#xff0c;也触动了无数家长的心弦。新版教材在内容、难度及教学理念上的全面升级&#xff0c;既为孩子们提供了更广阔的学习空间&#xff0…

STM32智能家居语音系统

简介 基于STM32构建的智能家居语音控制系统&#xff0c;采用ESP8266&#xff08;01s&#xff09;作为关键的WiFi模块。这一系统通过机智云开发平台实现与ESP8266的高效通信&#xff0c;遵循平台规范的协议&#xff0c;确保数据的可靠传输。系统支持WIFI_AIRLINK_MODE&#xff0…

免邀请码下载时代已来临,Xinstall为您保驾护航

在App推广的道路上&#xff0c;邀请码下载一直是一个让人头疼的问题。用户需要输入繁琐的邀请码才能完成下载&#xff0c;这不仅增加了用户的操作难度&#xff0c;也影响了App的推广效果。然而&#xff0c;随着Xinstall的免邀请码下载功能的推出&#xff0c;这一问题终于得到了…

VISION TRANSFORMER ADAPTER FORDENSE PREDICTIONS

总结 提出了一种新范式&#xff1a; 开发了 Vision Transformer Adapter (ViT-Adapter)&#xff0c;通过引入无预训练的适配器将视觉特定的归纳偏差&#xff08;例如局部空间信息&#xff09;引入普通 ViT&#xff0c;适应密集预测任务。 保留 ViT 灵活性&#xff1a; 与设计…

Linux日志-lastlog日志

作者介绍&#xff1a;简历上没有一个精通的运维工程师。希望大家多多关注作者&#xff0c;下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 Linux 系统中的日志是记录系统活动和事件的重要工具&#xff0c;它们可以帮助管理员监视系统状态、调查问题以及了解系统运行…