《C++标准程序库》小结八章-仿函数

1、仿函数有很多名字,比如函数对象,functional objects,functor,这些都是指代一个东西。


2、仿函数的优势是可以保存状态,其表面实现方式是在class对象内部重载operator()函数,模仿了函数foo()的形式来实现函数功能

比如void foo()转换成functor的基本形式:

class FunctionObejectType

{

public:

void operator(){.......}

int status;

}


3、C++中,仿函数比(非内联)函数指针效率高。不过在非STL场合,推荐用函数指针,比如纯C环境用了大量的函数指针,效率非常高。


4、注意传入目标函数的STL仿函数,是通过值传递进来的,被复制了一份,目标函数内部对仿函数的修改,不影响原来的仿函数


5、如果想要使得传入STL的仿函数发生变化,使用引用传递。for_each()函数的返回值就是改变后的仿函数。注意怎么使用引用传递,比如generate_n函数:

IntSequenceseq(1);//IntSequence是一个仿函数

generate_n<back_insert_iterator<list<int>> ,int, IntSequence&>(back_inserter(coll), 4, seq);

要在模板列表明确标示出是引用


6、《C++标准程序库》P303 说明remove_if有一个问题,因为其内部实现的find_if会把仿函数再次复制一份,如果编写的仿函数会自动变化,那么每次执行find_if函数使用的仿函数不会还是原版不会变化,从而产生bug,所以你最好自己重新做一个remove_if。另外这个例子也说明,仿函数的operator()重载最好是const,不然会出现很多莫名其妙的问题。


7、加入#include<functional> 可以使用很多已经写好的仿函数,并且可以使用bind系列函数。vs2008 sp1的tr1标准、boost和C++11的新bind函数有更强大的功能。


8、bind系列和not1,not2函数就是所谓的函数配接器。03标准里面有bind1st和bind2nd函数。灵活性已经很强了,不过只适用于仿函数,普通函数需要转换,见第10条。例子:

pos = find_if(coll.begin(), coll.end(), not1(bind2nd(modulus<int>(), 2)));//返回第一个偶数

 

9、成员函数的配接器,就是直接使用成员函数来完成STL的功能部分。使用方法有两种:

a)             mem_fun_ref(op),op是对象的一个成员函数的引用。用法:for_each(coll.begin(),coll.end(), bind2nd(mem_fun_ref(&Persom::print), “it is ”));

b)            mem_fun(op),op是对象指针的成员函数,注意这种情况下容器中存放的是对象指针。

这里有一个历史问题,就是mem_fun其实最好应该命名为mem_fun_ptr,不过最终没有这样做,很遗憾。


10、ptr_fun()可以把普通函数变为配接器可用组件。例子:

pos =find_if(coll.begin(), coll.end(), not1(ptr_fun(check)));

 

11、自定义仿函数,必须得继承unary_function和binary_function模板,才能使用配接器。


12、组合型函数(很强大的配接器)没有纳入STL标准,不追求效率可以自己实现,很简单。请参考《STL源码剖析》8.4.3节的实现。其接口有如下几种:

接口

本书名称

SGI STL标准

f(g(elem))

compose_f_gx

compose1

f( g(elem1, elem2) )

compose_f_gxy

 

f( g(elem) , h(elem) )

compose_f_gx_hx

compose2

f( g(elem1) , h(elem2) )

compose_f_gx_hy

 

 

书上的例子充分体现了函数也是对象的思想。其应用和C的函数指针有异曲同工之妙。

你可能感兴趣的:(《C++标准程序库》小结八章-仿函数)