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.