Pointers to non-static member functions!
Michel Fortin
michel.fortin at michelf.com
Wed Jun 8 13:41:17 PDT 2011
On 2011-06-08 15:21:47 -0400, "Steven Schveighoffer"
<schveiguy at yahoo.com> said:
>> This is not at all a feature of Objective-C. This was a workaround.
>> Tell me, if inside a template you have an alias to a member function,
>> how can I call that member function? This won't work:
>>
>> void callMe(alias memberFunc)(Object o) {
>> o.memberFunc(); // won't work, Object has no member called "memberFunc".
>> }
>
> In this case, the alias points at A.func or something like that, no?
Exactly.
> So you have enough information to figure out that the member function
> is from A?
Yes. (Although I'm not sure you can extract this info from the alias,
the compiler has it, and I have it through other means, namely
typeof(this)).
> That is my point, you almost never *don't know* where the member
> function comes from. And even if you don't, it's dangerous to simply
> assume this.
The member function here is an alias, the compiler knows where this
function comes from and can check whether the 'this' pointer is of the
right type. It just won't let us call it because there's no syntax.
That's the core of the problem.
I worked around that by adding a non-virtual member function that just
returns a delegate to the virtual one.
Constructing the delegate manually is a workaround to call that
non-virtual member. I can't call even a non-virtual member function
without it because I mixin the same template many times within the same
class, which creates ambiguous overloads for "resolveVirtualCall".
Taking the address directly and assigning it to a delegate works
because I'm not getting the symbol through the object but through the
current scope which gives precedence to a function in the template
scope. To make that clear, this works:
private static
R forwardVirtualCall(objc.runtime.id self, objc.runtime.SEL _cmd, A args) {
R delegate(A) delegate() resolve;
resolve.ptr = objc.msg.send!(void*)(self, objc.method.selector!("d_object"));
resolve.funcptr = &resolveVirtualCall;
return resolve()(args);
}
while this doesn't when mixing in the templates multiple times within a class:
private static
R forwardVirtualCall(objc.runtime.id self, objc.runtime.SEL _cmd, A args) {
auto o = cast(typeof(this))objc.msg.send!(void*)(self,
objc.method.selector!("d_object"));
return o.resolveVirtualCall()(args);
}
It gives this error:
/objc/bridge.d(253): Error:
cocoa.foundation.date.NSDate.ObjcBindMethod!(opAdd,NSDate,"addTimeInterval:",double).resolveVirtualCall
at /cocoa/foundation/date.d(245) conflicts with
cocoa.foundation.date.NSDate.ObjcBindMethod!(isEqualToDate,bool,"isEqualToDate:",NSDate).resolveVirtualCall
at /cocoa/foundation/date.d(245)
I'm sorry if this wasn't clear the first time, I think it wasn't for me
either. It's been a long time since I written or even used that code.
To, to summarize: Calling a virtual function relied on defining and
calling a non-virtual member. A non-virtual member which was ambiguous
and could be called only through a manually-crafted delegate. Hence my
need for a manually crafted delegate.
> In my proposal, I'd guess that &memberFunc would give you a
> 'delegate-function' pointer, which you could then cast o to the right
> type (assuming it is that type) and pass it into the function.
>
> i.e.:
>
> auto fptr = &memberFunc;
> fptr(cast(thisType!(fptr))o); // thisType gets the type of the 'this'
> argument from the delegate-function pointer
That would probably work as it's just sugar for creating a delegate
manually, with some added type safeties.
>> Although even there it won't work very well if your member is a virtual
>> function. I needed to use an ever stranger workaround for that. Here's
>> the actual code from the Objective-C bridge (it's a template which be
>> mixed in the class):
>
> This is an entirely different thing, a delegate removes the
> virtual-ness of the call. &A.func points to A's function, not to the
> virtual version (it can't possibly know that without an instance).
> Having a way to say "call vtable entry for A.func" for a specific
> object would be nice, but is not a delegate.
It'd be nice to have that, even if just as a library solution. Do we
have a __traits to get the vtable offset of a function?
>>> All this is dependent on the idea that a delegate cannot be constructed
>>> unless you have the original method (or a type-safe
>>> 'delegate-function' such as int function(A this)). I really think
>>> that makes sense.
>>
>> I won't disagree with anything you say, because I do agree. I know my
>> use case is a fringe one, and I don't need it anymore so I don't care
>> much. And it'd only need one small thing for it to work without all
>> that cumbersome hack:
>>
>> o.memberFunc() // where methodFunc is an alias to a member of o
>
> I'd much prefer memberFunc(o); This is of course for a
> delegate-function pointer, not for an alias. I'm not sure how an
> alias would work.
Agree. Also, an alias could work using the same syntax too if we had UFCS. :-)
--
Michel Fortin
michel.fortin at michelf.com
http://michelf.com/
More information about the Digitalmars-d
mailing list