Member pointers in D!
Mehrdad
wfunction at hotmail.com
Sat Jun 16 20:05:56 PDT 2012
Would this be a useful addition for Phobos?
They're type-checked member function/variable pointers for D.
I haven't tested them with opDispatch or 'alias this' yet, but
they should work correctly for regular members.
The usage is pretty simple... it even works at compile time:
struct Foo { int x; }
const a = MemberPtr!(Foo, q{x}); // shorthand
pragma(msg, a.get(Foo(1))); // 1
MemberPtr!(Foo, int) b = MemberPtr!(Foo, q{x}); // longhand
auto f = Foo(2);
b.deref(f) = 3; // by reference, unlike 'get'
assert(f.x == 3);
and it should also work for member functions.
//----------------------------------------
template MemberPtr(T, string memberName) if (isInstanceMember!(T,
memberName))
{
enum MemberPtr =
MemberPtr!(T, typeof(__traits(getMember, T, memberName)))(
staticIndexOf!(memberName, __traits(allMembers, T)));
}
struct MemberPtr(T, TMember)
{
size_t index = -1;
auto address(ref inout(T) o) inout
{
foreach (i, m; __traits(allMembers, T))
{
static if (isInstanceMember!(T, m, TMember))
{
// 'switch' might be faster
// but the optimizer can worry about that instead :)
if (this.index == i)
{
return &__traits(getMember, o, m);
}
}
}
static if (is(typeof(return)) /*has the return type been
inferred yet?*/)
{
assert(0, "Invalid member pointer!");
}
else { return (inout(TMember)*).init; }
}
ref auto deref(ref inout(T) o) inout
{
static if (isSomeFunction!(ReturnType!(typeof(&this.address))))
{
return this.address(o);
}
else
{
return *this.address(o);
}
}
ref auto get(inout(T) o) inout
{
return this.deref(o);
}
}
private template isStaticFunction(T, string m)
{
static if (
__traits(compiles,
__traits(isStaticFunction, __traits(getMember, T, m))))
{
enum isStaticFunction =
__traits(isStaticFunction, __traits(getMember, T, m));
}
else { enum isStaticFunction = false; }
}
private template isInstanceMember(T, string m, TMember = void)
if (hasMember!(T, m))
{
enum isInstanceMember =
!isStaticFunction!(T, m) &&
(__traits(compiles, __traits(getMember, T, m).offsetof) ||
isSomeFunction!(__traits(getMember, T, m))) &&
(is(TMember == void) || /* optional */
is(typeof(__traits(getMember, T.init, m)) : TMember));
}
unittest
{
struct S
{
int m1;
void m2() { }
static __gshared int s1;
static void s2() { }
}
static assert(isInstanceMember!(S, q{m1}));
static assert(isInstanceMember!(S, q{m2}));
static assert(!isInstanceMember!(S, q{s1}));
static assert(!isInstanceMember!(S, q{s2}));
}
More information about the Digitalmars-d
mailing list