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. }  
posted @ 2020-09-09 14:40  白伟碧一些小心得  阅读(165)  评论(0编辑  收藏  举报