Topic: Reconsidering lambdas in unevaluated contexts
Author: Louis Dionne <ldionne.2@gmail.com>
Date: Tue, 29 Sep 2015 12:31:01 -0700 (PDT)
Raw View
------=_Part_470_136901664.1443555061080
Content-Type: multipart/alternative;
boundary="----=_Part_471_279776217.1443555061081"
------=_Part_471_279776217.1443555061081
Content-Type: text/plain; charset=UTF-8
Hi,
I would like to re-open a discussion about allowing lambdas inside
unevaluated
contexts. For the record, here is a good explanation of the rationale for
disallowing them:
http://stackoverflow.com/q/22232164/627587
and the original discussion that started the debate:
https://groups.google.com/forum/#!msg/comp.lang.c++.moderated/J9MbhcOrAzY/XjKeWEbU1EcJ
Summary of the problem
Let me summarize my understanding of the rationale (please correct me if I'm
wrong on something):
1. Allowing lambdas in unevaluated contexts creates the problem that
performing
SFINAE inside the lambda is hard to implement for compilers. For example:
template <typename X>
auto f(X x) -> decltype([](auto x) {
// Some expression(s) that might be invalid, but SFINAE should
be
// performed. Since these expressions can be arbitrarily
complex,
// this is like SFINAE on steroids, which is hard to implement.
}(x));
2. Knowing the type of a lambda is pretty much useless, since that type is
unique anyway. Hence, the following would hold:
static_assert(!std::is_same<
decltype([](auto x, auto y) { return x + y; }),
decltype([](auto x, auto y) { return x + y; })
>::value, "");
In particular, this means that code like
using Plus = decltype([](auto x, auto y) { return x + y; });
Plus plus = [](auto x, auto y) { return x + y; };
is not valid, which seems to reduce the usefulness of the feature.
3. Since lambdas have unique types, how should we mangle the signature of
a function having a lambda in it? Consider the following:
void f(decltype([](auto x) { }));
How should we mangle the signature of `f`, and how can we make sure that
it
is mangled the same way inside each translation unit where this
declaration
appears?
Having found a compelling use case for lambdas inside unevaluated contexts,
I think it is worth reconsidering that restriction, which seems too strong.
The use case
The use case is performing type-level computations (like Boost.MPL) using
generic lambdas rather than a custom domain specific language (like MPL
LambdaExpressions). This new way of doing type-level computations is
exploited
in the Boost.Hana library [1]. Here is an explanation of that technique.
First, let's assume we have heterogeneous algorithms, which are basically
STL algorithms that work on tuples (a bit like Boost.Fusion, too):
// Returns the first element of `tuple` for which `pred` returns a
// true-valued `std::integral_constant`.
template <typename ...T, typename Predicate>
auto find_if(std::tuple<T...> tuple, Predicate pred);
It is also possible to define other algorithms like `for_each`, `transform`
and so on, but let's keep this minimal. Now, we can define a wrapper to
represent a type using an object, and we can define type traits (or
arbitrary
metafunctions) as normal functions taking such wrappers:
template <typename T>
struct Type { using type = T; };
template <typename T>
std::is_pointer<T> is_pointer(Type<T>) { return {}; }
Finally, we can use these in conjunction with our heterogeneous algorithms
to perform type-level computations using the usual C++ syntax:
auto types = std::make_tuple(Type<int>{}, Type<float*>{}, Type<char>{});
auto first_ptr = find_if(types, [](auto t) {
return is_pointer(t);
});
using FirstPtr = decltype(first_ptr)::type;
Within this new paradigm, it would often be useful to have lambdas inside
unevaluated contexts in order to skip the intermediate `first_ptr` variable.
Indeed, it would be more natural to simply write
using FirstPtr = decltype(find_if(types, [](auto t) {
return is_pointer(t);
}))::type;
Lifting the restriction
Clearly, point (2) of the rationale given above does not apply anymore,
since
there is a very clear use case of lambdas inside unevaluated contexts. While
you might not be convinced by the above example, Boost.Hana [1] contains
many
serious examples where this would be useful.
Secondly, preventing lambdas from appearing in unevaluated contexts for the
sole purpose of point (3) is arguably way overkill. Indeed, we do not need
the actual type of a lambda to appear inside a function signature in the
general case; we merely need to be able to pass a lambda to another function
and then use `decltype` on the result. Similarly, it would be better
(although
still too strong) if `decltype([]() {})` was prohibited for reason (3), but
prohibiting `decltype([](){} ())` (note the call to the lambda) seems to be
overly restrictive.
I have talked to Richard Smith about this at CppCon 2015, and IIRC he said
that restrictions on what could and couldn't appear inside a mangled name
was
now being stated explicitly in the standard. Hence, point (3) might not even
be a valid reason anymore.
Finally, there's point (1) about SFINAE. IMO, it would be better than
nothing
if the standard just said that no SFINAE could happen inside the lambda's
body,
so that a hard error is triggered instead. This would lead the door open to
adding support for SFINAE inside lambdas at a later time, and would enable
many use cases right now.
Also, FWIW, Clang has a bug right now that _sometimes_ makes it possible to
use lambdas inside unevaluated contexts. So it is definitely possible to
implement it. See [2] for more information.
I'd like to gather thoughts and comments about lifting this restriction, and
to confirm that reason (3) does not apply anymore. If there are no reasons
not
to proceed, I will then open a core issue (I was told it was the best way to
do this).
Regards,
Louis Dionne
[1]: https://github.com/ldionne/hana
[2]: https://github.com/ldionne/hana/issues/4#issuecomment-51244672
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_471_279776217.1443555061081
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>Hi,</div><div><br></div><div>I would like to re-open =
a discussion about allowing lambdas inside unevaluated</div><div>contexts. =
For the record, here is a good explanation of the rationale for</div><div>d=
isallowing them:</div><div><br></div><div>=C2=A0 =C2=A0 http://stackoverflo=
w.com/q/22232164/627587</div><div><br></div><div>and the original discussio=
n that started the debate:</div><div><br></div><div>=C2=A0 =C2=A0 https://g=
roups.google.com/forum/#!msg/comp.lang.c++.moderated/J9MbhcOrAzY/XjKeWEbU1E=
cJ</div><div><br></div><div><br></div><div><font size=3D"4">Summary of the =
problem</font></div><div><font size=3D"4"><br></font></div><div>Let me summ=
arize my understanding of the rationale (please correct me if I'm</div>=
<div>wrong on something):</div><div><br></div><div>1. Allowing lambdas in u=
nevaluated contexts creates the problem that performing</div><div>=C2=A0 =
=C2=A0SFINAE inside the lambda is hard to implement for compilers. For exam=
ple:</div><div><br></div><div class=3D"prettyprint" style=3D"background-col=
or: rgb(250, 250, 250); border: 1px solid rgb(187, 187, 187); word-wrap: br=
eak-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span =
style=3D"color: #000;" class=3D"styled-by-prettify">=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-prettify">tem=
plate</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify"><</span><sp=
an style=3D"color: #008;" class=3D"styled-by-prettify">typename</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify"> X</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">></span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </=
span><span style=3D"color: #008;" class=3D"styled-by-prettify">auto</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"> f</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify">X x</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">)</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-=
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"color: #008;" class=3D"styled-by-prettify">auto</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> x</span><spa=
n 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=
: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
</span><span style=3D"color: #800;" class=3D"styled-by-prettify">// Some ex=
pression(s) that might be invalid, but SFINAE should be</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 </span><span style=3D"color: #800;" class=3D"styled-by-pr=
ettify">// performed. Since these expressions can be arbitrarily complex,</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color: #800;" clas=
s=3D"styled-by-prettify">// this is like SFINAE on steroids, which is hard =
to implement.</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">}(</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify">x</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">));</span></div></code></div><div><br></div><div><br></div><div>2. =
Knowing the type of a lambda is pretty much useless, since that type is</di=
v><div>=C2=A0 =C2=A0unique anyway. Hence, the following would hold:</div><d=
iv><br></div><div class=3D"prettyprint" style=3D"background-color: rgb(250,=
250, 250); border: 1px solid rgb(187, 187, 187); word-wrap: break-word;"><=
code class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"col=
or: #000;" class=3D"styled-by-prettify">=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span>=
<span style=3D"color: #008;" class=3D"styled-by-prettify">static_assert</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">(!</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"colo=
r: #000;" class=3D"styled-by-prettify">is_same</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify"><</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
</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"color: #008;" class=3D"styled-by-prettify">auto</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"> x</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;" cla=
ss=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> y</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">)</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span s=
tyle=3D"color: #008;" class=3D"styled-by-prettify">return</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> x </span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">+</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"> y</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">}),</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><=
br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color: #=
008;" class=3D"styled-by-prettify">decltype</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">([](</span><span style=3D"color: #008;" cl=
ass=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> x</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">auto<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> y</span><s=
pan 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=
: #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">return</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> x </span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">+</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
y</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">})</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">>::</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify">value</span><spa=
n 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=
: #080;" class=3D"styled-by-prettify">""</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">);</span></div></code></div><div><b=
r></div><div>=C2=A0 =C2=A0In particular, this means that code like</div><di=
v><br></div><div class=3D"prettyprint" style=3D"background-color: rgb(250, =
250, 250); border: 1px solid rgb(187, 187, 187); word-wrap: break-word;"><c=
ode class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify">=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><=
span style=3D"color: #008;" class=3D"styled-by-prettify">using</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"=
color: #606;" class=3D"styled-by-prettify">Plus</span><span style=3D"color:=
#000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-b=
y-prettify">decltype</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">([](</span><span style=3D"color: #008;" class=3D"styled-by-pretti=
fy">auto</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> x=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> y</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">)</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"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">ret=
urn</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> x </sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">+</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"> y</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: #660;" cla=
ss=3D"styled-by-prettify">});</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"co=
lor: #606;" class=3D"styled-by-prettify">Plus</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> plus </span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">=3D</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: #008;" class=3D"styled-by-pr=
ettify">auto</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> x</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span s=
tyle=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> y</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: #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">return</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
x </span><span style=3D"color: #660;" class=3D"styled-by-prettify">+</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> y</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">};</span></div></code></div><div><br></div>=
<div>=C2=A0 =C2=A0 is not valid, which seems to reduce the usefulness of th=
e feature.</div><div><br></div><div>3. Since lambdas have unique types, how=
should we mangle the signature of</div><div>=C2=A0 =C2=A0a function having=
a lambda in it? Consider the following:</div><div><br></div><div><div clas=
s=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); border: 1p=
x solid rgb(187, 187, 187); word-wrap: break-word;"><code class=3D"prettypr=
int"><div class=3D"subprettyprint"><span style=3D"color: #000;" class=3D"st=
yled-by-prettify">=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color: =
#008;" class=3D"styled-by-prettify">void</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify"> f</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">(</span><span style=3D"color: #008;" class=3D"style=
d-by-prettify">decltype</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">([](</span><span style=3D"color: #008;" class=3D"styled-by-pre=
ttify">auto</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> x</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: #660;" class=3D"styled-by-prettify">{</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">}));</span></div></code></div></div><div><b=
r></div><div>=C2=A0 =C2=A0How should we mangle the signature of `f`, and ho=
w can we make sure that it</div><div>=C2=A0 =C2=A0is mangled the same way i=
nside each translation unit where this declaration</div><div>=C2=A0 =C2=A0a=
ppears?</div><div><br></div><div>Having found a compelling use case for lam=
bdas inside unevaluated contexts,</div><div>I think it is worth reconsideri=
ng that restriction, which seems too strong.</div><div><br></div><div><br><=
/div><div><font size=3D"4">The use case</font></div><div><font size=3D"4"><=
br></font></div><div>The use case is performing type-level computations (li=
ke Boost.MPL) using</div><div>generic lambdas rather than a custom domain s=
pecific language (like MPL</div><div>LambdaExpressions). This new way of do=
ing type-level computations is exploited</div><div>in the Boost.Hana librar=
y [1]. Here is an explanation of that technique.</div><div><br></div><div>F=
irst, let's assume we have heterogeneous algorithms, which are basicall=
y</div><div>STL algorithms that work on tuples (a bit like Boost.Fusion, to=
o):</div><div><br></div><div class=3D"prettyprint" style=3D"background-colo=
r: rgb(250, 250, 250); border: 1px solid rgb(187, 187, 187); word-wrap: bre=
ak-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify">=C2=A0 =C2=A0 </span><sp=
an style=3D"color: #800;" class=3D"styled-by-prettify">// Returns the first=
element of `tuple` for which `pred` returns a</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span><span style=3D=
"color: #800;" class=3D"styled-by-prettify">// true-valued `std::integral_c=
onstant`.</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><=
br>=C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-pre=
ttify">template</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify"><=
</span><span style=3D"color: #008;" class=3D"styled-by-prettify">typename</=
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">T</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">typename</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #606;" class=3D"styled-by-p=
rettify">Predicate</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">></span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"><br>=C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-=
prettify">auto</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> find_if</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">std</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify">tuple</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify"><</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify">T</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">...></span><span style=3D"color: #000;"=
class=3D"styled-by-prettify"> tuple</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #606;" class=3D"styled-by-pr=
ettify">Predicate</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> pred</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">);</span></div></code></div><div><br></div><div>It is also possible to de=
fine other algorithms like `for_each`, `transform`</div><div>and so on, but=
let's keep this minimal. Now, we can define a wrapper to</div><div>rep=
resent a type using an object, and we can define type traits (or arbitrary<=
/div><div>metafunctions) as normal functions taking such wrappers:</div><di=
v><br></div><div class=3D"prettyprint" style=3D"background-color: rgb(250, =
250, 250); border: 1px solid rgb(187, 187, 187); word-wrap: break-word;"><c=
ode class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify">=C2=A0 =C2=A0 </span><span style=3D"=
color: #008;" class=3D"styled-by-prettify">template</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660=
;" class=3D"styled-by-prettify"><</span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">typename</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> T</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">></span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"><br>=C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=3D"st=
yled-by-prettify">struct</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify"> </span><span style=3D"color: #606;" class=3D"styled-by-prett=
ify">Type</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">using</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> type </span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"> T</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">};</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><b=
r><br>=C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-=
prettify">template</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">&=
lt;</span><span style=3D"color: #008;" class=3D"styled-by-prettify">typenam=
e</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> T</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">></span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 std</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify">is_pointer</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify">T</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">></span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> is_pointer</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #606;" cla=
ss=3D"styled-by-prettify">Type</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify"><</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify">T</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">>)</span><span 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"> </span><span styl=
e=3D"color: #008;" class=3D"styled-by-prettify">return</span><span 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;" c=
lass=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">}</span></div></code></div><div><br></div><div>Finally, =
we can use these in conjunction with our heterogeneous algorithms</div><div=
>to perform type-level computations using the usual C++ syntax:</div><div><=
br></div><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250=
, 250); border: 1px solid rgb(187, 187, 187); word-wrap: break-word;"><code=
class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: =
#000;" class=3D"styled-by-prettify">=C2=A0 =C2=A0 </span><span style=3D"col=
or: #008;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> types </span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> std</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify">make_tuple</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">(</span><span style=3D"color: #606;" class=3D"styled-by-prettify"=
>Type</span><span style=3D"color: #080;" class=3D"styled-by-prettify"><i=
nt></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: #606;" class=3D"styled-by-prettify">Type</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify"><</span><span style=3D"=
color: #008;" class=3D"styled-by-prettify">float</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: #606;" cl=
ass=3D"styled-by-prettify">Type</span><span style=3D"color: #080;" class=3D=
"styled-by-prettify"><char></span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">{});</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"><br>=C2=A0 =C2=A0 </span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> first_ptr </span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify"> find_if</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y">types</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: #660;" class=3D"styled-by-prettify">[](</span><span styl=
e=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> t</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-by-pre=
ttify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color: #008;" =
class=3D"styled-by-prettify">return</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> is_pointer</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify">t</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">);</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
<br>=C2=A0 =C2=A0 </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">});</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
><br>=C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">using</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> </span><span style=3D"color: #606;" class=3D"styled-by-prettify">First=
Ptr</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span =
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"co=
lor: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify">first_ptr</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">)::</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">type</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">;</span></div></code></div><div><br></div><div>Within thi=
s new paradigm, it would often be useful to have lambdas inside</div><div>u=
nevaluated contexts in order to skip the intermediate `first_ptr` variable.=
</div><div>Indeed, it would be more natural to simply write</div><div><br><=
/div><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 25=
0); border: 1px solid rgb(187, 187, 187); word-wrap: break-word;"><code cla=
ss=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #000=
;" class=3D"styled-by-prettify">=C2=A0 =C2=A0 </span><span style=3D"color: =
#008;" class=3D"styled-by-prettify">using</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"> </span><span style=3D"color: #606;" class=
=3D"styled-by-prettify">FirstPtr</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">d=
ecltype</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify">find_if</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify">types</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: #660;" =
class=3D"styled-by-prettify">[](</span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> t</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: #660;" class=3D"styled-by-prettify">{</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0=
=C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-prett=
ify">return</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> is_pointer</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">t</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">}))::</span><spa=
n style=3D"color: #000;" class=3D"styled-by-prettify">type</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">;</span></div></code></div>=
<div><br></div><div><br></div><div><font size=3D"4">Lifting the restriction=
</font></div><div><font size=3D"4"><br></font></div><div>Clearly, point (2)=
of the rationale given above does not apply anymore, since</div><div>there=
is a very clear use case of lambdas inside unevaluated contexts. While</di=
v><div>you might not be convinced by the above example, Boost.Hana [1] cont=
ains many</div><div>serious examples where this would be useful.</div><div>=
<br></div><div>Secondly, preventing lambdas from appearing in unevaluated c=
ontexts for the</div><div>sole purpose of point (3) is arguably way overkil=
l. Indeed, we do not need</div><div>the actual type of a lambda to appear i=
nside a function signature in the</div><div>general case; we merely need to=
be able to pass a lambda to another function</div><div>and then use `declt=
ype` on the result. Similarly, it would be better (although</div><div>still=
too strong) if `decltype([]() {})` was prohibited for reason (3), but</div=
><div>prohibiting `decltype([](){} ())` (note the call to the lambda) seems=
to be</div><div>overly restrictive.</div><div><br></div><div>I have talked=
to Richard Smith about this at CppCon 2015, and IIRC he said</div><div>tha=
t restrictions on what could and couldn't appear inside a mangled name =
was</div><div>now being stated explicitly in the standard. Hence, point (3)=
might not even</div><div>be a valid reason anymore.</div><div><br></div><d=
iv>Finally, there's point (1) about SFINAE. IMO, it would be better tha=
n nothing</div><div>if the standard just said that no SFINAE could happen i=
nside the lambda's body,</div><div>so that a hard error is triggered in=
stead. This would lead the door open to</div><div>adding support for SFINAE=
inside lambdas at a later time, and would enable</div><div>many use cases =
right now.</div><div><br></div><div>Also, FWIW, Clang has a bug right now t=
hat _sometimes_ makes it possible to</div><div>use lambdas inside unevaluat=
ed contexts. So it is definitely possible to</div><div>implement it. See [2=
] for more information.</div><div><br></div><div>I'd like to gather tho=
ughts and comments about lifting this restriction, and</div><div>to confirm=
that reason (3) does not apply anymore. If there are no reasons not</div><=
div>to proceed, I will then open a core issue (I was told it was the best w=
ay to</div><div>do this).</div><div><br></div><div>Regards,</div><div>Louis=
Dionne</div><div><br></div><div>[1]: https://github.com/ldionne/hana</div>=
<div>[2]: https://github.com/ldionne/hana/issues/4#issuecomment-51244672</d=
iv><div><br></div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_471_279776217.1443555061081--
------=_Part_470_136901664.1443555061080--
.
Author: Thiago Macieira <thiago@macieira.org>
Date: Tue, 29 Sep 2015 13:48:34 -0700
Raw View
On Tuesday 29 September 2015 12:31:01 Louis Dionne wrote:
> 3. Since lambdas have unique types, how should we mangle the signature of
> a function having a lambda in it? Consider the following:
>
> void f(decltype([](auto x) { }));
>
> How should we mangle the signature of `f`, and how can we make sure that
> it
> is mangled the same way inside each translation unit where this
> declaration
> appears?
This one is easy. It's mangled as "f(decltype(lambda#1 of the declaration))".
In other words, a circular reference to itself. By ODR, we know that all
declarations have the same lambda declaration, so we don't need to mangle it:
we know it's the same.
Of course, the function above isn't callable, as per your point #2 before.
--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center
PGP/GPG: 0x6EF45358; fingerprint:
E067 918B B660 DBD1 105C 966C 33F5 F005 6EF4 5358
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
.
Author: Richard Smith <richard@metafoo.co.uk>
Date: Tue, 29 Sep 2015 19:07:36 -0700
Raw View
--001a113d2d34f9e37e0520ed64e3
Content-Type: text/plain; charset=UTF-8
On Tue, Sep 29, 2015 at 12:31 PM, Louis Dionne <ldionne.2@gmail.com> wrote:
> Hi,
>
> I would like to re-open a discussion about allowing lambdas inside
> unevaluated
> contexts. For the record, here is a good explanation of the rationale for
> disallowing them:
>
> http://stackoverflow.com/q/22232164/627587
>
> and the original discussion that started the debate:
>
>
> https://groups.google.com/forum/#!msg/comp.lang.c++.moderated/J9MbhcOrAzY/XjKeWEbU1EcJ
>
>
> Summary of the problem
>
> Let me summarize my understanding of the rationale (please correct me if
> I'm
> wrong on something):
>
> 1. Allowing lambdas in unevaluated contexts creates the problem that
> performing
> SFINAE inside the lambda is hard to implement for compilers. For
> example:
>
> template <typename X>
> auto f(X x) -> decltype([](auto x) {
> // Some expression(s) that might be invalid, but SFINAE
> should be
> // performed. Since these expressions can be arbitrarily
> complex,
> // this is like SFINAE on steroids, which is hard to
> implement.
> }(x));
>
>
> 2. Knowing the type of a lambda is pretty much useless, since that type is
> unique anyway. Hence, the following would hold:
>
> static_assert(!std::is_same<
> decltype([](auto x, auto y) { return x + y; }),
> decltype([](auto x, auto y) { return x + y; })
> >::value, "");
>
> In particular, this means that code like
>
> using Plus = decltype([](auto x, auto y) { return x + y; });
> Plus plus = [](auto x, auto y) { return x + y; };
>
> is not valid, which seems to reduce the usefulness of the feature.
>
> 3. Since lambdas have unique types, how should we mangle the signature of
> a function having a lambda in it? Consider the following:
>
> void f(decltype([](auto x) { }));
>
> How should we mangle the signature of `f`, and how can we make sure
> that it
> is mangled the same way inside each translation unit where this
> declaration
> appears?
>
> Having found a compelling use case for lambdas inside unevaluated contexts,
> I think it is worth reconsidering that restriction, which seems too strong.
>
>
> The use case
>
> The use case is performing type-level computations (like Boost.MPL) using
> generic lambdas rather than a custom domain specific language (like MPL
> LambdaExpressions). This new way of doing type-level computations is
> exploited
> in the Boost.Hana library [1]. Here is an explanation of that technique.
>
> First, let's assume we have heterogeneous algorithms, which are basically
> STL algorithms that work on tuples (a bit like Boost.Fusion, too):
>
> // Returns the first element of `tuple` for which `pred` returns a
> // true-valued `std::integral_constant`.
> template <typename ...T, typename Predicate>
> auto find_if(std::tuple<T...> tuple, Predicate pred);
>
> It is also possible to define other algorithms like `for_each`, `transform`
> and so on, but let's keep this minimal. Now, we can define a wrapper to
> represent a type using an object, and we can define type traits (or
> arbitrary
> metafunctions) as normal functions taking such wrappers:
>
> template <typename T>
> struct Type { using type = T; };
>
> template <typename T>
> std::is_pointer<T> is_pointer(Type<T>) { return {}; }
>
> Finally, we can use these in conjunction with our heterogeneous algorithms
> to perform type-level computations using the usual C++ syntax:
>
> auto types = std::make_tuple(Type<int>{}, Type<float*>{}, Type<char>
> {});
> auto first_ptr = find_if(types, [](auto t) {
> return is_pointer(t);
> });
> using FirstPtr = decltype(first_ptr)::type;
>
> Within this new paradigm, it would often be useful to have lambdas inside
> unevaluated contexts in order to skip the intermediate `first_ptr`
> variable.
> Indeed, it would be more natural to simply write
>
> using FirstPtr = decltype(find_if(types, [](auto t) {
> return is_pointer(t);
> }))::type;
>
>
> Lifting the restriction
>
> Clearly, point (2) of the rationale given above does not apply anymore,
> since
> there is a very clear use case of lambdas inside unevaluated contexts.
> While
> you might not be convinced by the above example, Boost.Hana [1] contains
> many
> serious examples where this would be useful.
>
> Secondly, preventing lambdas from appearing in unevaluated contexts for the
> sole purpose of point (3) is arguably way overkill. Indeed, we do not need
> the actual type of a lambda to appear inside a function signature in the
> general case; we merely need to be able to pass a lambda to another
> function
> and then use `decltype` on the result. Similarly, it would be better
> (although
> still too strong) if `decltype([]() {})` was prohibited for reason (3), but
> prohibiting `decltype([](){} ())` (note the call to the lambda) seems to be
> overly restrictive.
>
> I have talked to Richard Smith about this at CppCon 2015, and IIRC he said
> that restrictions on what could and couldn't appear inside a mangled name
> was
> now being stated explicitly in the standard. Hence, point (3) might not
> even
> be a valid reason anymore.
>
See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1607 for
the relevant change.
> Finally, there's point (1) about SFINAE. IMO, it would be better than
> nothing
> if the standard just said that no SFINAE could happen inside the lambda's
> body,
> so that a hard error is triggered instead. This would lead the door open to
> adding support for SFINAE inside lambdas at a later time, and would enable
> many use cases right now.
>
> Also, FWIW, Clang has a bug right now that _sometimes_ makes it possible to
> use lambdas inside unevaluated contexts. So it is definitely possible to
> implement it. See [2] for more information.
>
> I'd like to gather thoughts and comments about lifting this restriction,
> and
> to confirm that reason (3) does not apply anymore. If there are no reasons
> not
> to proceed, I will then open a core issue (I was told it was the best way
> to
> do this).
>
> Regards,
> Louis Dionne
>
> [1]: https://github.com/ldionne/hana
> [2]: https://github.com/ldionne/hana/issues/4#issuecomment-51244672
>
> --
>
> ---
> You received this message because you are subscribed to the Google Groups
> "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> Visit this group at
> http://groups.google.com/a/isocpp.org/group/std-proposals/.
>
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
--001a113d2d34f9e37e0520ed64e3
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">On T=
ue, Sep 29, 2015 at 12:31 PM, Louis Dionne <span dir=3D"ltr"><<a href=3D=
"mailto:ldionne.2@gmail.com" target=3D"_blank">ldionne.2@gmail.com</a>><=
/span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px =
0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-l=
eft-style:solid;padding-left:1ex"><div dir=3D"ltr"><div>Hi,</div><div><br><=
/div><div>I would like to re-open a discussion about allowing lambdas insid=
e unevaluated</div><div>contexts. For the record, here is a good explanatio=
n of the rationale for</div><div>disallowing them:</div><div><br></div><div=
>=C2=A0 =C2=A0 <a href=3D"http://stackoverflow.com/q/22232164/627587" targe=
t=3D"_blank">http://stackoverflow.com/q/22232164/627587</a></div><div><br><=
/div><div>and the original discussion that started the debate:</div><div><b=
r></div><div>=C2=A0 =C2=A0 <a href=3D"https://groups.google.com/forum/#!msg=
/comp.lang.c++.moderated/J9MbhcOrAzY/XjKeWEbU1EcJ" target=3D"_blank">https:=
//groups.google.com/forum/#!msg/comp.lang.c++.moderated/J9MbhcOrAzY/XjKeWEb=
U1EcJ</a></div><div><br></div><div><br></div><div><font size=3D"4">Summary =
of the problem</font></div><div><font size=3D"4"><br></font></div><div>Let =
me summarize my understanding of the rationale (please correct me if I'=
m</div><div>wrong on something):</div><div><br></div><div>1. Allowing lambd=
as in unevaluated contexts creates the problem that performing</div><div>=
=C2=A0 =C2=A0SFINAE inside the lambda is hard to implement for compilers. F=
or example:</div><div><br></div><div style=3D"border:1px solid rgb(187,187,=
187);word-wrap:break-word;background-color:rgb(250,250,250)"><code><div><sp=
an style=3D"color:rgb(0,0,0)">=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span styl=
e=3D"color:rgb(0,0,136)">template</span><span style=3D"color:rgb(0,0,0)"> <=
/span><span style=3D"color:rgb(102,102,0)"><</span><span style=3D"color:=
rgb(0,0,136)">typename</span><span style=3D"color:rgb(0,0,0)"> X</span><spa=
n style=3D"color:rgb(102,102,0)">></span><span style=3D"color:rgb(0,0,0)=
"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,0,136)"=
>auto</span><span style=3D"color:rgb(0,0,0)"> f</span><span style=3D"color:=
rgb(102,102,0)">(</span><span style=3D"color:rgb(0,0,0)">X x</span><span st=
yle=3D"color:rgb(102,102,0)">)</span><span style=3D"color:rgb(0,0,0)"> </sp=
an><span style=3D"color:rgb(102,102,0)">-></span><span style=3D"color:rg=
b(0,0,0)"> </span><span style=3D"color:rgb(0,0,136)">decltype</span><span s=
tyle=3D"color:rgb(102,102,0)">([](</span><span style=3D"color:rgb(0,0,136)"=
>auto</span><span style=3D"color:rgb(0,0,0)"> x</span><span style=3D"color:=
rgb(102,102,0)">)</span><span style=3D"color:rgb(0,0,0)"> </span><span styl=
e=3D"color:rgb(102,102,0)">{</span><span style=3D"color:rgb(0,0,0)"><br>=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color:rgb(136,=
0,0)">// Some expression(s) that might be invalid, but SFINAE should be</sp=
an><span style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 </span><span style=3D"color:rgb(136,0,0)">// performed. Since these =
expressions can be arbitrarily complex,</span><span style=3D"color:rgb(0,0,=
0)"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"col=
or:rgb(136,0,0)">// this is like SFINAE on steroids, which is hard to imple=
ment.</span><span style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 </span><span style=3D"color:rgb(102,102,0)">}(</span><span style=3D"col=
or:rgb(0,0,0)">x</span><span style=3D"color:rgb(102,102,0)">));</span></div=
></code></div><div><br></div><div><br></div><div>2. Knowing the type of a l=
ambda is pretty much useless, since that type is</div><div>=C2=A0 =C2=A0uni=
que anyway. Hence, the following would hold:</div><div><br></div><div style=
=3D"border:1px solid rgb(187,187,187);word-wrap:break-word;background-color=
:rgb(250,250,250)"><code><div><span style=3D"color:rgb(0,0,0)">=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,0,136)">static_assert</=
span><span style=3D"color:rgb(102,102,0)">(!</span><span style=3D"color:rgb=
(0,0,0)">std</span><span style=3D"color:rgb(102,102,0)">::</span><span styl=
e=3D"color:rgb(0,0,0)">is_same</span><span style=3D"color:rgb(102,102,0)">&=
lt;</span><span style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,0,136)">decltype</span><spa=
n style=3D"color:rgb(102,102,0)">([](</span><span style=3D"color:rgb(0,0,13=
6)">auto</span><span style=3D"color:rgb(0,0,0)"> x</span><span style=3D"col=
or:rgb(102,102,0)">,</span><span style=3D"color:rgb(0,0,0)"> </span><span s=
tyle=3D"color:rgb(0,0,136)">auto</span><span style=3D"color:rgb(0,0,0)"> y<=
/span><span style=3D"color:rgb(102,102,0)">)</span><span style=3D"color:rgb=
(0,0,0)"> </span><span style=3D"color:rgb(102,102,0)">{</span><span style=
=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(0,0,136)">return</sp=
an><span style=3D"color:rgb(0,0,0)"> x </span><span style=3D"color:rgb(102,=
102,0)">+</span><span style=3D"color:rgb(0,0,0)"> y</span><span style=3D"co=
lor:rgb(102,102,0)">;</span><span style=3D"color:rgb(0,0,0)"> </span><span =
style=3D"color:rgb(102,102,0)">}),</span><span style=3D"color:rgb(0,0,0)"><=
br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color:rg=
b(0,0,136)">decltype</span><span style=3D"color:rgb(102,102,0)">([](</span>=
<span style=3D"color:rgb(0,0,136)">auto</span><span style=3D"color:rgb(0,0,=
0)"> x</span><span style=3D"color:rgb(102,102,0)">,</span><span style=3D"co=
lor:rgb(0,0,0)"> </span><span style=3D"color:rgb(0,0,136)">auto</span><span=
style=3D"color:rgb(0,0,0)"> y</span><span style=3D"color:rgb(102,102,0)">)=
</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(10=
2,102,0)">{</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"c=
olor:rgb(0,0,136)">return</span><span style=3D"color:rgb(0,0,0)"> x </span>=
<span style=3D"color:rgb(102,102,0)">+</span><span style=3D"color:rgb(0,0,0=
)"> y</span><span style=3D"color:rgb(102,102,0)">;</span><span style=3D"col=
or:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,102,0)">})</span><span =
style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span sty=
le=3D"color:rgb(102,102,0)">>::</span><span style=3D"color:rgb(0,0,0)">v=
alue</span><span style=3D"color:rgb(102,102,0)">,</span><span style=3D"colo=
r:rgb(0,0,0)"> </span><span style=3D"color:rgb(0,136,0)">""</span=
><span style=3D"color:rgb(102,102,0)">);</span></div></code></div><div><br>=
</div><div>=C2=A0 =C2=A0In particular, this means that code like</div><div>=
<br></div><div style=3D"border:1px solid rgb(187,187,187);word-wrap:break-w=
ord;background-color:rgb(250,250,250)"><code><div><span style=3D"color:rgb(=
0,0,0)">=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,0,136=
)">using</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"colo=
r:rgb(102,0,102)">Plus</span><span style=3D"color:rgb(0,0,0)"> </span><span=
style=3D"color:rgb(102,102,0)">=3D</span><span style=3D"color:rgb(0,0,0)">=
</span><span style=3D"color:rgb(0,0,136)">decltype</span><span style=3D"co=
lor:rgb(102,102,0)">([](</span><span style=3D"color:rgb(0,0,136)">auto</spa=
n><span style=3D"color:rgb(0,0,0)"> x</span><span style=3D"color:rgb(102,10=
2,0)">,</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color=
:rgb(0,0,136)">auto</span><span style=3D"color:rgb(0,0,0)"> y</span><span s=
tyle=3D"color:rgb(102,102,0)">)</span><span style=3D"color:rgb(0,0,0)"> </s=
pan><span style=3D"color:rgb(102,102,0)">{</span><span style=3D"color:rgb(0=
,0,0)"> </span><span style=3D"color:rgb(0,0,136)">return</span><span style=
=3D"color:rgb(0,0,0)"> x </span><span style=3D"color:rgb(102,102,0)">+</spa=
n><span style=3D"color:rgb(0,0,0)"> y</span><span style=3D"color:rgb(102,10=
2,0)">;</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color=
:rgb(102,102,0)">});</span><span style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 </span><span style=3D"color:rgb(102,0,102)">Plus</span><s=
pan style=3D"color:rgb(0,0,0)"> plus </span><span style=3D"color:rgb(102,10=
2,0)">=3D</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"col=
or:rgb(102,102,0)">[](</span><span style=3D"color:rgb(0,0,136)">auto</span>=
<span style=3D"color:rgb(0,0,0)"> x</span><span style=3D"color:rgb(102,102,=
0)">,</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:r=
gb(0,0,136)">auto</span><span style=3D"color:rgb(0,0,0)"> y</span><span sty=
le=3D"color:rgb(102,102,0)">)</span><span style=3D"color:rgb(0,0,0)"> </spa=
n><span style=3D"color:rgb(102,102,0)">{</span><span style=3D"color:rgb(0,0=
,0)"> </span><span style=3D"color:rgb(0,0,136)">return</span><span style=3D=
"color:rgb(0,0,0)"> x </span><span style=3D"color:rgb(102,102,0)">+</span><=
span style=3D"color:rgb(0,0,0)"> y</span><span style=3D"color:rgb(102,102,0=
)">;</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rg=
b(102,102,0)">};</span></div></code></div><div><br></div><div>=C2=A0 =C2=A0=
is not valid, which seems to reduce the usefulness of the feature.</div><d=
iv><br></div><div>3. Since lambdas have unique types, how should we mangle =
the signature of</div><div>=C2=A0 =C2=A0a function having a lambda in it? C=
onsider the following:</div><div><br></div><div><div style=3D"border:1px so=
lid rgb(187,187,187);word-wrap:break-word;background-color:rgb(250,250,250)=
"><code><div><span style=3D"color:rgb(0,0,0)">=C2=A0 =C2=A0 =C2=A0 =C2=A0 <=
/span><span style=3D"color:rgb(0,0,136)">void</span><span style=3D"color:rg=
b(0,0,0)"> f</span><span style=3D"color:rgb(102,102,0)">(</span><span style=
=3D"color:rgb(0,0,136)">decltype</span><span style=3D"color:rgb(102,102,0)"=
>([](</span><span style=3D"color:rgb(0,0,136)">auto</span><span style=3D"co=
lor:rgb(0,0,0)"> x</span><span style=3D"color:rgb(102,102,0)">)</span><span=
style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,102,0)">{<=
/span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102=
,102,0)">}));</span></div></code></div></div><div><br></div><div>=C2=A0 =C2=
=A0How should we mangle the signature of `f`, and how can we make sure that=
it</div><div>=C2=A0 =C2=A0is mangled the same way inside each translation =
unit where this declaration</div><div>=C2=A0 =C2=A0appears?</div><div><br><=
/div><div>Having found a compelling use case for lambdas inside unevaluated=
contexts,</div><div>I think it is worth reconsidering that restriction, wh=
ich seems too strong.</div><div><br></div><div><br></div><div><font size=3D=
"4">The use case</font></div><div><font size=3D"4"><br></font></div><div>Th=
e use case is performing type-level computations (like Boost.MPL) using</di=
v><div>generic lambdas rather than a custom domain specific language (like =
MPL</div><div>LambdaExpressions). This new way of doing type-level computat=
ions is exploited</div><div>in the Boost.Hana library [1]. Here is an expla=
nation of that technique.</div><div><br></div><div>First, let's assume =
we have heterogeneous algorithms, which are basically</div><div>STL algorit=
hms that work on tuples (a bit like Boost.Fusion, too):</div><div><br></div=
><div style=3D"border:1px solid rgb(187,187,187);word-wrap:break-word;backg=
round-color:rgb(250,250,250)"><code><div><span style=3D"color:rgb(0,0,0)">=
=C2=A0 =C2=A0 </span><span style=3D"color:rgb(136,0,0)">// Returns the firs=
t element of `tuple` for which `pred` returns a</span><span style=3D"color:=
rgb(0,0,0)"><br>=C2=A0 =C2=A0 </span><span style=3D"color:rgb(136,0,0)">// =
true-valued `std::integral_constant`.</span><span style=3D"color:rgb(0,0,0)=
"><br>=C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,0,136)">template</spa=
n><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,102=
,0)"><</span><span style=3D"color:rgb(0,0,136)">typename</span><span sty=
le=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,102,0)">...</s=
pan><span style=3D"color:rgb(0,0,0)">T</span><span style=3D"color:rgb(102,1=
02,0)">,</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"colo=
r:rgb(0,0,136)">typename</span><span style=3D"color:rgb(0,0,0)"> </span><sp=
an style=3D"color:rgb(102,0,102)">Predicate</span><span style=3D"color:rgb(=
102,102,0)">></span><span style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 <=
/span><span style=3D"color:rgb(0,0,136)">auto</span><span style=3D"color:rg=
b(0,0,0)"> find_if</span><span style=3D"color:rgb(102,102,0)">(</span><span=
style=3D"color:rgb(0,0,0)">std</span><span style=3D"color:rgb(102,102,0)">=
::</span><span style=3D"color:rgb(0,0,0)">tuple</span><span style=3D"color:=
rgb(102,102,0)"><</span><span style=3D"color:rgb(0,0,0)">T</span><span s=
tyle=3D"color:rgb(102,102,0)">...></span><span style=3D"color:rgb(0,0,0)=
"> tuple</span><span style=3D"color:rgb(102,102,0)">,</span><span style=3D"=
color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,0,102)">Predicate</s=
pan><span style=3D"color:rgb(0,0,0)"> pred</span><span style=3D"color:rgb(1=
02,102,0)">);</span></div></code></div><div><br></div><div>It is also possi=
ble to define other algorithms like `for_each`, `transform`</div><div>and s=
o on, but let's keep this minimal. Now, we can define a wrapper to</div=
><div>represent a type using an object, and we can define type traits (or a=
rbitrary</div><div>metafunctions) as normal functions taking such wrappers:=
</div><div><br></div><div style=3D"border:1px solid rgb(187,187,187);word-w=
rap:break-word;background-color:rgb(250,250,250)"><code><div><span style=3D=
"color:rgb(0,0,0)">=C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,0,136)">=
template</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"colo=
r:rgb(102,102,0)"><</span><span style=3D"color:rgb(0,0,136)">typename</s=
pan><span style=3D"color:rgb(0,0,0)"> T</span><span style=3D"color:rgb(102,=
102,0)">></span><span style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 </spa=
n><span style=3D"color:rgb(0,0,136)">struct</span><span style=3D"color:rgb(=
0,0,0)"> </span><span style=3D"color:rgb(102,0,102)">Type</span><span style=
=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,102,0)">{</span>=
<span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(0,0,136)"=
>using</span><span style=3D"color:rgb(0,0,0)"> type </span><span style=3D"c=
olor:rgb(102,102,0)">=3D</span><span style=3D"color:rgb(0,0,0)"> T</span><s=
pan style=3D"color:rgb(102,102,0)">;</span><span style=3D"color:rgb(0,0,0)"=
> </span><span style=3D"color:rgb(102,102,0)">};</span><span style=3D"color=
:rgb(0,0,0)"><br><br>=C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,0,136)=
">template</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"co=
lor:rgb(102,102,0)"><</span><span style=3D"color:rgb(0,0,136)">typename<=
/span><span style=3D"color:rgb(0,0,0)"> T</span><span style=3D"color:rgb(10=
2,102,0)">></span><span style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 std=
</span><span style=3D"color:rgb(102,102,0)">::</span><span style=3D"color:r=
gb(0,0,0)">is_pointer</span><span style=3D"color:rgb(102,102,0)"><</span=
><span style=3D"color:rgb(0,0,0)">T</span><span style=3D"color:rgb(102,102,=
0)">></span><span style=3D"color:rgb(0,0,0)"> is_pointer</span><span sty=
le=3D"color:rgb(102,102,0)">(</span><span style=3D"color:rgb(102,0,102)">Ty=
pe</span><span style=3D"color:rgb(102,102,0)"><</span><span style=3D"col=
or:rgb(0,0,0)">T</span><span style=3D"color:rgb(102,102,0)">>)</span><sp=
an style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,102,0)">=
{</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(0=
,0,136)">return</span><span style=3D"color:rgb(0,0,0)"> </span><span style=
=3D"color:rgb(102,102,0)">{};</span><span style=3D"color:rgb(0,0,0)"> </spa=
n><span style=3D"color:rgb(102,102,0)">}</span></div></code></div><div><br>=
</div><div>Finally, we can use these in conjunction with our heterogeneous =
algorithms</div><div>to perform type-level computations using the usual C++=
syntax:</div><div><br></div><div style=3D"border:1px solid rgb(187,187,187=
);word-wrap:break-word;background-color:rgb(250,250,250)"><code><div><span =
style=3D"color:rgb(0,0,0)">=C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,=
0,136)">auto</span><span style=3D"color:rgb(0,0,0)"> types </span><span sty=
le=3D"color:rgb(102,102,0)">=3D</span><span style=3D"color:rgb(0,0,0)"> std=
</span><span style=3D"color:rgb(102,102,0)">::</span><span style=3D"color:r=
gb(0,0,0)">make_tuple</span><span style=3D"color:rgb(102,102,0)">(</span><s=
pan style=3D"color:rgb(102,0,102)">Type</span><span style=3D"color:rgb(0,13=
6,0)"><int></span><span style=3D"color:rgb(102,102,0)">{},</span><spa=
n style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,0,102)">T=
ype</span><span style=3D"color:rgb(102,102,0)"><</span><span style=3D"co=
lor:rgb(0,0,136)">float</span><span style=3D"color:rgb(102,102,0)">*>{},=
</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(10=
2,0,102)">Type</span><span style=3D"color:rgb(0,136,0)"><char></span>=
<span style=3D"color:rgb(102,102,0)">{});</span><span style=3D"color:rgb(0,=
0,0)"><br>=C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,0,136)">auto</spa=
n><span style=3D"color:rgb(0,0,0)"> first_ptr </span><span style=3D"color:r=
gb(102,102,0)">=3D</span><span style=3D"color:rgb(0,0,0)"> find_if</span><s=
pan style=3D"color:rgb(102,102,0)">(</span><span style=3D"color:rgb(0,0,0)"=
>types</span><span style=3D"color:rgb(102,102,0)">,</span><span style=3D"co=
lor:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,102,0)">[](</span><spa=
n style=3D"color:rgb(0,0,136)">auto</span><span style=3D"color:rgb(0,0,0)">=
t</span><span style=3D"color:rgb(102,102,0)">)</span><span style=3D"color:=
rgb(0,0,0)"> </span><span style=3D"color:rgb(102,102,0)">{</span><span styl=
e=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=
=3D"color:rgb(0,0,136)">return</span><span style=3D"color:rgb(0,0,0)"> is_p=
ointer</span><span style=3D"color:rgb(102,102,0)">(</span><span style=3D"co=
lor:rgb(0,0,0)">t</span><span style=3D"color:rgb(102,102,0)">);</span><span=
style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 </span><span style=3D"color:r=
gb(102,102,0)">});</span><span style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0=
</span><span style=3D"color:rgb(0,0,136)">using</span><span style=3D"color=
:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,0,102)">FirstPtr</span><s=
pan style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,102,0)"=
>=3D</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rg=
b(0,0,136)">decltype</span><span style=3D"color:rgb(102,102,0)">(</span><sp=
an style=3D"color:rgb(0,0,0)">first_ptr</span><span style=3D"color:rgb(102,=
102,0)">)::</span><span style=3D"color:rgb(0,0,0)">type</span><span style=
=3D"color:rgb(102,102,0)">;</span></div></code></div><div><br></div><div>Wi=
thin this new paradigm, it would often be useful to have lambdas inside</di=
v><div>unevaluated contexts in order to skip the intermediate `first_ptr` v=
ariable.</div><div>Indeed, it would be more natural to simply write</div><d=
iv><br></div><div style=3D"border:1px solid rgb(187,187,187);word-wrap:brea=
k-word;background-color:rgb(250,250,250)"><code><div><span style=3D"color:r=
gb(0,0,0)">=C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,0,136)">using</s=
pan><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,0=
,102)">FirstPtr</span><span style=3D"color:rgb(0,0,0)"> </span><span style=
=3D"color:rgb(102,102,0)">=3D</span><span style=3D"color:rgb(0,0,0)"> </spa=
n><span style=3D"color:rgb(0,0,136)">decltype</span><span style=3D"color:rg=
b(102,102,0)">(</span><span style=3D"color:rgb(0,0,0)">find_if</span><span =
style=3D"color:rgb(102,102,0)">(</span><span style=3D"color:rgb(0,0,0)">typ=
es</span><span style=3D"color:rgb(102,102,0)">,</span><span style=3D"color:=
rgb(0,0,0)"> </span><span style=3D"color:rgb(102,102,0)">[](</span><span st=
yle=3D"color:rgb(0,0,136)">auto</span><span style=3D"color:rgb(0,0,0)"> t</=
span><span style=3D"color:rgb(102,102,0)">)</span><span style=3D"color:rgb(=
0,0,0)"> </span><span style=3D"color:rgb(102,102,0)">{</span><span style=3D=
"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"co=
lor:rgb(0,0,136)">return</span><span style=3D"color:rgb(0,0,0)"> is_pointer=
</span><span style=3D"color:rgb(102,102,0)">(</span><span style=3D"color:rg=
b(0,0,0)">t</span><span style=3D"color:rgb(102,102,0)">);</span><span style=
=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 </span><span style=3D"color:rgb(102=
,102,0)">}))::</span><span style=3D"color:rgb(0,0,0)">type</span><span styl=
e=3D"color:rgb(102,102,0)">;</span></div></code></div><div><br></div><div><=
br></div><div><font size=3D"4">Lifting the restriction</font></div><div><fo=
nt size=3D"4"><br></font></div><div>Clearly, point (2) of the rationale giv=
en above does not apply anymore, since</div><div>there is a very clear use =
case of lambdas inside unevaluated contexts. While</div><div>you might not =
be convinced by the above example, Boost.Hana [1] contains many</div><div>s=
erious examples where this would be useful.</div><div><br></div><div>Second=
ly, preventing lambdas from appearing in unevaluated contexts for the</div>=
<div>sole purpose of point (3) is arguably way overkill. Indeed, we do not =
need</div><div>the actual type of a lambda to appear inside a function sign=
ature in the</div><div>general case; we merely need to be able to pass a la=
mbda to another function</div><div>and then use `decltype` on the result. S=
imilarly, it would be better (although</div><div>still too strong) if `decl=
type([]() {})` was prohibited for reason (3), but</div><div>prohibiting `de=
cltype([](){} ())` (note the call to the lambda) seems to be</div><div>over=
ly restrictive.</div><div><br></div><div>I have talked to Richard Smith abo=
ut this at CppCon 2015, and IIRC he said</div><div>that restrictions on wha=
t could and couldn't appear inside a mangled name was</div><div>now bei=
ng stated explicitly in the standard. Hence, point (3) might not even</div>=
<div>be a valid reason anymore.</div></div></blockquote><div><br></div><div=
>See=C2=A0<a href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defect=
s.html#1607">http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1=
607</a> for the relevant change.</div><div>=C2=A0</div><blockquote class=3D=
"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;borde=
r-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><di=
v dir=3D"ltr"><div>Finally, there's point (1) about SFINAE. IMO, it wou=
ld be better than nothing</div><div>if the standard just said that no SFINA=
E could happen inside the lambda's body,</div><div>so that a hard error=
is triggered instead. This would lead the door open to</div><div>adding su=
pport for SFINAE inside lambdas at a later time, and would enable</div><div=
>many use cases right now.</div><div><br></div><div>Also, FWIW, Clang has a=
bug right now that _sometimes_ makes it possible to</div><div>use lambdas =
inside unevaluated contexts. So it is definitely possible to</div><div>impl=
ement it. See [2] for more information.</div><div><br></div><div>I'd li=
ke to gather thoughts and comments about lifting this restriction, and</div=
><div>to confirm that reason (3) does not apply anymore. If there are no re=
asons not</div><div>to proceed, I will then open a core issue (I was told i=
t was the best way to</div><div>do this).</div><div><br></div><div>Regards,=
</div><div>Louis Dionne</div><div><br></div><div>[1]: <a href=3D"https://gi=
thub.com/ldionne/hana" target=3D"_blank">https://github.com/ldionne/hana</a=
></div><div>[2]: <a href=3D"https://github.com/ldionne/hana/issues/4#issuec=
omment-51244672" target=3D"_blank">https://github.com/ldionne/hana/issues/4=
#issuecomment-51244672</a></div><span class=3D""><font color=3D"#888888"><d=
iv><br></div></font></span></div><span class=3D""><font color=3D"#888888">
<p></p>
-- <br>
<br>
--- <br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_=
blank">std-proposals+unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/" target=3D"_blank">http://groups.google.com/a/isocpp.org/gro=
up/std-proposals/</a>.<br>
</font></span></blockquote></div><br></div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
--001a113d2d34f9e37e0520ed64e3--
.
Author: Louis Dionne <ldionne.2@gmail.com>
Date: Fri, 2 Oct 2015 10:37:23 -0700 (PDT)
Raw View
------=_Part_1076_179658113.1443807443613
Content-Type: multipart/alternative;
boundary="----=_Part_1077_923330986.1443807443614"
------=_Part_1077_923330986.1443807443614
Content-Type: text/plain; charset=UTF-8
Great, so it really seems like the only "issue" left is to decide what to
do with SFINAE
inside the body of a lambda. I'll go ahead and open a core issue, and what
to do with
SFINAE can be dealt with then.
Regards,
Louis
On Tuesday, 29 September 2015 22:07:41 UTC-4, Richard Smith wrote:
>
> On Tue, Sep 29, 2015 at 12:31 PM, Louis Dionne <ldio...@gmail.com
> <javascript:>> wrote:
>
>> Hi,
>>
>> I would like to re-open a discussion about allowing lambdas inside
>> unevaluated
>> contexts. For the record, here is a good explanation of the rationale for
>> disallowing them:
>>
>> http://stackoverflow.com/q/22232164/627587
>>
>> and the original discussion that started the debate:
>>
>>
>> https://groups.google.com/forum/#!msg/comp.lang.c++.moderated/J9MbhcOrAzY/XjKeWEbU1EcJ
>>
>>
>> Summary of the problem
>>
>> Let me summarize my understanding of the rationale (please correct me if
>> I'm
>> wrong on something):
>>
>> 1. Allowing lambdas in unevaluated contexts creates the problem that
>> performing
>> SFINAE inside the lambda is hard to implement for compilers. For
>> example:
>>
>> template <typename X>
>> auto f(X x) -> decltype([](auto x) {
>> // Some expression(s) that might be invalid, but SFINAE
>> should be
>> // performed. Since these expressions can be arbitrarily
>> complex,
>> // this is like SFINAE on steroids, which is hard to
>> implement.
>> }(x));
>>
>>
>> 2. Knowing the type of a lambda is pretty much useless, since that type is
>> unique anyway. Hence, the following would hold:
>>
>> static_assert(!std::is_same<
>> decltype([](auto x, auto y) { return x + y; }),
>> decltype([](auto x, auto y) { return x + y; })
>> >::value, "");
>>
>> In particular, this means that code like
>>
>> using Plus = decltype([](auto x, auto y) { return x + y; });
>> Plus plus = [](auto x, auto y) { return x + y; };
>>
>> is not valid, which seems to reduce the usefulness of the feature.
>>
>> 3. Since lambdas have unique types, how should we mangle the signature of
>> a function having a lambda in it? Consider the following:
>>
>> void f(decltype([](auto x) { }));
>>
>> How should we mangle the signature of `f`, and how can we make sure
>> that it
>> is mangled the same way inside each translation unit where this
>> declaration
>> appears?
>>
>> Having found a compelling use case for lambdas inside unevaluated
>> contexts,
>> I think it is worth reconsidering that restriction, which seems too
>> strong.
>>
>>
>> The use case
>>
>> The use case is performing type-level computations (like Boost.MPL) using
>> generic lambdas rather than a custom domain specific language (like MPL
>> LambdaExpressions). This new way of doing type-level computations is
>> exploited
>> in the Boost.Hana library [1]. Here is an explanation of that technique.
>>
>> First, let's assume we have heterogeneous algorithms, which are basically
>> STL algorithms that work on tuples (a bit like Boost.Fusion, too):
>>
>> // Returns the first element of `tuple` for which `pred` returns a
>> // true-valued `std::integral_constant`.
>> template <typename ...T, typename Predicate>
>> auto find_if(std::tuple<T...> tuple, Predicate pred);
>>
>> It is also possible to define other algorithms like `for_each`,
>> `transform`
>> and so on, but let's keep this minimal. Now, we can define a wrapper to
>> represent a type using an object, and we can define type traits (or
>> arbitrary
>> metafunctions) as normal functions taking such wrappers:
>>
>> template <typename T>
>> struct Type { using type = T; };
>>
>> template <typename T>
>> std::is_pointer<T> is_pointer(Type<T>) { return {}; }
>>
>> Finally, we can use these in conjunction with our heterogeneous algorithms
>> to perform type-level computations using the usual C++ syntax:
>>
>> auto types = std::make_tuple(Type<int>{}, Type<float*>{}, Type<char>
>> {});
>> auto first_ptr = find_if(types, [](auto t) {
>> return is_pointer(t);
>> });
>> using FirstPtr = decltype(first_ptr)::type;
>>
>> Within this new paradigm, it would often be useful to have lambdas inside
>> unevaluated contexts in order to skip the intermediate `first_ptr`
>> variable.
>> Indeed, it would be more natural to simply write
>>
>> using FirstPtr = decltype(find_if(types, [](auto t) {
>> return is_pointer(t);
>> }))::type;
>>
>>
>> Lifting the restriction
>>
>> Clearly, point (2) of the rationale given above does not apply anymore,
>> since
>> there is a very clear use case of lambdas inside unevaluated contexts.
>> While
>> you might not be convinced by the above example, Boost.Hana [1] contains
>> many
>> serious examples where this would be useful.
>>
>> Secondly, preventing lambdas from appearing in unevaluated contexts for
>> the
>> sole purpose of point (3) is arguably way overkill. Indeed, we do not need
>> the actual type of a lambda to appear inside a function signature in the
>> general case; we merely need to be able to pass a lambda to another
>> function
>> and then use `decltype` on the result. Similarly, it would be better
>> (although
>> still too strong) if `decltype([]() {})` was prohibited for reason (3),
>> but
>> prohibiting `decltype([](){} ())` (note the call to the lambda) seems to
>> be
>> overly restrictive.
>>
>> I have talked to Richard Smith about this at CppCon 2015, and IIRC he said
>> that restrictions on what could and couldn't appear inside a mangled name
>> was
>> now being stated explicitly in the standard. Hence, point (3) might not
>> even
>> be a valid reason anymore.
>>
>
> See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1607 for
> the relevant change.
>
>
>> Finally, there's point (1) about SFINAE. IMO, it would be better than
>> nothing
>> if the standard just said that no SFINAE could happen inside the lambda's
>> body,
>> so that a hard error is triggered instead. This would lead the door open
>> to
>> adding support for SFINAE inside lambdas at a later time, and would enable
>> many use cases right now.
>>
>> Also, FWIW, Clang has a bug right now that _sometimes_ makes it possible
>> to
>> use lambdas inside unevaluated contexts. So it is definitely possible to
>> implement it. See [2] for more information.
>>
>> I'd like to gather thoughts and comments about lifting this restriction,
>> and
>> to confirm that reason (3) does not apply anymore. If there are no
>> reasons not
>> to proceed, I will then open a core issue (I was told it was the best way
>> to
>> do this).
>>
>> Regards,
>> Louis Dionne
>>
>> [1]: https://github.com/ldionne/hana
>> [2]: https://github.com/ldionne/hana/issues/4#issuecomment-51244672
>>
>> --
>>
>> ---
>> You received this message because you are subscribed to the Google Groups
>> "ISO C++ Standard - Future Proposals" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to std-proposal...@isocpp.org <javascript:>.
>> To post to this group, send email to std-pr...@isocpp.org <javascript:>.
>> Visit this group at
>> http://groups.google.com/a/isocpp.org/group/std-proposals/.
>>
>
>
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_1077_923330986.1443807443614
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Great, so it really seems like the only "issue" =
left is to decide what to do with SFINAE<div>inside the body of a lambda. I=
'll go ahead and open a core issue, and what to do with</div><div>SFINA=
E can be dealt with then.</div><div><br></div><div>Regards,</div><div>Louis=
<br><div><br>On Tuesday, 29 September 2015 22:07:41 UTC-4, Richard Smith w=
rote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8e=
x;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><di=
v class=3D"gmail_quote">On Tue, Sep 29, 2015 at 12:31 PM, Louis Dionne <spa=
n dir=3D"ltr"><<a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-=
mailto=3D"J6ErfSgkCgAJ" rel=3D"nofollow" onmousedown=3D"this.href=3D'ja=
vascript:';return true;" onclick=3D"this.href=3D'javascript:';r=
eturn true;">ldio...@gmail.com</a>></span> wrote:<br><blockquote class=
=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;bo=
rder-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">=
<div dir=3D"ltr"><div>Hi,</div><div><br></div><div>I would like to re-open =
a discussion about allowing lambdas inside unevaluated</div><div>contexts. =
For the record, here is a good explanation of the rationale for</div><div>d=
isallowing them:</div><div><br></div><div>=C2=A0 =C2=A0 <a href=3D"http://s=
tackoverflow.com/q/22232164/627587" target=3D"_blank" rel=3D"nofollow" onmo=
usedown=3D"this.href=3D'http://www.google.com/url?q\75http%3A%2F%2Fstac=
koverflow.com%2Fq%2F22232164%2F627587\46sa\75D\46sntz\0751\46usg\75AFQjCNGe=
u-mu0FPvdVXW6YyjLs6qylcltg';return true;" onclick=3D"this.href=3D'h=
ttp://www.google.com/url?q\75http%3A%2F%2Fstackoverflow.com%2Fq%2F22232164%=
2F627587\46sa\75D\46sntz\0751\46usg\75AFQjCNGeu-mu0FPvdVXW6YyjLs6qylcltg=
9;;return true;">http://stackoverflow.com/q/<wbr>22232164/627587</a></div><=
div><br></div><div>and the original discussion that started the debate:</di=
v><div><br></div><div>=C2=A0 =C2=A0 <a href=3D"https://groups.google.com/fo=
rum/#!msg/comp.lang.c++.moderated/J9MbhcOrAzY/XjKeWEbU1EcJ" target=3D"_blan=
k" rel=3D"nofollow" onmousedown=3D"this.href=3D'https://groups.google.c=
om/forum/#!msg/comp.lang.c++.moderated/J9MbhcOrAzY/XjKeWEbU1EcJ';return=
true;" onclick=3D"this.href=3D'https://groups.google.com/forum/#!msg/c=
omp.lang.c++.moderated/J9MbhcOrAzY/XjKeWEbU1EcJ';return true;">https://=
groups.google.com/<wbr>forum/#!msg/comp.lang.c++.<wbr>moderated/J9MbhcOrAzY=
/<wbr>XjKeWEbU1EcJ</a></div><div><br></div><div><br></div><div><font size=
=3D"4">Summary of the problem</font></div><div><font size=3D"4"><br></font>=
</div><div>Let me summarize my understanding of the rationale (please corre=
ct me if I'm</div><div>wrong on something):</div><div><br></div><div>1.=
Allowing lambdas in unevaluated contexts creates the problem that performi=
ng</div><div>=C2=A0 =C2=A0SFINAE inside the lambda is hard to implement for=
compilers. For example:</div><div><br></div><div style=3D"border:1px solid=
rgb(187,187,187);word-wrap:break-word;background-color:rgb(250,250,250)"><=
code><div><span style=3D"color:rgb(0,0,0)">=C2=A0 =C2=A0 =C2=A0 =C2=A0 </sp=
an><span style=3D"color:rgb(0,0,136)">template</span><span style=3D"color:r=
gb(0,0,0)"> </span><span style=3D"color:rgb(102,102,0)"><</span><span st=
yle=3D"color:rgb(0,0,136)">typename</span><span style=3D"color:rgb(0,0,0)">=
X</span><span style=3D"color:rgb(102,102,0)">></span><span style=3D"col=
or:rgb(0,0,0)"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color:=
rgb(0,0,136)">auto</span><span style=3D"color:rgb(0,0,0)"> f</span><span st=
yle=3D"color:rgb(102,102,0)">(</span><span style=3D"color:rgb(0,0,0)">X x</=
span><span style=3D"color:rgb(102,102,0)">)</span><span style=3D"color:rgb(=
0,0,0)"> </span><span style=3D"color:rgb(102,102,0)">-></span><span styl=
e=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(0,0,136)">decltype<=
/span><span style=3D"color:rgb(102,102,0)">([](</span><span style=3D"color:=
rgb(0,0,136)">auto</span><span style=3D"color:rgb(0,0,0)"> x</span><span st=
yle=3D"color:rgb(102,102,0)">)</span><span style=3D"color:rgb(0,0,0)"> </sp=
an><span style=3D"color:rgb(102,102,0)">{</span><span style=3D"color:rgb(0,=
0,0)"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"c=
olor:rgb(136,0,0)">// Some expression(s) that might be invalid, but SFINAE =
should be</span><span style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color:rgb(136,0,0)">// performed=
.. Since these expressions can be arbitrarily complex,</span><span style=3D"=
color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><spa=
n style=3D"color:rgb(136,0,0)">// this is like SFINAE on steroids, which is=
hard to implement.</span><span style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 </span><span style=3D"color:rgb(102,102,0)">}(</span><spa=
n style=3D"color:rgb(0,0,0)">x</span><span style=3D"color:rgb(102,102,0)">)=
);</span></div></code></div><div><br></div><div><br></div><div>2. Knowing t=
he type of a lambda is pretty much useless, since that type is</div><div>=
=C2=A0 =C2=A0unique anyway. Hence, the following would hold:</div><div><br>=
</div><div style=3D"border:1px solid rgb(187,187,187);word-wrap:break-word;=
background-color:rgb(250,250,250)"><code><div><span style=3D"color:rgb(0,0,=
0)">=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,0,136)">s=
tatic_assert</span><span style=3D"color:rgb(102,102,0)">(!</span><span styl=
e=3D"color:rgb(0,0,0)">std</span><span style=3D"color:rgb(102,102,0)">::</s=
pan><span style=3D"color:rgb(0,0,0)">is_same</span><span style=3D"color:rgb=
(102,102,0)"><</span><span style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,0,136)">declt=
ype</span><span style=3D"color:rgb(102,102,0)">([](</span><span style=3D"co=
lor:rgb(0,0,136)">auto</span><span style=3D"color:rgb(0,0,0)"> x</span><spa=
n style=3D"color:rgb(102,102,0)">,</span><span style=3D"color:rgb(0,0,0)"> =
</span><span style=3D"color:rgb(0,0,136)">auto</span><span style=3D"color:r=
gb(0,0,0)"> y</span><span style=3D"color:rgb(102,102,0)">)</span><span styl=
e=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,102,0)">{</span=
><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(0,0,136)=
">return</span><span style=3D"color:rgb(0,0,0)"> x </span><span style=3D"co=
lor:rgb(102,102,0)">+</span><span style=3D"color:rgb(0,0,0)"> y</span><span=
style=3D"color:rgb(102,102,0)">;</span><span style=3D"color:rgb(0,0,0)"> <=
/span><span style=3D"color:rgb(102,102,0)">}),</span><span style=3D"color:r=
gb(0,0,0)"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=
=3D"color:rgb(0,0,136)">decltype</span><span style=3D"color:rgb(102,102,0)"=
>([](</span><span style=3D"color:rgb(0,0,136)">auto</span><span style=3D"co=
lor:rgb(0,0,0)"> x</span><span style=3D"color:rgb(102,102,0)">,</span><span=
style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(0,0,136)">auto=
</span><span style=3D"color:rgb(0,0,0)"> y</span><span style=3D"color:rgb(1=
02,102,0)">)</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"=
color:rgb(102,102,0)">{</span><span style=3D"color:rgb(0,0,0)"> </span><spa=
n style=3D"color:rgb(0,0,136)">return</span><span style=3D"color:rgb(0,0,0)=
"> x </span><span style=3D"color:rgb(102,102,0)">+</span><span style=3D"col=
or:rgb(0,0,0)"> y</span><span style=3D"color:rgb(102,102,0)">;</span><span =
style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,102,0)">})<=
/span><span style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </sp=
an><span style=3D"color:rgb(102,102,0)">>::</span><span style=3D"color:r=
gb(0,0,0)">value</span><span style=3D"color:rgb(102,102,0)">,</span><span s=
tyle=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(0,136,0)">"=
"</span><span style=3D"color:rgb(102,102,0)">);</span></div></code></d=
iv><div><br></div><div>=C2=A0 =C2=A0In particular, this means that code lik=
e</div><div><br></div><div style=3D"border:1px solid rgb(187,187,187);word-=
wrap:break-word;background-color:rgb(250,250,250)"><code><div><span style=
=3D"color:rgb(0,0,0)">=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"col=
or:rgb(0,0,136)">using</span><span style=3D"color:rgb(0,0,0)"> </span><span=
style=3D"color:rgb(102,0,102)">Plus</span><span style=3D"color:rgb(0,0,0)"=
> </span><span style=3D"color:rgb(102,102,0)">=3D</span><span style=3D"colo=
r:rgb(0,0,0)"> </span><span style=3D"color:rgb(0,0,136)">decltype</span><sp=
an style=3D"color:rgb(102,102,0)">([](</span><span style=3D"color:rgb(0,0,1=
36)">auto</span><span style=3D"color:rgb(0,0,0)"> x</span><span style=3D"co=
lor:rgb(102,102,0)">,</span><span style=3D"color:rgb(0,0,0)"> </span><span =
style=3D"color:rgb(0,0,136)">auto</span><span style=3D"color:rgb(0,0,0)"> y=
</span><span style=3D"color:rgb(102,102,0)">)</span><span style=3D"color:rg=
b(0,0,0)"> </span><span style=3D"color:rgb(102,102,0)">{</span><span style=
=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(0,0,136)">return</sp=
an><span style=3D"color:rgb(0,0,0)"> x </span><span style=3D"color:rgb(102,=
102,0)">+</span><span style=3D"color:rgb(0,0,0)"> y</span><span style=3D"co=
lor:rgb(102,102,0)">;</span><span style=3D"color:rgb(0,0,0)"> </span><span =
style=3D"color:rgb(102,102,0)">});</span><span style=3D"color:rgb(0,0,0)"><=
br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color:rgb(102,0,102)">=
Plus</span><span style=3D"color:rgb(0,0,0)"> plus </span><span style=3D"col=
or:rgb(102,102,0)">=3D</span><span style=3D"color:rgb(0,0,0)"> </span><span=
style=3D"color:rgb(102,102,0)">[](</span><span style=3D"color:rgb(0,0,136)=
">auto</span><span style=3D"color:rgb(0,0,0)"> x</span><span style=3D"color=
:rgb(102,102,0)">,</span><span style=3D"color:rgb(0,0,0)"> </span><span sty=
le=3D"color:rgb(0,0,136)">auto</span><span style=3D"color:rgb(0,0,0)"> y</s=
pan><span style=3D"color:rgb(102,102,0)">)</span><span style=3D"color:rgb(0=
,0,0)"> </span><span style=3D"color:rgb(102,102,0)">{</span><span style=3D"=
color:rgb(0,0,0)"> </span><span style=3D"color:rgb(0,0,136)">return</span><=
span style=3D"color:rgb(0,0,0)"> x </span><span style=3D"color:rgb(102,102,=
0)">+</span><span style=3D"color:rgb(0,0,0)"> y</span><span style=3D"color:=
rgb(102,102,0)">;</span><span style=3D"color:rgb(0,0,0)"> </span><span styl=
e=3D"color:rgb(102,102,0)">};</span></div></code></div><div><br></div><div>=
=C2=A0 =C2=A0 is not valid, which seems to reduce the usefulness of the fea=
ture.</div><div><br></div><div>3. Since lambdas have unique types, how shou=
ld we mangle the signature of</div><div>=C2=A0 =C2=A0a function having a la=
mbda in it? Consider the following:</div><div><br></div><div><div style=3D"=
border:1px solid rgb(187,187,187);word-wrap:break-word;background-color:rgb=
(250,250,250)"><code><div><span style=3D"color:rgb(0,0,0)">=C2=A0 =C2=A0 =
=C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,0,136)">void</span><span st=
yle=3D"color:rgb(0,0,0)"> f</span><span style=3D"color:rgb(102,102,0)">(</s=
pan><span style=3D"color:rgb(0,0,136)">decltype</span><span style=3D"color:=
rgb(102,102,0)">([](</span><span style=3D"color:rgb(0,0,136)">auto</span><s=
pan style=3D"color:rgb(0,0,0)"> x</span><span style=3D"color:rgb(102,102,0)=
">)</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb=
(102,102,0)">{</span><span style=3D"color:rgb(0,0,0)"> </span><span style=
=3D"color:rgb(102,102,0)">}));</span></div></code></div></div><div><br></di=
v><div>=C2=A0 =C2=A0How should we mangle the signature of `f`, and how can =
we make sure that it</div><div>=C2=A0 =C2=A0is mangled the same way inside =
each translation unit where this declaration</div><div>=C2=A0 =C2=A0appears=
?</div><div><br></div><div>Having found a compelling use case for lambdas i=
nside unevaluated contexts,</div><div>I think it is worth reconsidering tha=
t restriction, which seems too strong.</div><div><br></div><div><br></div><=
div><font size=3D"4">The use case</font></div><div><font size=3D"4"><br></f=
ont></div><div>The use case is performing type-level computations (like Boo=
st.MPL) using</div><div>generic lambdas rather than a custom domain specifi=
c language (like MPL</div><div>LambdaExpressions). This new way of doing ty=
pe-level computations is exploited</div><div>in the Boost.Hana library [1].=
Here is an explanation of that technique.</div><div><br></div><div>First, =
let's assume we have heterogeneous algorithms, which are basically</div=
><div>STL algorithms that work on tuples (a bit like Boost.Fusion, too):</d=
iv><div><br></div><div style=3D"border:1px solid rgb(187,187,187);word-wrap=
:break-word;background-color:rgb(250,250,250)"><code><div><span style=3D"co=
lor:rgb(0,0,0)">=C2=A0 =C2=A0 </span><span style=3D"color:rgb(136,0,0)">// =
Returns the first element of `tuple` for which `pred` returns a</span><span=
style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 </span><span style=3D"color:r=
gb(136,0,0)">// true-valued `std::integral_constant`.</span><span style=3D"=
color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,0,136=
)">template</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"c=
olor:rgb(102,102,0)"><</span><span style=3D"color:rgb(0,0,136)">typename=
</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(10=
2,102,0)">...</span><span style=3D"color:rgb(0,0,0)">T</span><span style=3D=
"color:rgb(102,102,0)">,</span><span style=3D"color:rgb(0,0,0)"> </span><sp=
an style=3D"color:rgb(0,0,136)">typename</span><span style=3D"color:rgb(0,0=
,0)"> </span><span style=3D"color:rgb(102,0,102)">Predicate</span><span sty=
le=3D"color:rgb(102,102,0)">></span><span style=3D"color:rgb(0,0,0)"><br=
>=C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,0,136)">auto</span><span s=
tyle=3D"color:rgb(0,0,0)"> find_if</span><span style=3D"color:rgb(102,102,0=
)">(</span><span style=3D"color:rgb(0,0,0)">std</span><span style=3D"color:=
rgb(102,102,0)">::</span><span style=3D"color:rgb(0,0,0)">tuple</span><span=
style=3D"color:rgb(102,102,0)"><</span><span style=3D"color:rgb(0,0,0)"=
>T</span><span style=3D"color:rgb(102,102,0)">...></span><span style=3D"=
color:rgb(0,0,0)"> tuple</span><span style=3D"color:rgb(102,102,0)">,</span=
><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,0,10=
2)">Predicate</span><span style=3D"color:rgb(0,0,0)"> pred</span><span styl=
e=3D"color:rgb(102,102,0)">);</span></div></code></div><div><br></div><div>=
It is also possible to define other algorithms like `for_each`, `transform`=
</div><div>and so on, but let's keep this minimal. Now, we can define a=
wrapper to</div><div>represent a type using an object, and we can define t=
ype traits (or arbitrary</div><div>metafunctions) as normal functions takin=
g such wrappers:</div><div><br></div><div style=3D"border:1px solid rgb(187=
,187,187);word-wrap:break-word;background-color:rgb(250,250,250)"><code><di=
v><span style=3D"color:rgb(0,0,0)">=C2=A0 =C2=A0 </span><span style=3D"colo=
r:rgb(0,0,136)">template</span><span style=3D"color:rgb(0,0,0)"> </span><sp=
an style=3D"color:rgb(102,102,0)"><</span><span style=3D"color:rgb(0,0,1=
36)">typename</span><span style=3D"color:rgb(0,0,0)"> T</span><span style=
=3D"color:rgb(102,102,0)">></span><span style=3D"color:rgb(0,0,0)"><br>=
=C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,0,136)">struct</span><span =
style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,0,102)">Typ=
e</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(1=
02,102,0)">{</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"=
color:rgb(0,0,136)">using</span><span style=3D"color:rgb(0,0,0)"> type </sp=
an><span style=3D"color:rgb(102,102,0)">=3D</span><span style=3D"color:rgb(=
0,0,0)"> T</span><span style=3D"color:rgb(102,102,0)">;</span><span style=
=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,102,0)">};</span=
><span style=3D"color:rgb(0,0,0)"><br><br>=C2=A0 =C2=A0 </span><span style=
=3D"color:rgb(0,0,136)">template</span><span style=3D"color:rgb(0,0,0)"> </=
span><span style=3D"color:rgb(102,102,0)"><</span><span style=3D"color:r=
gb(0,0,136)">typename</span><span style=3D"color:rgb(0,0,0)"> T</span><span=
style=3D"color:rgb(102,102,0)">></span><span style=3D"color:rgb(0,0,0)"=
><br>=C2=A0 =C2=A0 std</span><span style=3D"color:rgb(102,102,0)">::</span>=
<span style=3D"color:rgb(0,0,0)">is_pointer</span><span style=3D"color:rgb(=
102,102,0)"><</span><span style=3D"color:rgb(0,0,0)">T</span><span style=
=3D"color:rgb(102,102,0)">></span><span style=3D"color:rgb(0,0,0)"> is_p=
ointer</span><span style=3D"color:rgb(102,102,0)">(</span><span style=3D"co=
lor:rgb(102,0,102)">Type</span><span style=3D"color:rgb(102,102,0)"><</s=
pan><span style=3D"color:rgb(0,0,0)">T</span><span style=3D"color:rgb(102,1=
02,0)">>)</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"=
color:rgb(102,102,0)">{</span><span style=3D"color:rgb(0,0,0)"> </span><spa=
n style=3D"color:rgb(0,0,136)">return</span><span style=3D"color:rgb(0,0,0)=
"> </span><span style=3D"color:rgb(102,102,0)">{};</span><span style=3D"col=
or:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,102,0)">}</span></div><=
/code></div><div><br></div><div>Finally, we can use these in conjunction wi=
th our heterogeneous algorithms</div><div>to perform type-level computation=
s using the usual C++ syntax:</div><div><br></div><div style=3D"border:1px =
solid rgb(187,187,187);word-wrap:break-word;background-color:rgb(250,250,25=
0)"><code><div><span style=3D"color:rgb(0,0,0)">=C2=A0 =C2=A0 </span><span =
style=3D"color:rgb(0,0,136)">auto</span><span style=3D"color:rgb(0,0,0)"> t=
ypes </span><span style=3D"color:rgb(102,102,0)">=3D</span><span style=3D"c=
olor:rgb(0,0,0)"> std</span><span style=3D"color:rgb(102,102,0)">::</span><=
span style=3D"color:rgb(0,0,0)">make_tuple</span><span style=3D"color:rgb(1=
02,102,0)">(</span><span style=3D"color:rgb(102,0,102)">Type</span><span st=
yle=3D"color:rgb(0,136,0)"><int></span><span style=3D"color:rgb(102,1=
02,0)">{},</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"co=
lor:rgb(102,0,102)">Type</span><span style=3D"color:rgb(102,102,0)"><</s=
pan><span style=3D"color:rgb(0,0,136)">float</span><span style=3D"color:rgb=
(102,102,0)">*>{},</span><span style=3D"color:rgb(0,0,0)"> </span><span =
style=3D"color:rgb(102,0,102)">Type</span><span style=3D"color:rgb(0,136,0)=
"><char></span><span style=3D"color:rgb(102,102,0)">{});</span><span =
style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 </span><span style=3D"color:rg=
b(0,0,136)">auto</span><span style=3D"color:rgb(0,0,0)"> first_ptr </span><=
span style=3D"color:rgb(102,102,0)">=3D</span><span style=3D"color:rgb(0,0,=
0)"> find_if</span><span style=3D"color:rgb(102,102,0)">(</span><span style=
=3D"color:rgb(0,0,0)">types</span><span style=3D"color:rgb(102,102,0)">,</s=
pan><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,1=
02,0)">[](</span><span style=3D"color:rgb(0,0,136)">auto</span><span style=
=3D"color:rgb(0,0,0)"> t</span><span style=3D"color:rgb(102,102,0)">)</span=
><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,102,=
0)">{</span><span style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 </span><span style=3D"color:rgb(0,0,136)">return</span><span style=3D"c=
olor:rgb(0,0,0)"> is_pointer</span><span style=3D"color:rgb(102,102,0)">(</=
span><span style=3D"color:rgb(0,0,0)">t</span><span style=3D"color:rgb(102,=
102,0)">);</span><span style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 </span>=
<span style=3D"color:rgb(102,102,0)">});</span><span style=3D"color:rgb(0,0=
,0)"><br>=C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,0,136)">using</spa=
n><span style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,0,1=
02)">FirstPtr</span><span style=3D"color:rgb(0,0,0)"> </span><span style=3D=
"color:rgb(102,102,0)">=3D</span><span style=3D"color:rgb(0,0,0)"> </span><=
span style=3D"color:rgb(0,0,136)">decltype</span><span style=3D"color:rgb(1=
02,102,0)">(</span><span style=3D"color:rgb(0,0,0)">first_ptr</span><span s=
tyle=3D"color:rgb(102,102,0)">)::</span><span style=3D"color:rgb(0,0,0)">ty=
pe</span><span style=3D"color:rgb(102,102,0)">;</span></div></code></div><d=
iv><br></div><div>Within this new paradigm, it would often be useful to hav=
e lambdas inside</div><div>unevaluated contexts in order to skip the interm=
ediate `first_ptr` variable.</div><div>Indeed, it would be more natural to =
simply write</div><div><br></div><div style=3D"border:1px solid rgb(187,187=
,187);word-wrap:break-word;background-color:rgb(250,250,250)"><code><div><s=
pan style=3D"color:rgb(0,0,0)">=C2=A0 =C2=A0 </span><span style=3D"color:rg=
b(0,0,136)">using</span><span style=3D"color:rgb(0,0,0)"> </span><span styl=
e=3D"color:rgb(102,0,102)">FirstPtr</span><span style=3D"color:rgb(0,0,0)">=
</span><span style=3D"color:rgb(102,102,0)">=3D</span><span style=3D"color=
:rgb(0,0,0)"> </span><span style=3D"color:rgb(0,0,136)">decltype</span><spa=
n style=3D"color:rgb(102,102,0)">(</span><span style=3D"color:rgb(0,0,0)">f=
ind_if</span><span style=3D"color:rgb(102,102,0)">(</span><span style=3D"co=
lor:rgb(0,0,0)">types</span><span style=3D"color:rgb(102,102,0)">,</span><s=
pan style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,102,0)"=
>[](</span><span style=3D"color:rgb(0,0,136)">auto</span><span style=3D"col=
or:rgb(0,0,0)"> t</span><span style=3D"color:rgb(102,102,0)">)</span><span =
style=3D"color:rgb(0,0,0)"> </span><span style=3D"color:rgb(102,102,0)">{</=
span><span style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </spa=
n><span style=3D"color:rgb(0,0,136)">return</span><span style=3D"color:rgb(=
0,0,0)"> is_pointer</span><span style=3D"color:rgb(102,102,0)">(</span><spa=
n style=3D"color:rgb(0,0,0)">t</span><span style=3D"color:rgb(102,102,0)">)=
;</span><span style=3D"color:rgb(0,0,0)"><br>=C2=A0 =C2=A0 </span><span sty=
le=3D"color:rgb(102,102,0)">}))::</span><span style=3D"color:rgb(0,0,0)">ty=
pe</span><span style=3D"color:rgb(102,102,0)">;</span></div></code></div><d=
iv><br></div><div><br></div><div><font size=3D"4">Lifting the restriction</=
font></div><div><font size=3D"4"><br></font></div><div>Clearly, point (2) o=
f the rationale given above does not apply anymore, since</div><div>there i=
s a very clear use case of lambdas inside unevaluated contexts. While</div>=
<div>you might not be convinced by the above example, Boost.Hana [1] contai=
ns many</div><div>serious examples where this would be useful.</div><div><b=
r></div><div>Secondly, preventing lambdas from appearing in unevaluated con=
texts for the</div><div>sole purpose of point (3) is arguably way overkill.=
Indeed, we do not need</div><div>the actual type of a lambda to appear ins=
ide a function signature in the</div><div>general case; we merely need to b=
e able to pass a lambda to another function</div><div>and then use `decltyp=
e` on the result. Similarly, it would be better (although</div><div>still t=
oo strong) if `decltype([]() {})` was prohibited for reason (3), but</div><=
div>prohibiting `decltype([](){} ())` (note the call to the lambda) seems t=
o be</div><div>overly restrictive.</div><div><br></div><div>I have talked t=
o Richard Smith about this at CppCon 2015, and IIRC he said</div><div>that =
restrictions on what could and couldn't appear inside a mangled name wa=
s</div><div>now being stated explicitly in the standard. Hence, point (3) m=
ight not even</div><div>be a valid reason anymore.</div></div></blockquote>=
<div><br></div><div>See=C2=A0<a href=3D"http://www.open-std.org/jtc1/sc22/w=
g21/docs/cwg_defects.html#1607" target=3D"_blank" rel=3D"nofollow" onmoused=
own=3D"this.href=3D'http://www.google.com/url?q\75http%3A%2F%2Fwww.open=
-std.org%2Fjtc1%2Fsc22%2Fwg21%2Fdocs%2Fcwg_defects.html%231607\46sa\75D\46s=
ntz\0751\46usg\75AFQjCNE0O3LEnXjnN54B9b3_BLgFJ_Fxvg';return true;" oncl=
ick=3D"this.href=3D'http://www.google.com/url?q\75http%3A%2F%2Fwww.open=
-std.org%2Fjtc1%2Fsc22%2Fwg21%2Fdocs%2Fcwg_defects.html%231607\46sa\75D\46s=
ntz\0751\46usg\75AFQjCNE0O3LEnXjnN54B9b3_BLgFJ_Fxvg';return true;">http=
://www.open-std.org/<wbr>jtc1/sc22/wg21/docs/cwg_<wbr>defects.html#1607</a>=
for the relevant change.</div><div>=C2=A0</div><blockquote class=3D"gmail_=
quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-=
color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir=
=3D"ltr"><div>Finally, there's point (1) about SFINAE. IMO, it would be=
better than nothing</div><div>if the standard just said that no SFINAE cou=
ld happen inside the lambda's body,</div><div>so that a hard error is t=
riggered instead. This would lead the door open to</div><div>adding support=
for SFINAE inside lambdas at a later time, and would enable</div><div>many=
use cases right now.</div><div><br></div><div>Also, FWIW, Clang has a bug =
right now that _sometimes_ makes it possible to</div><div>use lambdas insid=
e unevaluated contexts. So it is definitely possible to</div><div>implement=
it. See [2] for more information.</div><div><br></div><div>I'd like to=
gather thoughts and comments about lifting this restriction, and</div><div=
>to confirm that reason (3) does not apply anymore. If there are no reasons=
not</div><div>to proceed, I will then open a core issue (I was told it was=
the best way to</div><div>do this).</div><div><br></div><div>Regards,</div=
><div>Louis Dionne</div><div><br></div><div>[1]: <a href=3D"https://github.=
com/ldionne/hana" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.hr=
ef=3D'https://www.google.com/url?q\75https%3A%2F%2Fgithub.com%2Fldionne=
%2Fhana\46sa\75D\46sntz\0751\46usg\75AFQjCNEdX7j5Af05lFscT3aoqqOO-kg6dw'=
;;return true;" onclick=3D"this.href=3D'https://www.google.com/url?q\75=
https%3A%2F%2Fgithub.com%2Fldionne%2Fhana\46sa\75D\46sntz\0751\46usg\75AFQj=
CNEdX7j5Af05lFscT3aoqqOO-kg6dw';return true;">https://github.com/ldionn=
e/<wbr>hana</a></div><div>[2]: <a href=3D"https://github.com/ldionne/hana/i=
ssues/4#issuecomment-51244672" target=3D"_blank" rel=3D"nofollow" onmousedo=
wn=3D"this.href=3D'https://www.google.com/url?q\75https%3A%2F%2Fgithub.=
com%2Fldionne%2Fhana%2Fissues%2F4%23issuecomment-51244672\46sa\75D\46sntz\0=
751\46usg\75AFQjCNHRHnG6Vj3IOD_WNchkL0IcLCOCOA';return true;" onclick=
=3D"this.href=3D'https://www.google.com/url?q\75https%3A%2F%2Fgithub.co=
m%2Fldionne%2Fhana%2Fissues%2F4%23issuecomment-51244672\46sa\75D\46sntz\075=
1\46usg\75AFQjCNHRHnG6Vj3IOD_WNchkL0IcLCOCOA';return true;">https://git=
hub.com/ldionne/<wbr>hana/issues/4#issuecomment-<wbr>51244672</a></div><spa=
n><font color=3D"#888888"><div><br></div></font></span></div><span><font co=
lor=3D"#888888">
<p></p>
-- <br>
<br>
--- <br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"=
J6ErfSgkCgAJ" rel=3D"nofollow" onmousedown=3D"this.href=3D'javascript:&=
#39;;return true;" onclick=3D"this.href=3D'javascript:';return true=
;">std-proposal...@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"javascript:" target=3D"_bla=
nk" gdf-obfuscated-mailto=3D"J6ErfSgkCgAJ" rel=3D"nofollow" onmousedown=3D"=
this.href=3D'javascript:';return true;" onclick=3D"this.href=3D'=
;javascript:';return true;">std-pr...@isocpp.org</a>.<br>
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.href=
=3D'http://groups.google.com/a/isocpp.org/group/std-proposals/';ret=
urn true;" onclick=3D"this.href=3D'http://groups.google.com/a/isocpp.or=
g/group/std-proposals/';return true;">http://groups.google.com/a/<wbr>i=
socpp.org/group/std-<wbr>proposals/</a>.<br>
</font></span></blockquote></div><br></div></div>
</blockquote></div></div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_1077_923330986.1443807443614--
------=_Part_1076_179658113.1443807443613--
.
Author: =?UTF-8?Q?Agust=c3=adn_K-ballo_Berg=c3=a9?= <kaballo86@hotmail.com>
Date: Fri, 2 Oct 2015 15:03:39 -0300
Raw View
On 10/2/2015 2:37 PM, Louis Dionne wrote:
> Great, so it really seems like the only "issue" left is to decide what
> to do with SFINAE
> inside the body of a lambda. I'll go ahead and open a core issue, and
> what to do with
> SFINAE can be dealt with then.
I'm not sure I understand this concern, how does the unevaluated context=20
make things differently? I don't know if "immediate context" has a=20
normative definition, but the body of a lambda does not say immediate=20
context to me.
Consider the example you gave:
template <typename X>
auto f(X x) -> decltype([](auto x) { /*...*/ }(x));
f(42);
I would expect that to be equivalent to this:
template <typename X, typename F>
auto f(X x, F&& f) -> decltype(std::forward<F>()(x));
f(42, [](auto x) { /*...*/ });
That lambda has a placeholder for return type, so decltype must=20
instantiate the body to deduce the return type. Any errors within the=20
instantiation of the body are not in the immediate context, and that=20
results in a hard error today.
Now change it to have an explicit return type:
template <typename X, typename F>
auto f(X x, F&& f) -> decltype(std::forward<F>()(x));
f(42, [](auto x) -> void { /*...*/ });
No instantiation happens here, and the expression within decltype is=20
well-formed regardless of the body of the lambda.
Regards,
--=20
Agust=C3=ADn K-ballo Berg=C3=A9.-
http://talesofcpp.fusionfenix.com
--=20
---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.
.
Author: Louis Dionne <ldionne.2@gmail.com>
Date: Fri, 2 Oct 2015 11:43:41 -0700 (PDT)
Raw View
------=_Part_1091_2056980021.1443811421310
Content-Type: multipart/alternative;
boundary="----=_Part_1092_2127315604.1443811421311"
------=_Part_1092_2127315604.1443811421311
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
I think your point of view is the correct one. I mentionned this issue=20
because=20
it was raised in the original discussion [1] about lambdas in unevaluated
contexts. In that discussion (from 2010), Daniel Kr=C3=BCgler said:
There would indeed exist a huge number of use-cases for allowing lambda
expressions, it would probably extremely extend possible sfinae cases
(to include complete code "sand-boxes"). The reason why they became
excluded was due to exactly this extreme extension of sfinae cases (you
were opening a Pandora box for the compiler) [...]
However, after reading your analysis, I think the behavior of a lambda's=20
body=20
inside a SFINAE context is clear and well defined, and should be as you say=
..
FWIW, this is the behavior that I would expect and be happy with.
Seems like the only thing left is to write a core issue!
Regards,
Louis
[1]:=20
https://groups.google.com/d/msg/comp.lang.c++.moderated/J9MbhcOrAzY/XjKeWEb=
U1EcJ
On Friday, 2 October 2015 14:03:40 UTC-4, Agust=C3=ADn K-ballo Berg=C3=A9 w=
rote:
>
> On 10/2/2015 2:37 PM, Louis Dionne wrote:=20
> > Great, so it really seems like the only "issue" left is to decide what=
=20
> > to do with SFINAE=20
> > inside the body of a lambda. I'll go ahead and open a core issue, and=
=20
> > what to do with=20
> > SFINAE can be dealt with then.=20
>
> I'm not sure I understand this concern, how does the unevaluated context=
=20
> make things differently? I don't know if "immediate context" has a=20
> normative definition, but the body of a lambda does not say immediate=20
> context to me.=20
>
> Consider the example you gave:=20
>
> template <typename X>=20
> auto f(X x) -> decltype([](auto x) { /*...*/ }(x));=20
> f(42);=20
>
> I would expect that to be equivalent to this:=20
>
> template <typename X, typename F>=20
> auto f(X x, F&& f) -> decltype(std::forward<F>()(x));=20
> f(42, [](auto x) { /*...*/ });=20
>
> That lambda has a placeholder for return type, so decltype must=20
> instantiate the body to deduce the return type. Any errors within the=20
> instantiation of the body are not in the immediate context, and that=20
> results in a hard error today.=20
>
> Now change it to have an explicit return type:=20
>
> template <typename X, typename F>=20
> auto f(X x, F&& f) -> decltype(std::forward<F>()(x));=20
> f(42, [](auto x) -> void { /*...*/ });=20
>
> No instantiation happens here, and the expression within decltype is=20
> well-formed regardless of the body of the lambda.=20
>
> Regards,=20
> --=20
> Agust=C3=ADn K-ballo Berg=C3=A9.-=20
> http://talesofcpp.fusionfenix.com=20
>
--=20
---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.
------=_Part_1092_2127315604.1443811421311
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>I think your point of view is the correct one. I ment=
ionned this issue because=C2=A0</div><div>it was raised in the original dis=
cussion [1] about lambdas in unevaluated</div><div>contexts. In that discus=
sion (from 2010), Daniel Kr=C3=BCgler said:</div><div><br></div><div>=C2=A0=
=C2=A0 There would indeed exist a huge number of use-cases for allowing la=
mbda</div><div>=C2=A0 =C2=A0 expressions, it would probably extremely exten=
d possible sfinae cases</div><div>=C2=A0 =C2=A0 (to include complete code &=
quot;sand-boxes"). The reason why they became</div><div>=C2=A0 =C2=A0 =
excluded was due to exactly this extreme extension of sfinae cases (you</di=
v><div>=C2=A0 =C2=A0 were opening a Pandora box for the compiler) [...]</di=
v><div><br></div><div>However, after reading your analysis, I think the beh=
avior of a lambda's body=C2=A0</div><div>inside a SFINAE context is cle=
ar and well defined, and should be as you say.</div><div>FWIW, this is the =
behavior that I would expect and be happy with.</div><div><br></div><div>Se=
ems like the only thing left is to write a core issue!</div><div><br></div>=
<div>Regards,</div><div>Louis</div><div><br></div><div>[1]: https://groups.=
google.com/d/msg/comp.lang.c++.moderated/J9MbhcOrAzY/XjKeWEbU1EcJ</div><div=
><br></div><br>On Friday, 2 October 2015 14:03:40 UTC-4, Agust=C3=ADn K-bal=
lo Berg=C3=A9 wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;m=
argin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On 10/2/2=
015 2:37 PM, Louis Dionne wrote:
<br>> Great, so it really seems like the only "issue" left is =
to decide what
<br>> to do with SFINAE
<br>> inside the body of a lambda. I'll go ahead and open a core iss=
ue, and
<br>> what to do with
<br>> SFINAE can be dealt with then.
<br>
<br>I'm not sure I understand this concern, how does the unevaluated co=
ntext=20
<br>make things differently? I don't know if "immediate context&qu=
ot; has a=20
<br>normative definition, but the body of a lambda does not say immediate=
=20
<br>context to me.
<br>
<br>Consider the example you gave:
<br>
<br>=C2=A0 =C2=A0 =C2=A0template <typename X>
<br>=C2=A0 =C2=A0 =C2=A0auto f(X x) -> decltype([](auto x) { /*...*/ }(x=
));
<br>=C2=A0 =C2=A0 =C2=A0f(42);
<br>
<br>I would expect that to be equivalent to this:
<br>
<br>=C2=A0 =C2=A0 =C2=A0template <typename X, typename F>
<br>=C2=A0 =C2=A0 =C2=A0auto f(X x, F&& f) -> decltype(std::forw=
ard<F>()(x))<wbr>;
<br>=C2=A0 =C2=A0 =C2=A0f(42, [](auto x) { /*...*/ });
<br>
<br>That lambda has a placeholder for return type, so decltype must=20
<br>instantiate the body to deduce the return type. Any errors within the=
=20
<br>instantiation of the body are not in the immediate context, and that=20
<br>results in a hard error today.
<br>
<br>Now change it to have an explicit return type:
<br>
<br>=C2=A0 =C2=A0 =C2=A0template <typename X, typename F>
<br>=C2=A0 =C2=A0 =C2=A0auto f(X x, F&& f) -> decltype(std::forw=
ard<F>()(x))<wbr>;
<br>=C2=A0 =C2=A0 =C2=A0f(42, [](auto x) -> void { /*...*/ });
<br>
<br>No instantiation happens here, and the expression within decltype is=20
<br>well-formed regardless of the body of the lambda.
<br>
<br>Regards,
<br>--=20
<br>Agust=C3=ADn K-ballo Berg=C3=A9.-
<br><a href=3D"http://talesofcpp.fusionfenix.com" target=3D"_blank" rel=3D"=
nofollow" onmousedown=3D"this.href=3D'http://www.google.com/url?q\75htt=
p%3A%2F%2Ftalesofcpp.fusionfenix.com\46sa\75D\46sntz\0751\46usg\75AFQjCNGrO=
c8fm1PhW0305mMc5XVd9NU-_Q';return true;" onclick=3D"this.href=3D'ht=
tp://www.google.com/url?q\75http%3A%2F%2Ftalesofcpp.fusionfenix.com\46sa\75=
D\46sntz\0751\46usg\75AFQjCNGrOc8fm1PhW0305mMc5XVd9NU-_Q';return true;"=
>http://talesofcpp.fusionfenix.<wbr>com</a>
<br></blockquote></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_1092_2127315604.1443811421311--
------=_Part_1091_2056980021.1443811421310--
.
Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Sat, 3 Oct 2015 10:13:44 +0300
Raw View
On 2 October 2015 at 21:43, Louis Dionne <ldionne.2@gmail.com> wrote:
> Seems like the only thing left is to write a core issue!
I think you need to write a paper and present it to Evolution. Something like
this is well beyond the limits of what we consider soluble by a Core issue.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
.