Generic method that takes in either delegate or function

Lutger Blijdestijn lutger.blijdestijn at gmail.com
Wed Jan 12 00:55:30 PST 2011


%u wrote:

> Hi,
> 
> Is there any way to specify a parameter as "something that can be called
> with parameter types A, B, C and that returns a value of type D", without
> caring whether it's a delegate, a function, or an object that overloads
> opCall? (This might require the use of templates, but I still can't figure
> it out...)
> 
> Thank you!

Yes, look at std.traits. isCallable determines if a type can be called, 
ReturnType gives you the return type and ParameterTypeTuple obtaines a tuple 
of the parameters. In this example I used all three, isCallable is implied 
by the latter two so that is actually redundant:

import std.traits;
import std.stdio;
import std.typetuple;

int square(int a)
{
    return a*a;
}

struct Squarer
{
    int opCall(int a)
    {
        return a * a;
    }
}

void foo(T)(T fun, int num)
    if (isCallable!(T)
        && is(ReturnType!fun == int)
        && is(ParameterTypeTuple!(T) == TypeTuple!(int)))
{
    writeln("square of ", num, ":", fun(num));
}

void main()
{
    foo(&square, 2);
    Squarer functor;
    foo(functor, 2);
    foo((int a) { return a * a; }, 2);
}

Another (efficient) way to do this is with alias template parameters, this 
determines not the type of the object / function / delegate, but the actual 
symbol directly. However, it must be able to access that symbol, see this 
example:

void foo2(alias fun)(int num)
    if (isCallable!(fun)
        && is(ReturnType!(fun) == int)
        && is(ParameterTypeTuple!(fun) == TypeTuple!(int)))
{
    writeln("square of ", num, ":", fun(num));
}

void main()
{
    Squarer functor;
    foo2!square(2);
    //foo2!functor(2); error: cannot access frame of function D main
    foo2!((int a) { return a * a; })(2);
}

foo2 is trying to call opCall of the functor object, but it is a local 
variable of the main function so it cannot be called this way.


More information about the Digitalmars-d-learn mailing list