Topic: Casting pointers to member functions


Author: pkt@lpi.liant.com (Scott Turner)
Date: Tue, 29 Nov 1994 18:07:19 GMT
Raw View
In article <3becnt$pim@giga.bga.com>, jamshid@ses.com (Jamshid Afshar) wrote:

> Has the ANSI/ISO decided what kind of pointer to member function casts
> are legal?  Many C++ GUI libraries implement a form of callbacks like
> in the example below.  They require that casting a void(Derived::*)()
> to a void(Base::*)() work and that the resulting Base ptm can be used
> directly without casting it back to a Derived ptm.

The GUI library I support (C++/Views) uses this mode of casting in a
single inheritance hierarchy.  We have ported C++/Views to the majority
of the popular compilers for MS-Windows, OS/2, and Macintosh, and to
a dozen compilers on Unix.  Over the course of our porting efforts, every
compiler we tried but one allowed this mode of casting.

The working paper now says that these casts are undefined.  This is
good.  Everyone has been casting member pointers for years, with no
indication in the ARM and working paper of which casts are not defined
-- and they can't *all* be defined!  Libraries like ours may start to
support alternative implementations that don't rely on member pointer casts.
But it won't always be easy for users of these libraries to move to a
revised implementation -- in some cases it will be a great inconvenience.
So the best compilers will continue to support the member pointer casts that
they now support.

> PS: I'm hoping ANSI/ISO will decide that Derived=>Base ptm casts are
> always undefined

The working paper says, "If the pointer to member converted is not
the null member pointer value and class B does not contain or inherit
the original member, the result of the cast is undefined."  Otherwise
Derived=>Base ptm casts are defined, i.e. no picnic for compiler
developers. :-)
--
Scott Turner
Liant Software Corp., Framingham, Massachusetts, USA
pkt@lpi.liant.com




Author: bgibbons@taligent.com (Bill Gibbons)
Date: Tue, 29 Nov 1994 20:19:02 GMT
Raw View
In article <3becnt$pim@giga.bga.com>, jamshid@ses.com (Jamshid Afshar) wrote:

> Has the ANSI/ISO decided what kind of pointer to member function casts
> are legal?  Many C++ GUI libraries implement a form of callbacks like
> in the example below.  They require that casting a void(Derived::*)()
> to a void(Base::*)() work and that the resulting Base ptm can be used
> directly without casting it back to a Derived ptm.
>
> Current compilers differ in how they handle it.  Some crash while
> others work as long as multiple inheritence or virtual inheritance is
> not involved.  I'm hoping ANSI/ISO has made a clear decision on this
> subject since it will have a great affect on the correctness of lots
> of code already in existence and on the ptm optimization possibilities
> compilers will have.

This is still an open issue.  As part of resolving other pointer to member
issues, the working paper was changed to make it undefined what happens
when you cast a pointer to member to a class which does not contain the
original member.  But that was with the understanding that the issue is
not dead.

(By "contains the original member", I mean declares or inherits that
exact member.  Overrides do not count, so you can't cast to a base class
just because it contains a member with the same name - that isn't the
same member. Another way to put this is that you can freely downcast a
pointer to member, but when you upcast it you can't go beyond the
original class.)

But most compilers will allow casts to base classes not containing the
original member, and dereferencing with a base class pointer (to a
derived class object), and do the right thing at least part of the time.

Some compilers will try to optimize the PM dereference if the base class
does not use multiple inheritance or does not have virtual functions.
The optimizations can be defeated by adding a dummy base class and/or
a dummy virtual function.

(But this trick doesn't work for virtual inheritance.  If the PM is cast
to a virtual base not containing the original member, and dereferenced with
a derived class object, the dereference would require a downcast from a
virtual base.  So this capability has not been proposed.)

> PS: I'm hoping ANSI/ISO will decide that Derived=>Base ptm casts are
> always undefined, thus allowing compilers to optimize the size of ptms
> for simpler classes and avoiding the ugliness of special-cases and the
> hairy issues related to equality comparisons.

It still isn't possible to optimize the size, because it's valid to declare
a pointer to a member of a incomplete class:

     class T;
     void (T::*pf)();

(This was confirmed as part of the recent clarifications.)

The ugly problems with equality comparisons are gone.  Since there is no
good way to compare pointers to virtual member functions, any comparison
involving a pointer to virtual member is now unspecified (except comparing
to the null pointer to member, i.e. zero.)

That leaves performance.  Allowing these upcasts (to base classes not
containing the original member) would force compilers to generate code to
handle virtual functions and multiple inheritance for every pointer to
member dereference, even when the pointer's class does not contain virtual
functions or use multiple inheritance.

The cost of handling multiple inheritance is typically one instruction.
The cost of handling virtual function calls depends on the implementation.
For a thunk-based implementation the cost is zero.  For a cfront-style
implementation the cost is several additional instructions, but only one
or two will actually be executed in the nonvirtual case.

This seems like a small price to pay.  The deciding factor is more likely
to be language complexity than performance.

Again, this is an open issue before the standards committee but unless the
committee takes explicit action, the result of casting a PM to a base class
which does not contain the original member will be undefined.




Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Sun, 4 Dec 1994 00:02:44 GMT
Raw View
In article <3becnt$pim@giga.bga.com> jamshid@ses.com (Jamshid Afshar) writes:
>Has the ANSI/ISO decided what kind of pointer to member function casts
>are legal?

 An upcast to a class not containing the member is undefined.

 It is possible this will be extended.

>PS: I'm hoping ANSI/ISO will decide that Derived=>Base ptm casts are
>always undefined, thus allowing compilers to optimize the size of ptms
>for simpler classes and avoiding the ugliness of special-cases and the
>hairy issues related to equality comparisons.

 They are not "always" undefined. They are well defined
IF the base contains the member ( or one of its bases ).

 WOOPS: Caveat -- without checking the exact wording
I'm not sure if the cast itself is undefined, or just the
use of the pointer to member after casting.


--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189




Author: jamshid@ses.com (Jamshid Afshar)
Date: 29 Nov 1994 05:03:57 GMT
Raw View
Has the ANSI/ISO decided what kind of pointer to member function casts
are legal?  Many C++ GUI libraries implement a form of callbacks like
in the example below.  They require that casting a void(Derived::*)()
to a void(Base::*)() work and that the resulting Base ptm can be used
directly without casting it back to a Derived ptm.

Current compilers differ in how they handle it.  Some crash while
others work as long as multiple inheritence or virtual inheritance is
not involved.  I'm hoping ANSI/ISO has made a clear decision on this
subject since it will have a great affect on the correctness of lots
of code already in existence and on the ptm optimization possibilities
compilers will have.

  class Button : public Window {
  public:
     typedef void (Window::*CB)();

     Button( Window& parent, CB callback )
        : _parent(parent), _callback(callback) {}

     void pressed() { (_parent.*_callback)(); }  // guaranteed to work?
  private:
     Window& _parent;
     CB _callback;
  };

  class MyWindow : public Window {
     Button _cancelb;
  public:
     MyWindow() : _cancelb( *this, (Button::CB) &MyWindow::cancel ) {}
     void cancel() { /*...*/ }
  };

PS: I'm hoping ANSI/ISO will decide that Derived=>Base ptm casts are
always undefined, thus allowing compilers to optimize the size of ptms
for simpler classes and avoiding the ugliness of special-cases and the
hairy issues related to equality comparisons.

Jamshid Afshar
jamshid@ses.com