digitalmars.D - Member pointers in D!
- Mehrdad (96/96) Jun 16 2012 Would this be a useful addition for Phobos?
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})); }
Jun 16 2012