今天看到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 << *p << 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
)
到此就分解到最原始的状态了,也就很简单了,就是一个简简单单的拟函数的问题了。
水平有限,多多指教!