implementing default opCmp

Paul Backus snarwin at gmail.com
Wed Nov 18 23:02:23 UTC 2020


On Wednesday, 18 November 2020 at 22:29:17 UTC, Steven 
Schveighoffer wrote:
> I have a struct like this:
>
> struct S
> {
>    int x;
>    int y;
> }
>
> and I want a default comparison. The problem is, that 
> comparison doesn't have a default, and requires I implement 
> opCmp. While this is useful for the compiler, there's no 
> default I know of that is an easy one-liner.

Here's a stab at a totally generic version that I haven't unit 
tested at all, except to verify that it works for your example 
struct S:

auto cmp(T, U)(auto ref T lhs, auto ref U rhs)
{
     import core.lifetime: forward;

     static if (__traits(compiles, lhs.opCmp(rhs)))
         return forward!lhs.opCmp(forward!rhs);
     else static if (__traits(compiles, rhs.opCmp(lhs)))
         return -forward!rhs.opCmp(forward!lhs);
     else
         return lhs < rhs ? -1 : lhs > rhs ? 1 : 0;
}

mixin template defaultOpCmp()
{
     import std.traits: isAggregateType;

     static assert(isAggregateType!(typeof(this)),
     	"opCmp can only be overloaded for aggregate types.");

     auto opCmp()(auto ref typeof(this) other)
     {
         import std.traits: ReturnType, CommonType, Fields;
         import std.meta: Map = staticMap;

         alias cmpType(T) = ReturnType!((T lhs, T rhs) => cmp(lhs, 
rhs));
         alias Result = CommonType!(Map!(cmpType, 
Fields!(typeof(this))));

         Result result;

         static foreach (i, _; typeof(this).tupleof)
             if (result == 0)
             	result = cmp(this.tupleof[i], other.tupleof[i]);

         return result;
     }
}


More information about the Digitalmars-d-learn mailing list