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

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

std::binary_function

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

template <class _Arg1, class _Arg2, class _Result>
struct binary_function
{   // base class for binary functions
    typedef _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 operands
        return (op(value, _Right));
    }

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

protected:
    _Fn2                               op;      // the functor to apply
    typename _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 adapter
    typename _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 operands
	return (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));

猜你喜欢

转载自blog.csdn.net/weixin_43717839/article/details/132635689