html5微网站源码,代理网址ip,阿里云域名 设置网站,长沙正规关键词优化价格从优转载#xff1a;http://www.cnblogs.com/wuchanming/p/4411867.html 本文乃作者学习《C标准程序库》的学习笔记#xff0c;首先介绍了仿函数#xff08;函数对象#xff09;和函数适配器#xff08;配接器#xff09;的概念#xff0c;然后列出STL中所有的仿函数#x…转载http://www.cnblogs.com/wuchanming/p/4411867.html 本文乃作者学习《C标准程序库》的学习笔记首先介绍了仿函数函数对象和函数适配器配接器的概念然后列出STL中所有的仿函数以及函数适配器并摘录了几个例子演示仿函数和函数适配器的用法最后讨论了仿函数的组合以及实现方法。 1.仿函数是什么东西 《C标准程序库》里对仿函数的解释是仿函数是泛型编程强大威力和纯粹抽象概念的又一例证。你可以说任何东西只要其行为像函数它就是一个函数。因此如果你定义了一个对象行为像函数它就可以被当做函数来用。 那么什么才算具备函数行为呢所谓函数行为是指可以使用小括号传递参数籍以调用某个东西。例如
function(argc1, argc2); 如果你指望对象也可以如此这般就必须让它们也可以被调用——通过小括号的运用和参数的传递。你只需要定义operator()并给予合适的参数型别
class X
{public: // define function call operator return-value operator()(arguments) const; ...... }; 现在你可以把这个类别的对象当做函数来调用了
X fo;
...... // call operator () for function object to fo(argc1, argc2); 上述调用等价于
fo.operator() (argc1, argc2); 总结如下:
函数对象是一个普通对象重载了operator ()操作符函数对象一般都比较简单主要用到operator()操作其他成员函数和成员变量都是为operator()服务 为了帮助理解仿函数我们来看一个例子
#include algorithm
class gen_by_two { public: gen_by_two( int seed 0 ) : _seed( seed ){} int operator()() { return _seed 2; } private: int _seed; }; vectorint ivec( 10 ); // fills ivec: 102 104 106 108 110 112 114 116 118 120 generate_n( ivec.begin(), ivec.size(), gen_by_two(100) );或者generate_n( ivec.begin(), ivec.size(), gen_by_two() ); 上面的程序使用generate_n函数给容器赋值在调用gen_by_two(100)的时候我们其实是生成了一个对象并调用对象的构造函数给成员变量赋值然后多次v.size())调用该变量的operator()成员函数将返回的值依次存入容器中。 2.函数适配器又是什么东西 函数适配器又称函数配接器是只能够将仿函数和另一个仿函数或某个值或某一个函数结合起来的仿函数。函数适配器声明于functional中。 下面来看一个例子
find_if(coll.begin(), coll.end(), //range bind2nd(greaterint(), 42));criterion 其中表达式bind2nd(greaterint(),42)导致一个组合型的仿函检查某个int值是否大于42.实际上bind2nd是将一个二元仿函数转换为一个一元仿函数。bind2nd的意思就是将42作为比较(greaterint())函数的第二个参数也就相当于是elem.value 42如果容器中没有42这个值那么下面这条语句和上面的语句是一样的。
find_if(coll.begin(), coll.end(), //range bind1st(lessint(), 42));criterion 上面两个小例子演示了适配器的功能同时还讲解了bind1st和bind2nd的区别。 3.预定义的仿函数 4.预定义的函数适配器 5.仿函数(以及函数适配器)的使用示例 下面摘录几个《C标准程序库》上的例子以及个别我自己补充的实例用于演示仿函数的使用希望能够通过例子快速掌握仿函数。 5.1 查找25或者35第一次出现的位置
pos find_if(coll.begin(), coll.end(), //range compose_f_gx_hx(logical_orbool(), //criterion bind2nd(equal_toint(), 25), bind2nd(equal_toint(), 35))); 5.2 将集合中全部元素都设为相反值
transform(coll.begin(), coll.end(),//source coll.begin(),//destination negateint());//operation 5.3 对集合中的所有元素求平方
transform(coll.begin(), coll.end(),//first source coll.begin(),//second source coll.begin(),//destination multipliesint());//operation 5.4 所有元素乘以10
transform(coll.begin(), coll.end(),//source back_inserter(coll2),//destination bind2nd(multipliesint(),10));//operation 5.5 将a替换为b
replace_if(coll2.begin(), coll2.end(),//range bind2nd(equal_toint(), 70),//replace criterion 42);//new value 5.6 删除小于50的元素
coll.erase(remove_if(coll.begin(), coll.end(),//range bind2nd(lessint(), 50)), //remove criterion coll.end()); 5.7 返回第一个偶数
pos find_if(coll.begin(), coll.end(), //range not1(bind2nd(modulusint(), 2))); 上面几个例子都还是挺使用的返回第一偶数么怎么看怎么奇怪没有关系我们来看一个不奇怪的 5.8 调整数组顺序使得奇数位于偶数前面
stable_partition(v.begin(), v.end(), bind2nd(modulusint(), 2)); 关于这里用到的泛型算法如果还有不熟悉的可以参考这里 5.9 mem_fun_ref 与mem_fun 的区别以及用法
mem_fun_ref:调用某个对象的成员函数mem_fun:功能和mem_fun_ref 一样如果容器里存放的是指向对象的指针而不是对象则应该使用mem_fun 下面来看一个使用mem_fun_ref 的例子假设我们定义了一个类Person,并且定义了一个print 的成员函数容器coll 里存放了coll.size() 个Person 对象现在要调用每个对象的print 成员函数那么我们就可以像下面这样。
class Person
{ public: ... void print() const { std::cout name std::endl; } void printWithPrefix(std::string prefix) const { std::cout prefix name std::endl; } private: std::string name; }; void foo(const std::vectorPerson coll) { for_each(coll.begin(), coll.end(), mem_fun_ref(Person::print)); } 我们不能直接把一个成员函数传递给一个算法所以这里必须运用函数适配器下面这种做法会导致编译错误。
for_each(coll.begin(), coll.end(), Person::print); //ERROR 通过使用函数适配器我们还可以像被调用的成员函数传递一个参数。如下所示 //call member function printWithPrefix() for each elementfor_each(coll.begin(), coll.end(), bind2nd(mem_fun_ref(Person::printWithPrefix), person:)); 5.10 ptr_fun ptr_fun 使得我们能够在其他函数适配器中使用一般函数加入你自己定义了一个函数check()用于检验容器中的中的元素是否符合某种条件你就可以这样
pos find_if(coll.begin(), coll.end(), not1(ptr_fun(check))); 这里不能使用not1(check)因为not1()需要用到由仿函数提供的某些特殊型别. 第二种用法是当你有一个双参数的全局函数又想把它当做一个单参数函数来使用可以用如下语句
//find first string that is not empty
pos find_if(coll.begin(), coll.end(), bind2nd(ptr_fun(strcmp),)); 6.让自定义的仿函数也可以使用函数适配器 你可以编写自己的仿函数但如果希望它们能够和函数适配器搭配运用就必须满足某些条件必须提供一些型别成员来反映其参数和返回值的型别。为了方便我们C标准库提供了一些结构如下 转载http://mingxinglai.com/cn/2012/09/function-object/