一。标准库定义的函数对象:
标准库定义了一组用于算术、关系、逻辑运算的函数对象类,他们都是类模板,定义在头文件functional中;
1. 在这里举一个算术函数对象类型的例子:plus<Type> 对2个给定元素进行 + 运算,它定义了调用操作符的类模板,所以是二元函数对象;
要对数值1和2进行加法运算,可以写如下代码:
plus<int> add; //定义加法运算的类模板的实例;
int sum = add(1, 2); //调用了类模板plus定义的调用操作符函数;
2. 将标准库函数对象应用于算法,用到二元函数对象greater<Type>,返回真假值,如果第一个参数大于第二个参数,返回真值,否则返回假值;
例如,对vector 中的元素从大到小排序:
int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
vector<int> ivec(a, a+8);
sort(ivec.begin(), ivec.end(), greater<int>()); //算法sort的第三个实参为一个临时对象,由类模板greator<Type>实例化,并调用默认构造函数生成临时对象,算法sort使用该临时对象的调用操作符比较元素;
二元函数对象返回的真假值,是第一个参数相对于第二个参数的结果,即第一个参数小于,等于,或大于第二参数,则返回真值;
二。函数适配器:
对于上述例子,如果在vector中查找大于5的所有元素,我们可以使用算法find_if,但是find_if的第三个参数为一个接受一个形参的函数,而且find_if只传递一个实参到函数对象,但是函数对象greator<Type>是二元函数对象,接受两个形参,并且还要和被查找的值5进行比较,所以以下写法是错误的:
find_if(ivec.begin(), ivec.end(), greater<int>());
现在遇到的问题就是如何将接受两个形参的函数对象转换为接受一个形参的函数对象,以及如何指定被比较的数值5,于是函数适配器产生了:
函数适配器就是通过将一个操作数绑定到给定值而将二元函数对象转换为一元函数对象,函数适配器分为两类:绑定器 与 求反器;
1. 绑定器:bind1st:将给定值绑定到二元函数对象的第一个实参; bind2nd:将给定值绑定到二元函数对象的第二个实参;他们的返回值都是一元函数对象;
此例中,可以将数值5绑定到二元函数对象greater<Type>的第二个实参,那么greater<Type>的第一个实参就由find_if算法函数提供,因此使用bind2nd适配器;
vector<int>::iterator ite = ivec.begin();
while((ite = find_if(ite, ivec.end(), bind2nd(greater<int>(), 5))) != ivec.end())
{
cout << *ite << " ";
ite++;
}
bind2nd返回一个一元函数对象,根据greater<int>的实参类型进行实参模板推断,在这里推断出的模板实参是int类型,根据构造函数greater<int>()生成的greater函数对象,返回一个带有两个实参返回类型为bool型的函数对象,第一个实参是vector元素的类型,第二个就是被比较的数值5,形式类似 boo fun(int val, 5),然后就可以用该一元函数对象对每个元素同数值5进行比较了;
此例也可以使用适配器 bind1st 与 函数对象less<Type>进行组合,即将5绑定到 less 的第一个操作数,第二个参数就是算法函数传进的元素,less<Type>用于比较第一个值是否小于第二个值;
2. 求反器:not1:对一元函数对象的结果取反; not2:对二元函数对象的结果取反;
//如下语句功能是统计小于等于5的元素个数,用到了表示 <= 的函数对象less_equal<Type>;
size_t n1 = count_if(ivec.begin(), ivec.end(), bind2nd(less_equal<int>(), 5));
如果改为统计不小于等于5的元素个数,修改语句如下:
size_t n1 = count_if(ivec.begin(), ivec.end(), not1(bind2nd(less_equal<int>(), 5)));
因为bind2nd返回的是一元函数对象,所以使用not1,而不是not2;
全部代码:
#include <functional>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
vector<int> ivec(a, a+8);
size_t n1 = count_if(ivec.begin(), ivec.end(), bind2nd(less_equal<int>(), 5));
cout << "n1:" << n1 << endl;
//size_t n = count_if(ivec.begin(), ivec.end(), not1(bind2nd(less_equal<int>(), 5)));
size_t n2 = count_if(ivec.begin(), ivec.end(), bind1st(less_equal<int>(), 5));
cout << "n2:" << n2 << endl;
less_equal<int> le;
size_t n3 = le(5, 8);
cout << "n3:" << n3 << endl;