boost::mem_fn和std::mem_fun在MSVC6.0上的表现

类别:VC语言 点击:0 评论:0 推荐:
boost::mem_fn和std::mem_fun在MSVC6.0上的表现

Article last modified on 2002-8-7

----------------------------------------------------------------

The information in this article applies to:

-          C/C++

-          Microsoft Visual C++ 6.0(SP5)

----------------------------------------------------------------

boost::mem_fn的简单介绍:

boost::mem_fn是std::mem_fun系列的一个扩展。它的文档链接为:

http://www.boost.org/libs/bind/mem_fn.html。

mem_fn最为人所熟知的作用是,将一个成员函数作用在一个容器上,就像这样std::for_each(v.begin(),  v.end(),  boost::mem_fn(&Shape::draw))就可以让容器vector中的每一个元素都执行一遍draw方法。

第二个用法是,它可以帮助把一个函数指针模拟得像一个函数实体(function object)。比如:

template<class It, class R, class T> void for_each(

It first,

It last,

R (T::*pmf) () )

{

    std::for_each(first,  last,  boost::mem_fn(pmf) );

}

这样,你就可以这么调用:

for_each(v.begin(), v.end(), &Shape::draw);

 

但是仅就这些功能,是不足以让开发者舍弃std::mem_fun[_ref]。有什么理由吗?

std::mem_fun[_ref]在MSVC6.0中的编译错误: 第一个问题:std::mem_fun为什么非要成员函数有返回值呢?

试验代码:

class Stuff

{

public:

       std::string m_Name;

 

       // This function works under VC6, because it returns a value from the function.

       // Note: there is nothing special about returning an int; it could be any data

       // type.

       int printName()

       {

              std::cout << m_Name << std::endl;

              return 0;

       }

 

       // This function would not work under VC6, although Josuttis provides

    //     a similar example.

//   void printName()

//     {

//            std::cout << m_Name << std::endl;

//     }      

};

 

void main()

{

       std::vector<Stuff> v;

       Stuff s1;

       s1.m_Name = "Brandon";

       v.push_back(s1);

       std::for_each(v.begin(), v.end(), std::mem_fun_ref(&Stuff::printName));

}

编译结果:

只有把printname成员函数声明为有返回值的形式,才能编译通过;

如果声明为void printname(),则会出现下面的编译错误:

f:\program files\microsoft visual studio\vc98\include\functional(263) : error C2562: '()' : 'void' function returning a value

f:\program files\microsoft visual studio\vc98\include\functional(262) : see declaration of '()'

f:\program files\microsoft visual studio\vc98\include\functional(263) : while compiling class-template member function 'void __thiscall std::mem_fun_ref_t<void,class Stuff>::operator ()(class Stuff &) const'

原来是因为MSVC的stl的实现为:

template<class _R, class _Ty>

       class mem_fun_ref_t : public unary_function<_Ty, _R>

{

 ………….

_R operator()(_Ty& _X) const

              {return ((_X.*_Ptr)()); }

}

也就是说,operator()非要将成员函数的返回值作为它的返回值,而不管这个成员函数是否有返回值。

暂且不管这种做法是否有道理,它确实会带来不便。

 

第二个问题:std::mem_fun最多只能支持成员函数有一个参数

试验代码:

class StoreVals  

{

   int val;

public:

   StoreVals ( ) { val = 0; }

 

   int lessconst ( int k , int m)  {val -= k + m; return val; }

};

 

int main(int argc, char* argv[])

{

       std::vector <StoreVals* > v2;

    std::for_each(

                              v2.begin( ),

                              v2.end( ),

                              std::bind2nd (

                                                        std::mem_fun1<int, StoreVals,int>

                                                               ( &StoreVals::lessconst ),

                                                        5

                                                     )

                             ); 

       return 0;

}

std::mem_fun和std::mem_fun_ref支持的成员函数没有参数,而std::mem_fun1和std::mem_fun1_ref支持的成员函数只有一个参数,然后就到此为止了。

如果我们有这样一个函数int lessconst ( int k , int m)  {val -= k + m; return val; },就没办法利用std::mem_fun了。

第三个问题:std::mem_fun不支持智能指针

std::mem_fun只能处理raw pointer,而无法处理smart pointer。

第四个问题:std::mem_fun不支持__stdcall的调用约定

试验代码:

class Stuff

{

public:

       std::string m_Name;

       int __stdcall printName()

       {

              std::cout << m_Name << std::endl;

              return 0;

       }

};

 

void main()

{

       std::vector<Stuff> v;

       Stuff s1;

       s1.m_Name = "Brandon";

       v.push_back(s1);

       std::for_each(v.begin(), v.end(), std::mem_fun_ref(&Stuff::printName));

}

编译结果:

error C2664: 'mem_fun_ref' : cannot convert parameter 1 from 'int (__stdcall Stuff::*)(void)' to 'int (__thiscall Stuff::*)(void)'

Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

这样,你就无法让Windows API functions,COM interface member functions和std::mem_fun一起使用了。

第五个问题:有std::mem_fun和std::mem_fun_ref,还有 std::mem_fun1、std::mem_fun1_ref等等,使用起来复杂

 

怎么样?看到std::mem_fun[_ref]的局限性了吧。下面我们来看看boost:;mem_fn[_ref]是怎样改进的。

boost::mem_fn[_ref]的改进: 第一个问题:boost::mem_fn允许成员函数没有返回值

试验代码:

class Stuff

{

public:

       std::string m_Name;

void printName()

{

       std::cout << m_Name << std::endl;

}     

};

void main()

{

       std::vector<Stuff> v;

       Stuff s1;

       s1.m_Name = "Brandon";

       v.push_back(s1);

       std::for_each(v.begin(), v.end(), boost::mem_fn(&Stuff::printName));

}

编译通过。

第二个问题:boost::mem_fn最多只能支持成员函数有8个参数

试验代码:

       mem_fn(&X::g8)(sp, 1, 2, 3, 4, 5, 6, 7, 8);

 

如果还要把一个多参数成员函数作用于一个容器的话,好像就用不了boost::mem_fn了。我试了试,只有下面这种不是成员函数的情况能编译通过。

class StoreVals  

{

   int val;

public:

   StoreVals ( ) { val = 0; }

   friend int lessconst( StoreVals* _sto, int k , int m);

};

int lessconst( StoreVals* _psto, int k , int m)

{

       _psto->val -= k + m;

       return _psto->val;

}

void main()

{

       std::vector <StoreVals* > v2;

  std::for_each(

v2.begin( ),

v2.end( ),

         boost::bind(

                                             lessconst , _1, 5, 7

                                            )

              );

}

如果把lessconst声明为成员函数,就编译不过去了,如下所示:

class StoreVals  

{

   int val;

public:

   StoreVals ( ) { val = 0; }

   int lessconst1 ( StoreVals* _psto, int k , int m)

   {

              _psto->val -= k + m;

              return _psto->val;

       }

}

void main()

{

       std::vector <StoreVals* > v2;

  std::for_each(

v2.begin( ),

v2.end( ),

         boost::bind(

                                             &StoreVals::lessconst1 , _1, 5, 7

                                            )

              );

}

出来一大堆莫名其妙的错误(57个),像

error C2780: 'class boost::_bi::bind_t<R,class boost::_mfi::dm<R,T>,class boost::_bi::list1<class boost::_bi::value<R> > > __cdecl boost::bind(R T::*,A1)' : expects 2 arguments - 4 provided

之流的。不知道为什么。

 

第三个问题:boost::mem_fn支持智能指针 第四个问题:boost::mem_fn支持__stdcall的调用约定

要想让boost::mem_fn支持__stdcall调用约定,必须在

#include <boost/bind.hpp>

#include <boost/mem_fn.hpp>

之前定义一个宏:

#define BOOST_MEM_FN_ENABLE_STDCALL

请注意,必须在这两个头文件include之前定义宏,否则仍然会有这样的编译错误:

error C2665: 'mem_fn' : none of the 2 overloads can convert parameter 1 from type 'int (__stdcall Stuff::*)(void)'

第五个问题:无论什么情况,只用一个boost:mem_fn即可

所以,你可以这样,也可以那样,但是请记住boost::mem_fn吧。

 

本文档所包含的信息代表了在发布之日,ZhengYun 对所讨论问题的当前看法,Zhengyun 不保证所给信息在发布之日以后的准确性。

本文档仅供参考。对本文档中的信息,Zhengyun 不做任何明示或默示的保证。

 

Written by [email protected]

本文地址:http://com.8s8s.com/it/it2348.htm