概述
仿函数,也叫做函数对象。
- 就实现意义而言,“函数对象”比较贴切:一种具有函数特性的对象
- 就行为而言,“仿函数”更贴切:这种东西可以像函数一样被调用,被调用者则以对象所定义的function call operator扮演函数的实质角色
仿函数的主要作用?用来搭配STL算法
- STL所提供的各种算法,往往有两个版本。其中一个版本表现出最常用的某种运算,第二个版本则表项出最泛化的演算流程,允许用户“以template参数来指定所要才行的策略。
- 以accumulate为例,其第一版本将指定范围内的所有元素相加,第二版本允许你指定某种操作,取代第一版本中的“相加”行为
- 以sort为例,其第一版本以operator<为排序时的元素位置调整依据,第二版本则运行用户指定任何“操作”,务求排序后的两两相邻的元素都能令该操作结果为true
- 要将某种“操作当做算法的参数,有两种方法:
- 第一种:先将“操作”设计为一个函数,再将函数指针当做算法的一个参数
- 第二种:将“操作”设计为一个仿函数(在语言层面是一个class),再以该仿函数产生一个对象,并以此对象作为算法的一个参数
- 那为什么不用“函数指针”而要引入仿函数呢?因为函数指针不能满足STL对抽象性的要求,也不能满足软件积木的要求:函数指针无法和STL其他组件(比如adapter)搭配,产生更灵活的变化
就实现上来看,仿函数其实是一个“行为类似函数”的对象。为了能够“行为类似函数”,其类别定义中必须自定义(或者说改写、重载)function call运算子(operator())。拥有这样的运算子之后,我们就可以在仿函数的对象后面加上一对(),以此调用仿函数定义的operator()
#include <functional>
#include <iostream>
int main(){
std::greater<int> ig;
std::cout << std::boolalpha << ig(4, 6) << "\n";
std::cout << std::greater<int>()(4, 6);
}
STL仿函数的分类,如果以操作数的个数划分,可以为:
以功能划分:
任何应用程序想要使用STL内建的仿函数,必须引入<functional>
头文件,STL将它们实际定义于<stl_functional.h>
中
可配接(Adaptable)的关键
在STL的六大组件中,仿函数扮演一种策略的角色,它可以让STL算法更灵活。而更灵活的关键,在于STL仿函数的可配接性。
所谓的可配接性,指的是STL 仿函数应该有能力被函数配接器修饰,彼此像积木一样串接。为了adaptable,每一个仿函数必须定义自己的相应型别。
- 这些相应型别是为了让配接器能够取出,获得仿函数的某些信息。
- 相应型别都只是一些typedef,所有必要操作在编译期就全部完成了,对程序的执行效率没有影响,不带来任何额外负担。
- 仿函数的相应型别主要用来表现函数参数型别和传回值型别。为了方便起见,<stl_functional.h>定义了两个classes,分别表示一元仿函数和 二元仿函数,其中没有任何data members或者members function,唯有一些型别定义。任何仿函数,只要依个人需求选择继承其中一个class,就自动拥有了那些相应型别,也就自动拥有了配接能力
unary_function
unary_function用来表示一元函数的参数型别和返回值型别。定义如下:
使用如下:
// 下面仿函数继承了unary_function
template<class T>
struct negate : public std::unary_function<T, T>{
T operator() (const T& x) const {
return -x;
};
};
// 下面adaptable用来表示某个仿函数的逻辑负值
template<class Predicate>
class unary_negate{
public:
bool operator() (const typename Predicate::argument_ctype& x) const{
}
};
binary_function
binary_function用来表示一元函数的第一参数型别、第二参数型别。定义如下:
使用如下:
// 下面仿函数继承了binary_function
template<class T>
struct plus : public std::binary_function<T, T, T>{
T operator() (const T& x, const T & y) const {
return x + y;
};
};
// 下面adaptable用来将某个二元仿函数转换为一元仿函数
template<class Operation>
class binder1st{
protected:
Operation op;
typename Operation::first_argument_type value;
public:
bool operator() (const typename Operation::second_argument_type& x) const{
}
};
算术仿函数
STL内建的算术类仿函数,支持加法、减法、乘法、除法、模数(余数)、否定运算。除了“否定”运算为一元运算,其他都是二元运算
使用:
#include <functional>
#include <iostream>
int main(){
std::plus<int> plusobj;
std::minus<int> minusobj;
std::cout << plusobj(3, 5) << "\n";
std::cout << minusobj(3, 5) << "\n";
std::cout << std::negate<int>()(3) << "\n";
std::cout << std::plus<int>()(3, 5) << "\n";
}
std::accumulate(vec.begin(), vec.end(), std::multiplies<int>());
关系运算符
STL支持6中关系运算,每一种都是二元运算
定义如下: