On Mon, May 18, 2009 at 12:12 PM, Andrei Alexandrescu <seewebsiteforem...@erdani.org> wrote: > Ok, now with the advent (or rediscovery) of allMembers which I had no idea > existed, we're ready to start some serious butt-kick reflection facilities. > > For starters, I'd like to present you with the following challenge. Given > any class C, e.g.: > > class C > { > void foo(int) { ... } > int bar(string) { ... } > } > > define a template class Finalize(T) such that Finalize!(C) is the same as > the following hand-written class: > > final class FinalizeC : C > { > final void foo(int a) { return super.foo(a); } > final int bar(string a) { return super.bar(a); } > } > > Finalize is cool when you need some functionality from an exact class and > you don't want to pay indirect calls throughout. All calls through > Finalize!(C)'s methods will resolve to static calls. > > > Have at it!
module foo; import std.conv; import std.bind; import std.stdio; import std.traits; import std.metastrings; string ParamTypes(func)() { auto s = func.stringof; int begin = s.length - 1; int nesting = 0; for(; begin > 0; begin--) { if(s[begin] == ')') nesting++; else if(s[begin] == '(') { nesting--; if(nesting == 0) break; } } return s[begin .. $]; } string ParamList(func)() { auto s = ParamTypes!(func)()[1 .. $ - 1]; // strip off parens string ret = " "; // could have weird spaces in the type, so look for a comma and get the text from the last space until it size_t lastSpace = 0; foreach(i, c; s) { if(c == ' ') lastSpace = i; else if(c == ',') ret ~= s[lastSpace + 1 .. i] ~ ","; } if(s.length - lastSpace > 0) ret ~= s[lastSpace + 1 .. $] ~ ","; return ret[0 .. $ - 1]; // chop off trailing comma } template VirtualOverloadImpl(string methodName, alias method) { enum VirtualOverloadImpl = "override " ~ ReturnType!(method).stringof ~ " " ~ methodName ~ ParamTypes!(typeof(&method))() ~ "{ return super." ~ methodName ~ "(" ~ ParamList!(typeof(&method))() ~ "); }"; } string VirtualOverloads(T, string method)() { string ret = ""; foreach(overload; __traits(getVirtualFunctions, T, method)) { ret ~= "override " ~ ReturnType!(overload).stringof ~ " " ~ method ~ ParamTypes!(typeof(&overload))() ~ "{ return super." ~ method ~ "(" ~ ParamList!(typeof(&overload))() ~ "); }\n"; } return ret; } template FinalizeMembers(T, size_t idx = 0) { static if(idx >= __traits(allMembers, T).length) alias void FinalizeMembers; else { static if(__traits(isVirtualFunction, __traits(getMember, T, __traits(allMembers, T)[idx])) && !__traits(isFinalFunction, __traits(getMember, T, __traits(allMembers, T)[idx]))) { mixin(VirtualOverloads!(T, __traits(allMembers, T)[idx])()); } mixin FinalizeMembers!(T, idx + 1); } } final class Finalize(T) : T { // this(T...)(T args) if(is(typeof(new T(args)))) { super(args); } mixin FinalizeMembers!T; } class C { // this(int x) { writefln("new C: %s", x); } void foo(float x) { writeln(x); } void foo(char c) { writeln(c); } int bar(string s) { return to!int(s); } } void main() { auto c = new C(); c.foo(4.9); writeln(c.bar("5")); auto c2 = new Finalize!(C)(); c2.foo(4.9); writeln(c2.bar("5")); } Weird bug: if one of your methods takes a single int parameter (no more, no less, and it has to be 'int', no other basic type triggers it), DMD inserts a spurious pair of parens in the .stringof, as in "void function((int))", causing the parameter type and name extraction to fail.