Pointer to member variable again
Kirk McDonald
kirklin.mcdonald at gmail.com
Wed Jul 30 22:20:35 PDT 2008
Steven Schveighoffer wrote:
> "Kirk McDonald" wrote
>
>>Steven Schveighoffer wrote:
>>
>>>"ws" wrote
>>>
>>>
>>>>Suppose i have the following:
>>>>
>>>>int function() fp;
>>>>int *ptr;
>>>>class Cls
>>>>{
>>>>int k;
>>>>int foo() { return 0; }
>>>>}
>>>>
>>>>void main()
>>>>{
>>>>fp = &Cls.foo;
>>>>
>>>>Cls c = new Cls;
>>>>ptr = &c.k; // <-- why always need a new instance?
>>>>}
>>>>
>>>>As compared to delegate, is there no analogous way to specify this?
>>>>
>>>>ptr = &Cls.k
>>>>
>>>>Thanks!
>>>
>>>
>>>In fact, this should fail to compile. The fact that it succeeds is a
>>>bug. You should enter it in bugzilla (is it already there?)
>>>
>>>Did you try running it? I get a segfault.
>>>
>>>fp is a member function, which means it needs a hidden 'this' pointer.
>>>When you assign &Cls.foo to fp, this should result in the same error as
>>>if you typed Cls.foo():
>>>
>>>Error: need 'this' to access member foo
>>>
>>>-Steve
>>
>>A direct, C++-style pointer-to-member-function is occasionally useful.
>>(Though rarely, since delegates are more useful nearly every time.)
>>Allowing this syntax is the only sensible way to get access to them. The
>>resulting pointer can then manually be shoved into a delegate:
>>
>>void function() fp = &Cls.foo;
>>Cls c = new Cls;
>>void delegate() dg;
>>dg.funcptr = fp;
>>dg.ptr = c; // I forget if a cast to void* is necessary...
>>dg();
>>
>>Pyd relies on this behavior to implement its class wrapping, and it would
>>be fairly inconvenient if it went away.
>
>
> I had no idea you could build delegates this way. But even still, the
> function signature is not correct, it should be something like:
>
> void function(Cls c) fp = &Cls.foo;
>
> But in any case, the original code seems like dangerous behavior to allow
> without casting. There should at least be a cast involved so the user is
> forced to say "yes, I know that the function signature isn't correct, do it
> anyways". I still say this should be a bug.
>
> -Steve
>
>
The only really correct (that is, type-safe) solution is to do something
like what C++ does. The syntax for this is astoundingly ugly, but let me
walk you through it. (This is C++ code, so brace yourself.) :-)
class C {
public:
virtual void foo()=0; // an abstract ("pure virtual") method
};
// Alias the pointer type.
typedef void (C::* ptr_t)();
void f(C* c) {
// Take the address of the method.
ptr_t fn = &C::foo;
// Call it on the instance.
(c->*fn)();
}
Several things deserve mention:
1) The syntax is just weird. Take this:
typedef void (C::* ptr_t)();
That is aliasing the type "void (C::*)()" to the name ptr_t. That type
is a function pointer type. It's like a void function() which can only
apply to member functions of class C. C::* basically means "pointer to
member of C."
On the other side of the equation, we have:
(c->*fn)();
This is binding the pointer-to-member "fn" to the instance pointed to by
c, and then calling the result. In the example, it is basically
equivalent to:
c->foo();
->* is an operator in its own right in C++.
2) It does a virtual call!
Where a pointer-to-member-function is a regular function pointer in D,
in C++ it is basically just the index of the function in the vtable.
(Unless, of course, the member function isn't virtual.)
As an aside, it is precisely the non-virtual nature of these
pointers-to-member-functions that Pyd exploits. The details behind this
chicanery are more involved than I want to describe here.
3) The pointers are type-safe. This bears mentioning again: Only member
functions of class C (which have that particular signature) can be
assigned to a variable of that ptr_t type above. This is exactly in line
with what you were saying: void function() is not the correct type for
the function pointer.
As it is, pointers-to-member-functions are basically a half-feature in
D. You can do it, but it arguably breaks the type system in weird ways.
I would argue that this is fine, since they are innately ugly.
--
Kirk McDonald
http://kirkmcdonald.blogspot.com
Pyd: Connecting D and Python
http://pyd.dsource.org
More information about the Digitalmars-d-learn
mailing list