Topic: What's the latest on casting ptrs to mbr funcs?


Author: imp@village.org (Warner Losh)
Date: 1995/04/28
Raw View
In article <MCOOK.95Apr25001014@erawan.cognex.com>,
Michael Cook  <mcook@cognex.com> wrote:
>>>>>> "JAF" == John Andrew Fingerhut <jaf3@ritz.cec.wustl.edu> writes:
>
> JAF>  cout << func (&d, (int (Base::*)()) &Derived::mbrfunc) << endl;
>
>That's not valid, because `Base' does not have a member function `mbrfunc'
>(generally speaking).  The ARM explains this point.  Basically, you can cast
>implicitly from B::* to D::* if you can also cast implicitly from D to B (the
>implicit casting works in the other direction for member functions).

I'm afraid that it is valid.  The last draft of the standard says that
mbrfunc need not be a member of B.

This technique is used extensively in the OI library and we've gone to
great lengths to make sure that it is valid and portible.

Now then, if mbrfunc had different args, was varadic, etc, then it
would be invalid.  Or if Base was not an unambiguous subclass of
Derived, you'd have problems.

Warner





Author: imp@village.org (Warner Losh)
Date: 1995/04/28
Raw View
In article <3nr20e$1vo@rover.village.org>, Warner Losh <imp@village.org> wrote:
>I'm afraid that it is valid.  The last draft of the standard says that
>mbrfunc need not be a member of B.

That should read the last draft of the standard that I have, which is
unfortunately 1 year old (Jan 94).

Warner





Author: Michael Cook <mcook@cognex.com>
Date: 1995/04/25
Raw View
>>>>> "JAF" == John Andrew Fingerhut <jaf3@ritz.cec.wustl.edu> writes:

 JAF>  cout << func (&d, (int (Base::*)()) &Derived::mbrfunc) << endl;

That's not valid, because `Base' does not have a member function `mbrfunc'
(generally speaking).  The ARM explains this point.  Basically, you can cast
implicitly from B::* to D::* if you can also cast implicitly from D to B (the
implicit casting works in the other direction for member functions).





Author: bgibbons@taligent.com (Bill Gibbons)
Date: 1995/04/27
Raw View
In article <3ngo28$6ea@ritz.cec.wustl.edu>, Stephen Gevers wrote:

> Is this construct well defined by the draft Standard?  If so, what are the
> specified limitations (Multiple Inheritance? Virtual Inheritance?)
-- example edited for brevity --
>
> struct Base { };
>
> struct Derived : Base {
>      void     mbrfunc() { }
> };
>
> void func (Base *b, void (Base::*f)()) {
>      (b->*f)();
> }
>
> main () {
>       Derived d;
>       func (&d, (void (Base::*)()) &Derived::mbrfunc);
> }

The behavior is currently undefined.  By the nature of pointers to members,
most (maybe all) conforming compilers are capable of handling this, and
will handle the single inheritance case correctly.

And most (maybe all) conforming compilers are capable of handling the
multiple inheritance case too; but some of them make assumptions about
the absence of a MI offset adjustment and/or whether the call could be
virtual, and deliberately generate code which cannot handle multiple
inheritance and/or dereferencing a virtual PM with a non-polymorphic
static type.

Such optimizations are allowed under the current draft standard.
But they yield extremely small savings compared to the
utility of making the cast (and dereference) work correctly.

(The savings for assuming single inheritance is one or two instructions;
the savings for assuming non-virtual calls is zero for an implementation
which uses virtual call thunks, which is the most reasonable implementation
of pointers to virtual members anyway.)

And since this kind of code often works today, and cannot usually be
diagnosed at compile time, it will frequently be used accidentally even
if the behavior remains undefined.  This will be an ongoing maintainence
and portability problem.

I've been trying to convince the committee to make the above case
well-defined, but it's getting late in the process and the chances for
fixing this are not good.


Bill Gibbons
bgibbons@taligent.com

--
Bill Gibbons
bgibbons@taligent.com





Author: jaf3@ritz.cec.wustl.edu (John Andrew Fingerhut)
Date: 1995/04/24
Raw View
Is this construct well defined by the draft Standard?  If so, what are the
specified limitations (Multiple Inheritance? Virtual Inheritance?)

#include <iostream.h>

class Base {
};

class Derived : public Base {
 int i;
public:
 Derived (int d = 3) : i(d) { }
 int mbrfunc();
};

int Derived::mbrfunc()
{
 return i;
}

int func (Base *b, int (Base::*f)())
{
 return (b->*f)();
}

main ()
{
 Derived d;
 cout << func (&d, (int (Base::*)()) &Derived::mbrfunc) << endl;
}

--
Stephen Gevers
sg3235@shelob.sbc.com