December 24, 2006
I came up with this function to make it easier to make libraries that can take function pointers or delegates for things like callbacks.  Basically it creates a dummy struct to function as the context for the delegate, which then calls the original function.  I guess that's a thunk?  Anyway:

template DelegatizeImpl(alias fn)
{
    private import std.traits;

    static assert(is(typeof(fn) == function), "Delegatize - input is not a
function");

    private alias ReturnType!(fn) RetType;
    private alias ParameterTypeTuple!(fn) ParamTypes;
    private alias RetType delegate(ParamTypes) DGType;

    private struct S
    {
        RetType func(ParamTypes params)
        {
            return fn(params);
        }
    }

    private S context;

    DGType Delegatize()
    {
        return &context.func;
    }
}

template Delegatize(alias fn)
{
    alias DelegatizeImpl!(fn).Delegatize Delegatize;
}

To use it, just make a function:

void func(int x, int y)
{
    writefln("func: ", x, ", ", y);
}

And then call it:

auto dg = Delegatize!(func)();
dg(4, 5); // prints "func: 4, 5"

The type of the delegate returned will have the same return type and parameter types as the source function.

One issue with this is that it doesn't support default parameters -- but then again, D doesn't support that when getting a delegate of an aggregate method period, so there's really no way around it.


December 24, 2006
Jarrett Billingsley wrote:
> I came up with this function to make it easier to make libraries that can take function pointers or delegates for things like callbacks.  Basically it creates a dummy struct to function as the context for the delegate, which then calls the original function.  I guess that's a thunk?  Anyway:
> 
[...]
> 
> To use it, just make a function:
> 
> void func(int x, int y)
> {
>     writefln("func: ", x, ", ", y);
> }
> 
> And then call it:
> 
> auto dg = Delegatize!(func)();
> dg(4, 5); // prints "func: 4, 5"
> 

I guess that's a common thing to need to do. I wrote one of my own a while back. It trades a bit of a runtime hit (notice the new and assignment) for runtime flexibility (it can take a runtime function pointer).




T delegate(A) Fn2Dg(T, A...)(T function(A) f)
{
   struct tmp
   {
      typeof(f) fn;
      T ret(A args){ return fn(args); }
   };

   tmp* ret = new tmp;
   ret.fn = f;
   return &ret.ret;
}

char fn(int i, char j);
char delegate(int, char) dg = Fn2Dg(&fn);
char function(int, char) fp = &fn;
char delegate(int, char) dgr = Fn2Dg(fp);




It comes from my paper on D:
http://www.webpages.uidaho.edu/~shro822/term_008.pdf