Topic: Default constructed lambda closures
Author: =?UTF-8?Q?R=C3=B3bert_D=C3=A1vid?= <lrdxgm@gmail.com>
Date: Sun, 30 Dec 2012 14:10:27 -0800 (PST)
Raw View
------=_Part_311_3759921.1356905427393
Content-Type: text/plain; charset=ISO-8859-1
Hello everyone,
what would you think about lambda closure types with empty capture lists
having a default constructor?
Why do I think it would be beneficial? I want to something similar to:
struct Rect {
double a;
double b;
};
typedef std::set<Rect, decltype([](const Rect& l, const Rect& r){ return l.a
*l.b < r.a*r.b; })> RectsByArea;
typedef std::set<Rect, decltype([](const Rect& l, const Rect& r){ return l.
a+l.b < r.a+r.b; })> RectsByCirc;
typedef std::set<Rect, decltype([](const Rect& l, const Rect& r){ return l.
a*l.a+l.b*l.b < r.a*l.a+r.b*r.b; })> RectsByDiag;
RectsByArea ra;
RectsByCirc rc;
RectsByDiag rd;
Using C++/11 this will fail with the lambda not having a default
constructor. Why? The default constructor of std::set is actually a
two-parameter constructor with default parameters: first to the comparator,
the second to the allocator. Now the allocator here is not the problem, but
the comparator, what is here the lambda - and it does not have a default
constructor.
For some compilers, there is actually a more-less usable workaround that
almost does what I wanted (tested with Visual Studio 2010 and GCC 4.6):
auto byArea = [](const Rect& l, const Rect& r){ return l.a*l.a+l.b*l.b < r.a
*l.a+r.b*r.b; }
std::set<Rect, decltype(byArea)> rectsByArea(byArea);
The code here is still (somewhat) local, but for some functions it
explodes: for example, the copy assignment operator - being a template, we
are good until we want to use them... Also, it breaks under Visual Studio
2012 (and possibly more compilers as well): there, if the comparator has a
sizeof of 0, it does not store it, just default-constructs when needed -
with the lambda, we are back to square one.
I know this can be avoided by having a few plain old functors with
operator(), but the whole idea of lambdas is that the functor is written
in-line.
The change to the standard would be "minor": in section 5.1.2.19, it
currently states (at least in the latest public draft n3337):
The closure type associated with a lambda-expression has a deleted (8.4.3)
> default constructor and a deleted
> copy assignment operator.
>
This should be changed to define a default constructor for closures without
lambda captures, the same way it defines a conversion operator to a
function pointer for them - something similar to:
The closure type for a lambda-expression with no lambda-capture has a
> public implicitly-declared (12.8) default constructor. Closure types
> associated with a lambda-expression with more than zero lambda-captures
> have a deleted (8.4.3) default constructor and a deleted copy assignment
> operator.
>
My only concern if default construction could break something - but I could
not find anything like that.
What do you think?
--
------=_Part_311_3759921.1356905427393
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Hello everyone,<br><br>what would you think about lambda closure types with=
empty capture lists having a default constructor?<br><br>Why do I think it=
would be beneficial? I want to something similar to:<div class=3D"prettypr=
int" style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, =
187, 187); border-style: solid; border-width: 1px; word-wrap: break-word;">=
<code class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"co=
lor: #008;" class=3D"styled-by-prettify">struct</span><span style=3D"color:=
#000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #606;" c=
lass=3D"styled-by-prettify">Rect</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"><br> </span><span style=3D"color: #008;" class=3D"styled-=
by-prettify">double</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> a</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbs=
p; </span><span style=3D"color: #008;" class=3D"styled-by-prettify">d=
ouble</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> b</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">};</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"><br><br>typedef std</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"col=
or: #008;" class=3D"styled-by-prettify">set</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify"><</span><span style=3D"color: #606;" cl=
ass=3D"styled-by-prettify">Rect</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettif=
y">decltype</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>([](</span><span style=3D"color: #008;" class=3D"styled-by-prettify">const=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><s=
pan style=3D"color: #606;" class=3D"styled-by-prettify">Rect</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">&</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> l</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D=
"styled-by-prettify">const</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> </span><span style=3D"color: #606;" class=3D"styled-by-pre=
ttify">Rect</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>&</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> r</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">){</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">return</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> l</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">.</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify">a</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">*</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify">l</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify">b </span><=
span style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> r</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">.</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify">a</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">*</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify">r</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">.</span><span style=3D"color: #000;" class=3D"styled-by-prettify">b<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">})></span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> RectsByArea</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br><br></span><code class=3D"prettyp=
rint"><span style=3D"color: #000;" class=3D"styled-by-prettify"><code class=
=3D"prettyprint"><span style=3D"color: #000;" class=3D"styled-by-prettify">=
typedef </span></code>std</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">::</span><span style=3D"color: #008;" class=3D"styled-by-pre=
ttify">set</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
<</span><span style=3D"color: #606;" class=3D"styled-by-prettify">Rect</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">decltype</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">([](</span><span style=3D"co=
lor: #008;" class=3D"styled-by-prettify">const</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #606;" cl=
ass=3D"styled-by-prettify">Rect</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">&</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> l</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
</span><span style=3D"color: #008;" class=3D"styled-by-prettify">const</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span s=
tyle=3D"color: #606;" class=3D"styled-by-prettify">Rect</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">&</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> r</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">){</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"sty=
led-by-prettify">return</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"> l</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">.</span><span style=3D"color: #000;" class=3D"styled-by-prettify">a+</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify"></span><span=
style=3D"color: #000;" class=3D"styled-by-prettify">l</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">.</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify">b </span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify"><</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> r</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">.</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy">a</span><span style=3D"color: #660;" class=3D"styled-by-prettify">+</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify">r</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">.</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify">b</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">})></span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> RectsByCirc;</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br><br></span></code><code class=3D"prettyprint"><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"><code class=3D"prettyprint"=
><span style=3D"color: #000;" class=3D"styled-by-prettify">typedef </span><=
/code>std::set<Rect, </span></code><code class=3D"prettyprint"><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"><code class=3D"prettyprint=
"><code class=3D"prettyprint"><span style=3D"color: #008;" class=3D"styled-=
by-prettify">decltype</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">([](</span><span style=3D"color: #008;" class=3D"styled-by-prett=
ify">const</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
</span><span style=3D"color: #606;" class=3D"styled-by-prettify">Rect</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">&</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> l</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" =
class=3D"styled-by-prettify">const</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #606;" class=3D"style=
d-by-prettify">Rect</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">&</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> r</span><span style=3D"color: #660;" class=3D"styled-by-prettify">){</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><spa=
n style=3D"color: #008;" class=3D"styled-by-prettify">return</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> l</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">.</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify">a*l.a+</span><span style=3D"color: #660;" =
class=3D"styled-by-prettify"></span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify">l</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">.</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
>b*l.b </span><span style=3D"color: #660;" class=3D"styled-by-prettify"><=
;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> r</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">.</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify">a</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">*l.a+</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify">r</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">.</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify">b</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">*r.b;</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">})>=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> RectsByDi=
ag;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br=
>RectsByArea ra;<br>RectsByCirc rc;<br>RectsByDiag rd;<br></span></code></c=
ode></span><span style=3D"color: #000;" class=3D"styled-by-prettify"></span=
></code></div></code></div><br>Using C++/11 this will fail with the lambda =
not having a default constructor. Why? The default constructor of std::set =
is actually a two-parameter constructor with default parameters: first to t=
he comparator, the second to the allocator. Now the allocator here is not t=
he problem, but the comparator, what is here the lambda - and it does not h=
ave a default constructor.<br><br>For some compilers, there is actually a m=
ore-less usable workaround that almost does what I wanted (tested with Visu=
al Studio 2010 and GCC 4.6):<br><div class=3D"prettyprint" style=3D"backgro=
und-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-sty=
le: solid; border-width: 1px; word-wrap: break-word;"><code class=3D"pretty=
print"><div class=3D"subprettyprint"><span style=3D"color: #606;" class=3D"=
styled-by-prettify">auto byArea =3D []</span><code class=3D"prettyprint"><c=
ode class=3D"prettyprint"><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"><code class=3D"prettyprint"><code class=3D"prettyprint"><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"colo=
r: #008;" class=3D"styled-by-prettify">const</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> </span><span style=3D"color: #606;" clas=
s=3D"styled-by-prettify">Rect</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">&</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify"> l</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </=
span><span style=3D"color: #008;" class=3D"styled-by-prettify">const</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span sty=
le=3D"color: #606;" class=3D"styled-by-prettify">Rect</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">&</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> r</span><span style=3D"color: #660;"=
class=3D"styled-by-prettify">){</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"style=
d-by-prettify">return</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> l</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">.</span><span style=3D"color: #000;" class=3D"styled-by-prettify">a*l.a+=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify"></span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify">l</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">.</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify">b*l.b </span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify"><</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> r</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">.</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify">a</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">*l.a+</span><span style=3D"color: #000;" class=3D"styled-by-prettify">r</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify">b</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">*r.b;</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">}</span></code></code></span></code></code=
><span style=3D"color: #660;" class=3D"styled-by-prettify"></span><br>std::=
set<Rect, decltype(byArea)> rectsByArea(byArea);<br></div></code></di=
v>The code here is still (somewhat) local, but for some functions it explod=
es: for example, the copy assignment operator - being a template, we are go=
od until we want to use them... Also, it breaks under Visual Studio 2012 (a=
nd possibly more compilers as well): there, if the comparator has a sizeof =
of 0, it does not store it, just default-constructs when needed - with the =
lambda, we are back to square one.<br><br>I know this can be avoided by hav=
ing a few plain old functors with operator(), but the whole idea of lambdas=
is that the functor is written in-line.<br><br>The change to the standard =
would be "minor": in section 5.1.2.19, it currently states (at least in the=
latest public draft n3337):<br><br><blockquote style=3D"margin: 0px 0px 0p=
x 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;" cla=
ss=3D"gmail_quote">The closure type associated with a lambda-expression has=
a deleted (8.4.3) default constructor and a deleted<br>copy assignment ope=
rator.<br></blockquote><br>This should be changed to define a default const=
ructor for closures without lambda captures, the same way it defines a conv=
ersion operator to a function pointer for them - something similar to:<br><=
br><blockquote style=3D"margin: 0px 0px 0px 0.8ex; border-left: 1px solid r=
gb(204, 204, 204); padding-left: 1ex;" class=3D"gmail_quote">The closure ty=
pe for a lambda-expression with no lambda-capture has a public implicitly-d=
eclared (12.8) default constructor. Closure types associated with a lambda-=
expression with more than zero lambda-captures have a deleted (8.4.3) defau=
lt constructor and a deleted copy assignment operator.<br></blockquote><br>=
My only concern if default construction could break something - but I could=
not find anything like that.<br>What do you think?<br>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_311_3759921.1356905427393--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sun, 30 Dec 2012 15:20:29 -0800 (PST)
Raw View
------=_Part_1268_4990831.1356909629937
Content-Type: text/plain; charset=ISO-8859-1
Lambda functions are not intended to be a quick way of writing a functor
that you intend to use from multiple places. It's for writing a function
locally which you can pass as callbacks or to algorithms and the like. They
exist to make code more readable and make it more obvious what you're doing.
Just make a functor. It's not that hard, and it will be *far* more readable
for the user. I certainly don't want to see IntelliSense tell me that the
typedef RectByArea is "std::set<Rect, decltype([](const Rect& l, const
Rect& r){ return l.a*l.b < r.a*r.b; })>".
--
------=_Part_1268_4990831.1356909629937
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Lambda functions are not intended to be a quick way of writing a functor th=
at you intend to use from multiple places. It's for writing a function loca=
lly which you can pass as callbacks or to algorithms and the like. They exi=
st to make code more readable and make it more obvious what you're doing.<b=
r><br>Just make a functor. It's not that hard, and it will be <i>far</i> mo=
re readable for the user. I certainly don't want to see IntelliSense tell m=
e that the typedef RectByArea is "std::set<Rect, decltype([](const Rect&=
amp; l, const Rect& r){ return l.a*l.b < r.a*r.b; })>".<br>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_1268_4990831.1356909629937--
.
Author: =?UTF-8?Q?R=C3=B3bert_D=C3=A1vid?= <lrdxgm@gmail.com>
Date: Sun, 30 Dec 2012 15:44:39 -0800 (PST)
Raw View
------=_Part_62_19658109.1356911079802
Content-Type: text/plain; charset=ISO-8859-1
I agree that lambdas are made only to pass callbacks and to algorithms and
the like - this is 'the like' part :) Take note, the example is watered
down for easier understanding. I have found quite a few times that having a
lambda - a locally written functor - passed as a comparator to a container
would produce a lot cleaner code (and with the workaround, it does, if one
can live with its current drawbacks).
Lambdas are a way to write a functor locally, and that is exactly what I am
looking for. Why making the restriction of disallowed re-usage? For some
cases (like in the example), the lack of the default constructor prevents
that - and if it does not break anything else, why preventing.
For a compiler, no-capture lambdas are already special case because of the
conversion to function pointer, so this is not too complicating to
implement.
It is not *hard* to make a functor, but extending that logic, why do we
have lambdas at all?
--
------=_Part_62_19658109.1356911079802
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
I agree that lambdas are made only to pass callbacks and to algorithms and =
the like - this is 'the like' part :) Take note, the example is watered dow=
n for easier understanding. I have found quite a few times that having a la=
mbda - a locally written functor - passed as a comparator to a container wo=
uld produce a lot cleaner code (and with the workaround, it does, if one ca=
n live with its current drawbacks).<br><br>Lambdas are a way to write a fun=
ctor locally, and that is exactly what I am looking for. Why making the res=
triction of disallowed re-usage? For some cases (like in the example), the =
lack of the default constructor prevents that - and if it does not break an=
ything else, why preventing.<br><br>For a compiler, no-capture lambdas are =
already special case because of the conversion to function pointer, so this=
is not too complicating to implement.<br><br>It is not <i>hard</i> to make=
a functor, but extending that logic, why do we have lambdas at all?<br>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_62_19658109.1356911079802--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sun, 30 Dec 2012 17:08:59 -0800 (PST)
Raw View
------=_Part_165_23228150.1356916139828
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On Sunday, December 30, 2012 3:44:39 PM UTC-8, R=F3bert D=E1vid wrote:
>
> I agree that lambdas are made only to pass callbacks and to algorithms an=
d=20
> the like - this is 'the like' part :) Take note, the example is watered=
=20
> down for easier understanding. I have found quite a few times that having=
a=20
> lambda - a locally written functor - passed as a comparator to a containe=
r=20
> would produce a lot cleaner code (and with the workaround, it does, if on=
e=20
> can live with its current drawbacks).
>
> Lambdas are a way to write a functor locally, and that is exactly what I=
=20
> am looking for. Why making the restriction of disallowed re-usage? For so=
me=20
> cases (like in the example), the lack of the default constructor prevents=
=20
> that - and if it does not break anything else, why preventing.
>
> For a compiler, no-capture lambdas are already special case because of th=
e=20
> conversion to function pointer, so this is not too complicating to=20
> implement.
>
> It is not *hard* to make a functor, but extending that logic, why do we=
=20
> have lambdas at all?
>
Because lambdas improve code locality. 99 times out of 100, if you're=20
instantiating a template, you're probably going to instantiate it in more=
=20
than one function. Especially given your example of a typedef in a header.
Within a function, in C++98, you couldn't create a struct and use it in a=
=20
template. Lambdas are a way to put code in the function where it is used.=
=20
We don't have that problem in a header like this. You're not harming code=
=20
locality by moving the "lambda" one line up like this:
struct CompareByArea{ bool operator()(const Rect& l, const Rect& r){ return=
l
..a*l.b < r.a*r.b; }};
typedef std::set<Rect, CompareByArea> RectsByArea;
Plus, odds are good that you will want to use `CompareByArea` in more than=
=20
one place.
It's not a question of implementation burden. It's a question of whether we=
=20
should *ever* encourage users to type "decltype([]...)". I do not think we=
=20
should; nothing good comes of that.
--=20
------=_Part_165_23228150.1356916139828
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<br><br>On Sunday, December 30, 2012 3:44:39 PM UTC-8, R=F3bert D=E1vid wro=
te:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;=
border-left: 1px #ccc solid;padding-left: 1ex;">I agree that lambdas are ma=
de only to pass callbacks and to algorithms and the like - this is 'the lik=
e' part :) Take note, the example is watered down for easier understanding.=
I have found quite a few times that having a lambda - a locally written fu=
nctor - passed as a comparator to a container would produce a lot cleaner c=
ode (and with the workaround, it does, if one can live with its current dra=
wbacks).<br><br>Lambdas are a way to write a functor locally, and that is e=
xactly what I am looking for. Why making the restriction of disallowed re-u=
sage? For some cases (like in the example), the lack of the default constru=
ctor prevents that - and if it does not break anything else, why preventing=
..<br><br>For a compiler, no-capture lambdas are already special case becaus=
e of the conversion to function pointer, so this is not too complicating to=
implement.<br><br>It is not <i>hard</i> to make a functor, but extending t=
hat logic, why do we have lambdas at all?<br></blockquote><div><br>Because =
lambdas improve code locality. 99 times out of 100, if you're instantiating=
a template, you're probably going to instantiate it in more than one funct=
ion. Especially given your example of a typedef in a header.<br><br>Within =
a function, in C++98, you couldn't create a struct and use it in a
template. Lambdas are a way to put code in the function where it is=20
used. We don't have that problem in a header like this. You're not harming =
code locality by moving the "lambda" one line up like this:<br><br><div cla=
ss=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); border-co=
lor: rgb(187, 187, 187); border-style: solid; border-width: 1px; word-wrap:=
break-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><sp=
an style=3D"color: #008;" class=3D"styled-by-prettify">struct</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"c=
olor: #606;" class=3D"styled-by-prettify">CompareByArea</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" =
class=3D"styled-by-prettify">bool</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"style=
d-by-prettify">operator</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">()(</span><span style=3D"color: #008;" class=3D"styled-by-pret=
tify">const</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> </span><span style=3D"color: #606;" class=3D"styled-by-prettify">Rect</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">&</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> l</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;"=
class=3D"styled-by-prettify">const</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> </span><span style=3D"color: #606;" class=3D"styl=
ed-by-prettify">Rect</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">&</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> r</span><span style=3D"color: #660;" class=3D"styled-by-prettify">){<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><sp=
an style=3D"color: #008;" class=3D"styled-by-prettify">return</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> l</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">.</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify">a</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">*</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify">l</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">.</span><span style=3D"color: #000;" class=3D"styled-by-prettify">b =
</span><span style=3D"color: #660;" class=3D"styled-by-prettify"><</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> r</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">.</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify">a</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">*</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">r</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">.</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify">b</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">}};</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"co=
lor: #008;" class=3D"styled-by-prettify">typedef</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> std</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">::</span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">set</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify"><</span><span style=3D"color: #606;" class=3D"styled-by=
-prettify">Rect</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </s=
pan><span style=3D"color: #606;" class=3D"styled-by-prettify">CompareByArea=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">></span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span st=
yle=3D"color: #606;" class=3D"styled-by-prettify">RectsByArea</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">;</span></div></code></d=
iv><br>Plus, odds are good that you will want to use `CompareByArea` in mor=
e than one place.<br><br>It's not a question of implementation burden. It's=
a question of whether we should <i>ever</i> encourage users to type "declt=
ype([]...)". I do not think we should; nothing good comes of that.<br></div=
>
<p></p>
-- <br />
<br />
<br />
<br />
------=_Part_165_23228150.1356916139828--
.
Author: Nevin Liber <nevin@eviloverlord.com>
Date: Mon, 31 Dec 2012 09:43:57 -0600
Raw View
--0015174bddc61fbabb04d227e4b3
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On 30 December 2012 16:10, R=F3bert D=E1vid <lrdxgm@gmail.com> wrote:
> Hello everyone,
>
> what would you think about lambda closure types with empty capture lists
> having a default constructor?
>
+1.
> For some compilers, there is actually a more-less usable workaround that
> almost does what I wanted (tested with Visual Studio 2010 and GCC 4.6):
> auto byArea =3D [](const Rect& l, const Rect& r){ return l.a*l.a+l.b*l.b =
< r
> .a*l.a+r.b*r.b; }
> std::set<Rect, decltype(byArea)> rectsByArea(byArea);
>
As most of my sets/maps tend to be class members, the above technique
doesn't work, and I end up writing explicit function object types to deal
with it.
The change to the standard would be "minor": in section 5.1.2.19, it
> currently states (at least in the latest public draft n3337):
>
> The closure type for a lambda-expression with no lambda-capture has a
>> public implicitly-declared (12.8) default constructor.
>
>
I think the above is the only change you need.
--=20
Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404
--=20
--0015174bddc61fbabb04d227e4b3
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
On 30 December 2012 16:10, R=F3bert D=E1vid <span dir=3D"ltr"><<a href=
=3D"mailto:lrdxgm@gmail.com" target=3D"_blank">lrdxgm@gmail.com</a>></sp=
an> wrote:<br><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" =
style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hello everyone,<br><br>what would you think about lambda closure types with=
empty capture lists having a default constructor?<br></blockquote><div><br=
></div><div>+1.</div><div><br></div><blockquote class=3D"gmail_quote" style=
=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>For some compilers, there is actually a more-less usable workaround tha=
t almost does what I wanted (tested with Visual Studio 2010 and GCC 4.6):<b=
r><div style=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,=
187);border-style:solid;border-width:1px;word-wrap:break-word">
<code><div><span style=3D"color:#606">auto byArea =3D []</span><code><code>=
<span style><code><code><span style=3D"color:#660">(</span><span style=3D"c=
olor:#008">const</span><span style> </span><span style=3D"color:#606">Rect<=
/span><span style=3D"color:#660">&</span><span style> l</span><span sty=
le=3D"color:#660">,</span><span style> </span><span style=3D"color:#008">co=
nst</span><span style> </span><span style=3D"color:#606">Rect</span><span s=
tyle=3D"color:#660">&</span><span style> r</span><span style=3D"color:#=
660">){</span><span style> </span><span style=3D"color:#008">return</span><=
span style> l</span><span style=3D"color:#660">.</span><span style>a*l.a+</=
span><span style=3D"color:#660"></span><span style>l</span><span style=3D"c=
olor:#660">.</span><span style>b*l.b </span><span style=3D"color:#660"><=
</span><span style> r</span><span style=3D"color:#660">.</span><span style>=
a</span><span style=3D"color:#660">*l.a+</span><span style>r</span><span st=
yle=3D"color:#660">.</span><span style>b</span><span style=3D"color:#660">*=
r.b;</span><span style> </span><span style=3D"color:#660">}</span></code></=
code></span></code></code><span style=3D"color:#660"></span><br>
std::set<Rect, decltype(byArea)> rectsByArea(byArea);<br></div></code=
></div></blockquote><div><br></div><div>As most of my sets/maps tend to be =
class members, the above technique doesn't work, and I end up writing e=
xplicit function object types to deal with it.</div>
<div><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex=
;border-left:1px #ccc solid;padding-left:1ex">The change to the standard wo=
uld be "minor": in section 5.1.2.19, it currently states (at leas=
t in the latest public draft n3337):<br>
<br><blockquote style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb=
(204,204,204);padding-left:1ex" class=3D"gmail_quote">The closure type for =
a lambda-expression with no lambda-capture has a public implicitly-declared=
(12.8) default constructor.</blockquote>
</blockquote><div><br></div><div>=A0I think the above is the only change yo=
u need.</div></div>-- <br>=A0Nevin ":-)" Liber=A0 <mailto:<a h=
ref=3D"mailto:nevin@eviloverlord.com" target=3D"_blank">nevin@eviloverlord.=
com</a>>=A0 (847) 691-1404
<p></p>
-- <br />
<br />
<br />
<br />
--0015174bddc61fbabb04d227e4b3--
.