class C
{
int foo() { printf("invoke C.foo()\n"); return 1; }
int bar() { printf("invoke C.bar()\n"); return 2; }
int bar(string s) { printf("invoke C.bar(string)\n"); return s.length; }
}
class D : C
{
override int foo() { printf("invoke D.func\n"); return 4; }
}
void main()
{
D d = new D();
MemFunPtr!C.foo!() fpFoo = d;
MemFunPtr!C.bar!() fpBar = d;
MemFunPtr!C.bar!(string) fpBar2 = d;
assert(fpFoo() == 4);
assert(fpBar() == 2);
assert(fpBar2("hello") == 5);
static assert(fpFoo.sizeof == (void*).sizeof);
}
// ---------------------
// Implementation
// ---------------------
import std.traits, std.typetuple;
template MemFunPtr(C) if (is(C == class))
{
mixin GenName!C;
}
mixin template GenName(C, size_t i = 0)
{
alias names = allMembers!C;
static if (i >= names.length)
{
/* do nothing */
}
else
{
enum name = names[i];
alias vfuncs = TypeTuple!(__traits(getVirtualFunctions, C, name));
static if (vfuncs.length > 0)
{
struct _Impl(Params...)
{
private:
C obj;
alias VtblEntry = GetVtblEntry!(C, name, Params);
private:
this(C obj) { this.obj = obj; }
auto ref opCall(Params args)
{
alias R = ReturnType!(VtblEntry.func);
R delegate(Params) dg;
dg.ptr = *cast(void**)&obj;
dg.funcptr = cast(R function(Params))obj.__vptr[VtblEntry.vindex];
return dg(args);
}
}
mixin("alias _Impl "~name~";");
}
mixin .GenName!(C, i + 1);
}
}
template GetVtblEntry(C, string name, Params...)
{
alias names = allMembers!C;
template Impl(size_t ofs, size_t i)
{
alias vfuncs = TypeTuple!(__traits(getVirtualFunctions, C, names[i]));
static if (names[i] != name)
{
alias Impl = Impl!(ofs + vfuncs.length, i + 1);
}
else
{
static assert(vfuncs.length > 0);
template Impl2(size_t j)
{
static if (is(ParameterTypeTuple!(vfuncs[j]) == Params))
{
enum vindex = ofs + j;
alias func = vfuncs[j];
}
else
alias Impl2 = Impl2!(j + 1);
}
alias Impl = Impl2!(0);
}
}
alias GetVtblEntry = Impl!(1/*vtbl[0] == TypeInfo*/, 0);
}
template baseMembers(BC...)
{
static if (BC.length > 1)
{
alias baseMembers =
TypeTuple!( allMembers!(BC[0]),
baseMembers!(BC[1 .. $]) );
}
else static if (BC.length == 1)
{
alias baseMembers = allMembers!(BC[0]);
}
else
alias baseMembers = TypeTuple!();
}
template derivedMembers(C)
{
alias derivedMembers =
TypeTuple!( __traits(derivedMembers, C) );
}
template allMembers(C)
{
alias allMembers =
TypeTuple!( baseMembers!(BaseClassesTuple!C),
__traits(derivedMembers, C) );
}