[gnu.g++] ptr to member function, even worse

tiemann@YAHI.STANFORD.EDU (Michael Tiemann) (05/04/89)

   Path: mit-eddie!ll-xn!ames!ncar!boulder!stan!garya
   From: garya@solbourne.com (Gary Aitken)
   Newsgroups: comp.lang.c++
   Date: 3 May 89 22:39:31 GMT
   Organization: Solbourne Computer Inc., Longmont, Co.
   Lines: 51
   Apparently-To: lang-c++-netnews-dist@wheaties.ai.mit.edu

   OK, everyone has been real helpful and with a few patches and fixes we've
   managed to figure out what g++ and cfront are doing with address of
   virtual function references.  But the whole problem is even worse than
   I originally mentioned...

   Consider a function

	   dispatch(objp,fnp)

   which has very little knowledge of its arguments.  It knows the following:

	   objp is a pointer to a C++ object
	   fnp  is a pointer to a member function for objp (possibly virtual)

   In particular, dispatch has no knowledge of the base class for objp.
So objp is a void*?  If so, I think this is a flawed use of void*.
I don't see any reason why objp's type should be so lost that no base
class is known.  But even if this is so, things can still be made to work.

   None of the methods/syntax discussed so far will allow dispatch to call
   fnp on behalf of objp.  The code generated by cfront assumes knowledge
   of where the virtual table is located based on the base class type;
   the virtual table offset is not in a constant place.
You are looking at old versions of g++ and cfront.  The 2.0 spec shows
how to implement pointers to member functions which are robust enough
to solve this problem.  A pointer to member function is no longer just
a function address or an index into the elusive vtable.  Rather, it is
a triple, occupying 64 bits, which contains enough information (in
worst case) to:

	1.  Find the `base' of objp
	2.  Find the appropriate vtable within objp
	3.  Provide the correct index into the found vtable
	    to perform a virtual function call as though all
	    the information were available.

depending on the values of the various elements in the triple.

   I can see one resolution to this problem:

   Have cfront force the virtual table to always be at offset 0, so

	   (objp->*fnp)()

   can be made to always work.
The paper by Lippman and Stroustrup on implementing pointers to member
functions (in the Denver '88 USENIX C++ Technical Conference
Proceedings) is one of many places which shows why this is not a good
idea.

   The solution we currently use (mentioned previously) is a mod to cfront
   which allows

	   fnp = &objp->f

   to return the actual address of the member function, and use a C call

	   (*fnp)(objp)

   Unfortunately, this won't work in some even more esoteric cases, such as
   when the object has a member which is the address of a member function of
   itself or another object, and the function involved is virtual.  Besides,
   the above fix relies on knowledge of the implementation (this is passed by
   cfront as 1st arg).
Right.  And there are several other reasons why this will not work in
the presence of multiple inheritance.

   Anybody have other thoughts or answers for something that works today?
   This is a major hangup for us, since we have user applications inserting
   objects and callback functions in a dispatch table.
Your problems should find solutions when C++ 2.0 compilers become
available, from AT&T in about 2 months, and from GNU in about one.

   -- 
   Gary Aitken

   Solbourne Computer Inc.    ARPA: garya@Solbourne.COM
   Longmont, CO               UUCP: ...!{boulder,sun}!stan!garya

Michael