// released into public domain import std.traits; import std.stdio; class Foo { int prop() { writefln("Foo.prop_get"); return 1; } int prop(int x) { writefln(x); return 0; } } class Bar { int prop(int x) { writefln(x); return 0; } int prop() { writefln("Bar.prop_get"); return 2; } } void main() { auto f = new Foo(); auto setter = Setter!("prop").fn(f); auto getter = Getter!("prop").fn(f); auto b = getter(); // prints Foo.prop_get setter(b); // prints 1 auto f2 = new Bar(); setter = Setter!("prop").fn(f2); getter = Getter!("prop").fn(f2); b = getter(); // prints Bar.prop_get setter(b); // prints 2 } template Getter(string name) { mixin GS_etterImpl!(false); } template Setter(string name) { mixin GS_etterImpl!(true); } template GS_etterImpl(bool isSetter) { FnType!(isSetter, name, T).Type fn(T)(T t) { const int i = FnIndex!(isSetter, name, T).val; static if (i >= 0) return &__traits(getVirtualFunctions, t, name)[i]; } } template FnType(bool isSetter, string name, T) { const int i = FnIndex!(isSetter, name, T).val; static if (i == -1) static assert(false, "No setter by name '" ~ name ~ "' found in type '" ~ T.stringof ~ "'"); else { alias typeof(__traits(getVirtualFunctions, T, name)[i]) FnType; alias ReturnType!(FnType) delegate(ParameterTypeTuple!(FnType)) Type; } } template FnIndex(bool isSetter, string name, T, int i = 0) { // it's the setter if it has one param, the getter if it has 0 private const int _requiredParams = isSetter ? 1 : 0; template Pred(S) { const bool Matches = (ParameterTypeTuple!(S).length == _requiredParams); } const int val = IndexOf!(Pred, typeof(__traits(getVirtualFunctions, T, name)) ); } // finds the index of the first element in T such that Pred!(T).Matches == true template IndexOf(alias Pred, T...) { const int IndexOf = IndexOfImpl!(Pred, 0, T); } template IndexOfImpl(alias Pred, int i, T...) { static if (i == T.length) const int IndexOfImpl = -1; else static if (Pred!(T[i]).Matches) const int IndexOfImpl = i; else const int IndexOfImpl = IndexOfImpl!(Pred, i+1, T); }