一. 什么是Lambda ^=Up UB
所谓Lambda,简单的说就是快速的小函数生成。 Z.VVY\
在C++中,STL的很多算法都要求使用者提供一个函数对象。例如for_each函数,会要求用户提供一个表明“行为”的函数对象。以vector<bool>为例,如果想使用for_each对其中的各元素全部赋值为true,一般需要这么一个函数对象, Fc42TH
p
[ nYwJ
IXX^C}\,
H}JH339
class filler Gl}=Q7
{ j s7J#b7
public : CWt,cwFW
void operator ()( bool & i) const {i = true ;} UZ&bT'>;9g
} ; O,: en t|
o_os;
&|Z:8]'P
这样实现不但麻烦,而且不直观。而如果使用lambda,则允许用户使用一种直观和见解的方式来处理这个问题。以boost.lambda为例,刚才的问题可以这么解决: T4qbyui{
ugucq},[
6}{2W<
Uj6R?E{Jt
for_each(v.begin(), v.end(), _1 = true ); F]SexP4:A
E}\^GNT
QT\S>}
那么下面,就让我们来实现一个lambda库。 sStaTR{
$eRxCX?b2
=^=9z'u"=
xdp{y=,[
二. 战前分析 +<@7x16
首先要说明的是,我并没有读过boost.lambda或其他任何lambda库的代码,因此如代码有雷同,纯属巧合。 c?b?x
6 2
开始实现以前,首先要分析出大致的实现手法。先让我们来看几段使用Lambda的代码 3(6i6 vV
[0F+t,`
"YHe]R>3s
for_each(v.begin(), v.end(), _1 = 1 ); >MS}7Hk\
/* --------------------------------------------- */ )#i]exZ
vector < int *> vp( 10 ); #Rjm3#gc
transform(v.begin(), v.end(), vp.begin(), & _1); )N`ia%p_]
/* --------------------------------------------- */ QQ1+uY
sort(vp.begin(), vp.end(), * _1 > * _2); ;STO!^9~
/* --------------------------------------------- */ |~rDEv3
int b = * find_if(v.begin, v.end(), _1 >= 3 && _1 < 5 ); 3"!2C,3c#
/* --------------------------------------------- */ )!p=0&z@{
for_each(vp.begin(), vp.end(), cout << * _1 << ' \n ' );
<k/'mBDk
/* --------------------------------------------- */ kB"Sh_:m
for_each(vp.begin(), vp.end(), cout << constant( ' \n ' ) << * _1); g8!!:fdu
QBY7ZT05Gt
d*8 c,x
kn`KU.J.
看了之后,我们可以思考一些问题: 8uS1HE\%
1._1, _2是什么? NzNAhlXj3
显然_1和_2都满足C++对于标识符的要求,可见_1和_2都是对象。 xg\M9&J
2._1 = 1是在做什么? S
#&HB
既然_1是一个对象,那么_1的类必然重载了operator=(int)。那么operator=返回什么呢?该函数所返回的对象被传入for_each的第3个参数,可见其返回了一个函数对象。现在整个流程就很清楚了。_1 = 1调用了operator=,其返回了一个函数对象,该函数对象能够将参数1赋值为1。 h'w9=Pk~6y
Ok,回答了这两个问题之后,我们的思路就很清晰了。如果要实现operator=,那么至少要实现2个类,一个用于产生_1的对象,另一个用于代表operator=返回的函数对象。 8~\Fpz|Og
qs 52)$
Zdj~B1
三. 动工 `H^Nc\P#
首先实现一个能够范型的进行赋值的函数对象类: DQH _@-q
aztP`S$h
4D9lZa}
XC0G5rtB
template < typename T > lb`P9mbr+
class assignment x-CYG?-x
{ W&BwBp]K
T value; %w6> 3#e
public : CG$S?
assignment( const T & v) : value(v) {} M1Od%nz3
template < typename T2 > )Qb1$%r.
T2 & operator ()(T2 & rhs) const { return rhs = value; } @l>\vs<
} ; M+)%gnq`u
G-bG}9vc]
Nr3td`;
其中operator()被声明为模版函数以支持不同类型之间的赋值。 %v
:a
然后我们就可以书写_1的类来返回assignment pRUN[[L
c{rX7+bN
zO9|s}J8q
WO^smCk
class holder ./J.OU1
{ OQW#BBet@
public : 1\kOjF)l
template < typename T > J
A4'e@
assignment < T > operator = ( const T & t) const 5|S|HZ8G
{ Q gDjc'
return assignment < T > (t); PFUb\AY
} ~ E>D0o
} ; k;;?3)!
wC'KI8-
UQ`%,D
由于该类是一个空类,因此我们可以在其后放心大胆的写上: &FkKnz4IZ
n*@^c$&P
static holder _1; /o+,
=7hY
Ok,现在一个最简单的lambda就完工了。你可以写 J>]' {!+
+7N6]pK|"
for_each(v.begin(), v.end(), _1 = 1 ); HBo^8wN
而不用手动写一个函数对象。 !+9H=u
.I
{X
Ai(M06P:h
IP&En8W+
四. 问题分析 >OZ+k(saL
虽然基本上一个Lambda已经初步实现出来了,但是仔细想想,问题也是很多的。 &