Topic: Allowing overloadable operators to be
Author: "Billy O'Neal" <billy.oneal@gmail.com>
Date: Sat, 8 Feb 2014 15:03:30 -0800
Raw View
--089e015383e4d31c0504f1ed1f23
Content-Type: text/plain; charset=UTF-8
That would have different behavior than the standard conditional operator.
If the left argument can be converted to the right, and the right to the
left, with the same rank, then the program is ill formed.
Billy O'Neal
https://github.com/BillyONeal/ <https://bitbucket.org/BillyONeal/>
http://stackoverflow.com/users/82320/billy-oneal
On Sat, Feb 8, 2014 at 2:35 PM, David Stone <deusexsophismata@gmail.com>wrote:
> The conditional operator is a bit trickier. I would also like to overload
> that operator, but the problem is that it has short-circuit evaluation.
> Unless it received special treatment, all arguments would always be
> evaluated once, and the recommendation would be "never overload it", much
> like operator&& and operator|| right now. My actual use case doesn't change
> what the operator means, just the type. Unfortunately, we defined
> std::common_type in terms of operator?:, not the other way around.
> operator?: only works in the case where one of the two possible results can
> be converted to the other, but in my use case, the common type of my
> numeric type is a numeric type that contains the range of both values. This
> has forced me to use the hideous implementation of a macro defined as
>
> ((condition) ? \
> static_cast<std::common_type_t<decltype(lhs), decltype(rhs)>>(lhs) : \
> static_cast<std::common_type_t<decltype(lhs), decltype(rhs)>>(rhs))
>
>
> Where std::common_type has been specialized for my integer type to return
> an integer that can hold values that either can hold.
>
> I don't know of a good answer to this problem. It would surprise people to
> write a function where the arguments are not always evaluated exactly once,
> but it would also surprise people to always evaluate both possible results.
>
> --
>
> ---
> 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/.
--089e015383e4d31c0504f1ed1f23
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">That would have different behavior than the standard condi=
tional operator. If the left argument can be converted to the right, and th=
e right to the left, with the same rank, then the program is ill formed.</d=
iv>
<div class=3D"gmail_extra"><br clear=3D"all"><div><div dir=3D"ltr"><div>Bil=
ly O'Neal</div><div><a href=3D"https://bitbucket.org/BillyONeal/" targe=
t=3D"_blank">https://github.com/BillyONeal/</a></div><div><a href=3D"http:/=
/stackoverflow.com/users/82320/billy-oneal" target=3D"_blank">http://stacko=
verflow.com/users/82320/billy-oneal</a></div>
</div></div>
<br><br><div class=3D"gmail_quote">On Sat, Feb 8, 2014 at 2:35 PM, David St=
one <span dir=3D"ltr"><<a href=3D"mailto:deusexsophismata@gmail.com" tar=
get=3D"_blank">deusexsophismata@gmail.com</a>></span> wrote:<br><blockqu=
ote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc s=
olid;padding-left:1ex">
<div dir=3D"ltr">The conditional operator is a bit trickier. I would also l=
ike to overload that operator, but the problem is that it has short-circuit=
evaluation. Unless it received special treatment, all arguments would alwa=
ys be evaluated once, and the recommendation would be "never overload =
it", much like operator&& and operator|| right now. My actual =
use case doesn't change what the operator means, just the type. Unfortu=
nately, we defined std::common_type in terms of operator?:, not the other w=
ay around. operator?: only works in the case where one of the two possible =
results can be converted to the other, but in my use case, the common type =
of my numeric type is a numeric type that contains the range of both values=
.. This has forced me to use the hideous implementation of a macro defined a=
s<br>
<br><div style=3D"border:1px solid rgb(187,187,187);background-color:rgb(25=
0,250,250)"><code><div><span style=3D"color:rgb(102,102,0)">((</span><span>=
condition</span><span style=3D"color:rgb(102,102,0)">)</span><span> </span>=
<span style=3D"color:rgb(102,102,0)">?</span><span> </span><span style=3D"c=
olor:rgb(102,102,0)">\</span><span><br>
=C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,0,136)">static_cast</span><=
span style=3D"color:rgb(102,102,0)"><</span><span>std</span><span style=
=3D"color:rgb(102,102,0)">::</span><span>common_type_t</span><span style=3D=
"color:rgb(102,102,0)"><</span><span style=3D"color:rgb(0,0,136)">declty=
pe</span><span style=3D"color:rgb(102,102,0)">(</span><span>lhs</span><span=
style=3D"color:rgb(102,102,0)">),</span><span> </span><span style=3D"color=
:rgb(0,0,136)">decltype</span><span style=3D"color:rgb(102,102,0)">(</span>=
<span>rhs</span><span style=3D"color:rgb(102,102,0)">)>>(</span><span=
>lhs</span><span style=3D"color:rgb(102,102,0)">)</span><span> </span><span=
style=3D"color:rgb(102,102,0)">:</span><span> </span><span style=3D"color:=
rgb(102,102,0)">\</span><span><br>
=C2=A0 =C2=A0 </span><span style=3D"color:rgb(0,0,136)">static_cast</span><=
span style=3D"color:rgb(102,102,0)"><</span><span>std</span><span style=
=3D"color:rgb(102,102,0)">::</span><span>common_type_t</span><span style=3D=
"color:rgb(102,102,0)"><</span><span style=3D"color:rgb(0,0,136)">declty=
pe</span><span style=3D"color:rgb(102,102,0)">(</span><span>lhs</span><span=
style=3D"color:rgb(102,102,0)">),</span><span> </span><span style=3D"color=
:rgb(0,0,136)">decltype</span><span style=3D"color:rgb(102,102,0)">(</span>=
<span>rhs</span><span style=3D"color:rgb(102,102,0)">)>>(</span><span=
>rhs</span><span style=3D"color:rgb(102,102,0)">))</span><span><br>
<br></span></div></code></div><br>Where std::common_type has been specializ=
ed for my integer type to return an integer that can hold values that eithe=
r can hold.<br><br>I don't know of a good answer to this problem. It wo=
uld surprise people to write a function where the arguments are not always =
evaluated exactly once, but it would also surprise people to always evaluat=
e both possible results.<br>
</div><div class=3D"HOEnZb"><div class=3D"h5">
<p></p>
-- <br>
=C2=A0<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%2Bunsubscribe@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>
</div></div></blockquote></div><br></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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<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 />
--089e015383e4d31c0504f1ed1f23--
.
Author: "Billy O'Neal" <billy.oneal@gmail.com>
Date: Mon, 24 Feb 2014 13:45:30 -0800
Raw View
--f46d0444711d5755f004f32de666
Content-Type: text/plain; charset=UTF-8
Even that isn't quite the way the built in operator?: works. Most notably,
it would allow the user to completely change the conversion / value
category that the normal operator?: uses. The rules under 5.16 [expr.cond]
have lots of edge cases; even places that result in the program being ill
formed as a result of type deduction against the second and third arguments.
Would you expect everyone overloading this operator to read / understand
this entire type deduction process in order to determine
ParentOfLeftAndRight above?
Finally, I note that the above program has a bug even if this were allowed,
because the result of LeftExpr or RightExpr have the temporaries to which
the references are bound only live to the end of the enclosing expression;
and optionally have their lifetime extended by being assigned to a
reference. Users expect the enclosing expression to be the one containing
the use of operator?:, not the expression inside the operator?: operator
overload. That makes code like the following undefined behavior, even
though it is perfectly well defined for the builtin ?: :
#include <iostream>
#include <string>
#include <cstdlib>
std::string Left()
{
return "left temporary";
}
std::string Right()
{
return "right temporary";
}
// Assuming string const& operator?(string const&, string const&)
int main() {
std::string const& val = (rand() % 2 ? Left() : Right());
std::cout << val << std::endl;
}
Billy O'Neal
https://github.com/BillyONeal/ <https://bitbucket.org/BillyONeal/>
http://stackoverflow.com/users/82320/billy-oneal
On Mon, Feb 24, 2014 at 12:53 PM, Adam Nevraumont <afn@theorem.ca> wrote:
>
>
> On Saturday, February 22, 2014 12:21:28 AM UTC-5, myri...@gmail.com wrote:
>>
>> It'd be hacky as all hell, but there is a way that overloading ?: could
>> work without losing short-circuiting or breaking the language *too*much. I don't really know why you'd want to overload ?: in the first
>> place, but this could work:
>>
>> const ParentOfLeftAndRight &operator ?:(
>> const Conditional &conditional,
>> std::function<const Left &()> getLeft,
>> std::function<const Right &>() getRight)
>> {
>> return conditional.Evaluate() ? getLeft() : getRight();
>> }
>>
>> In other words, have the compiler generate lambdas for the expressions on
>> the left and right sides of the colon, and try to find an operator ?:
>> function that has an overload that will take that argument trio.
>>
> Rather,
> template<typename LeftExpr, typename RightExpr>
> std::common_type_t< std::result_of_t<LeftExpr()>,
> std::result_of_t<RightExpr()> > operator?:(
> Conditional const& condition,
> LeftExpr&& lhs,
> RightExpr && rhs
> )
> {
> if (condition)
> return std::forward<LeftExpr>(lhs)();
> else
> return std::forward<RightExpr>(rhs)();
> }
> where
> cond?lhs:rhs;
> is transformed into
> operator?:( cond, [&]{return lhs;}, [&]{return rhs;} )
> with maybe some verbage to make sure perfect forwarding occurs.
>
> You could naturally do the same with && and ||. Some way (maybe something
> as hacky as the int argument to ++) to distinguish between the
> short-circuit and "traditional" overloads of && and ||.
>
> Short-circuit overloads could be preferred, or it could be ambiguous if
> both exist and are otherwise equally good.
>
> Adding a non-short-circuit ?: seems like a bad idea, for the same reason
> why nobody wants to override && and ||. But if we first added
> short-circuit && and ||, we can add short-circuit ?: and skip the
> non-short-circuit version...
>
>
>
>
> --
>
> ---
> 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/.
--f46d0444711d5755f004f32de666
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Even that isn't quite the way the built in operator?: =
works. Most notably, it would allow the user to completely change the conve=
rsion / value category that the normal operator?: uses. The rules under 5.1=
6 [expr.cond] have lots of edge cases; even places that result in the progr=
am being ill formed as a result of type deduction against the second and th=
ird arguments.<div>
<br></div><div>Would you expect everyone overloading this operator to read =
/ understand this entire type deduction process in order to determine=C2=A0=
<span style=3D"font-family:arial,sans-serif;font-size:13px">ParentOfLeftAnd=
Right</span><span style=3D"font-family:arial,sans-serif;font-size:13px">=C2=
=A0above?</span></div>
<div><span style=3D"font-family:arial,sans-serif;font-size:13px"><br></span=
></div><div><span style=3D"font-family:arial,sans-serif;font-size:13px">Fin=
ally, I note that the above program has a bug even if this were allowed, be=
cause the result of LeftExpr or RightExpr have the temporaries to which the=
references are bound only live to the end of the enclosing expression; and=
optionally have their lifetime extended by being assigned to a reference. =
Users expect the enclosing expression to be the one containing the use of o=
perator?:, not the expression inside the operator?: operator overload. That=
makes code like the following undefined behavior, even though it is perfec=
tly well defined for the builtin ?: :</span></div>
<div><span style=3D"font-family:arial,sans-serif;font-size:13px"><br></span=
></div><div><div><font face=3D"arial, sans-serif">#include <iostream>=
</font></div><div><font face=3D"arial, sans-serif">#include <string><=
/font></div>
<div><font face=3D"arial, sans-serif">#include <cstdlib></font></div>=
<div><font face=3D"arial, sans-serif"><br></font></div><div><font face=3D"a=
rial, sans-serif">std::string Left()</font></div><div><font face=3D"arial, =
sans-serif">{</font></div>
<div><font face=3D"arial, sans-serif"><span class=3D"" style=3D"white-space=
:pre"> </span>return "left temporary";</font></div><div><font fac=
e=3D"arial, sans-serif">}</font></div><div><font face=3D"arial, sans-serif"=
><br>
</font></div>
<div><font face=3D"arial, sans-serif">std::string Right()</font></div><div>=
<font face=3D"arial, sans-serif">{</font></div><div><font face=3D"arial, sa=
ns-serif"><span class=3D"" style=3D"white-space:pre"> </span>return "r=
ight temporary";</font></div>
<div><font face=3D"arial, sans-serif">}</font></div><div><font face=3D"aria=
l, sans-serif"><br></font></div><div><font face=3D"arial, sans-serif">// As=
suming string const& operator?(string const&, string const&)</f=
ont></div>
<div><font face=3D"arial, sans-serif"><br></font></div><div><font face=3D"a=
rial, sans-serif">int main() {</font></div><div><font face=3D"arial, sans-s=
erif"><span class=3D"" style=3D"white-space:pre"> </span>std::string const&=
amp; val =3D (rand() % 2 ? Left() : Right());</font></div>
<div><font face=3D"arial, sans-serif"><span class=3D"" style=3D"white-space=
:pre"> </span>std::cout << val << std::endl;</font></div><div><=
font face=3D"arial, sans-serif">}</font></div></div><div><span style=3D"fon=
t-family:arial,sans-serif;font-size:13px"><br>
</span></div></div><div class=3D"gmail_extra"><br clear=3D"all"><div><div d=
ir=3D"ltr"><div>Billy O'Neal</div><div><a href=3D"https://bitbucket.org=
/BillyONeal/" target=3D"_blank">https://github.com/BillyONeal/</a></div><di=
v><a href=3D"http://stackoverflow.com/users/82320/billy-oneal" target=3D"_b=
lank">http://stackoverflow.com/users/82320/billy-oneal</a></div>
</div></div>
<br><br><div class=3D"gmail_quote">On Mon, Feb 24, 2014 at 12:53 PM, Adam N=
evraumont <span dir=3D"ltr"><<a href=3D"mailto:afn@theorem.ca" target=3D=
"_blank">afn@theorem.ca</a>></span> wrote:<br><blockquote class=3D"gmail=
_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:=
1ex">
<div dir=3D"ltr"><br><br>On Saturday, February 22, 2014 12:21:28 AM UTC-5, =
<a href=3D"mailto:myri...@gmail.com" target=3D"_blank">myri...@gmail.com</a=
> wrote:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8=
ex;border-left:1px #ccc solid;padding-left:1ex">
<div dir=3D"ltr">It'd be hacky as all hell, but there is a way that ove=
rloading ?: could work without losing short-circuiting or breaking the lang=
uage <i>too</i> much.=C2=A0 I don't really know why you'd want to o=
verload ?: in the first place, but this could work:<br>
<br>const ParentOfLeftAndRight &operator ?:(<br>=C2=A0=C2=A0=C2=A0 cons=
t Conditional &conditional,<br>=C2=A0=C2=A0=C2=A0 std::function<cons=
t Left &()> getLeft,<br>=C2=A0=C2=A0=C2=A0 std::function<const Ri=
ght &>() getRight)<br>{<br>=C2=A0 return conditional.Evaluate() ? ge=
tLeft() : getRight();<br>
}<br><br>In other words, have the compiler generate lambdas for the express=
ions on the left and right sides of the colon, and try to find an operator =
?: function that has an overload that will take that argument trio.<br>
</div></blockquote><div>=C2=A0Rather,<br>template<typename LeftExpr, typ=
ename RightExpr><br>std::common_type_t< std::result_of_t<LeftExpr(=
)>, std::result_of_t<RightExpr()> > operator?:(<br>=C2=A0=C2=A0=
Conditional const& condition,<br>
=C2=A0=C2=A0 LeftExpr&& lhs,<br>=C2=A0=C2=A0 RightExpr && r=
hs<br>)<br>{<br>=C2=A0 if (condition)<br>=C2=A0=C2=A0=C2=A0 return std::for=
ward<LeftExpr>(lhs)();<br>=C2=A0 else<br>=C2=A0=C2=A0=C2=A0 return st=
d::forward<RightExpr>(rhs)();<br>}<br>where<br>cond?lhs:rhs;<br>
is transformed into<br>operator?:( cond, [&]{return lhs;}, [&]{retu=
rn rhs;} )<br>with maybe some verbage to make sure perfect forwarding occur=
s.<br><br>You could naturally do the same with && and ||.=C2=A0 Som=
e way (maybe something as hacky as the int argument to ++) to distinguish b=
etween the short-circuit and "traditional" overloads of &&=
; and ||.<br>
<br>Short-circuit overloads could be preferred, or it could be ambiguous if=
both exist and are otherwise equally good.<br><br>Adding a non-short-circu=
it ?: seems like a bad idea, for the same reason why nobody wants to overri=
de && and ||.=C2=A0 But if we first added short-circuit && =
and ||, we can add short-circuit ?: and skip the non-short-circuit version.=
...<span class=3D"HOEnZb"><font color=3D"#888888"><br>
<br><br>=C2=A0=C2=A0 <br></font></span></div></div><span class=3D"HOEnZb"><=
font color=3D"#888888">
<p></p>
-- <br>
=C2=A0<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%2Bunsubscribe@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>
<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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<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 />
--f46d0444711d5755f004f32de666--
.
Author: Nicola Gigante <nicola.gigante@gmail.com>
Date: Tue, 25 Feb 2014 10:28:35 +0100
Raw View
> Il giorno 22/feb/2014, alle ore 06:21, myriachan@gmail.com ha scritto:
> In other words, have the compiler generate lambdas for the expressions on=
the left and right sides of the colon, and try to find an operator ?: func=
tion that has an overload that will take that argument trio.
>=20
Why not address the problem more generally? Other languages just have a "la=
zy" keyword for function argument to enable lazy evaluation. That turns the=
parameter into an implicit nullary lambda that returns the specified type.=
This would address the problem of operator&& and every other operator like=
that, basically the same way of functional languages like Haskell:
bool operator&&(lazy bool lhs, lazy bool rhs) { return lhs && rhs; }
I suppose the right semantics would be that, if evaluated, the arguments si=
de effects are evaluated once, so the code inside the function can use the =
variable how many times it wants without re-executing the underlying lambda=
..=20
Of course, lazy function parameters have a _lot_ of other applications, and=
such a feature would merit a separate discussion.
> Melissa
--=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/.
.