一. 什么是Lambda 26B]b{Iz{
所谓Lambda,简单的说就是快速的小函数生成。 v#q7hw=
在C++中,STL的很多算法都要求使用者提供一个函数对象。例如for_each函数,会要求用户提供一个表明“行为”的函数对象。以vector<bool>为例,如果想使用for_each对其中的各元素全部赋值为true,一般需要这么一个函数对象, - Ob'/d5&
_Jx.?8
T?4MFx#
bX6eNk-L
class filler 2 DJs'"8
{ 7m~.V[l1
public : y2;uG2IS_g
void operator ()( bool & i) const {i = true ;} yDg`9q.ckm
} ; `wj<d>m
KC9_H>
%JeT,{
这样实现不但麻烦,而且不直观。而如果使用lambda,则允许用户使用一种直观和见解的方式来处理这个问题。以boost.lambda为例,刚才的问题可以这么解决: ekND>Qjj
5,cq-`
y!&6"l$K]
X,y0J
for_each(v.begin(), v.end(), _1 = true ); qF C0$:z&
.|^L\L(!
1v)ur\>R
那么下面,就让我们来实现一个lambda库。 m^Qc9s#D
\2KwF}[m
&\#If:
I(y:Td
二. 战前分析 ShbW[*5
首先要说明的是,我并没有读过boost.lambda或其他任何lambda库的代码,因此如代码有雷同,纯属巧合。 V]dzKNFi
开始实现以前,首先要分析出大致的实现手法。先让我们来看几段使用Lambda的代码 _LU]5$\b
=&jLwy
=Y
Je\745
for_each(v.begin(), v.end(), _1 = 1 ); h}r .(MVt
/* --------------------------------------------- */ U2m86@E
vector < int *> vp( 10 ); m>B^w)&C
transform(v.begin(), v.end(), vp.begin(), & _1); hg[ob+"
/* --------------------------------------------- */ %"B+;{y(5
sort(vp.begin(), vp.end(), * _1 > * _2); L9ECF;)
/* --------------------------------------------- */ MKzIY:ug
int b = * find_if(v.begin, v.end(), _1 >= 3 && _1 < 5 ); 21Mr2-#z
/* --------------------------------------------- */ UfIH!6Q
for_each(vp.begin(), vp.end(), cout << * _1 << ' \n ' ); D@A@5pvS
/* --------------------------------------------- */ 70hm9b-
for_each(vp.begin(), vp.end(), cout << constant( ' \n ' ) << * _1); VN6h:-&iY
,j\1UAa
=$xxkc.~G
@'>h P
看了之后,我们可以思考一些问题: ^h
#0e:7<
1._1, _2是什么? [hC-} 9
显然_1和_2都满足C++对于标识符的要求,可见_1和_2都是对象。 "I+71Ce
2._1 = 1是在做什么? }TE4)vXs
既然_1是一个对象,那么_1的类必然重载了operator=(int)。那么operator=返回什么呢?该函数所返回的对象被传入for_each的第3个参数,可见其返回了一个函数对象。现在整个流程就很清楚了。_1 = 1调用了operator=,其返回了一个函数对象,该函数对象能够将参数1赋值为1。 7vO3+lT/Y;
Ok,回答了这两个问题之后,我们的思路就很清晰了。如果要实现operator=,那么至少要实现2个类,一个用于产生_1的对象,另一个用于代表operator=返回的函数对象。 Hj\>&vMf
g:<2yT
7.U
CX"
三. 动工 50h?#u6?
首先实现一个能够范型的进行赋值的函数对象类: F7[ 55RcP
EAafi<n
Zpc R
whFaL}2C
template < typename T > 12r]"?@|s
class assignment |:)UNb?R"O
{ C]H'z
T value; o+Cd\D69S
public : "g}m xPe
assignment( const T & v) : value(v) {} T6_LiB@
template < typename T2 > R8ZI}C1
T2 & operator ()(T2 & rhs) const { return rhs = value; } DvL/xlN
} ; =, kH(rp2
S 2vjjS
N;N,5rxV
其中operator()被声明为模版函数以支持不同类型之间的赋值。 l@C39VP
然后我们就可以书写_1的类来返回assignment ROH 2KSt
-aj) _.d
3s25Rps
h|m>JDxn
class holder w
K)/m`{g
{ o m9zb&{tu
public : Nr6[w|Tzd
template < typename T > oY Y?`<N#
assignment < T > operator = ( const T & t) const e:2e5gz
{ +7%}SV 2)
return assignment < T > (t); 4l)Q
} |a!y%R=
} ; \ct7~!qM
;F3#AO4(
XQW9/AzN f
由于该类是一个空类,因此我们可以在其后放心大胆的写上: _}G1/`09#
?VM4_dugf
static holder _1; 8":O\^i
Ok,现在一个最简单的lambda就完工了。你可以写 _pZ2^OO@
#\DKU@|h
for_each(v.begin(), v.end(), _1 = 1 ); cow]qe6K
而不用手动写一个函数对象。 iLhxcM2K
ftr?@^
BBkYc:B=SA
o]gS=iLp
四. 问题分析 UB5X2uBv
虽然基本上一个Lambda已经初步实现出来了,但是仔细想想,问题也是很多的。 uPZ<hG#K
1, 我们现在是把_1和functor看成两个不同的存在,会导致代码的重复。 78o>UWA:
2, 目前这个Lambda还无法实现如_1 = 2 = 3这样的链式操作。 Fkq;Q
3, 我们没有设计好如何处理多个参数的functor。 0{0A,;b
下面我们可以对这几个问题进行分析。 <