Topic: Arbitrary function for parameter pack expansion by
Author: =?UTF-8?Q?Jules_P=C3=A9nuchot?= <jules@penuchot.com>
Date: Sun, 14 Oct 2018 19:33:49 -0700 (PDT)
Raw View
------=_Part_1334_1897456759.1539570829687
Content-Type: multipart/alternative;
boundary="----=_Part_1335_1639328010.1539570829688"
------=_Part_1335_1639328010.1539570829688
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
Hello everyone,
I would like to propose an extension for parameter pack expansion.
Currently only infix operators are allowed to reduce parameter pack=20
expansions. The only ways to replace these operators by an arbitrary=20
function would be to override them directly, which is obviously not a good=
=20
option, or to create a specific decorator class to be able to replace the=
=20
operator.
I will use a function piping function as an example case to illustrate the=
=20
existing (limited) methods and the one I propose.
Direct override method :
#include <iostream>
template<typename F, typename G>
auto operator | (F f, G g)
{
return [=3D] (auto e)
{
return g(f(e));
};
};
int main()
{
auto plus_1 =3D [](auto arg) { return arg + 1; };
auto mult_2 =3D [](auto arg) { return arg * 2; };
auto pipe =3D [](auto... Functions)
{
return ( Functions | ... );
};
auto test =3D pipe(mult_2, mult_2, plus_1, plus_1);
std::cout << test(10) << std::endl;
return 0;
}
Decorator class method :
#include <iostream>
template<typename F>
struct pipe_decorator
{
F f;
};
template<typename Fa, typename Fb>
auto operator | (pipe_decorator<Fa> da, pipe_decorator<Fb> db)
{
auto fun =3D [=3D](auto elmt){ return db.f(da.f(elmt)); };
return pipe_decorator<decltype(fun)>{ fun };
}
int main()
{
auto plus_1 =3D [](auto arg){ return arg + 1; };
auto mult_2 =3D [](auto arg){ return arg * 2; };
auto pipe =3D [](auto... Functions)
{
return ( pipe_decorator<decltype(Functions)>{ Functions } | ... ).f;
};
auto test =3D pipe(mult_2, mult_2, plus_1, plus_1);
std::cout << test(10) << std::endl;
return 0;
}
The decorator method is much better as it avoids overriding the operator=20
for all the functions, however it is not yet self-contained as it still=20
requires to create a class and an operator both external to the function we=
=20
need it in.
Being able to reduce packs with an arbitrary function would even allow us=
=20
to use lambda-capture in this context, which isn't possible in this case=20
without using std::function and therefore missing the optimizations that=20
these solutions benefit from; the code is properly unrolled and partially=
=20
evaluated at compile-time by gcc 7.1 in both cases. clang 7.0.0 wasn't able=
=20
to compile the *direct override method* but it performed the same=20
optimizations as gcc for the *decorator class method*.
The parameter pack expansion is as simple as a map-reduce, we can easily=20
alter the function mapped to each parameter but not the reduction function,=
=20
and there is no reason other than syntax for such a constraint.
Here's what it could look like :
#include <iostream>
int main()
{
auto plus_1 =3D [](auto arg){ return arg + 1; };
auto mult_2 =3D [](auto arg){ return arg * 2; };
auto pipe_funs =3D [](auto F, auto G)
{
return [=3D](auto elmt) { return G(F(elmt)); };
};
auto fallthrough =3D [](auto e)
{
return e;
};
auto pipe =3D [](auto... Functions)
{
return std::parameter_map_reduce(fallthrough, pipe_funs, Functions...);
};
auto test =3D pipe(mult_2, mult_2, plus_1, plus_1);
std::cout << test(10) << std::endl;
return 0;
}
The simple addition of such an "std::parameter_map_reduce" function would=
=20
make it possible without even changing the language's syntax. The first=20
argument would be the function to map, the second one would be the reductor=
=20
then the rest would be the parameters to reduce. An even more minimalistic=
=20
approach would be to add an "std::parameter_reduce" function as we can=20
already map a function to the parameters, but adding both would expose more=
=20
granular options.
Any feedback or criticism regarding this proposal is welcome.
Regards,
Jules P=C3=A9nuchot
--=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.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/8788ce93-157b-464a-8325-bfbe296c38b8%40isocpp.or=
g.
------=_Part_1335_1639328010.1539570829688
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Hello everyone,<div><br></div><div>I would like to propose=
an extension for parameter pack expansion.</div><div><br></div><div>Curren=
tly only infix operators are allowed to reduce parameter pack expansions. T=
he only ways to replace these operators by an arbitrary function would be t=
o override them directly, which is obviously not a good option, or to creat=
e a specific decorator class to be able to replace the operator.</div><div>=
<br></div><div>I will use a function piping function as an example case to =
illustrate the existing (limited) methods and the one I propose.</div><div>=
<br></div><div>Direct override method :</div><div><div class=3D"prettyprint=
" style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187=
, 187); border-style: solid; border-width: 1px; overflow-wrap: break-word;"=
><code class=3D"prettyprint"><div class=3D"subprettyprint"><div class=3D"su=
bprettyprint"><div class=3D"subprettyprint"><font color=3D"#660066">#includ=
e <iostream></font></div><div class=3D"subprettyprint"><font color=3D=
"#660066"><br></font></div><div class=3D"subprettyprint"><font color=3D"#66=
0066">template<typename F, typename G></font></div><div class=3D"subp=
rettyprint"><font color=3D"#660066">auto operator | (F f, G g)</font></div>=
<div class=3D"subprettyprint"><font color=3D"#660066">{</font></div><div cl=
ass=3D"subprettyprint"><font color=3D"#660066">=C2=A0 return [=3D] (auto e)=
</font></div><div class=3D"subprettyprint"><font color=3D"#660066">=C2=A0 {=
</font></div><div class=3D"subprettyprint"><font color=3D"#660066">=C2=A0 =
=C2=A0 return g(f(e));</font></div><div class=3D"subprettyprint"><font colo=
r=3D"#660066">=C2=A0 };</font></div><div class=3D"subprettyprint"><font col=
or=3D"#660066">};</font></div><div class=3D"subprettyprint"><font color=3D"=
#660066"><br></font></div><div class=3D"subprettyprint"><font color=3D"#660=
066">int main()</font></div><div class=3D"subprettyprint"><font color=3D"#6=
60066">{</font></div><div class=3D"subprettyprint"><font color=3D"#660066">=
=C2=A0 auto plus_1 =3D [](auto arg) { return arg + 1; };</font></div><div c=
lass=3D"subprettyprint"><font color=3D"#660066">=C2=A0 auto mult_2 =3D [](a=
uto arg) { return arg * 2; };</font></div><div class=3D"subprettyprint"><fo=
nt color=3D"#660066"><br></font></div><div class=3D"subprettyprint"><font c=
olor=3D"#660066">=C2=A0 auto pipe =3D [](auto... Functions)</font></div><di=
v class=3D"subprettyprint"><font color=3D"#660066">=C2=A0 {</font></div><di=
v class=3D"subprettyprint"><font color=3D"#660066">=C2=A0 =C2=A0 return ( F=
unctions | ... );</font></div><div class=3D"subprettyprint"><font color=3D"=
#660066">=C2=A0 };</font></div><div class=3D"subprettyprint"><font color=3D=
"#660066"><br></font></div><div class=3D"subprettyprint"><font color=3D"#66=
0066">=C2=A0 auto test =3D pipe(mult_2, mult_2, plus_1, plus_1);</font></di=
v><div class=3D"subprettyprint"><font color=3D"#660066"><br></font></div><d=
iv class=3D"subprettyprint"><font color=3D"#660066">=C2=A0 std::cout <&l=
t; test(10) << std::endl;</font></div><div class=3D"subprettyprint"><=
font color=3D"#660066"><br></font></div><div class=3D"subprettyprint"><font=
color=3D"#660066">=C2=A0 return 0;</font></div><div class=3D"subprettyprin=
t"><font color=3D"#660066">}</font></div></div><div><br></div></div></code>=
</div><br>Decorator class method :</div><div><div class=3D"prettyprint" sty=
le=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187=
); border-style: solid; border-width: 1px; overflow-wrap: break-word;"><cod=
e class=3D"prettyprint"><div class=3D"subprettyprint"><div class=3D"subpret=
typrint"><div class=3D"subprettyprint"><div class=3D"subprettyprint"><font =
color=3D"#660066">#include <iostream></font></div><div class=3D"subpr=
ettyprint"><font color=3D"#660066"><br></font></div><div class=3D"subpretty=
print"><font color=3D"#660066">template<typename F></font></div><div =
class=3D"subprettyprint"><font color=3D"#660066">struct pipe_decorator</fon=
t></div><div class=3D"subprettyprint"><font color=3D"#660066">{</font></div=
><div class=3D"subprettyprint"><font color=3D"#660066">=C2=A0 F f;</font></=
div><div class=3D"subprettyprint"><font color=3D"#660066">};</font></div><d=
iv class=3D"subprettyprint"><font color=3D"#660066"><br></font></div><div c=
lass=3D"subprettyprint"><font color=3D"#660066">template<typename Fa, ty=
pename Fb></font></div><div class=3D"subprettyprint"><font color=3D"#660=
066">auto operator | (pipe_decorator<Fa> da, pipe_decorator<Fb>=
db)</font></div><div class=3D"subprettyprint"><font color=3D"#660066">{</f=
ont></div><div class=3D"subprettyprint"><font color=3D"#660066">=C2=A0 auto=
fun =3D [=3D](auto elmt){ return db.f(da.f(elmt)); };</font></div><div cla=
ss=3D"subprettyprint"><font color=3D"#660066"><br></font></div><div class=
=3D"subprettyprint"><font color=3D"#660066">=C2=A0 return pipe_decorator<=
;decltype(fun)>{ fun };</font></div><div class=3D"subprettyprint"><font =
color=3D"#660066">}</font></div><div class=3D"subprettyprint"><font color=
=3D"#660066"><br></font></div><div class=3D"subprettyprint"><font color=3D"=
#660066">int main()</font></div><div class=3D"subprettyprint"><font color=
=3D"#660066">{</font></div><div class=3D"subprettyprint"><font color=3D"#66=
0066">=C2=A0 auto plus_1 =3D [](auto arg){ return arg + 1; };</font></div><=
div class=3D"subprettyprint"><font color=3D"#660066">=C2=A0 auto mult_2 =3D=
[](auto arg){ return arg * 2; };</font></div><div class=3D"subprettyprint"=
><font color=3D"#660066"><br></font></div><div class=3D"subprettyprint"><fo=
nt color=3D"#660066">=C2=A0 auto pipe =3D [](auto... Functions)</font></div=
><div class=3D"subprettyprint"><font color=3D"#660066">=C2=A0 {</font></div=
><div class=3D"subprettyprint"><font color=3D"#660066">=C2=A0 =C2=A0 return=
( pipe_decorator<decltype(Functions)>{ Functions } | ... ).f;</font>=
</div><div class=3D"subprettyprint"><font color=3D"#660066">=C2=A0 };</font=
></div><div class=3D"subprettyprint"><font color=3D"#660066"><br></font></d=
iv><div class=3D"subprettyprint"><font color=3D"#660066">=C2=A0 auto test =
=3D pipe(mult_2, mult_2, plus_1, plus_1);</font></div><div class=3D"subpret=
typrint"><font color=3D"#660066"><br></font></div><div class=3D"subprettypr=
int"><font color=3D"#660066">=C2=A0 std::cout << test(10) << st=
d::endl;</font></div><div class=3D"subprettyprint"><font color=3D"#660066">=
<br></font></div><div class=3D"subprettyprint"><font color=3D"#660066">=C2=
=A0 return 0;</font></div><div class=3D"subprettyprint"><font color=3D"#660=
066">}</font></div><div><br></div></div></div></div></code></div><div><br><=
/div>The decorator method is much better as it avoids overriding the operat=
or for all the functions, however it is not yet self-contained as it still =
requires to create a class and an operator both external to the function we=
need it in.<br></div><div><br></div><div>Being able to reduce packs with a=
n arbitrary function would even allow us to use lambda-capture in this cont=
ext, which isn't possible in this case without using std::function and =
therefore missing the optimizations that these solutions benefit from; the =
code is properly unrolled and partially evaluated at compile-time by gcc 7.=
1 in both cases. clang 7.0.0 wasn't able to compile the <i>direct overr=
ide method</i> but it performed the same optimizations as gcc for the <i>de=
corator class method</i>.</div><div><br></div><div>The parameter pack expan=
sion is as simple as a map-reduce, we can easily alter the function mapped =
to each parameter but not the reduction function, and there is no reason ot=
her than syntax for such a constraint.</div><div><br></div><div>Here's =
what it could look like :</div><div><br></div><div><div class=3D"prettyprin=
t" style=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 18=
7, 187); border-style: solid; border-width: 1px; overflow-wrap: break-word;=
"><code class=3D"prettyprint"><div class=3D"subprettyprint"><div class=3D"s=
ubprettyprint"><font color=3D"#660066">#include <iostream></font></di=
v><div class=3D"subprettyprint"><font color=3D"#660066"><br></font></div><d=
iv class=3D"subprettyprint"><font color=3D"#660066">int main()</font></div>=
<div class=3D"subprettyprint"><font color=3D"#660066">{</font></div><div cl=
ass=3D"subprettyprint"><font color=3D"#660066">=C2=A0 auto plus_1 =3D [](au=
to arg){ return arg + 1; };</font></div><div class=3D"subprettyprint"><font=
color=3D"#660066">=C2=A0 auto mult_2 =3D [](auto arg){ return arg * 2; };<=
/font></div><div class=3D"subprettyprint"><font color=3D"#660066"><br></fon=
t></div><div class=3D"subprettyprint"><font color=3D"#660066">=C2=A0 auto p=
ipe_funs =3D [](auto F, auto G)</font></div><div class=3D"subprettyprint"><=
font color=3D"#660066">=C2=A0 {</font></div><div class=3D"subprettyprint"><=
font color=3D"#660066">=C2=A0 =C2=A0 return [=3D](auto elmt) { return G(F(e=
lmt)); };</font></div><div class=3D"subprettyprint"><font color=3D"#660066"=
>=C2=A0 };</font></div><div class=3D"subprettyprint"><font color=3D"#660066=
"><br></font></div><div class=3D"subprettyprint"><font color=3D"#660066">=
=C2=A0 auto fallthrough =3D [](auto e)</font></div><div class=3D"subprettyp=
rint"><font color=3D"#660066">=C2=A0 {</font></div><div class=3D"subprettyp=
rint"><font color=3D"#660066">=C2=A0 =C2=A0 return e;</font></div><div clas=
s=3D"subprettyprint"><font color=3D"#660066">=C2=A0 };</font></div><div cla=
ss=3D"subprettyprint"><font color=3D"#660066"><br></font></div><div class=
=3D"subprettyprint"><font color=3D"#660066">=C2=A0 auto pipe =3D [](auto...=
Functions)</font></div><div class=3D"subprettyprint"><font color=3D"#66006=
6">=C2=A0 {</font></div><div class=3D"subprettyprint"><font color=3D"#66006=
6">=C2=A0 =C2=A0=C2=A0return std::parameter_map_reduce(fallthrough, pipe_fu=
ns, Functions...);</font></div><div class=3D"subprettyprint"><font color=3D=
"#660066">=C2=A0 };</font></div><div class=3D"subprettyprint"><font color=
=3D"#660066"><br></font></div><div class=3D"subprettyprint"><font color=3D"=
#660066">=C2=A0 auto test =3D pipe(mult_2, mult_2, plus_1, plus_1);</font><=
/div><div class=3D"subprettyprint"><font color=3D"#660066"><br></font></div=
><div class=3D"subprettyprint"><font color=3D"#660066">=C2=A0 std::cout <=
;< test(10) << std::endl;</font></div><div class=3D"subprettyprint=
"><font color=3D"#660066"><br></font></div><div class=3D"subprettyprint"><f=
ont color=3D"#660066">=C2=A0 return 0;</font></div><div class=3D"subprettyp=
rint"><font color=3D"#660066">}</font></div><div><br></div></div></code></d=
iv><br>The simple addition of such an "std::parameter_map_reduce"=
function would make it possible without even changing the language's s=
yntax. The first argument would be the function to map, the second one woul=
d be the reductor then the rest would be the parameters to reduce. An even =
more minimalistic approach would be to add an "std::parameter_reduce&q=
uot; function as we can already map a function to the parameters, but addin=
g both would expose more granular options.</div><div><br></div><div>Any fee=
dback or criticism regarding this proposal is welcome.</div><div><br></div>=
<div>Regards,</div><div>Jules P=C3=A9nuchot</div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/8788ce93-157b-464a-8325-bfbe296c38b8%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/8788ce93-157b-464a-8325-bfbe296c38b8=
%40isocpp.org</a>.<br />
------=_Part_1335_1639328010.1539570829688--
------=_Part_1334_1897456759.1539570829687--
.