I know some people don't like abusing opDollar, but here's my implementation:

import std.traits, std.algorithm, std.conv;
private struct Named(string n, T) {
    enum name = n;
    T value;
}
private auto makeNameIndex(NamedList...)(string[] names) {
    auto indices = new size_t[](names.length);
    foreach(i, n ; NamedList) {
        auto x = names.countUntil(n.name);
assert(x >= 0, "Keyword Parameter \"" ~ n.name ~ "\" does not exist in " ~ text(names));
        indices[x] = i;
    }
    return indices;
}
private immutable struct KeyWordDollar {
    @property
    auto opDispatch(string param, T)(T t) {
        return Named!(param,T)(t);
    }
}
private struct KeyWordManager(alias f) {
    private enum paramNames = [ParameterIdentifierTuple!f];

    auto opDollar(size_t pos = 0)() const {
        return immutable KeyWordDollar();
    }
    auto opIndex(NamedArgs...)(NamedArgs namedArgs) {
        enum ordering = makeNameIndex!NamedArgs(paramNames);
        ParameterTypeTuple!f args;
        foreach(i, ref a; args) {
            a = namedArgs[ ordering[i] ].value;
        }
        return f(args);
    }
}
auto kw(alias f)() {
    return KeyWordManager!f();
}

int foo(int x, int y) {
    return x+y;
}
unittest {
    assert(8 == kw!foo[$.y = 5, $.x = 3]);
}

Reply via email to