Andrei Alexandrescu <seewebsiteforem...@erdani.org> wrote:

I do something similar with RefCounted. There are problems - you need to know in advance which functions you can implement on a null container (empty and length are obvious candidates, but there could be others).

Static functions can safely be called. Hence, this template:


import std.traits;

template isStaticFunc(T, string fn) {
    enum isStaticFunc = is(typeof({
        mixin("alias T."~fn~" func;");
        ParameterTypeTuple!func args;
        mixin("T."~fn~"(args);");
    }));
}


Now, Ref can look like this:


struct Ref(Impl) {
    private Impl* _impl;
    @property ref Impl impl() {
        return *(_impl = (_impl ? _impl : new Impl));
    }
//alias impl this; // Apparently, alias this takes precedence over opDispatch, so // using both doesn't work. Well, unless you put opDispatch in Impl.

auto opDispatch(string name, T...)(T args) if ( isStaticFunc!(Impl, name)) {
        mixin("return impl."~name~"(_impl,args);");
    }
}

struct ExampleImpl {
    static int length(ExampleImpl* that) {
        return that ? that.actualLength : 0;
    }
    int actualLength( ) {
        return 42;
    }
}


import std.stdio;

void main( ) {
    Ref!ExampleImpl a;

    writeln( a.length );
}


--
Simen

Reply via email to