Boost源码解析之mem_fn

熟悉STL的人知道,mem_fun_ref是STL中对于成员函数引用的实现,主要为了兼容泛型算法使用

成员函数,对容器元素进行具体操作。举个简单的例子,依次输出容器元素信息,如下:

#include <iostream>
#include <string>
#include <list>
#include <algorithm>
#include "boost/mem_fn.hpp"

using namespace std;
using namespace boost;

class Users
{
public:
    Users(int id,string name)
    {
        this->id = id;
        this->name = name;
    }
    void output()
    {
        cout << "id:" << id << " , name:" << name <<  endl;
    }
public:
    int id;
    string name;
};

int main()
{
        list<Users> lstUsers;
        Users user1(1,"zhangsan"),user2(2,"lisi");

        lstUsers.push_back(user1);
        lstUsers.push_back(user2);
        
        //函数对象重载()接受的是对象引用,参见for_each的实现
        /*
        template <class InputIterator, class Function>
        Function for_each(InputIterator first, InputIterator last, Function f) {
       for ( ; first != last; ++first)
          f(*first);
          return f;
        }*/
        //具体调用
        std::for_each(lstUsers.begin(), lstUsers.end(), std::mem_fun_ref(&Users::output));
}

执行输出结果:

假设for_each第三个参数,function f接受的是指针类型,那么mem_fun_ref显然就要

换成mem_fun。STL中mem_fun_ref和mem_fun的源码实现如下:

/*mem_fun源码实现*/
template <class S, class T>
inline mem_fun_t<S,T> mem_fun(S (T::*f)()) { 
  return mem_fun_t<S,T>(f);
}
template <class S, class T>
class mem_fun_t : public unary_function<T*, S> {
public:
  explicit mem_fun_t(S (T::*pf)()) : f(pf) {}
  S operator()(T* p) const { return (p->*f)(); }//重载函数调用符,参数为指针类型
private:
  S (T::*f)();
};

/*mem_fun_ref源码实现*/
template <class S, class T>
inline mem_fun_ref_t<S,T> mem_fun_ref(S (T::*f)()) { 
  return mem_fun_ref_t<S,T>(f);
}
template <class S, class T>
class mem_fun_ref_t : public unary_function<T, S> {
public:
  explicit mem_fun_ref_t(S (T::*pf)()) : f(pf) {}
  S operator()(T& r) const { return (r.*f)(); }//重载函数调用符,参数为引用类型
private:
  S (T::*f)();
};

我们在使用成员函数作为函数参数时就得根据具体的函数要求是指针类型和引用类型,

来区分是使用men_fun还是men_fun_ref。

然而,在boost库的bind子库中对成员函数指针和成员函数引用,做了新的演绎,源码如下:

template<class R, class T> _mfi::dm<R, T> mem_fn(R T::*f)
{
    return _mfi::dm<R, T>(f);//mem_fn函数本质是返回一个dm对象。
}
//dm的具体实现如下:
template<class R, class T> class dm
{
public:
    typedef R const & result_type;//返回值类型
    typedef T const * argument_type;//参数类型
private:  
    typedef R (T::*F);//函数指针定义
    F f_;
    template<class U> R const & call(U & u, T const *) const
    {
        return (u.*f_);
    }
    template<class U> R const & call(U & u, void const *) const
    {
        return (get_pointer(u)->*f_);
    }
public:
    explicit dm(F f): f_(f) {}
    R & operator()(T * p) const   //重载指针类型
    {
        return (p->*f_);
    }
    R const & operator()(T const * p) const //重载指针类型
    {
        return (p->*f_);
    }
    template<class U> R const & operator()(U const & u) const //重载引用类型
    {
        return call(u, &u);
    }
};

即我们在使用mem_fn时,无需关注是创建一个成员函数引用还是成员函数指针。dm的实现重载了指针类型和引用类型两个版本。
我们讲上面的例子中的具体调用行
std::for_each(lstUsers.begin(), lstUsers.end(), std::mem_fun_ref(&Users::output));
替换为
std::for_each(lstUsers.begin(), lstUsers.end(), boost::mem_fn(&Users::output));
将得到一样的效果。
然而,对于每次调用都得显式的去写std::mem_fun_ref或是boost::mem_fn着实也是有点麻烦。
能否只需要传&Users::output?答案是可以的,我们可以对for_each进行一个简单的二次封装。

template<class Iter, class R, class T>
void for_each(Iter first, Iter last, R (T::*pmf) ())
{
  std::for_each(first, last, boost::mem_fn(pmf) );
}
进行封装之后,具体调用就变更为:
for_each(lstUsers.begin(),lstUsers.end(),&Users::output);
显然这样的调用,让人更一目了然。

最后将全文各种调用汇总起来,还是基于第一个例子的修改补充版本,如下:

#include <iostream>
#include <string>
#include <list>
#include <algorithm>
#include "boost/mem_fn.hpp"

using namespace std;
using namespace boost;

class Users
{
public:
    Users(int id,string name)
    {
        this->id = id;
        this->name = name;
    }
    void output()
    {
        cout << "id:" << id << " , name:" << name <<  endl;
    }
public:
    int id;
    string name;
};

template<class Iter, class R, class T> 
void for_each(Iter first, Iter last, R (T::*pmf) ()) { std::for_each(first, last, boost::mem_fn(pmf) ); } int main() { list<Users> lstUsers; Users user1(1,"zhangsan"),user2(2,"lisi"); lstUsers.push_back(user1); lstUsers.push_back(user2); //std::mem_fun_ref std::for_each(lstUsers.begin(), lstUsers.end(), std::mem_fun_ref(&Users::output)); //试验下mem_fun,接受的是对象的指针 std::mem_fun(&Users::output)(&(*lstUsers.begin())); //boost::mem_fn版本的调用 std::for_each(lstUsers.begin(), lstUsers.end(), boost::mem_fn(&Users::output)); //二次封装for_each之后的调用版本 for_each(lstUsers.begin(),lstUsers.end(),&Users::output); }

 

posted @ 2016-03-27 23:17  chuyongliu  阅读(847)  评论(0编辑  收藏  举报