type of if statement used for operator overloading?

Jeremy DeHaan dehaan.jeremiah at gmail.com
Tue Feb 5 23:41:14 PST 2013


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


More information about the Digitalmars-d-learn mailing list