The other way is better, but since you asked...

On Wednesday, 8 June 2016 at 01:42:55 UTC, Carl Vogel wrote:
Now, I can use something like isCallable std.traits to make sure the predicate is a Callable, and there are various function traits in the module that I could combine with `is` clauses to enforce the signature it seems, but that seems very clunky. Is there a better way?

You could put all that stuff into one single template like this:

template isCompatibleCallable(alias Src, alias Dest) {
     static assert(isSomeFunction!Src || isCallable!Src,
                                   "Source is not callable");
     static assert(isSomeFunction!Dest || isCallable!Dest,
                                   "Destination is not callable");

static assert(is(ParameterTypeTuple!Src == ParameterTypeTuple!Dest),
                                "Type Tuples differ");
  pragma(msg,ParameterStorageClassTuple!Src ==
                                ParameterStorageClassTuple!Dest);
  static assert(ParameterStorageClassTuple!Src ==
                                ParameterStorageClassTuple!Dest,
                                "Storage classes differ");
  static assert(is(ReturnType!Src == ReturnType!Dest),
                                "Return type differs");
  immutable bool isCompatibleFunction = true;
}

That works if you have a "default action" when the callable isn't specified, because you can match the Callable to the default one. So like...

bool default_less(T)(T a, T b) { return a < b; }

T[] sortArray(alias less = default_less!T, T)(T[] arr) if(isCompatibleCallable(less,default_less!T) { ... }

But it's probably clearer to use that is(typeof({ how this function will be called })) trick.

Reply via email to