zoukankan      html  css  js  c++  java
  • bind1st, bind2nd, mem_fun, mem_fun_ref, ptr_fun这几个的使用

    bind1st, bind2nd, mem_fun, mem_fun_ref,这三个函数的使用

    bind1st 为一个有两个参数的函数绑定第一个参数, 名字已经很明确了 bind first parameter
    bind2nd 为一个有两个参数的函数绑定第二个参数.

    如果是自定义的函数对象需要去继承unary_function,binary_function

    首先看一下下面几个辅助函数和结构体,它们是bind1stbind2nd的基础

    1.unary_function
    这个结构体负责对一元函数的描述:


    1 template <class _Arg, class _Result>
    2 struct unary_function
    3 {
    4     typedef _Arg argument_type;   ///< @c argument_type is the type of the
    5                                        ///     argument (no surprises here)

    7     typedef _Result result_type;  ///< @c result_type is the return type
    8 };


    2.binary_function
    这个结构体负责对二元函数的描述:


    1 template <class _Arg1, class _Arg2, class _Result>
    2 struct binary_function
    3 {
    4     typedef _Arg1 first_argument_type;   ///< the type of the first argument
    5     ///  (no surprises here)

    7     typedef _Arg2 second_argument_type;  ///< the type of the second argument
    8     typedef _Result result_type;         ///< type of the return type
    9 };

    3.binder1st类


     1 template <class _Operation>
     2 class binder1st
     3         : public unary_function < typename _Operation::second_argument_type,
     4         typename _Operation::result_type >
     5 {
     6     protected:
     7         _Operation op;
     8         typename _Operation::first_argument_type value;
     9     public:
    10         binder1st( const _Operation& __x,
    11                    const typename _Operation::first_argument_type& __y )
    12                 : op( __x ), value( __y ) {}
    13 
    14         typename _Operation::result_type
    15         operator()( const typename _Operation::second_argument_type& __x ) const
    16         { return op( value, __x ); }
    17 
    18         // _GLIBCXX_RESOLVE_LIB_DEFECTS
    19         // 109.  Missing binders for non-const sequence elements
    20         typename _Operation::result_type
    21         operator()( typename _Operation::second_argument_type& __x ) const
    22         { return op( value, __x ); }
    23 };

    注意7~8行的op和value,分别用来保存绑定的函数操作和值。而在14~16行,可以看到这里直接使用op来处理value和__x参数。
    从这两段代码可以看到,binder1st可以把二元函数间接变成一元函数(通过binder1st的operator()调用)。另外,14~15行的result_type、
    second_argument_type和first_argument_type也意味着,如果我们自己要写一个可以由bind1st绑定的函数,那么最好是先从unary_function
    和binary_function结构体中继承相应的traits,然后再实现operator()函数。

    4.bind1st
    bind1st函数实质上就是返回了一个binder1st类对象,注意看下面第7行代码:


    1 /// One of the @link s20_3_6_binder binder functors@endlink.
    2 template <class _Operation, class _Tp>
    3 inline binder1st<_Operation>
    4 bind1st( const _Operation& __fn, const _Tp& __x )
    5 {
    6     typedef typename _Operation::first_argument_type _Arg1_type;
    7     return binder1st<_Operation>( __fn, _Arg1_type( __x ) );
    8 }

    5.binder2nd和bind2nd
    与binder1st和bind1st类似,只是使用Op调用的参数位置发生了变化而已


    什么时候使用呢?
    当我们的回调函数有两个参数,可是程序代码在调用这个回调的时候,只有一个参数,怎么办呢,这时候就可以用 bind1st 或者 bind2nd. 那么到的是用 bind1st 还是 bind2nd 呢, 这个时候就要看 回调的参数和你需要的参数的顺序了,如果例程代码调用你的回调函数传入的参数,其实是你想要的第二个参数,那么就用 bind1st(para1, para2) 在para2 中传入你的第一个参数;同理,如果例程代码调用你的回调函数传入的参数,其实是你想要的第一个参数,那么就用 bind2nd(para1, para2) 在para2 中传入你的第二个参数,是不是很简单

    在说 mem_fun, mem_fun_ref
    这是调用 成员函数, 有 _ref 的很明显是 调用 类引用 的成员函数, mem_fun 并不是调用类的成员函数,是类指针 的成员函数

    // mem_fun example
    #include <iostream>
    #include <functional>
    #include <vector>
    #include <algorithm>
    #include <string>
    using namespace std;


    class CPerson
    {
    public:
        CPerson(string name):m_name(name)
        {

        }
        virtual ~CPerson()
        {

        }

        void printname()
        {
            cout << m_name << endl;
        }
       
        void printcompany( string strcompany)
        {
            cout << m_name << " " << strcompany << endl;
        }
       
    private:
        string m_name;
    };

    int _tmain(int argc, _TCHAR* argv[])
    {
        CPerson p1("tom");
        CPerson p2("jerry");
        vector <CPerson> vecperson;
        vecperson.push_back(p1);
        vecperson.push_back(p2);
        for_each(vecperson.begin(), vecperson.end(), mem_fun_ref(&CPerson::printname));
       

        //
        // mem_fun
        //
        CPerson * pp1 = &p1;
        CPerson * pp2 = &p2;
       
        vector <CPerson*> vecpersonptr;
        vecpersonptr.push_back(pp1);
        vecpersonptr.push_back(pp2);
        for_each(vecpersonptr.begin(), vecpersonptr.end(), mem_fun(&CPerson::printname));
        return 0;
    }

    如果我的成员函数有参数那又该怎么办呢?
    很自然我们想到 bind1st(mem_fun, ...) bind1st(mem_fun_ref, ...);且慢,到底是bind1st 还是 bind2nd 呢,这个就要看具体代码了,如本例的 printcompany,他的参数 strcompany 就是第二个参数,为嘛是第二个参数不解释了,所以应该是 bind2nd(..., ...)

        for_each(vecpersonptr.begin(), vecpersonptr.end(), bind2nd(mem_fun(&CPerson::printcompany), "abc") );
       
    什么?你想看看 bind1st 的例子,这个也好办需要多加几行代码
       
        vector <string> vecstring;
        vecstring.push_back("abc");
        vecstring.push_back("def");
        for_each(vecstring.begin(), vecstring.end(), bind1st(mem_fun(&CPerson::printcompany), pp1) );
       
    最终的代码就是这个样子
    int _tmain(int argc, _TCHAR* argv[])
    {
        CPerson p1("tom");
        CPerson p2("jerry");
        vector <CPerson> vecperson;
        vecperson.push_back(p1);
        vecperson.push_back(p2);
        for_each(vecperson.begin(), vecperson.end(), mem_fun_ref(&CPerson::printname));
       

        //
        // mem_fun
        //
        CPerson * pp1 = &p1;
        CPerson * pp2 = &p2;
       
        vector <CPerson*> vecpersonptr;
        vecpersonptr.push_back(pp1);
        vecpersonptr.push_back(pp2);
        for_each(vecpersonptr.begin(), vecpersonptr.end(), mem_fun(&CPerson::printname));


        for_each(vecpersonptr.begin(), vecpersonptr.end(), bind2nd(mem_fun(&CPerson::printcompany), "abc") );
       
        vector <string> vecstring;
        vecstring.push_back("abc");
        vecstring.push_back("def");
        for_each(vecstring.begin(), vecstring.end(), bind1st(mem_fun(&CPerson::printcompany), pp1) );

        return 0;
    }
    还想看 mem_fun_ref 的例子,好贪心呀
    for_each(vecperson.begin(), vecperson.end(), bind2nd(mem_fun_ref(&CPerson::printcompany), "abc") );
    for_each(vecstring.begin(), vecstring.end(), bind1st(mem_fun_ref(&CPerson::printcompany), p1) );
    好大功告成,编译,嗯,出错了
    for_each(vecstring.begin(), vecstring.end(), bind1st(mem_fun_ref(&CPerson::printcompany), p1) ); compile error
    为嘛嗫?
    仔细看源码,呵呵原来是 const 的问题 bind1st 的两个参数都是 const 类型, 可是 mem_fun_ref 的参数偏偏不要const的
    看来 bind1st 和 mem_fun_ref 不兼容呀

    怎么办呢???????

    也好办 直接把 CPerson::printcompany() 变成 CPerson::printcompany() const 的形式就好了

    最终代码:

    class CPerson
    {
    public:
        CPerson(string name):m_name(name)
        {
        }
        virtual ~CPerson()
        {

        }

        void printname()
        {
            cout << m_name << endl;
        }

        void printcompany( string strcompany) const
        {
            cout << m_name << " " << strcompany << endl;
        }
    private:
        string  m_name;
    };

    int _tmain(int argc, _TCHAR* argv[])
    {
        CPerson p1("tom");
        CPerson p2("jerry");
        vector <CPerson> vecperson;
        vecperson.push_back(p1);
        vecperson.push_back(p2);
        for_each(vecperson.begin(), vecperson.end(), mem_fun_ref(&CPerson::printname));

        for_each(vecperson.begin(), vecperson.end(), bind2nd(mem_fun_ref(&CPerson::printcompany), "abc") );
       
        //
        // mem_fun
        //
        CPerson * pp1 = &p1;
        CPerson * pp2 = &p2;
       
        vector <CPerson*> vecpersonptr;
        vecpersonptr.push_back(pp1);
        vecpersonptr.push_back(pp2);
        for_each(vecpersonptr.begin(), vecpersonptr.end(), mem_fun(&CPerson::printname));

        for_each(vecpersonptr.begin(), vecpersonptr.end(), bind2nd(mem_fun(&CPerson::printcompany), "abc") );

        vector <string> vecstring;
        vecstring.push_back("abc");
        vecstring.push_back("def");
        for_each(vecstring.begin(), vecstring.end(), bind1st(mem_fun(&CPerson::printcompany), pp1) );

        for_each(vecstring.begin(), vecstring.end(), bind1st(mem_fun_ref(&CPerson::printcompany), p1) );

        return 0;

    }

    参考:

    http://www.cppblog.com/Young/archive/2011/01/09/138199.html

    ptr_fun的使用

    ptr_fun是将一个普通的函数适配成一个functor,添加上argument type和result type等类型, 其实现如下(例子里面是binary_function,unary_function同理): 

    C++代码  收藏代码
    1. template<class _Arg1,  
    2.     class _Arg2,  
    3.     class _Result> inline  
    4.     pointer_to_binary_function<_Arg1, _Arg2, _Result,  
    5.         _Result(__fastcall *)(_Arg1, _Arg2)>  
    6.             ptr_fun(_Result (__fastcall *_Left)(_Arg1, _Arg2))  
    7.     {   // return pointer_to_binary_function functor adapter  
    8.     return (std::pointer_to_binary_function<_Arg1, _Arg2, _Result,  
    9.         _Result (__fastcall *)(_Arg1, _Arg2)>(_Left));  
    10.     }  


    由上面的代码可见,ptr_fun只是将一个普通的函数(或者函数指针)适配成类pointer_to_binary_function,而该类实际上是binary_function的子类,这样出来的functor就有利于同STL的算法等适配。 
    下面的例子就是说明了使用ptr_fun将普通的函数适配成bind1st或bind2nd能够使用的functor,否则对bind1st或bind2nd直接绑定普通函数,则编译出错。 

    C++代码  收藏代码
      1. #include <algorithm>  
      2. #include <functional>  
      3. #include <iostream>  
      4.   
      5. using namespace std;  
      6.   
      7. int sum(int arg1, int arg2)  
      8. {  
      9.     cout<<"ARG 1: "<<arg1<<endl;  
      10.     cout<<"ARG 2: "<<arg2<<endl;  
      11.   
      12.     int sum = arg1 + arg2;  
      13.     cout<<"SUM: "<<sum<<endl;  
      14.   
      15.     return sum;  
      16. }  
      17.   
      18. int main(int argc,char* argv[])  
      19. {  
      20.     bind1st(ptr_fun(sum),1)(2); // the same as sum(1,2)  
      21.     bind2nd(ptr_fun(sum),1)(2); //the same as sum(2,1)  
      22.   
      23.     getchar();  
      24.     return 0;  
      25. }  
  • 相关阅读:
    Excel表格函数逻辑排错
    MobaXterm体验最好的SSH客户端
    Excel中的常用函数
    Shell 知识点2020
    Linux 知识点2020
    Python知识点2020
    es6 模版字符串
    es6对象定义简写
    es6解构赋值
    ES6 let const关键字
  • 原文地址:https://www.cnblogs.com/bwbfight/p/13638691.html
Copyright © 2011-2022 走看看