C++ STL新特性:not1 not2 mem_fun mem_fun_ref mem_fn等函数(详解+示例代码)

建议先补充基础知识,否则生啃本节可能会有一定难度:
C++STL:仿函数
C++STL: bind函数绑定

谓词

首先来解释一下,什么是谓词? 当我们调用一个仿函数的时候,我们的仿函数重载的括号运算符函数接受的参数数量决定了是一元谓词,还是二元谓词:

  • 一元谓词仿函数接受一个参数,比如输入一个数字和一个固定的10比较,判断这个数是否有大于10 。这个仿函数就是接受一元谓词的仿函数。
class Greater1
{
public:
	bool operator()(const int& a)const
	{
		return a > 10;
	}
};
  • 二元谓词仿函数接受两个参数,他们两个进行操作,这个仿函数就是接受二元谓词的仿函数。
class Greater2
{
public:
	bool operator()(const int& a,const int& b)const
	{
		return a > b;
	}
};

not1函数

作用:对接受一元谓词的仿函数取反

指定类型

//not:对一元谓词的仿函数取反
class Greater1
{
public:
	using argument_type = int;
	bool operator()(const int& val)const
	{
		return val > 10;	//大于10吗
	}
};
cout << boolalpha << Greater1()(50) << endl;	//正常的仿函数
auto _less1 = not1(Greater1());					//给我们自己制作的一元谓词仿函数取反
cout << boolalpha  << "not1我做的: " << _less1(50) << endl;

在这里插入图片描述

需要注意的点:

  • 为什么要在仿函数中加argument_type这个东西?
    解:我们按F12进入not1的定义可以发现:所谓的not1其实也是一个仿函数,叫做unary_function,我们把函数的指针传递给他,所以它就具有了一个函数,它接受一个argument_type的东西做为它的重载括号运算符的形参类型,它有默认的result_type作为它的返回值bool,然后直接对这个函数取反,这样就会形成了我们的一元谓词仿函数的取反。(原理就是这么简单明了)
    在这里插入图片描述
  • not1 只能对接受一元谓词的仿函数取反,无法对二元谓词取反,我们可以用not2。

***继承标准库

我们也可以不在我们的仿函数指定argument_type,直接继承。

//not:对一元谓词的仿函数取反
class Greater1:public unary_function<int,bool>
{
public:
	bool operator()(const int& val)const
	{
		return val > 10;	//大于10吗
	}
};
cout << boolalpha << Greater1()(50) << endl;
auto _less1 = not1(Greater1());			//给我们自己制作的一元谓词仿函数取反
cout << boolalpha  << "not1我做的: " << _less1(50) << endl;

在这里插入图片描述
需要注意的点:

  • 我们通过上一个讲解,可以知道not1的原型为unary_function,接受两个参数,直接继承此类,然后传递两个参数类型,一个是一元谓词类型,一个是返回类型,即可实现和上一个一样的功能。

not2函数

指定类型

class Greater2
{
public:
	using first_argument_type = int;
	using second_argument_type = int;
	bool operator()(const int& a,const int& b)const
	{
		return a > b;
	}
};
cout << boolalpha << Greater2()(5, 10) << endl;
auto _My_less = not2(Greater2());		//给我们自己制作的二元谓词仿函数取反
cout << boolalpha << "not2我做的: " << _My_less(5, 10) << endl;


需要注意的点:

  • 和我们的一元谓词一样,我们的not2二元谓词的原型是:first… 和second…分别作为第一个参数类型和第二个参数类型,默认返回为bool,所以我们直接指定first和second的类型,即可做到对二元谓词仿函数取反。
    在这里插入图片描述

***继承标准库

//not2:对二元谓词的仿函数取反
class Greater2:public binary_function<int,int,bool>
{
public:
	bool operator()(const int& a,const int& b)const
	{
		return a > b;
	}
};
cout << boolalpha << Greater2()(5, 10) << endl;
auto _My_less = not2(Greater2());		//给我们自己制作的二元谓词仿函数取反
cout << boolalpha << "not2我做的: " << _My_less(5, 10) << endl;

在这里插入图片描述

和上面一样,我们直接继承标准库not2的原型 binary_function,分别指定他们的类型,即可。


mem_fun函数

作用:把类成员函数转换为函数对象(仿函数),使用对象指针进行绑定

示例说明:

class Ani
{
public:
	int number = 0;
	void printDog()
	{
		cout << __FUNCTION__ << " 汪汪汪: " << number++ << endl;
	}
	void printCat()
	{
		cout << __FUNCTION__ << " 喵喵喵: " << number++ << endl;
	}
};
int main()
{
	Ani d;
	auto func1 = mem_fun(&Ani::printDog);	//传递成员函数指针,
	func1(&d);		//把成员函数转换为函数对象,使用可调用对象调用成员函数
	d.printDog();
}

在这里插入图片描述

mem_fun函数:把成员函数转换为函数对象,使用对象指针进行绑定,在调用的时候使用对象的指针(不能传递临时对象),即取地址的形式传入到func1函数中,以此来调用绑定的函数。

为什么要传递地址?
解析: mem_fun函数标准库原型:就是一个函数对象(仿函数),在重载的括号运算符里,使用了指针进行访问,因此在使用在个函数时,需要传递对象的指针。
在这里插入图片描述


mem_fun_ref函数

作用:把类成员函数转换为函数对象(仿函数),使用对象引用进行绑定

class Ani
{
public:
	int number = 0;
	void printDog()
	{
		cout << __FUNCTION__ << " 汪汪汪: " << number++ << endl;
	}
	void printCat()
	{
		cout << __FUNCTION__ << " 喵喵喵: " << number++ << endl;
	}
};
int main()
{
	Ani c;
	auto fun2 = mem_fun_ref(&Ani::printCat);	//传递成员函数指针
	fun2(c);
	c.printCat();
	return 0;
}

在这里插入图片描述
mem_fun_ref:与mem_fun类似,只不过它是按照对象的引用进行绑定的,即在调用此函数时,不用取地址符号,它传递的是对象的引用。

注意:不能传递临时对象。

进入到mem_fun_ref的标准库原型:可以看到它也是一个仿函数,重载的括号运算符是按照引用传递的,其他的基本和mem_fun类似。
在这里插入图片描述


mem_fn函数

作用:把类成员函数转换为函数对象(仿函数),使用对象引用,指针,临时对象都能进行绑定

class Ani
{
public:
	void Anis(int a,int b,int c)
	{
		cout << a << " " << b << " " << c << endl;
	}
};
int main()
{
Ani all;
	auto fun3 = mem_fn(&Ani::Anis);
	fun3(Ani(), 1, 2, 3);
	fun3(&all, 1, 2, 3);
	fun3(all, 1, 2, 3);
	return 0;
}

在这里插入图片描述
与前两个分别按指针和引用进行绑定的类似,但不能按临时对象绑定相比。mem_fn可以绑定指针,引用,临时对象等三种都可以。


函数绑定示例

请认真看这个示例:

class Num
{
public:
	Num(const int& data)
		:val(data)
	{}
	void travel()
	{
		cout << val << " ";
	}

private:
	int val;
};
int main()
{
	vector<Num> a;
	for (int i = 0; i < 10; ++i)
	{
		a.emplace_back(i);
	}

	//将成员函数转变为函数对象
	for_each(a.begin(), a.end(),mem_fn(&Num::travel));
	cout << endl;
	for_each(a.begin(), a.end(), mem_fun_ref(&Num::travel));

	cout << endl;
	cout << endl;

	vector<Num*> b;
	for (int i = 0; i < 10; ++i)
	{
		b.emplace_back(new Num(i * 2));
	}
	for_each(b.begin(), b.end(), mem_fun(&Num::travel));

	return 0;
}

解析:

  • 第一个vector: 每一个元素都是一个Num,所以我们可以利用mem_fn或者mem_fun_ref函数类成员函数转换为 函数对象(仿函数),然后for_each算法接受此函数对象,传递进去,最后可以打印出vector的值
  • 第二个vector:每一个元素都是一个Num的指针,所以我们只能使用mem_fun函数 将类成员函数转换为 函数对象,使用指针进行绑定,因此mem_fun只接受指针类型的对象,所以无法使用前两个函数。

他们都提供了打印容器的合适函数类型,为函数的转换提供了方法:
在这里插入图片描述

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yuleo_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值