What are C++ functors and their uses?

后端 未结 14 1436
花落未央
花落未央 2020-11-21 04:27

I keep hearing a lot about functors in C++. Can someone give me an overview as to what they are and in what cases they would be useful?

14条回答
  •  伪装坚强ぢ
    2020-11-21 04:59

    To add on, I have used function objects to fit an existing legacy method to the command pattern; (only place where the beauty of OO paradigm true OCP I felt ); Also adding here the related function adapter pattern.

    Suppose your method has the signature:

    int CTask::ThreeParameterTask(int par1, int par2, int par3)
    

    We will see how we can fit it for the Command pattern - for this, first, you have to write a member function adapter so that it can be called as a function object.

    Note - this is ugly, and may be you can use the Boost bind helpers etc., but if you can't or don't want to, this is one way.

    // a template class for converting a member function of the type int        function(int,int,int)
    //to be called as a function object
    template
    class mem_fun3_t
    {
      public:
    explicit mem_fun3_t(_Ret (_Class::*_Pm)(_arg1,_arg2,_arg3))
        :m_Ptr(_Pm) //okay here we store the member function pointer for later use
        {}
    
    //this operator call comes from the bind method
    _Ret operator()(_Class *_P, _arg1 arg1, _arg2 arg2, _arg3 arg3) const
    {
        return ((_P->*m_Ptr)(arg1,arg2,arg3));
    }
    private:
    _Ret (_Class::*m_Ptr)(_arg1,_arg2,_arg3);// method pointer signature
    };
    

    Also, we need a helper method mem_fun3 for the above class to aid in calling.

    template
    mem_fun3_t<_Ret,_Class,_arg1,_arg2,_arg3> mem_fun3 ( _Ret (_Class::*_Pm)          (_arg1,_arg2,_arg3) )
    {
      return (mem_fun3_t<_Ret,_Class,_arg1,_arg2,_arg3>(_Pm));
    }
    

    Now, in order to bind the parameters, we have to write a binder function. So, here it goes:

    template
    class binder3
    {
    public:
    //This is the constructor that does the binding part
    binder3(_Func fn,_Ptr ptr,_arg1 i,_arg2 j,_arg3 k)
        :m_ptr(ptr),m_fn(fn),m1(i),m2(j),m3(k){}
    
     //and this is the function object 
     void operator()() const
     {
            m_fn(m_ptr,m1,m2,m3);//that calls the operator
        }
    private:
        _Ptr m_ptr;
        _Func m_fn;
        _arg1 m1; _arg2 m2; _arg3 m3;
    };
    

    And, a helper function to use the binder3 class - bind3:

    //a helper function to call binder3
    template 
    binder3<_Func, _P1, _arg1, _arg2, _arg3> bind3(_Func func, _P1 p1,_arg1 i,_arg2 j,_arg3 k)
    {
        return binder3<_Func, _P1, _arg1, _arg2, _arg3> (func, p1,i,j,k);
    }
    

    Now, we have to use this with the Command class; use the following typedef:

    typedef binder3 ,T* ,int,int,int> F3;
    //and change the signature of the ctor
    //just to illustrate the usage with a method signature taking more than one parameter
    explicit Command(T* pObj,F3* p_method,long timeout,const char* key,
    long priority = PRIO_NORMAL ):
    m_objptr(pObj),m_timeout(timeout),m_key(key),m_value(priority),method1(0),method0(0),
    method(0)
    {
        method3 = p_method;
    }
    

    Here is how you call it:

    F3 f3 = PluginThreadPool::bind3( PluginThreadPool::mem_fun3( 
          &CTask::ThreeParameterTask), task1,2122,23 );
    

    Note: f3(); will call the method task1->ThreeParameterTask(21,22,23);.

    The full context of this pattern at the following link

提交回复
热议问题