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