Member function pointers

Manu turkeyman at gmail.com
Fri Jun 7 18:11:37 PDT 2013


On 8 June 2013 10:24, Adam D. Ruppe <destructionator at gmail.com> wrote:

> On Friday, 7 June 2013 at 23:54:55 UTC, Manu wrote:
>
>> The properties are already there...
>> but they're not properly typed.
>>
>
> I just don't think they can be unless we change the visible type which
> isn't always what we want.... but, check this out:
>
> // this new type keeps track of the exact type of the pointer
> // and manages the delegate so we can cast with some sanity...
> struct PointerToMemberFunction(Class, Ret, T...) if(is(Class : Object)) {
>         private Ret delegate(T) dg;
>         @property Class object() { return cast(Class) dg.ptr; }
>         @property void object(Class rhs) { dg.ptr = cast(void*) rhs; }
>         Ret opCall(T t) {
>                 assert(dg.ptr !is null, "null this");
>                 static if(is(Ret == void))
>                         dg(t);
>                 else
>                         return dg(t);
>         }
> }
>
> // this helps us construct the above
> template ptrToMember(alias blargh) {
>         // I'm writing out the function template longhand
>         // because I want to use blargh as a type and
>         // dmd won't let me do it without an intermediate
>
>         // dmd complains "type expected, not __traits" so we use
>         // this to work around it
>         template workaround(T) { alias workaround = T; }
>
>         alias ObjectType = workaround!(__traits(parent, blargh));
>
>         auto ptrToMember(ObjectType a = null) {
>                 import std.traits;
>                 PointerToMemberFunction!(
>                         ObjectType,
>                         ReturnType!blargh,
>                         ParameterTypeTuple!blargh
>                 ) mem;
>                 mem.dg.funcptr = &blargh;
>                 mem.dg.ptr = cast(void*) a;
>                 return mem;
>         }
> }
>
>
> actually i just realized maybe this should not be a function at all, so it
> is easy to use as a class member, without having to write an extra
> typeof(). That's probably more valuable than the initialiser which as
> you'll see below is optional anyway.
>
> Anyway, then you can use it like this:
>
> class A {
>         void foo() {writeln("foo from ", name);}
>         int bar(string s) {writeln("bar ",s," from ", name); return 10; }
>         this(string n) { name = n; }
>         string name;
> }
>
> class B : A {
>         this(string n) { super(n); }
>         override void foo() { writeln("derived foo from ", name); }
> }
>
>
> void main() {
>         A a = new A("a");
>         B c = new B("c");
>         Object ob = a;
>
>         auto ptr = ptrToMember!(B.foo)(c); // initialize the object here
>         ptr();
>         ptr.object = a;
>         ptr();
>
>         auto ptr2 = ptrToMember!(A.bar); // initialize to null..
>         ptr2.object = ptr.object; // can assign later
>         ptr2("hey");
> }
>
>
> And if you play around with the types there, you'll see the compile will
> fail if you do something uncool. Though the error messages sometimes suck,
> what the hell: "test2.d(58): Error: not a property ptr.object"... actually
> it is, but I was passing it an A when it required a B. That's a type
> mismatch, not a missing property.
>
> But whatever, at least it *did* fail to compile, so we have our type
> safety.
>
>
> And if I threw in an alias this on a getter property, we could assign
> these beasties to regular delegates too. Not half bad.
>
> But regular delegate assigning to this is prohibited because we can't be
> sure their context pointer is the right kind of class. This would be true
> if the compiler automatically did the ptrToMember!() too, so let's say we
> change &a.foo to return one of these strongly typed things instead of a
> void* delegate like it does now.
>
> auto ptr = &a.foo; // is ptr a void delegate() or a pointer to
> specifically a void() member of class A?
>
>
> That matters because if the former (current behavior), this compiles:
>
> ptr = { writeln("hello!"); };
>
>
> but if the latter, that will not, it will complain that the this pointers
> are of mismatching type (or "not a property" lol). Of course, with alias
> this style behavior, you could explicitly write out
>
> void delegate() ptr = &a.foo; // ok, use looser type
> ptr = {...}; // perfectly fine
>
>
>
> So I guess we wouldn't be losing much, but since we both agree a delegate
> is almost always what we want, maybe the library solution of ptrToMember is
> better to keep auto in a Just Works state.
>
>
>
> I'm presuming you're already doing something similar for your C++ interop,
> if not, I'm pretty sure this same idea would work there too, at least to a
> 'good enough' state, even if not technically portable.


I initially started with something like this. But look how much code it is!
I actually deleted it all and went for my non-portable hack.

My implementation was different. You've basically wrapped up a delegate,
and made something that emulates a delegate (I'm not sure why?).
I don't want a delegate, I want a function pointer. So my solution was
similar, but wrapped up a function pointer and aliased a delegate to the
correct type, then created a local delegate populating with 'this' and the
function at the call-site...
But it's all crap! It's really just abusing a delegate to get at the
concept it embed's which doesn't have a proper expression.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20130608/fdbc2f82/attachment.html>


More information about the Digitalmars-d mailing list