所有的仿函数定义在头文件<functional>中。
1.定义及分析
仿函数就是一个定义了operator()的对象。
class X
{
public:
//define "function call" operator
return-value operator() (arguments) const;
...
};
//现在这个类对象就可以当做函数一样使用
X fo;
...
fo(arg1, arg2); //call operator () for function object fo
//等同于
fo.operator() (arg1,arg2); //调用对象fo的operator()
凡是行为像函数,那么这个对象就是函数。仿函数就是这个意思,但是STL中为什么要用仿函数而不直接用函数呢?
首先STL是一个有自己规则的框架,函数指针无法和STL其他组件搭配(配接器),产生更灵活的变化:
仿函数应当有能力被函数配接器修饰,然后彼此合作形成一个整体。为了可配接仿函数需要定义自己的相应型别(和迭代器的型别的作用是一个含义)。由于STL只使用一元和二元仿函数,所以定义了两个class:unaru_function和binary_function。这两个类没有成员,只有一些型别定义。任何仿函数,只要依个人需求选择继承其中一个class,便自动拥有了那些相应型别,也就自动拥有了配接能力。
其次仿函数相对于函数指针有其自身优点:
1、 仿函数是智能型函数
就好比智能指针的行为像指针,其就可看作是一个指针。但是智能指针是定义的一个类对象,所以在具备指针功能的同时也有其他的能力。仿函数的能力也可以超越operator()。因为仿函数可以拥有成员函数和成员变量,这意味着仿函数拥有状态。另一个好处是可以在执行期初始化它们。
class AddValue
{
private:
int theValue; //the value to add
public:
AddValue(int v) : theValue(v) {}
void operator() (int& elem) const
{
elem += theValue;
}
};
AddValue addx (x); //+x
AddValue addy (y); //+y
AddValue(10))//常量
AddValue (*coll. begin())//变量
2、 仿函数都有自己的型别
这就是泛型编程编写仿函数。
3、 仿函数通常比一般函数快
就template的概念而言,由于更多细节在编译器就已确定,所以通常可能进行更好的最佳化。
2.预定义的仿函数
2.1算术类
除了否定为一元,其他都为二元仿函数。
加法:plus<T>
减法:minus<T>
乘法:multiplies<T>
除法:divides<T>
求余:modulus<T>
否定:negate<T>
2.2关系运算类
都是二元仿函数。
等于:equal_to<T>
不等于:not_equal_to<T>
大于:greater<T>
大于等于:greater_equal<T>
小于:less<T>
小于等于:less_equal<T>
2.3逻辑运算类
与和或为二元仿函数,否为一元仿函数。
与:logical_and<T>
或:logical_or<T>
否:logical_not<T>
3.仿函数配接器
仿函数配接器是配接器(仿函数、容器、迭代器)中最大的一部分。主要运用到的如以下所示:
绑定第一个参数为定值:bind1st(op,x)——效果op(x,param)
绑定第二个参数为定值:bind2nd(op,x)——效果op(param,x)
对一元仿函数逻辑取反:not1(op)——效果!op(param)
对二元仿函数逻辑取反:not2(op)——效果!op(param1,param2)
SGI版本特有的还有compose1和compose2,就是组合函数的意思:
compose1(op1,op2)——效果op1(op2())
举例:
判定元素不小于12:bind2nd(greater_equal<int>(),12)或者not1(bind2nd(less<int>(),12))
对元素x执行(x+2)*3:compose1(bind2nd(multiplies<int>,3),bind2nd(plus<int>(),2))
另外的函数配接器就是针对成员函数而设计的函数配接器:
mem_fun_ref(op) 调用op,是某对象的一个const成员函数
men_fun(op) 调用op,是某对象指针的一个const成员函数
注意,被men_fun_ref和men_fun调用的成员函数必须是const,C++标准库暂时不支持non-const成员函数提供函数配接器。
class Person
{
private:
std::string name;
public:
...
void print() const
{
std::cout << name << std::endl;
}
void printWithPrefix (std::string prefix) const
{
std::cout << prefix << name << std::endl;
}
};
void foo (const std::vector<Person>& coll)
{
using std::for_each;
using std::bind2nd;
using std::mem_fun_ref;
//对各个元素调用成员函数print
for_each (coll.begin(), coll.end(),mem_fun_ref(&Person::print));
//对各个元素调用成员函数printWithPrefix
//-"person: "是传递的一个参数,所以使用了bind2nd
for_each (coll.begin(), coll.end(),bind2nd (mem_fun_ref (&Person::printWithPrefix),"person: "));
}