一. 什么是Lambda E]~#EFc
所谓Lambda,简单的说就是快速的小函数生成。 |khFQ(
在C++中,STL的很多算法都要求使用者提供一个函数对象。例如for_each函数,会要求用户提供一个表明“行为”的函数对象。以vector<bool>为例,如果想使用for_each对其中的各元素全部赋值为true,一般需要这么一个函数对象, >qy62:co
/7Sg/d%c
{ /!ryOA65
N~v<8vJq`
class filler a] c03$f K
{ >wqWIw.w>
public : OjffN'a+N
void operator ()( bool & i) const {i = true ;} D]iyr>V6'
} ; P|ibUxSA~,
[AFR \{
q/*veL
这样实现不但麻烦,而且不直观。而如果使用lambda,则允许用户使用一种直观和见解的方式来处理这个问题。以boost.lambda为例,刚才的问题可以这么解决: [g"nu0sOK
Dj=$Q44
<e
9d5-2
qm_r~j
for_each(v.begin(), v.end(), _1 = true ); <^>
nR3E
Da[#X`Kp$
s~(`~Y4
那么下面,就让我们来实现一个lambda库。 |a7Kn/[`,
)g8Kicox5
ZZkc) @
%?V~7tHm>
二. 战前分析 PyI"B96gz
首先要说明的是,我并没有读过boost.lambda或其他任何lambda库的代码,因此如代码有雷同,纯属巧合。 a6h+?Q7uF
开始实现以前,首先要分析出大致的实现手法。先让我们来看几段使用Lambda的代码 Zp{K_ec{
,tZL"
EY !o#m
for_each(v.begin(), v.end(), _1 = 1 ); "+O/OKfR0
/* --------------------------------------------- */ ,\+N}F^
vector < int *> vp( 10 ); t; #@t/`
transform(v.begin(), v.end(), vp.begin(), & _1); AwuhFPG
/* --------------------------------------------- */ (0y!{ (a
sort(vp.begin(), vp.end(), * _1 > * _2); WaX!y$/z
/* --------------------------------------------- */ ;=P!fvHk
int b = * find_if(v.begin, v.end(), _1 >= 3 && _1 < 5 ); Ed0}$b
/* --------------------------------------------- */ g*_n|7pB
for_each(vp.begin(), vp.end(), cout << * _1 << ' \n ' ); 8]#J_|A6Z
/* --------------------------------------------- */ "tJ[M
for_each(vp.begin(), vp.end(), cout << constant( ' \n ' ) << * _1); $P8AU81
73u97oe>1
w?*79 u
Ht}?=ZzW
看了之后,我们可以思考一些问题: Uv<nJM
1._1, _2是什么? ,bM):
显然_1和_2都满足C++对于标识符的要求,可见_1和_2都是对象。 k]-Q3V
2._1 = 1是在做什么? 7zN7PHT=$t
既然_1是一个对象,那么_1的类必然重载了operator=(int)。那么operator=返回什么呢?该函数所返回的对象被传入for_each的第3个参数,可见其返回了一个函数对象。现在整个流程就很清楚了。_1 = 1调用了operator=,其返回了一个函数对象,该函数对象能够将参数1赋值为1。 Y0Tw:1a
Ok,回答了这两个问题之后,我们的思路就很清晰了。如果要实现operator=,那么至少要实现2个类,一个用于产生_1的对象,另一个用于代表operator=返回的函数对象。 C
%j%>X`
:!$+dr(d
EcytNYn
三. 动工 58mpW`Q
首先实现一个能够范型的进行赋值的函数对象类: !YO'u'4<aK
x@)cj
{ktwX\z
8ZjRMr}
template < typename T > mss.\
class assignment >bmdu\j5R
{ ;2?fz@KZ
T value; f*xv#G
public : *(wxNsK
assignment( const T & v) : value(v) {} fV6ddh
template < typename T2 > F4V) 0)G
T2 & operator ()(T2 & rhs) const { return rhs = value; } 2*gB ~Jn4
} ; PN J&{4wY
yP` K [/
C(>g4.-p8
其中operator()被声明为模版函数以支持不同类型之间的赋值。 }2c&ARQ.m>
然后我们就可以书写_1的类来返回assignment e6 <9`Xg
<dXeP/1w`
9G7Br s:
@0tX,Z9
class holder j}J=ZLr/V"
{ 5w~J"P6jg
public : heWQPM|s
template < typename T > aehB,l0
assignment < T > operator = ( const T & t) const |,H2ge
{ -~_|ZnuM9
return assignment < T > (t); %SCt_9u
} r1=j$G
} ; z'O+B}
?y"M>#
:7Uv)@iUk
由于该类是一个空类,因此我们可以在其后放心大胆的写上: sC2NFb-+&
XW2ZQMos1
static holder _1; G%!i="/9
Ok,现在一个最简单的lambda就完工了。你可以写 +RiI5.$=Z
VS7
for_each(v.begin(), v.end(), _1 = 1 ); QTN24 q4
而不用手动写一个函数对象。 Gv#bd05X
m9DTz$S.
i;Kax4k
a>d`g
四. 问题分析 SY@;u<Pd
虽然基本上一个Lambda已经初步实现出来了,但是仔细想想,问题也是很多的。 yVK l%GO
1, 我们现在是把_1和functor看成两个不同的存在,会导致代码的重复。 |S<!'rY
2, 目前这个Lambda还无法实现如_1 = 2 = 3这样的链式操作。 *<"{(sAvk
3, 我们没有设计好如何处理多个参数的functor。 79o=HiOF99
下面我们可以对这几个问题进行分析。 RHbbj}B
(_3'nFg
五. 问题1:一致性 cc1M9kVi
首先来看看1,合并_1和functor的最佳方法就是把_1本身也变成functor。那么_1的operator()会做什么事情呢?| sint":1FC
很明显,_1的operator()仅仅应该返回传进来的参数本身。 sK/ymEfRv
qM2m !
struct holder c&