import my_metastrings; import std.traits; void main() {} unittest { interface Foo { int foo(int, bool); int foo(int); string bar(); void VoidFunc(); } class Bar { int foo(int, bool) { return 1; } int foo(long) { return 2; } // covariant parameter types char[] bar() { return "Bar.bar".dup; } // contravariant return types int VoidFunc() { return 0; } // including over void } struct BarStruct { int foo(int, bool) { return 3; } int foo(long) { return 4; } char[] bar() { return "BarStruct.bar".dup; } int VoidFunc() { return 0; } } Foo f = toInterface!(Foo).wrap(new Bar()); assert(f.foo(5, true) == 1); assert(f.foo(6) == 2); assert(f.bar() == "Bar.bar"); f = toInterface!(Foo).wrap(BarStruct()); assert(f.foo(5, true) == 3); assert(f.foo(6) == 4); assert(f.bar() == "BarStruct.bar"); f = toInterface!(Foo).wrap(new BarStruct); assert(f.foo(5, true) == 3); assert(f.foo(6) == 4); assert(f.bar() == "BarStruct.bar"); } template toInterface(InterfaceType) { InterfaceType wrap(T)(T t) { return wrapExact(t); } InterfaceImpl!(InterfaceType, T) wrapExact(T)(T t) { return new InterfaceImpl!(InterfaceType, T)(t); } } private: class InterfaceImpl(BaseType, T) : BaseType { T impl; this(T val) { impl = val; } mixin(GenerateFunctions!(BaseType).gen()); } template GenerateFunctions(BaseType) { const members = __traits(allMembers, BaseType); const uint[] counts = GetCounts!(BaseType); string gen() { string val = ""; foreach (i, name; members) { for (uint x = 0; x < counts[i]; x++) { string fnType = formatStringTango(`typeof(__traits(getVirtualFunctions, BaseType, "{}")[{}])`, name, x); string retType = formatStringTango(`std.traits.ReturnType!({})`, fnType); string fnCall = formatStringTango(`impl.{}(t)`, name); val ~= formatStringTango( `{0} {1}(std.traits.ParameterTypeTuple!({2}) t) {{ static if ( .IsTypeDerived!(typeof({3}), {0}) && .IsTupleCovariant!(.Nested!(typeof(t)), .Nested!(std.traits.ParameterTypeTuple!({2})))) return {3}; else static assert(false, "Class '" ~ T.stringof ~ "' does not implement function " ~ .PrettyFunctionName!("{1}", {2}).gen() ); }`\n, retType, name, fnType, fnCall); } } return val; } }