refract

Return a Function object that captures all the aspects of fun, using the value of localName to represent the return and parameter types, and the UDAs. Set the Function's overloadIndex property to index, or to -1 if it is not specified.

The localName parameter is, in general, *not* the function name. Rather, it is a compile-time expression that involves only symbols that exist in the caller's scope, for example a function alias passed as a template parameter. See https://stackoverflow.com/questions/32615733/struct-composition-with-mixin-and-templates/32621854#32621854

for a detailed explanation.

refract
(
alias fun
string localName
int overloadIndex = -1
)
()
if (
is(typeof(fun) == function)
)

Parameters

fun

a function

localName

a string that represents fun in the caller's context

overloadIndex

index of fun in its overload set, or -1

Examples

pure @nogc int answer(lazy string question);
alias F = answer; // typically F is a template argument
static assert(
    refract!(F, "F").mixture ==
    "pure @nogc @system %s.ReturnType!(F) answer(%s.Parameters!(F) _0);"
    .format(__MODULE__, __MODULE__));
import std.format;
import std.traits : FunctionAttribute;
import bolts.experimental.refraction;

interface GrandTour {
    pure int foo() immutable;
    @nogc @trusted nothrow ref int foo(
        out real, return ref int, lazy int) const;
    @safe shared scope void bar(scope Object);
}

class Mock(Interface) : Interface {
    static foreach (member; __traits(allMembers, Interface)) {
        static foreach (fun; __traits(getOverloads, Interface, member)) {
            mixin({
                    enum Model = refract!(fun, "fun");
                    if (is(ReturnType!fun == void)) {
                        return Model.withBody("{}").mixture;
                    } else if (Model.attributes & FunctionAttribute.ref_) {
                        return Model.withBody(q{{
                                    static %s rv;
                                    return rv;
                                }}.format(Model.returnType)).mixture;
                    } else {
                        return Model.withBody(q{{
                                    return %s.init;
                                }}.format(Model.returnType)).mixture;
                    }
                }());
        }
    }
}

GrandTour mock = new Mock!GrandTour;
real x;
int i, l;
mock.foo(x, i, l++) = 1;
assert(mock.foo(x, i, l++) == 1);
assert(l == 0);

Meta