今天看到STL(标准模板库)里的一个函数,也就是一个 约束器--bind2nd(x, y),这个是一个模板函数,stl里面不止这么一个约束器,比如bind1st(x, y),相对而言bind2nd复杂一点,就谈一下这个函数这里。

在看这篇文章之前,建议先看看相关的资料,要求了解类模板及函数模板,容器,拟函数(仿函数或者称为函数对象),如果不了解基本的c++知识,那就不要看了,我用msvc讲解,sgi stl的stl其实差不多。

先看两个定义:

图1:

template  < class _Arg ,  class _Result >
struct unary_function {
  typedef _Arg argument_type;
  typedef _Result result_type;
};

template 
< class _Arg1 ,  class _Arg2 ,  class _Result >
struct binary_function {
  typedef _Arg1 first_argument_type;
  typedef _Arg2 second_argument_type;
  typedef _Result result_type;
};

 

这里unary_function和binary_function是我们后面要讲到的,而且stl里面的约束器,适配器等很多东西都用到这定义。

接着是约束器的定义,在functional头文件里面, 如下:

图2:

 

         //  TEMPLATE FUNCTION bind2nd
template < class  _Fn2,
    
class  _Ty >  inline
    binder2nd
< _Fn2 >  bind2nd( const  _Fn2 &  _Func,  const  _Ty &  _Right)
    
{    // return a binder2nd functor adapter
    typename _Fn2::second_argument_type _Val(_Right);
    
return (std::binder2nd<_Fn2>(_Func, _Val));
    }

 

std::binder2nd<_Fn2>是一个类定义,也在同一个头文件下面,定义如下:

图3:

 

template < class  _Fn2 >
    
class  binder2nd
        : 
public  unary_function < typename _Fn2::first_argument_type,
            typename _Fn2::result_type
>
    
{    // functor adapter _Func(left, stored)
public:
    typedef unary_function
<typename _Fn2::first_argument_type,
        typename _Fn2::result_type
> _Base;
    typedef typename _Base::argument_type argument_type;
    typedef typename _Base::result_type result_type;

    binder2nd(
const _Fn2& _Func,
        
const typename _Fn2::second_argument_type& _Right)
        : op(_Func), value(_Right)
        
{    // construct from functor and right operand
        }


    result_type 
operator()(const argument_type& _Left) const
        
{    // apply functor to operands
        return (op(_Left, value));
        }


    result_type 
operator()(argument_type& _Left) const
        
{    // apply functor to operands
        return (op(_Left, value));
        }


protected:
    _Fn2 op;    
// the functor to apply
    typename _Fn2::second_argument_type value;    // the right operand
    }
;

 

说到这里

template<class _Fn2>
class binder2nd
  : public unary_function<typename _Fn2::first_argument_type,
   typename _Fn2::result_type> 就要注意了,binder2nd类由unary_function类派生, 用到了_Fn2,而_Fn2一般的就是用到前面的binary_function类定义。

说到这里,都还没有接触到约束器bind2nd(x,y),那就再等一会,再看看拟函数的一个使用,实例一:

图4:

 

struct  club  {
    
string ss;
    club(
string a = "oh yeah"): ss(a) {}
    
~club() {}
    
bool operator () (club c) {
        
return c.ss == ss;
    }

    friend ostream 
& operator << (ostream &os, club &c);
}
;

ostream 
&   operator   <<  (ostream  & os, club  & c)  {
    
return os << c.ss;
}


int  main()  {
    list
<club> a;
    list
<club> b[2];
    a.push_back(st(
"a11"));
    a.push_back(st(
"a22"));
    a.push_back(st(
"a33"));
    a.push_back(st(
"a44"));
    list
<club>::iterator p = find_if(a.begin(), a.end(),club()); 
    
//p++;
    for (; p != a.end(); p++{
        cout 
<< *<< endl;
    }

}

 

看看find_if函数定义(头文件algorithm中):

图5:

 

template < class  _InIt,
    
class  _Pr >  inline
    _InIt _Find_if(_InIt _First, _InIt _Last, _Pr _Pred)
    
{    // find first satisfying _Pred
    _DEBUG_RANGE(_First, _Last);
    _DEBUG_POINTER(_Pred);
    
for (; _First != _Last; ++_First)
        
if (_Pred(*_First))
            
break;
    
return (_First);
    }


template
< class  _InIt,
    
class  _Pr >  inline
    _InIt find_if(_InIt _First, _InIt _Last, _Pr _Pred)
    
{    // find first satisfying _Pred
    _ASSIGN_FROM_BASE(_First,
        _Find_if(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Pred));
    
return (_First);
    }


 看看这一部分就晓得了:
    
for  (; _First  !=  _Last;  ++ _First)
        
if  (_Pred( * _First))
            
break ;
    
return  (_First);
find_if的第三个参数被用作,拟函数调用

 

上面的代码我想研究过stl的都明白是什么意思,我定义了一个club类,再find_if函数里面的第三个参数就是一个类对象,临时的,当iterator  p移动到a.begin(), a.end()之间时,find_if函数就会调用club类里面定义的operator ()重载,调用拟函数,而且给拟函数传入(*p),这里是一个club对象,这里要记住一点,就是拟函数的参数需要传值,由调用函数传值!

在看了一个简短的拟函数的使用后,我们进入约束器的使用,实例二:

图6:

#include  < iostream >
#include 
< list >
#include 
< algorithm >
#include 
< string >
#include 
< functional >

using   namespace  std;
int  main()  {
    list
<int> a;
    a.push_back(
11);
    a.push_back(
22);
    list
<int>::iterator p = find_if(a.begin(), a.end(), bind2nd(less<int>(), 7));
}

 

代码中的   bind2nd(less<int>(), 7)  在图2处过后就变成了

图7

 

list < int > ::iterator p  =  find_if(a.begin(), a.end(), bind2nd(less < int > (),  7 ))
||
||
list
< int > ::iterator p  =  find_if(a.begin(), a.end(), binder2nd <   **   > (less < int > (),  7 ) ) 

这里binder2nd
<   **> (less < int > 7 ) 其实就是一个binder2nd类临时对象,打星星符号的地方是表示binder2nd类使用的模板类型,这个要通过后面的模板类型推断。

在图3中可以看到binder2nd的构造函数:

    binder2nd(
const  _Fn2 &  _Func,
        
const  typename _Fn2::second_argument_type &  _Right)
        : op(_Func), value(_Right)
        
{    // construct from functor and right operand
        }

less<int>()传值给op,一个_Fn2类型的变量,7传值给value,一个int型值。

看less类定义,来推断_Fn2的具体类型。

 图8:

template  < class  _Tp >
struct  less :  public  binary_function < _Tp,_Tp, bool >
{
  
bool operator()(const _Tp& __x, const _Tp& __y) const
 

     
return __x < __y;
 }

}

由此推断,_Tp是int型

 那么图7里面的binder2nd< ** >(less<int>(), 7)可以推断为
binder2nd< _Fn2<int, int, bool>  > >(less<int>(), 7), 应该要知道,这个就是一个临时对象,这个临时对象里面的op = less<int> (), value = 7,那么它就要调用binder2nd里面的拟函数:

    result_type  operator ()(argument_type &  _Left)  const
        ......
{    // apply functor to operands
        return (op(_Left, value));
        }

_Left有外界传入值,也就是开始的find_if(……)函数传入。
那么这个函数返回之后变成了:


find_if(a.begin(), a.end(), op (_Left, 
7 ))  // op用less<int> ()对象替换之后
||
find_if(a.begin(), a.end(), less
< int > () (_Left,  7 ))

less
< int > () (_Left,  7 )又是一个拟函数,又要调用相应的operator ()操作符。

这个操作符号在头文件
< functional > 里面定义,图8里面有。

  
bool   operator ()( const  _Tp &  __x,  const  _Tp &  __y)  const
   

     
return __x < __y; 
}


设p为a.begin(), a.end(),之间一个指针,那么 find_if(a.begin(), a.end(), less
< int > () (_Left,  7 ))
在此演变为:
 find_if(a.begin(), a.end(), less
< int > () ( * p,  7 ))
再次演变为:
 find_if(a.begin(), a.end(), less
< int   > :: operator () ( * p,  7 )



 到此就分解到最原始的状态了,也就很简单了,就是一个简简单单的拟函数的问题了。

水平有限,多多指教!

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐