栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Term40:若一个类是函数子(functor),则应使它可配接(adaptable)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Term40:若一个类是函数子(functor),则应使它可配接(adaptable)

要读懂本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具有适配性)
template
   inline 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之源码:

  
  template
    struct 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)能力!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/718923.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号