一. 什么是Lambda bIX'|=
所谓Lambda,简单的说就是快速的小函数生成。 JOR ?xCc
在C++中,STL的很多算法都要求使用者提供一个函数对象。例如for_each函数,会要求用户提供一个表明“行为”的函数对象。以vector<bool>为例,如果想使用for_each对其中的各元素全部赋值为true,一般需要这么一个函数对象, *zf@J'
nA!Xb'y&
) <lpI';T
E^RPK{zO
class filler :HJ@/s!J
{ ][ ,NNXrc&
public : :sMc}k?9S
void operator ()( bool & i) const {i = true ;} zF&>1y.$
} ; # j=r
K3c(c%$<R
Oy @vh>RY
这样实现不但麻烦,而且不直观。而如果使用lambda,则允许用户使用一种直观和见解的方式来处理这个问题。以boost.lambda为例,刚才的问题可以这么解决:
=<_ei|ME
~7N>tjB
Ik9 2='Z
CoZXbTq
for_each(v.begin(), v.end(), _1 = true ); <2\4eusk
LPg1 G+e
@Ju!|G9z/p
那么下面,就让我们来实现一个lambda库。 NwK(<dzG
)$#
Ku2X
QQd%V#M?
*@M7J
二. 战前分析 SqiLp!Y`
首先要说明的是,我并没有读过boost.lambda或其他任何lambda库的代码,因此如代码有雷同,纯属巧合。 /1Xji0LK
开始实现以前,首先要分析出大致的实现手法。先让我们来看几段使用Lambda的代码 L@ b8,
91Cg
qU'O4TWZ
for_each(v.begin(), v.end(), _1 = 1 ); |_Y[931<
/* --------------------------------------------- */ &"90pBGK
vector < int *> vp( 10 ); W6Os|z9&|
transform(v.begin(), v.end(), vp.begin(), & _1); G8JwY\
/* --------------------------------------------- */ }F*u
9E
sort(vp.begin(), vp.end(), * _1 > * _2); ''@upZBJ
/* --------------------------------------------- */ 8a\
Pjk
int b = * find_if(v.begin, v.end(), _1 >= 3 && _1 < 5 ); 8:BPXdiK
/* --------------------------------------------- */ n..9F$a
for_each(vp.begin(), vp.end(), cout << * _1 << ' \n ' ); [@Db7]nG
/* --------------------------------------------- */ e[3rz%'Q
for_each(vp.begin(), vp.end(), cout << constant( ' \n ' ) << * _1); x*)@:W!
~(TS>ck@
;K'1dsA
bdn{Y
看了之后,我们可以思考一些问题: B:YUb{CJ
1._1, _2是什么? zLG5m]G4D
显然_1和_2都满足C++对于标识符的要求,可见_1和_2都是对象。 8Nr,Wq
2._1 = 1是在做什么? y6[^I'kz
既然_1是一个对象,那么_1的类必然重载了operator=(int)。那么operator=返回什么呢?该函数所返回的对象被传入for_each的第3个参数,可见其返回了一个函数对象。现在整个流程就很清楚了。_1 = 1调用了operator=,其返回了一个函数对象,该函数对象能够将参数1赋值为1。 JsOu
*9R
Ok,回答了这两个问题之后,我们的思路就很清晰了。如果要实现operator=,那么至少要实现2个类,一个用于产生_1的对象,另一个用于代表operator=返回的函数对象。 Eua\N<!aai
n3-2;xuNKE
K%Sy~6iD&
三. 动工 =Vgj=19X(
首先实现一个能够范型的进行赋值的函数对象类: xK`.^W
Unl6?_
@wWro?s'p
[:HT=LX3
template < typename T > ]-o0HY2
class assignment GEg8\
{ 9(%ptnya
T value; &Rgy/1
public : /4\!zPPj.
assignment( const T & v) : value(v) {} 7Y:~'&U|
template < typename T2 > oGzZ.K3 A
T2 & operator ()(T2 & rhs) const { return rhs = value; } y;N[#hY#CD
} ; 0Ey*ci^ue
a7#J af
lx<]v^
其中operator()被声明为模版函数以支持不同类型之间的赋值。 $7{V+>
然后我们就可以书写_1的类来返回assignment zWxKp;.
XgUvgJ
s)q;{wz
W&[}-E8<Y
class holder {`0GAW)q
{ Ly?yWS-x
public : /? n 9c;w
template < typename T > @0`Q
assignment < T > operator = ( const T & t) const lZTD>$
{ wL]7d3t
return assignment < T > (t); n<;TBK
} sF?N vp
} ; .7-Yu1{2
f
Q.ea#xh^
cGw* edgp6
由于该类是一个空类,因此我们可以在其后放心大胆的写上: v%|()Z0
2nOoG/6
E
static holder _1; K
(yuL[p`
Ok,现在一个最简单的lambda就完工了。你可以写 0:^L>MO
> m GO08X
for_each(v.begin(), v.end(), _1 = 1 ); K[ZgT$zZ
而不用手动写一个函数对象。 iVM{ L
oI9Jp`
4C&L