stl中容易出错的一个地方

哎...一个不起眼的地方折磨了我好长时间。。。
先看一个可以正常编译的程序
#include <iostream>
#include 
<functional>
#include 
<algorithm>
using namespace std;

class LessThan : public binary_function<int,int,bool> {
public:
    
bool operator()(const int& a,const int& b) const{
        
return a<b;
    }
};

int main(){
    
int a[]={6,5,8,9,10};
    vector
<int> v(a,a+5);
    vector
<int>::iterator i=adjacent_find(v.begin(),v.end(),not2(LessThan()));
    cout
<<*i<<endl;
    cout
<<*++i<<endl;
}
可以看到LessThan类是一个函数对象,由于要用到not2这个函数适配器,因此必须要继承自类binary_function这个模板类, binary_function也是非常的简单,就是定义了函数适配器所需要的一些typedef,我们看看标准库functional中的代码:
// TEMPLATE STRUCT binary_function
template<class _Arg1,class _Arg2,class _Result>
struct
 binary_function
    {    
// base class for binary functions
    typedef _Arg1 first_argument_type;
    typedef _Arg2 second_argument_type;
    typedef _Result result_type;
    };
可以看到,这个类就是把函数的2个参数和返回值类型typedef到了类里面。

我们再来看另外一个同样的例子,只不过这次先定义一个真正的函数lessthan(),然后再通过ptr_fun将其变成一个函数对象,那么理所当然的ptr_fun(lessthan)就应该等价于LessThan(),事实上下面这段代码的确也可以编译通过
#include <iostream>
#include 
<functional>
#include 
<algorithm>
using namespace std;

bool lessthan(const int& a,const int& b){
    
return a<b;
}

int main(){
    
int a[]={6,5,8,9,10};
    vector
<int> v(a,a+5);
    vector
<int>::iterator i=adjacent_find(v.begin(),v.end(),ptr_fun(lessthan));
    cout
<<*i<<endl;
    cout
<<*++i<<endl;
}
但是我们现在是要对lessthan的结果进行取反,那么就应该是not2(ptr_fun(lessthan))喽。嗯,试一下。
#include <iostream>
#include 
<functional>
#include 
<algorithm>
using namespace std;

bool lessthan(const int& a,const int& b){
    
return a<b;
}

int main(){
    
int a[]={6,5,8,9,10};
    vector
<int> v(a,a+5);
    vector
<int>::iterator i=adjacent_find(v.begin(),v.end(),not2(ptr_fun(lessthan)));
    cout
<<*i<<endl;
    cout
<<*++i<<endl;
}
天啊!!!编译不通过。。。到底是什么原因呢。。。 我们到头文件functional中去找!!
先来到ptr_fun,看下它的代码:
template<class _Arg1,class _Arg2,class _Result>
inline pointer_to_binary_function
<_Arg1, _Arg2, _Result, _Result(__cdecl *)(_Arg1, _Arg2)>  
  ptr_fun(_Result (__cdecl 
*_Left)(_Arg1, _Arg2))
  {    
// return pointer_to_binary_function functor adapter
 return (std::pointer_to_binary_function<_Arg1, _Arg2, _Result, _Result (__cdecl *)(_Arg1, _Arg2)>(_Left));
 }
可以看到ptr_fun简单调用了pointer_to_binary_function的构造函数(参数_Left),在这个例子中我们调用 ptr_fun(lessthan),所以_Arg1,_Arg2为const int&,_Result为bool,_Left为lessthan

恩,继续,看pointer_to_binary_function的定义
// TEMPLATE CLASS pointer_to_binary_function
template<class _Arg1,
    
class _Arg2,
    
class _Result,
    
class _Fn = _Result (*)(_Arg1, _Arg2)>
    
class pointer_to_binary_function
        : 
public binary_function<_Arg1, _Arg2, _Result>
    {    
// functor adapter (*pfunc)(left, right)
public:
    
explicit pointer_to_binary_function(_Fn _Left)
        : _Pfun(_Left)
        {    
// construct from pointer
        }

    _Result 
operator()(_Arg1 _Left, _Arg2 _Right) const
        {    
// call function with operands
        return (_Pfun(_Left, _Right));
        }

protected:
    _Fn _Pfun;    
// the function pointer
    };
ok 了,这个类就是个函数对象,继承自binary_function,保存了一些typedef,即first_argument_type, second_argument_type都为const int&,result_argument_type为bool,一些正常,所以第2个程序可以编译通过。
第三个程序就是在第二个的基础上加了个not2,看来是not2这个函数适配器出问题了。
看not2的定义:
// TEMPLATE FUNCTION not2
template<class _Fn2> inline
    binary_negate
<_Fn2> not2(const _Fn2& _Func)
    {    
// return a binary_negate functor adapter
    return (std::binary_negate<_Fn2>(_Func));
    }
恩,返回binary_negate类的实例,那么继续去找binary_negate的代码:
// TEMPLATE CLASS binary_negate
template<class _Fn2>
    
class binary_negate
        : 
public binary_function<typename _Fn2::first_argument_type,
            typename _Fn2::second_argument_type, 
bool>
    {    
// functor adapter !_Func(left, right)
public:
    
explicit binary_negate(const _Fn2& _Func)
        : _Functor(_Func)
        {    
// construct from functor
        }

    
bool operator()(const typename _Fn2::first_argument_type& _Left,
        
const typename _Fn2::second_argument_type& _Right) const
        {    
// apply functor to operands
        return (!_Functor(_Left, _Right));
        }

protected:
    _Fn2 _Functor;    
// the functor to apply
    };

哈哈,看出原因了吗?  就在运算符()重载上除了点问题,它的参数是const typename _Fn2::first_argument_type&  _Left,而我们的ptr_fun(lessthan)中的first_argument_type为const int &,那么相当与_left被定义的类型为const int & &,而在c++中没有引用的引用这种类型,所以编译器就报错啦。。
把我们的程序稍微改一下就可以了(把lessthan的定义中const int&改为int即可)

posted on 2007-02-21 22:32  woodfish  阅读(665)  评论(1编辑  收藏  举报

导航