Search code examples
cdelegatesfunction-pointersd

Pass delegates to external C functions in D


How do I pass a delegate to an external C function taking a function pointer, in D?


Solution

  • Let me cross post what I said on the newsgroup:

    How do I pass a delegate to an external C function taking a function pointer?

    You can't do it directly in general, unless you can modify the C function, then you can hack around it, but a delegate and a regular function pointer are pretty different animals.

    But perhaps you can magic hack it. Observe:

    // a C function that needs a plain function
    extern(C) void test(void function() f) {
        // pretend this is implemented in C
        f();
    }
    
    // just create a random delegate
    void delegate() foo(int a) {
        return { import std.stdio; writeln(a); };
    }
    
    // what we want to work
    void main() {
        auto dg = foo(10);
        dg(); // works
    
        //test(dg); // won't work
        test(bindDelegate(dg)); // we want this
    }
    
    // transform delegate into pointer..
    import std.traits;
    auto bindDelegate(T, string file = __FILE__, size_t line = __LINE__)(T t) if(isDelegate!T) {
        static T dg;
    
        dg = t;
    
        extern(C)
        static ReturnType!T func(ParameterTypeTuple!T args) {
                return dg(args);
        }
    
        return &func;
    }
    

    What bindDelegate does is create a special static variable and function for that specific call. It is as if we wrote a separate function and global to hold it.

    The __FILE__, __LINE__ things are a filthy hack to make it instantiate a separate variable+function pair for different lines so the global variable holding the delegate won't be so easily overwritten.