您的位置:首页 > 其它

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

2005-05-06 20:49 363 查看

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

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

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
zhengyun@tomosoft.com
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: