C++泛型编程:函数对象(仿函数)和谓词的概念、常见内建函数对象

要学习标准库STL,就不得不去了解函数对象和谓词,于是本人今天写篇博客做简要总结。

函数对象
概念:重载函数调用操作符的类,其对象称为函数对象。函数对象使用重载的()时,行为类似函数调用,因此也称为仿函数。另外,仿函数并不是类的特权,在结构体中也可以通过重载()实现仿函数。
本质:是一个类,或是一个结构体,不是一个函数。
使用特点
1.函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值。例如:

#include<iostream>
using namespace std;

class myAdd
{
public:
	int operator()(int a, int b)
	{
		return a + b;
	}
};

int main()
{
	myAdd add;
	cout << myAdd()(1, 2) << endl;//通过创建匿名函数对象调用()
	cout << add(3, 4) << endl;//通过函数对象调用()
	return 0;
}

2.函数对象超出普通函数的概念,函数对象可以有自己的状态。因为函数对象本质是一个类,所以可以在类内创建记录函数状态的成员,而普通函数无法做到,比如想要知道普通函数的调用次数,需要用户自己定义变量计数。例如:

#include<iostream>
#include<string>
using namespace std;

class myPrint
{
public:
	void operator()(string s)
	{
		cout << s << endl;
		times++;
	}
	static int times;//内部自己状态:调用次数
};
int myPrint::times = 0;//初始化

int main()
{
	myPrint myprint;
	myPrint()("C++STL");//匿名对象调用
	myprint("Hello world!");//函数对象调用
	myPrint()("Algorithm");
	myprint("Data Structure");
	cout << myPrint::times << endl;//输出调用次数,应为4
	return 0;
}

3.函数对象可以作为参数传递。例如:

#include<iostream>
#include<string>
using namespace std;

class myPrint
{
public:
	void operator()(string s)
	{
		cout << s << endl;
	}
};

void doPrint(myPrint print, string s)
{
	print(s);
}

int main()
{
	myPrint myprint;
	doPrint(myPrint(), "C++STL");//可以传递匿名对象
	doPrint(myprint, "Hello world!");//也可以传函数对象
	return 0;
}

谓词
概念:返回值为布尔类型bool的仿函数称为谓词。如果operator()接受一个参数,叫做一元谓词,如果operator()接受两个参数,叫做二元谓词
使用:在C++源码中,谓词形参用 _Pr _Pred 表示,即是说如果一个函数形参列表中出现_Pr _Pred,表示要给该函数传递一个谓词。既可以传递匿名的函数对象,也可以先在函数外定义好作用域足够的函数对象,再传递进去。如果形参列表出现 typename _Pr ,则是要传递谓词所在的类或结构体的名称。

提示:当使用setmap时,不想按照内置数据类型默认排序规则排序,或者保存的是自定义数据类型时,需要自行定义数据的排序规则,即定义一个用于排序的二元谓词,并把二元谓词的类的名称传递给类模板。例如:

class myCmp
{
public:
   bool operator()(int a,int b)
   {
        return a>b;
   }
};
set<int,myCmp> s;

当使用algorithm中的算法模板处理自定义数据,或者不想按默认规则处理时,也需要自行写出完成相应逻辑判断的谓词,并把谓词传递给函数模板。

内建函数对象:C++的functional头文件里已经帮我们重载了很多(),我们可以直接拿来使用,下面给出常见的内建函数对象:
1.算术仿函数:值得注意的是,前5个仿函数只支持两个相同数据类型的操作数做运算,所以只传递一个操作数的数据类型,另外注意,取反仿函数是一元谓词。

template<class T> T plus<T>//加法
template<class T> T minus<T>//减法
template<class T> T multiplies<T>//乘法
template<class T> T divides<T>//除法
template<class T> T modulus<T>//取模
template<class T> T negate<T>//取反,即取负数

2.关系仿函数:同上,它们只支持两个相同数据类型的操作数做比较,只传递一个操作数的数据类型。

template<class T> bool equal_to<T>//判断相于=
template<class T> bool not_equal_to<T>//判断不等于!=
template<class T> bool greater<T>//判断大于>
template<class T> bool greater_equal<T>//判断大于等于>=
template<class T> bool less<T>//判断小于<
template<class T> bool less_equal<T>//判断小于等于<=

3.逻辑仿函数:同样地逻辑与、逻辑或只支持两个相同数据类型的操作数做运算,只需传递一个操作数的数据类型,注意逻辑非是一元谓词。

template<class T> bool logical_and<T>//逻辑与
template<class T> bool logical_or<T>//逻辑或
template<class T> bool logical_not<T>//逻辑非
原创文章 34 获赞 87 访问量 2725

猜你喜欢

转载自blog.csdn.net/qq_44643644/article/details/105766917