浅谈C++绑定器bind1st、bind2nd和函数对象function

今天我们先来谈谈C++ 标准库里面的绑定器bind1stbind2nd 和函数对象function

C++ 绑定器和函数对象

    • 一、绑定器
    • 二、函数对象

一、绑定器

虽然在C++11标准中这两个绑定函数已经被弃用,但仍然值得我们深入思考其底层原理。从字面上理解,“绑定” 这两个字表明它可能将某个类型或值直接关联到了某个特定的 “位置” 上,其定义可以被概括为:

  • 🐶bind1st函数接受一个二元函数和一个值,返回一个新的函数对象,该函数对象将被绑定到二元函数的第一个参数上。这意味着第二个参数可以在调用时提供,而第一个参数是预先绑定的。

  • 🐱bind2nd函数接受一个二元函数和一个值,返回一个新的函数对象,该函数对象将被绑定到二元函数的第二个参数上。这意味着第一个参数可以在调用时提供,而第二个参数是预先绑定的。

简而言之,bind1st 把函数对象 operator() 重载函数的第一个形参变量绑定成一个确定的值,而bind2nd 函数则是把第二个形参变量绑定成一个确定的值。下面我们给出一个简单的示例来加深理解:

#include<iostream>
#include<functional>
#include<vector>
using namespace std;template<typename T>
void show_all(T& val)  //通用函数模板,用来输出所有元素
{typename T::iterator it = val.begin();while (it != val.end()){cout << *it << " "; it++;}
}int main()
{srand(time(NULL));vector<int> v;for (int i = 0; i < 20; i++)v.push_back(rand() % 100);//v.push_back(rand() % 100 + 50); 一定找不到// 使用 bind1st(greater<int>(), 50) 查找第一个大于50的元素auto it = find_if(v.begin(), v.end(), bind1st(greater<int>(), 50));//auto it = find_if(v.begin(), v.end(), bind2nd(less<int>(), 50));if (it != v.end()){v.insert(v.end(), 50);}show_all(v);return 0;
}

通过思考🤔🤔🤔,我们可以发现find_if查询的条件是基于它的第三个参数bind1st中的(greater<int>(), 50),我们看greater的底层源码可以知道,50实际上是替换了下图中的_Left,而从 v.begin() 到 v.end() 遍历到的元素将直接作为_Right传入,以此来判断是否有小于 50 的元素

在这里插入图片描述
同理,如果使用bind2nd,我们将greater<int>() 改为 less<int>() 能够得到同样的结果,这里就不在赘述了。下面我们自己来写写它们的简单底层实现(自用):

  1. 自定义查找函数 my_find_if:
template<typename Iterator, typename Compare>
Iterator my_find_if(Iterator first, Iterator last, Compare comp)
{while (first != last){if (comp(*first)) return first;first++;}return last;
}

通过模板参数 Iterator 接受任意迭代器类型,Compare 接受任意比较函数对象类型。在给定范围 [first, last) 内查找满足条件的第一个元素。循环遍历范围,使用传入的比较函数对象 comp 判断是否满足条件。如果找到满足条件的元素,返回该元素的迭代器;否则,返回 last。

  1. 一元函数对象 _Mybind1st 及其辅助函数 My_bind1st:
template<typename Compare, typename T>
class _Mybind1st
{
public:_Mybind1st(Compare comp, T val): _comp(comp), _val(val){}bool operator()(const T& second)  //传入容器里的所有元素{ return _comp(_val, second);// my_bind2nd(second, _val);}
private:Compare _comp;T _val;};template<typename Compare, typename T>
_Mybind1st<Compare, T>  My_bind1st(Compare comp, const T& val)
{return _Mybind1st<Compare, T>(comp, val);
}

定义了一个一元函数对象 _Mybind1st,用于在比较中固定第一个参数。_Mybind1st 类接受一个比较函数对象和一个固定值,通过 operator() 实现比较。辅助函数 My_bind1st 用于创建 _Mybind1st 类的实例,将比较函数对象和固定值传递给构造函数。

最后总结一句: 绑定器 + 二元函数对象 =》 一元函数对象

二、函数对象

函数对象是一个具有函数调用运算符(operator())的类对象。它可以像普通函数一样被调用,并且可以保存内部状态。函数对象可以用作参数传递给其他函数,也可以在算法中使用。在C++中,函数对象可以通过重载函数调用运算符来实现。函数调用运算符是一个特殊的成员函数,它没有函数名,只有一个参数列表和一个返回类型。当使用函数对象调用时,实际上就是调用了该运算符重载函数,相关代码如下:

#include<iostream>
#include<functional>
#include<string>
using namespace std;void hello1() { cout << "null" << endl; 
}void hello2(string str) { cout << str << endl; 
}int sum(int a, int b) { return a + b; 
}// 自定义的函数模板类
template<typename Fty>
class my_function {};// 部分特例化,用于处理函数指针
template<typename R, typename ...A>  
class my_function<R(A...)>  
{
public:// 函数指针类型using PFUNC = R(*)(A...);// 构造函数接受函数指针作为参数my_function(PFUNC pfunc) : _pfunc(pfunc) {}// 重载函数调用运算符,以调用函数指针R operator()(A ... arg){return _pfunc(arg ...);}private:PFUNC _pfunc;  // 存储函数指针
};class Test
{
public:void hello(string str) { cout << str << endl; }
};int main()
{// 使用标准库的functionfunction<void()> f1 = hello1;f1();function<void(string)> f2 = hello2;f2("hello");// 使用lambda表达式function<int(int, int)> f3 = [](int a, int b)->int {return a + b; };cout << f3(9, 9) << endl;// 以下两行被注释掉,因为需要修改成正确的方式处理成员函数指针// function<void(Test*, string)> f4 = &Test::hello;// f4(&Test(), "Test");// 使用自定义的my_function,包装普通函数my_function<int(int, int)> f5(sum);cout << f5(9, 9) << endl;// 使用自定义的my_function,包装函数对象my_function<void(string)> f6 = hello2;f6("my_hello2");return 0;
}

这里就不解释了,仅作为理解而已。


🌻🌻🌻以上就是有浅谈C++绑定器bind1st、bind2nd和函数对象function的相关内容,如果聪明的你浏览到这篇文章并觉得文章内容对你有帮助,请不吝动动手指,给博主一个小小的赞和收藏 🌻🌻🌻

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

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

相关文章

Explain

Explain EXPLAIN是MySQL提供的一种用于分析SQL查询执行计划的工具&#xff0c;通过它我们可以深入了解数据库如何执行一条SQL语句&#xff0c;以及优化器在选择索引、访问表和排序数据等方面的决策。 我整理了一份思维导图方便更好查看各个参数的意义&#xff0c;红色表示比较…

RabbitMq踩坑记录

1、连接报错&#xff1a;Broker not available; cannot force queue declarations during start: java.io.IOException 2.1、原因&#xff1a;端口不对 2.2、解决方案&#xff1a; 检查你的连接配置&#xff0c;很可能是你的yml里面的端口配置的是15672&#xff0c;更改为5672即…

css超出部分显示省略号

目录 前言 一、CSS单行实现 二、CSS多行实现&#xff08;CSS3出的&#xff0c;兼容性需要注意&#xff09; 三、微信小程序超过2行出现省略号实现 四、JavaScript脚本实现 前言 CSS文本溢出就显示省略号&#xff0c;就是在样式中指定了盒子的宽度与高度,有可能出现某些内…

LLM - 大语言模型(LLM) 概述

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/136617643 大语言模型(LLM, Large Language Model)的发展和应用是一个非常广泛的领域&#xff0c;涉及从早期的统计模型到现代基于深度学…

【AI+CAD】(二)LLM和VLM生成结构化数据结构(PPT/CAD/DXF)

当前LLM和VLM在PPT生成任务上已经小有成效,如ChatPPT。 @TOC 1. PPT-LLM LLM根据用户的instruction生成规范的绘制ppt的API语句:即使是最强的GPT-4 + CoT也只能达到20-30%的内容准确度。 LLM输入:User_instruction(当前+过去)、PPT_content、PPT_reader_API。其中 PPT_rea…

面试经典150题——随机链表的复制

​前两天断更了两天有点事情&#x1f917; 1. 题目描述 2. 题目分析与解析 2.1 思路一 开始还是没什么思路&#xff0c;没思路那就先把题目解决不管方法的好坏。如果不考虑复杂度&#xff0c;该怎么解决&#xff1f; 可以有这样的一种思路&#xff1a; 首先复制链表的所有节…

【python绘图】turle 绘图基本案例

文章目录 0. 基础知识1. 蟒蛇绘制2. 正方形绘制3. 六边形绘制4. 叠边形绘制5. 风轮绘制 0. 基础知识 资料来自中国mooc北京理工大学python课程 1. 蟒蛇绘制 import turtle turtle.setup(650, 350, 200, 200) turtle.penup() turtle.fd(-250) turtle.pendown() turtle.pen…

jeesite列表jqGrid表格底部汇总,基于onSelectRow和onSelectAll实现选中行汇总合计

一、最终效果图 二、表格启用复选框并初始化赋值 onSelectAll: function() { calc_sum(); }, onSelectRow: function() { calc_sum(); },// 加载成功后执行事件 ajaxSuccess: function(data){var dy = 0;var glbzqmrsdtyg = 0;var glbzqmrsschyg = 0;var glbzqmrsqtcy …

【贪心算法】Leetcode 55. 跳跃游戏

【贪心算法】Leetcode 55. 跳跃游戏 解法1解法2 ---------------&#x1f388;&#x1f388;55. 跳跃游戏 题目链接&#x1f388;&#x1f388;------------------- 解法1 关键点在于&#xff1a;不用拘泥于每次究竟跳几步&#xff0c;而是看覆盖范围&#xff0c;覆盖范围内…

Python 语法及入门 (超全超详细) 专为Python零基础 一篇博客让你完全掌握Python语法

前言&#xff1a; 本篇博客超级详细&#xff0c;请尽量使用电脑端结合目录阅读 阅读时请打开右侧 “只看目录” 方便阅读 一、什么是Python 1.1 Python的诞生 1989年&#xff0c;为了打发圣诞节假期&#xff0c;Gudio van Rossum吉多 范罗苏姆&#xff08;龟叔&#xff09;决…

Gitee配置SSH登录

一、背景 新入手的电脑&#xff0c;需要对Gitee上存放的项目进行更改上传&#xff0c;发现上传不了需要登录&#xff0c;便采用SSH密钥进行登录&#xff0c;防止远程管理工程中的信息泄露 二、前提 电脑已下载Git Bash工具&#xff0c;在项目下点击鼠标右键&#xff0c;进入…

Linux 中搭建 主从dns域名解析服务器

CSDN 成就一亿技术人&#xff01; 作者主页&#xff1a;点击&#xff01; Linux专栏&#xff1a;点击&#xff01; CSDN 成就一亿技术人&#xff01; ————前言———— 主从&#xff08;Master-Slave&#xff09;DNS架构是一种用于提高DNS系统可靠性和性能的配置方式。…

opencv人脸识别实战3:多线程和GUI界面设计(PyCharm实现)

一、多线程设计 1、在一个新线程中调用了 scan_face() 函数来进行人脸识别操作。根据识别结果&#xff0c;更新界面显示结果&#xff0c;最后释放资源。 def f_scan_face_thread():var.set(刷脸)ans scan_face()if ans 0:print("最终结果&#xff1a;无法识别")va…

《互联网的世界》第七讲-能源

本想聊聊 tcp 和 quic&#xff0c;但这些都属于术的范畴&#xff0c;变化多端&#xff0c;等孩子们长大了又不知变成什么样子了&#xff0c;趁这段时间在家&#xff0c;还是得讲一些相对不变的东西&#xff0c;或法或势。 从 安阳卖血糕的精巧篦子 想到如何做圆米粉和圆面条&a…

【管理咨询宝藏39】某四大咨询公司D记PPT模板

本报告首发于公号“管理咨询宝藏”&#xff0c;如需阅读完整版报告内容&#xff0c;请查阅公号“管理咨询宝藏”。 【管理咨询宝藏39】某四大咨询公司D记PPT模板 【格式】PPT版本&#xff0c;可编辑&#xff0c; 【关键词】PPT模板&#xff0c;PPT图表 【文件核心观点】 - 2…

什么是分段锁?

1、典型回答 分段锁是一种将锁细化到每个段(Segment) 级别的锁设计。在 ConcurrentHashMap 中&#xff0c;它将整个数据结构分成多个段&#xff0c;每个段只锁定自己的一部分数据。每个段可以看作是一个独立的分组&#xff0c;只锁定该段(Segment)内部的数据操作&#xff0c;不…

OJ_八皇后

题干 C实现 深度优先遍历&#xff0c;注意回溯打表法&#xff1a;先求出所有解&#xff0c;再存入一个容器中 #define _CRT_SECURE_NO_WARNINGS#include <iostream> #include <vector>using namespace std;vector<vector<int>> queenVec;//用来存在所…

2024年中国AI服务器行业发展

环洋咨询Global Info Research的AI服务器市场调研报告提供AI服务器市场的基本概况&#xff0c;包括定义&#xff0c;分类&#xff0c;应用和产业链结构&#xff0c;同时还讨论发展政策和计划以及制造流程和成本结构&#xff0c;分析AI服务器市场的发展现状与未来市场趋势&#…

Flink通讯模型—Akka与Actor模型

Carl Hewitt 在1973年对Actor模型进行了如下定义&#xff1a;"Actor模型是一个把Actor作为并发计算的通用原语". Actor是异步驱动&#xff0c;可以并行和分布式部署及运行的最小颗粒。也就是说&#xff0c;它可以被分配&#xff0c;分布&#xff0c;调度到不同的CPU&…

操作系统总结(第二周 第一堂)

前言&#xff1a; 第一周的重点就在于一张图表&#xff1a; 基于这张图&#xff0c;我们将陷入内核分为了两个大块Trap和Interrupt。同时我们知道一件事情任何一次I/O操作或者错误程序操作都将陷入内核&#xff0c;从而使得内核可以监控所有的外部设备以及维护整个电脑程序运行…