On Friday, 12 January 2018 at 00:16:07 UTC, aliak wrote:
Hi, so basically is there a way to:

void func(alias pred = null, Range)(Range range) {
// 1) check if pred(ElementType!Range.init, ElementType!Range.init) is equality
  // 2) check if isUnary!pred
  // 3) check if isBinary!pred
}

For 2 and 3, there's std.traits.arity. However, as you point out, it has some problems with templated functions. This template will handle those cases in conjunction with std.traits.arity:

import std.traits : arity, isCallable;

template arity(alias Fn, Args...)
if (is(typeof(Fn!Args)) && isCallable!(typeof(Fn!Args)))
{
    enum arity = .arity!(Fn!Args);
}

unittest {
    assert(arity!(() => 1) == 0);
    assert(arity!(a => a, int) == 1);
    assert(arity!((a,b) => a, int, float) == 2);

    void test(T)(T,T,T) {}
    assert(arity!(test, int) == 3);
}

Checking if a function is the equality function is much harder. Consider this function:

bool compare(int a, int b) {
    if (a == 2 && b = 3) return true;
    return a == b;
}

Clearly this is not an equality function, but for the vast majority of inputs, it behaves exactly the same.

There are other examples that make this hard. It's perfectly possible to overload opEquals and have it ignore some fields, or even access a database on the other side of the atlantic ocean. In these cases, evaluating the equality of two objects is not testable at compile time, and you simply cannot know.

In your examples you use string functions ("a == b", e.g.). These can of course be compared (you might want to do some processing, as "a==b" should give the same result as "b == a"). There's cases here where you can't be sure, of course.

All in all, I believe you're trying to solve the wrong problem, but I might be wrong. Care to give a bit more information so I get a better idea of why you want to do this?

--
  Simen

Reply via email to