要读懂本Term所说之内容,不妨请先看懂以下的test codes:
#include#include #include #include #include
#include using namespace std; class Widget { public: int mx, my; //const int yy; Widget(int x = 0, int y = 0) :mx(x), my(y) {} void testfunc()const { cout << "call testfunc!" << endl; } }; //自定义一个判断是否interesting的Pred bool isInteresting(const shared_ptr & pw) { if (pw->mx + pw->my > 6)return true;//此时认为widget是足够有趣的! return false;//此时认为widget是无趣的! } int main(void) { list > widgetPtrs; widgetPtrs.push_back(make_shared (1,2)); widgetPtrs.push_back(make_shared (2, 2)); widgetPtrs.push_back(make_shared (2, 3)); widgetPtrs.push_back(make_shared (6, 7)); widgetPtrs.push_back(make_shared (4, 5)); widgetPtrs.push_back(make_shared (1, 3)); widgetPtrs.push_back(make_shared (2, 4)); //下面首先找到"is Interesting"的Widget对象!并输出其信息! auto it = find_if(widgetPtrs.begin(),widgetPtrs.end(),isInteresting); if(it != widgetPtrs.end()){ cout<<"find the first intersting one!"< 运行结果:
再来看看ptr_fun的源代码:
//将函数指针适配对应的一元函数模板(使得该Functor具有适配性) templateinline pointer_to_unary_function<_Arg, _Result> ptr_fun(_Result (*__x)(_Arg)) { return pointer_to_unary_function<_Arg, _Result>(__x); } //将函数指针适配对应的二元函数模板(使得该Functor具有适配性) template inline pointer_to_binary_function<_Arg1, _Arg2, _Result> ptr_fun(_Result (*__x)(_Arg1, _Arg2)) { return pointer_to_binary_function<_Arg1, _Arg2, _Result>(__x); } ptr_fun只不过是完成一些类型定义(argument_type,first_argument_type,second_argument_type,result_type)的工作而已,但这些类型定义(当然,我们无需知道这些类型定义的细节,这些细节也不重要。只要会用函数适配器,并写出可适配的Functor即可!)恰恰是not1所必须的!实际上,在STL中并非只有not1才有这样的要求!4个标准的函数适配器(not1,not2,bind1st,bind2nd)都要求一些特殊的类型定义。提供了这些必要的类型定义的函数对象则被称之为可适配的(adaptable)函数对象。反之,如果函数对象缺少这些类型定义,则称之为不可适配的。
可适配的函数对象能够与其他STL组件更为默契地协同工作,它们能够应用于更多的上下文环境中,因此你应当尽可能地使你编写的函数对象可以适配(可配接)。这并不需要你付出多少代价,却可以为使用函数子(Functor)类的客户带来诸多的方便!
提供这些类型定义(使得Functor可适配)最简单的方式就是:
①当Functor的operator()有1个形参时,让Functor公有public继承std::unary_function(一元函数适配器类)
②当Functor的operator()有2个形参时,让Functor公有public继承std::binary_function(二元函数适配器类)
编写规则(注意!!!):
规则①传递给std::unary_function和std::binary_function的模板参数正是函数子Functor类的operator()的参数类型与返回值类型,并且返回值类型必须放在上述2个基类模板参数的最后一个位置。(why?你看看下面对应之源码即可看出来了)
规则②传递给std::unary_function和std::binary_function的非指针类型需要去除const和引用(&号)。
规则③对于以指针(包括smart pointer)作为参数or返回值类型的函数子Functor类,一般都让传递给std::unary_function和std::binary_function模板参数的类型与operator()的参数与返回值类型完成相同!
std::unary_function与std::binary_function之源码:
templatestruct unary_function { /// @c argument_type is the type of the argument typedef _Arg argument_type; /// @c result_type is the return type typedef _Result result_type; }; template struct binary_function { /// @c first_argument_type is the type of the first argument typedef _Arg1 first_argument_type; /// @c second_argument_type is the type of the second argument typedef _Arg2 second_argument_type; /// @c result_type is the return type typedef _Result result_type; }; test_codes:
#include#include #include #include #include #include using namespace std; struct myPred1 :public std::unary_function {//一个规范的Functor必须这么干! //因为这么干你的functor的通用型就更强! bool operator()(int v) { return v < 6; } }; struct myPred2 :public std::binary_function {//一个规范的Functor必须这么干! //因为这么干你的functor的通用型就更强! bool operator()(int v1,int v2)const { return v1 < v2; } }; struct myPred3 :public std::unary_function &,bool>{//一个规范的Functor必须这么干! //因为这么干你的functor的通用型就更强! bool operator()(const shared_ptr & sptr)const { //因为这里是指针类型,所有 照抄上去 一元函数适配器类中即可! return *sptr < 60; } }; int main(void) { cout<<"test myPred1(Functor)'s result: "< vec{ 1,2,3,4,5,6,7,8,9,10 }; vec.erase(remove_if(vec.begin(), vec.end(), myPred1()), vec.end()); for_each(vec.begin(), vec.end(), [](int v) {cout << v << "t"; }); cout << endl; cout<<"--------------------------------"< P2int; unordered_map infoHashMap{P2int(2,1),P2int(2,3),P2int(4,5),P2int(6,3),}; for(auto it = infoHashMap.begin();it!= infoHashMap.end();++it){ if( myPred2()(it->first,it->second) ){ infoHashMap.erase(it++);//一定要小心!对于map/set的任何修改其elems的操作 //or it = infoHashMap.erase(it); //这样做的目的都是始终保持其 迭代器 是 有效的 迭代器! //这需要我们使用时十分小心! //from 《Effective STL》's Term22:切勿直接修改set/map中的elems(这是我自己的理解,非原标题) } } for_each(infoHashMap.begin(),infoHashMap.end(),[](const P2int& p){ cout<<"1st: "< > studentScores; studentScores Scores; Scores.push_back(make_shared (59.5)); Scores.push_back(make_shared (60.5)); Scores.push_back(make_shared (78.5)); Scores.push_back(make_shared (90.0)); Scores.push_back(make_shared (98.5)); Scores.push_back(make_shared (57.0)); Scores.push_back(make_shared (67.5)); Scores.push_back(make_shared (52.0)); Scores.push_back(make_shared (34.0)); Scores.push_back(make_shared (21.5)); cout<<"before using remove_.erase() mode to delete elems from vector >:"< & sp){ cout<<*sp<<"t"; }); cout< >:"< & sp){ cout<<*sp<<"t"; }); cout< 运行结果:
总结:
本条款总结一句话,即:若一个类是函数子(functor),则应使它可配接(adaptable)。且每当你编写函数子Functor类(or结构)时,都应该坚持让你的函数子Functor类具有可适配(adaptable)能力!



