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.

Reply via email to