【C++】一文解析std::binary_function、std::bind1st、std::bind2nd、std::bind

news/2024/12/2 9:51:14/

STL中有一个叫做“适配器”的概念,它指的是某些函数可能定义了两个形参,但是某些算法需要的函数却有时候需要一个形参,那么就需要对其进行适配,将原本只需要两个参数的函数转变成需要1和参数就能正常运行的函数。就像你为你的笔记本充电,能直接一根火线一根零线直接接在你的电脑上吗?肯定也是需要一个适配器将国内标准电压转化成笔记本需要的额定电压。“适配器”就是由此而来。

std::binary_function

关于类 binary_function 的定义很简单,源码如下:

template <class _Arg1, class _Arg2, class _Result>
struct binary_function
{   // base class for binary functionstypedef _Arg1   first_argument_type;typedef _Arg2   second_argument_type;typedef _Result result_type;
};

这是一个二元函数的模板类,定义两个输入参数,一个返回值。我们如果想让我们自己写的仿函数支持适配器,那么就必须从binary_function派生出来。

#include <iostream>
#include <functional>template<typename T>
class MLess : public std::binary_function<T, T, bool>
{
public:bool operator() (const T& a, const T& b) const{return a < b;}
};

std::binary_function<T, T, bool> 前两个参数分别表示第一,第二个参数,bool表示operator的返回值。做完这些准备工作,就可以使用std::bind1st、std::bind2nd来进行适配了。

std::bind1st、std::bind2nd

  • bind1st 是将一个二元函数的第一个参数绑定为固定值的函数(实质上是仿函数类)
  • bind2nd 是将一个二元函数的第二个参数绑定为固定值的函数(实质上是仿函数类)

他们再使用的时候都需要加上头文件

关于bind1st的实现也很简单:

template <class _Fn2>
class binder1st : public unary_function<typename _Fn2::second_argument_type, typename _Fn2::result_type>
{   // functor adapter _Func(stored, right)
public:typedef unary_function<typename _Fn2::second_argument_type, typename _Fn2::result_type> _Base;typedef typename _Base::argument_type                                                   argument_type;typedef typename _Base::result_type                                                     result_type;binder1st(const _Fn2& _Func, const typename _Fn2::first_argument_type& _Left) : op(_Func), value(_Left){   // construct from functor and left operand}result_type operator()(const argument_type& _Right) const{   // apply functor to operandsreturn (op(value, _Right));}result_type operator()(argument_type& _Right) const{   // apply functor to operandsreturn (op(value, _Right));}protected:_Fn2                               op;      // the functor to applytypename _Fn2::first_argument_type value;   // the left operand
};// TEMPLATE FUNCTION bind1st
template <class _Fn2, class _Ty>
inline binder1st<_Fn2> bind1st(const _Fn2& _Func, const _Ty& _Left)
{   // return a binder1st functor adaptertypename _Fn2::first_argument_type _Val(_Left);return (binder1st<_Fn2>(_Func, _Val));
}

从代码中可以看出,bind1st 是一个函数模板,需要传入两个参数,_Func 和 _Left ,binder1st 是一个仿函数类,构造函数中将 _Func 赋值给了成员 op, _Left 赋值给我成员 value,重载的 () 正好调用的函数 op(value, _Right)。

如何使用bind1st呢:

auto lessObj = std::bind1st(MLess<int>(), 5);//实际上是返回一个新的函数对象 binder1st ,成员 op 为 MLess<int>() 对象, value 为 5

这里就是将5绑定到MLess的第一个参数中,即:

bool operator() (const T& b) const{return 5 < b;}

即:

result_type operator()(const argument_type& _Right) const
{	// apply functor to operandsreturn (op(value, _Right));
}

同理:bind2nd也是这样:

#include <iostream>
#include <functional>
#include <algorithm>
#include <list>template<typename T>
class MTestClass : public std::binary_function<T, T, void>
{
public:void operator() (const T& a, const T& b) const{if (a > b)std::cout << a << std::endl;}
};int main(int argc, char** argv)
{std::list<int> nList;nList.push_back(10);nList.push_back(20);nList.push_back(30);nList.push_back(40);nList.push_back(50);nList.push_back(60);std::for_each(nList.begin(), nList.end(), std::bind2nd(MTestClass<int>(), 30));system("pause");return 0;
}

std::bind

提起std::bind,可能你一下子就感觉熟悉不少,对,这个适配器应该比前面两个更“知名”一些,它提供的功能也完全覆盖了前两个适配器,例如,如果我们不使用std::bind1st、std::bind2nd,我们完全可以这么写:

   int res = count_if(coll.begin(), coll.end(), std::bind(less<int>(), 10, std::placeholders::_1)); // bind1st(less<int>(), 10));int res = count_if(coll.begin(), coll.end(), std::bind(less<int>(),std::placeholders::_1, 10)); // bind2st(less<int>(), 10));

http://www.ppmy.cn/news/1082179.html

相关文章

海格里斯HEGERLS高密度料箱式四向穿梭车存储系统有哪些显著优势?

近些年仓储货架向着自动化、智能化发展&#xff0c;因此市面上出现很多不同类型的智能自动化仓储货架。其中&#xff0c;最受企业青睐的便是四向穿梭车货架。四向穿梭车货架根据其载重不同可分为托盘式和料箱式两大类。这两种不同类型的四向穿梭车货架在结构形式和控制方式上基…

一文1800字从0到1使用Python Flask实战构建Web应用

Python Flask是一个轻量级的Web框架&#xff0c;它简单易用、灵活性高&#xff0c;适用于构建各种规模的Web应用。本文将介绍如何使用Python Flask框架来实战构建一个简单的Web应用&#xff0c;并展示其基本功能和特性。 第一部分&#xff1a;搭建开发环境 在开始之前我们需要…

Python入门教程 - 循环语句 (三)

目录 一、while循环 二、for循环 三、range函数 四、for循环变量的作用域 五、continue 和 break 一、while循环 i 1 while i < 100:print("循环执行中")print("当前循环第 %s 次" % i)i 1 print("循环执行完成") 循环执行中 当前循…

安防监控/视频存储/视频汇聚平台EasyCVR接入海康Ehome车载设备出现收流超时的原因排查

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。视频汇聚平台既具…

vxe table虚拟滚动

需求背景: 表格涉及手工录入&#xff0c;当数据量超过30条时&#xff0c;编辑会有明显卡顿&#xff0c;数据量越大&#xff0c;卡顿时间越久。 产品框架&#xff1a; vue2.5.2 view-design4.7.0 PS&#xff1a;前端基本没人管的老项目。。 原因: 1、组件实例过多 2、v…

剪枝基础与实战(5): 剪枝代码详解

对模型进行剪枝,我们只对有参数的层进行剪枝,我们基于BatchNorm2d对通道重要度 γ \gamma γ参数进行稀释训练。对BatchNorm2d及它的前后层也需要进行剪枝。主要针对有参数的层:Conv2d、BatchNorm2d、Linear。但是我们不会对Pool2d 层进行剪枝,因为Pool2d只用来做下采样,没…

testNG-@Factory详解+demo

Factory详解 简介策略&#xff1a;实例: 简介 Factory注解从字面意思上来讲就是采用工厂的方法来创建测试数据并配合完成测试&#xff0c;其主要应对的场景是&#xff1a;对于某一个测试用例或方法&#xff0c;我们需要输入多个测试数据进行测试&#xff0c;并且这些测试数据可…

【typeof instanceof Object.prototype.toString constructor区别】

几个数据类型判断区别 typeofinstanceofObject.prototype.toStringconstructor typeof 它返回的是一个字符串&#xff0c;表示未经过计算的操作数的类型 typeof(undefined) //"undefined"typeof(null) //"object"typeof(100) //"number"typeof…