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

Reply via email to