C++基础7:unary_function、binary_function、not1、bind2nd函数


前言

我在前面的文章中介绍了C++中的仿函数和函数适配器,这两个技术在STL中用的很广泛。今天我们研究下STL中的unary_function、binary_function、not1、bind2nd是如何实现的。


一、unary_function、binary_function

这两个函数比较简单,只是对形参和返回值加了别名,也就是typedef。下面看看源代码。

template<typename argType,typename resType>
struct unary_function
{
	typedef argType argument_type;
	typedef resType result_type;
};

template<typename arg1Type,typename arg2Type,typename resType>
struct binary_function
{
	typedef arg1Type first_argument_type;
	typedef arg2Type second_argument_type;
	typedef resType result_type;
};

你可能会纳闷,为什么要定义这两个没有任何成员的类。这关系到后续的函数适配器,适配器都是基于这两个类的。

二、bind2nd

bind2nd是一个函数适配器,它的作用是可以绑定第二参数;可以被适配的对象必须是继承了binary_function的。这就跟前面的联系起来了。

1.函数适配器的定义

函数适配器也可以叫函数修饰器,它可以给仿函数增加一些修饰功能,最后表现出来也是仿函数的样子。此处可类比设计模式中的修饰者模式。
我的理解函数适配器最重要的是两个函数,一个是构造函数,一个是Operator()重载。
Operator()重载没啥好讲的,函数适配器适配的对象是仿函数,适配完成后,还得是一个仿函数。
函数适配器的构造函数,需要接受一个仿函数和可能的参数 (有没有参数,看改适配器的功能),保存仿函数参数,供Operator()重载函数中使用

bind2nd 代码如下:

template<typename OP>
class bind2nd : public unary_function<typename OP::first_argument_type,typename OP::result_type>
{
protected:
	OP op;
	typename OP::second_argument_type arg;
public:
	bind2nd(const OP& x,typename const OP::second_argument_type& y):op(x),arg(y){}

	typename OP::result_type Operator()(typename const OP::first_argument_type& x)
	{
		return op(x,arg);
	}
}

关于以上的代码,有几个要点:
1.bind2nd构造函数接收一个仿函数和一个参数,该参数作为绑定的第二参数。
2.bind2nd只能适配继承了binary_function类的仿函数,因为构造函数和()重载函数都是用binary_function定义的类型。
比如:typename OP::second_argument_type arg; 等 typename是告诉编译器,后面跟的是一个类型。
3.()重载函数接收仿函数的第一参数,跟构造函数中接收的第二参数一起,作为仿函数的参数进行定义。
4.为了让bind2nd可以被进一步修饰,所以继承了unary_function。为什么不是binary_function呢?因为第二参数被绑定了,所以单参数的仿函数了。

2.bind2nd实例

代码如下:
先定义一个两参数的仿函数

template<typename T>
class greater : public binary_function<T,T,bool>
{
public:
	bool Operator()(const T& a,const T& b)
	{
		return a>b;
	}
}

该函数是比较两个数谁大,其实这样说不准确,不一定是两个数。因为模板仿函数,可以传入任意的实现了大于号运算符的类。

3.使用bind2nd修饰

#include <iostream>
using namespace std;
void main()
{
	int x = 10,y = 20;
	cout << greater<int>(x,y) << endl;

	cout << bind2nd<greater<int>>(greater<int>(),5)(10) << endl;
}

bind2nd<greater>(greater(),5) 这一串代码就是把greater的第二参数绑定成5了。然后把10当成第二参数传入,进行greater的比较。
看着这句代码是不是很长,后面我们可以用模板类的参数类型推断功能,去改写这句代码。

4.改造bind2nd

template<typename OP,typename T>
bind2nd<OP> bind2nd_func(const OP& op,const T& arg)
{
	typedef typename OP::second_argument_type stype;
	return bind2nd<OP>(op,stype(arg));
}

bind2nd_func函数的功能是帮助我们去生成bind2nd。 对于类型T的要求是能够用T类型的变量,初始化OP::second_argument_type类, “stype(arg)” 这句话就是这个要求。

改造后的调用代码,如下:

#include <iostream>
using namespace std;
void main()
{
	int x = 10,y = 20;
	cout << greater<int>(x,y) << endl;

	cout << bind2nd_fun(greater<int>(),5)(10) << endl;
}

这一段比较绕,大家静下心来,好好理解一下。

三、not1

not1也是一个函数适配器,它修饰继承了unary_function的仿函数。作用是在原始操作上进行取反。

1.not1定义

它的构造函数接收一个仿函数,Operator()重载接收仿函数的参数。
源代码如下:

template<typename OP>
class not1 : public myunaryfunction<typename OP::argument_type,bool>
{
protected:
	OP op;

public:
	explicit not1(const OP& x) : op(x) {}

	bool operator()(const typename OP::argument_type& a)
	{
		return !op(a);
	}
};

2.改造not1

跟bind2nd函数一样,我们也需要一个模板函数来生成not1类。
代码如下:

template<typename OP>
not1<OP>& not1_fun(const OP& op)
{
	return not1<OP>(op);
}

3.使用not1

代码如下:

#include <iostream>
using namespace std;
void main()
{
	int x = 10,y = 20;
	cout << greater<int>(x,y) << endl;
	
	if(not1_fun(bind2nd_fun(greater<int>(),5))(10) == true)
		cout << "true" << endl;
	else
		cout << "false" << endl;
}

总结

本篇比较详细的介绍了仿函数和函数适配器。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值