Most uses of the 'is expression' allows using a specifier to
name the entity that matched. So, inserting ReturnedDelegate in
your '== delegate' line gives the name ReturnedDelegate to the
delegate.
That name can be used further:
template exT(T, alias nextGen)
if (
// Ensure nextGen is a callable entity
isCallable!nextGen == true
// Ensure nextGen returns a delegate
&& is(ReturnType!nextGen ReturnedDelegate == delegate)
// <--
// Ensure nextGen takes one argument
&& arity!nextGen == 1
// Ensure that argument is of type T
&& is(ParameterTypeTuple!nextGen[0] == T)
// Ensure the returned delegate returns type T
&& is(ReturnType!ReturnedDelegate == T)
// Ensure the arity and parameter type of the delegate
// && arity!ReturnedDelegate == 1
&& ParameterTypeTuple!ReturnedDelegate.length == 1 //
<--
&& is(ParameterTypeTuple!ReturnedDelegate[0] == int) //
<--
)
{
// ...
}
However, since arity() takes an alias but ReturnedDelegate is a
type, I could not make it work. So, I use the length of the
parameter type tuple instead.
You can put all of those checks into a template and pass T and
nextGen to it:
template exT(T, alias nextGen)
if SatisfiesMyConditions!(T, nextGen)
{
// ...
}
I haven't attempted writing it but it will be similar to the
following syntax:
template canFlyAndLand(T)
{
enum canFlyAndLand = is (typeof(
{
T object;
object.prepare(); // should be preparable for flight
object.fly(1); // should be flyable for a certain
distance
object.land(); // should be landable
}()));
}
I've copied that example from under the "Named constraints"
section at
http://ddili.org/ders/d.en/templates_more.html
Phobos implementation has many examples of that as well.
Ali
Thank you! This is excellent, and I'll make great use of your
suggestions.
I would think you can check the delegate signature directly
without decomposing it. Something like this:
is(ReturnType!nextGen == T delegate (int))
This is a very concise way to do what I want to do, but this
check cares about other attributes of the function/delegate, i.e.
if the function or delegate is designated as pure or nothrow and
those don't show up in the check, it will fail. As in:
auto nextGen()
{
T genFunc(int x) nothrow
{
return 0;
}
return &genFunc;
}
genFunc will fail the is() check because the is check cares
whether the delegate is nothrow or not. Since I want folks to be
able to use my algorithm without caring about the implementation
details, I need to provide constraints for the parameter lists
and return types of their functions, but no constraints on
whatever attributes they want to slap onto their functions. I
will keep this in my toolbox, but I'll have to take the more
long-winded approach this time around.
Thank you both!