On Wednesday, 6 February 2013 at 06:38:11 UTC, Jonathan M Davis
wrote:
On Wednesday, February 06, 2013 07:24:10 Jeremy DeHaan wrote:
I've seen operator overloading done 3 different ways. In the
examples I provide they all compile and work as far as I can
tell. Is there any major difference between using a static if
vs
a regular if, or any situation that one would be better than
the
other?
struct Something1
{
Something1 opUnary(string s)()
{
if (s == "-")
{
return stuff;
}
}
}
Don't do this. You want to be generating different functions
for different
overloaded operators. This just introduces extra runtime
overhead. It also
fails to deal with all of the possible values of s.
struct Something2
{
Something2 opUnary(string s)()
{
static if (s == "-")
{
return stuff;
}
}
}
This is better but again fails to deal with all of the possible
values of s.
You'll get a nasty error message if a different value gets
passed in.
Also, I realize that if I wanted to overload just a single
operator and that was all, I could do:
struct Something3
{
Something3 opUnary(string s)()
if (s == "-")
{
return stuff;
}
}
But I am more curious about the first two.
The last one is by far the best, because it protects against
values for s that
you don't intend to overload for. You can with the second
example if you
really want to and have multiple operators that you want to
overload with the
same function, but you still need a template constraint to
protect against
values that you don't intend to handle. Pretty much _every_
template that you
write should have a template constraint on it.
And in many cases, overloaded operators should just use string
mixins. For
instance, core.time.Duration does this:
Duration opBinary(string op, D)(D rhs) @safe const pure nothrow
if((op == "+" || op == "-") &&
(is(_Unqual!D == Duration) ||
is(_Unqual!D == TickDuration)))
{
static if(is(_Unqual!D == Duration))
return Duration(mixin("_hnsecs " ~ op ~ "
rhs._hnsecs"));
else if(is(_Unqual!D == TickDuration))
return Duration(mixin("_hnsecs " ~ op ~ " rhs.hnsecs"));
}
It uses static ifs to differentiate between Duration and
TickDuration (since
they require different code), but the code doesn't
differentiate between the
operators. Rather, it just mixes in the string, and it'll do
the right thing
in both cases. The template constraint already protects against
operators that
it doesn't actually overload.
- Jonathan M Davis
Thanks for the info, Jonathan! I had no idea that I should
constrain the kinds of operators I was overloading if I have more
than two, but that makes sense and I will do this from now on.
Out of curiosity, what exactly happens when we don't constrain
what operators are being overloaded? Is it undefined behavior or
will the program just not compile?
And that is a cool use of mixins. They are still a pretty new
concept to me so I haven't looked into them much.
Thanks a lot for the info though!
Jeremy