D: Template constraint to show whether a given type is comparable

102 Views Asked by At

How would I write a template constraint for the following struct

struct Foo (T, U) {
}

to indicate that both T and U must be comparable using <? By that I mean that two Ts can be compared with < and two Us can be compared with < - a T and a U can be incomparable.

2

There are 2 best solutions below

0
On

I believe this will do what you ask, though there may be a more concise solution:

struct Foo (T, U) if (is(typeof(T.init < T.init) : bool) 
                   && is(typeof(U.init < U.init) : bool) 
{ }

You can clean it up a bit with a template:

enum bool isSelfComparable(T) = is(typeof(T.init < T.init) : bool);

struct Foo (T, U) if (isSelfComparable!T && isSelfComparable!U) { }
0
On

The most concise way that I can think of doing that at the moment is

struct Foo(T, U)
    if(is(typeof(T[0] < T[0])) && is(typeof(U[0] < U[0])))
{
}

but I'd probably declare it as

struct Foo(T, U)
    if(is(typeof(T.init < T.init)) && is(typeof(U.init < U.init)))
{
}

because it's more straightforward. Some folks might use the use of static arrays confusing, and it's not necessary. But it is technically a bit shorter.

The : bool portion in murphyslaw's answer isn't actually necessary, because < can't result in anything but bool, because the compiler translates <, <=, >, and >= to calls to opCmp on user-defined types, so the programmer doesn't have the opportunity to make them result in anything other than bool (and of course, the comparison operators result in bool for the built-in types). But murphyslaw's answer will work just as well. It's just more verbose than required.

The main place that : bool or == bool would be required would be if you wanted to accept a predicate rather than use the comparison operators directly (since then, you're dealing with an arbitrary function), and that's typically what the generic algorithms in Phobos end up doing. e.g. the signature of one of find's overloads is

InputRange find(alias pred = "a == b", InputRange, Element)
               (InputRange haystack, Element needle)
    if (isInputRange!InputRange &&
        is (typeof(binaryFun!pred(haystack.front, needle)) : bool))
{...}

But if you're planning on using the comparison operators directly, then simply checking that they compile is enough.