1 /// 2 module aslike; 3 4 import std.traits; 5 import std.string : join; 6 7 /// 8 struct Like(T) if (is(T == interface)) 9 { 10 private template dlgName(alias fn) { enum dlgName = "__dlg_" ~ fn.mangleof; } 11 private template fnAttr(alias fn) 12 { 13 enum fnAttr = [__traits(getFunctionAttributes, fn)].join(" "); 14 } 15 16 static foreach (m; [__traits(allMembers, T)]) 17 { 18 static if (__traits(isVirtualFunction, __traits(getMember, T, m))) 19 { 20 static foreach (fn; __traits(getOverloads, T, m)) 21 { 22 mixin("private ReturnType!fn delegate(Parameters!fn) " ~ fnAttr!fn ~ " " ~ dlgName!fn ~ ";"); 23 mixin("ReturnType!fn " ~ m ~ "(Parameters!fn args) " ~ fnAttr!fn ~ " { return " ~ dlgName!fn ~ "(args); }"); 24 } 25 } 26 } 27 } 28 29 /// 30 Like!T as(T, X)(auto ref X obj) if (is(T == interface)) 31 { 32 Like!T ret; 33 34 static foreach (m; [__traits(allMembers, T)]) 35 { 36 static if (__traits(isVirtualFunction, __traits(getMember, T, m))) 37 { 38 static foreach (fn; __traits(getOverloads, T, m)) 39 { 40 mixin("ret." ~ ret.dlgName!fn ~ " = &obj."~m~";"); 41 } 42 } 43 } 44 45 return ret; 46 } 47 48 version(unittest) 49 { 50 interface Foo 51 { 52 @safe: 53 void okda(); 54 nothrow const: 55 int one(); 56 int one(int x); 57 int two(); 58 } 59 60 static int useFoo(Like!Foo obj) @safe 61 { 62 obj.okda(); 63 return obj.one() + obj.two() + obj.one(100); 64 } 65 } 66 67 unittest 68 { 69 int k = 1; 70 71 struct Bar 72 { 73 int a, b; 74 @safe: 75 void okda() { k = 3; } 76 nothrow const: 77 int one() { return a * 2 + k; } 78 int one(int x) { return a * x; } 79 int two() { return a + b; } 80 } 81 82 assert(useFoo(Bar(2, 4).as!Foo) == 213); 83 } 84 85 unittest 86 { 87 static class Bar : Foo 88 { 89 void okda() {} 90 override const: 91 int one() { return 5; } 92 int one(int x) { return x * 2; } 93 int two() { return 3; } 94 } 95 96 assert(useFoo((new Bar).as!Foo) == 208); 97 }