从SGI的STl文档来看,STL functor(function object)模块主要分为两个部分:预先定义的functor
以及functor adaptors。除此之外,为了使客端程序员写出适用于functor adaptor的functor,STL
又定义了一系列基本上只包含typedef的空类型(例如unary_function)。用户只需要派生这些类,即
可让自己写的functor被functor adaptor使用。以下称类基类型为base functor。
base functor包括: unary_function, binary_function,分别表示只有一个参数的函数和有两个参数
的函数。实际上STL里还有一个所谓的generator,代表没有参数的函数。因为STL泛型算法一般最多
只会使用两个参数的函数,所以这里并没有定义更多参数的base functor。
可被functor adaptor使用的functor又称为adaptable function,根据参数的个数,会被命名为诸如
adaptable unary function, adaptable binary function。
一个返回值为bool的functor又被称为predicate,可被用于functor adaptor的predicate被称为
adaptable predicate。其实所谓的adaptable,只需要在类型内部typedef一些类型即可,一般包括
first_argument_type, second_argument_type, result_type。functor adaptor会使用这些定义。
预定义的functors都是些很简单的functor,基本上就是封装诸如plus, minus, equal_to之类的算术
运算,列举一个predefined functor的代码:
template <class _Tp>
struct plus : public binary_function<_Tp, _Tp, _Tp>
{
_Tp operator()(const _Tp& __x, const _Tp& __y) const
{
return __x + __y;
}
};
因为从binary_function(即我所谓的base functor)派生,因此这些predefined functor也是adaptable
function。
functor adaptors里有很多有趣的东西,其实functor adaptor也是一些functor(从SGI的观点来看,一般
的C函数,函数指针都算作functor)。所不同的是,他们通常会适配(adapt)一种functor到另一种。例如:
std::binder1st,严格地说它是一个函数模板,它会把一个adaptable binary function转换为一个
adaptable unary function,并绑定一个参数。又如: std::ptr_fun,它会将一个只有一个参数的C函数
适配成一个pointer_to_unary_function的functor。
下面列举一些具体的代码:
关于base functor,基本上就只有unary_function, binary_function :
template <class _Arg, class _Result>
struct unary_function
{
typedef _Arg argument_type;
typedef _Result result_type;
};
关于predefined functor,如之前列举的plus一样,再列举一个:
template <class _Tp>
struct greater : public binary_function<_Tp, _Tp, bool>
{
bool operator()(const _Tp& __x, const _Tp& __y) const
{
return __x > __y;
}
};
关于functor adaptors,也是我觉得比较有趣的部分,多列举几个:
template <class _Operation, class _Tp>
inline binder1st<_Operation>
bind1st(const _Operation& __fn, const _Tp& __x)
{
typedef typename _Operation::first_argument_type _Arg1_type;
return binder1st<_Operation>(__fn, _Arg1_type(__x));
}
bind1st返回的binder1st定义为:
template <class _Operation>
class binder1st : public unary_function<typename _Operation::second_argument_type,
typename _Operation::result_type>
{
protected:
_Operation op;
typename _Operation::first_argument_type value;
public:
binder1st(const _Operation& __x, const typename _Operation::first_argument_type& __y):
op(__x), value(__y)
{}
typename _Operation::result_type
operator()(const typename _Operation::second_argument_type& __x) const
{
return op(value, __x);
}
typename _Operation::result_type
operator()(typename _Operation::second_argument_type& __x) const
{
return op(value, __x);
}
};
值得一提的是,ptr_fun以及相关的pointer_to_unary_function, pointer_to_binary_function,基本上
就是用来绑定C函数的组件,不过这里采用了很基础的模板技术,因此只实现了绑定一个参数和两个参数
的C函数。这种组件类似于loki中的functor,以及boost中的bind,只是功能弱很多。与之相关的还有
mem_fun, mem_fun_ref, mem_fun1, mem_fun1_ref等,这些都是用于绑定成员函数的。另一方面,与其说
是绑定,还不如说适配,即将函数适配为functor(特指重载operator()的类)。( Mem_fun_t is an adaptor
for member functions )采用这些(ptr_fun, mem_fun之类的东西)组件,客端程序员可以很容易地将各种
运行体(Kevin似乎很喜欢发明各种名字)(C函数、成员函数)适配成functor,从而与STL泛型算法结合。
例如, SGI文档中给出的mem_fun例子:
struct B {
virtual void print() = 0;
};
struct D1 : public B {
void print() { cout << "I'm a D1" << endl; }
};
struct D2 : public B {
void print() { cout << "I'm a D2" << endl; }
};
int main()
{
vector<B*> V;
V.push_back(new D1);
V.push_back(new D2);
V.push_back(new D2);
V.push_back(new D1);
for_each(V.begin(), V.end(), mem_fun(&B::print));
}
注:以上分析基于dev-cpp中自带的stl,源代码见stl_functional.h。