Topic: Address of member functions


Author: jamshid@emx.cc.utexas.edu (Jamshid Afshar)
Date: 7 Jul 1993 13:19:58 -0500
Raw View
In article <1993Jul2.173354.25676@borland.com> pete@borland.com (Pete Becker) writes:
>In article <210q08INNmdl@emx.cc.utexas.edu> jamshid@emx.cc.utexas.edu (Jamshid Afshar) writes:
>>In article <1993Jun30.220757.10961@borland.com> pete@borland.com (Pete Becker) writes:
>>> No. An explicit cast makes this conversion legal. That's what the
>>>quoted language says: the explicit conversion is legal if one of the two
>>>classes is unambiguously derived from the other.
>>
>>[...example deleted where casting can't work when using -Vmd option...]
>>
> Handling the full power of pointers to member functions is expensive.
>Our compiler gives you some options so that you don't have to pay this price
>if you're sure that you don't need the full flexibility. If you enable those
>options and you're wrong about not needing the full flexibility your code
>will not work correctly. In some cases the compiler will recognize the
>problem and tell you about it, and in others it won't.

I think you missed my point.  I don't believe the ARM intends to allow
casts from a derived class member function pointer to a base class
member function pointer, regardless of compiler options.  Such casts
simply can't work with multiple inheritance because there's no way to
pass the correct `this' pointer:

 #include <iostream.h>

 class B {
 public:
    void b() { cout << "B::b()" << endl; }
 };

 class D : public virtual B {
    int i;
 public:
    D() : i(42) {}
    void d() { cout << "D::d(), i=" << i << endl; }
 };

 void call( B* b, void (B::*mfp)() )
 { (b->*mfp)(); }

 main() {
    D d;
    d.d();                           // outputs "D::d(), i=42"
    call( &d, (void(B::*)())&D::d ); // outputs "D::d(), i=[garbage]"
         // I don't think the ARM considers this cast legal and
         // using the resulting pointer certainly can't work.
    return 0;
 }

This code doesn't work on any compiler I tried, with any options (btw,
gcc 2.4.3 gave an incorrect parse error).

We know ARM 5.4 references 4.6:

 [explicit casts are allowed] when the two types are pointers
 to member functions of classes one of which is unambigously
 derived from the other ($4.6).

I believe this reference to 4.6 is a minor editing error and instead
4.8 "Pointers to Members" was intended (note, 4.6 does not discuss
member function pointers and it does reference 4.8).  ARM 4.8 only
allows conversions from a base class member pointer to a derived class
member pointer.  The inverse conversion is not allowed.  Contrary to
what Pete wrote, I don't think that the ARM intends to allow inverse
conversions when using an explicit cast.  I think Stroustrup
referenced 4.6 for exactly this reason (ie, "see 4.6 for details about
the class relationship requirements").

That's my interpretation of the ARM which is supported by code like
the above.  Does anyone else agree or disagree?

Jamshid Afshar
jamshid@emx.cc.utexas.edu




Author: Geir.Halbo@ugle.unit.no (Geir Halbo)
Date: 9 Jul 93 00:10:46
Raw View
In article <21f44eINNq7v@emx.cc.utexas.edu> jamshid@emx.cc.utexas.edu (Jamshid Afshar) writes:

   ARM 4.8 only
   allows conversions from a base class member pointer to a derived class
   member pointer.  The inverse conversion is not allowed.  Contrary to
   what Pete wrote, I don't think that the ARM intends to allow inverse
   conversions when using an explicit cast.  I think Stroustrup
   referenced 4.6 for exactly this reason (ie, "see 4.6 for details about
   the class relationship requirements").

   That's my interpretation of the ARM which is supported by code like
   the above.  Does anyone else agree or disagree?

Agreed.  What would otherwise be the state (attribute values) of the
derived class extension relative to the base class?  How about data
invariants?


  struct X {
    int a;
  };

  struct Y : public X {
    int b;
    Y(int y) { b=y; } // constructor, not used by cast
  };

  :

  X x; x.a = 1;
  cout << ((Y) x).b; // doesn't know what to print, nor how to construct


However, I believe adding an explicit conversion is different:

  class Y;

  struct X {
    int a;
    operator Y();
  };

  struct Y : public X { ... };

  X::operator Y() {
    return ...
  }


Do I make sense??

 - geir

--
MSc Geir Halbo     !  Department of Computer Systems and Telematics (IDT)
Halbo@idt.unit.no  !  Norwegian Institute of Technology             (NTH)
+ 47 7 59 36 74    !  University of Trondheim                      (UNIT)
G=Geir; S=Halbo; OU=IDT; O=Unit; P=Uninett; C=No




Author: pete@borland.com (Pete Becker)
Date: Thu, 8 Jul 1993 23:09:50 GMT
Raw View
In article <GEIR.HALBO.93Jul9001046@villtind.ugle.unit.no> Geir.Halbo@ugle.unit.no (Geir Halbo) writes:
>In article <21f44eINNq7v@emx.cc.utexas.edu> jamshid@emx.cc.utexas.edu (Jamshid Afshar) writes:
>
>   ARM 4.8 only
>   allows conversions from a base class member pointer to a derived class
>   member pointer.  The inverse conversion is not allowed.  Contrary to
>   what Pete wrote, I don't think that the ARM intends to allow inverse
>   conversions when using an explicit cast.  I think Stroustrup
>   referenced 4.6 for exactly this reason (ie, "see 4.6 for details about
>   the class relationship requirements").
>
>   That's my interpretation of the ARM which is supported by code like
>   the above.  Does anyone else agree or disagree?
>
>Agreed.  What would otherwise be the state (attribute values) of the
>derived class extension relative to the base class?  How about data
>invariants?
>
>

 Allowing the conversion is not the same thing as requiring it to make
sense. When you cast a pointer to base class into a pointer to derived it's
up to you to make sure that what you're doing actually makes sense. Same for
pointers to member functions.
 Here's an example that I would expect to work:

 class Base { void f(); };
 class Derived : public Base {};

 void (Derived::*dptr)() = &Base::f; // legal: implicit conversion
 void (Base::*bptr)() = (void (Derived::*)())dptr;

 Base *bp = new Base;
 (bp->*bptr)();

 -- Pete






Author: jamshid@emx.cc.utexas.edu (Jamshid Afshar)
Date: 2 Jul 1993 03:01:11 -0500
Raw View
Crossposted and redirected to comp.std.c++

In article <1993Jun30.220757.10961@borland.com> pete@borland.com (Pete Becker) writes:
>>ARM 5.4:
>> A pointer to member may be explicitly converted into a
>> different pointer to member when the two types are pointers to
>> members of the same class or when the two types are pointers
>> to member functions of classes one of which is unambigously
>> derived from the other (see 4.6).
                                ^^^^^^^
>>[...]
>>In fact explicit casting from void (Derived::*)() to void (Base::*)()
>>should already be rejected ...
>
> No. An explicit cast makes this conversion legal. That's what the
>quoted language says: the explicit conversion is legal if one of the two
>classes is unambiguously derived from the other.

I know that sure seems like I what it says, but I don't think that's
what was intended and I definitely don't think such casts should be
required to work.  Here's what I wrote in my June 24 article in this
thread:

 In article <20dnsjINNdjh@emx.cc.utexas.edu> I [Jamshid] wrote:
 >ARM 4.6 doesn't discuss m.f.p.'s but its commentary refers to 4.8
 >which only allows conversion from `void(Base::*)()' to
 >`void(Derived::*)()', but not vice-versa.  [...]
 >
 >Btw, I think ANSI should make 5.4 directly reference 4.8 and mention
 >its class relationship requirement otherwise people and compilers
 >might think *explicit* conversions from `void(Derived::*)()' to
 >`void(Base::*)()' are allowed.

I believe the reason for making m.f.p.'s so stubborn when it comes to
casting is to allow for size optimizations such as the optimizations
BC++ 3.1 performs for pointers to member functions of classes which do
not have any virtual bases.  You must use the switch "-Vmd" to get
this optimization.  For the classes:

 class Base { public: virtual void f(); };
 class Derived : public virtual Base {};
 void (Base::*bp)();
 void (Derived::*dp)();

`sizeof(bp)' is 4 while `sizeof(dp)' is 8, so casting `dp' to a
`void(Base::*)()' definitely won't work.  If I'm wrong and using
"-Vmd" makes BC++ an incorrect C++ compiler, then why bother putting
any restrictions on the casting of m.f.p.'s since any size
optimizations are lost?

Jamshid Afshar
jamshid@emx.cc.utexas.edu





Author: pete@borland.com (Pete Becker)
Date: Fri, 2 Jul 1993 17:33:54 GMT
Raw View
In article <210q08INNmdl@emx.cc.utexas.edu> jamshid@emx.cc.utexas.edu (Jamshid Afshar) writes:
>Crossposted and redirected to comp.std.c++
>
>In article <1993Jun30.220757.10961@borland.com> pete@borland.com (Pete Becker) writes:
>>>ARM 5.4:
>>> A pointer to member may be explicitly converted into a
>>> different pointer to member when the two types are pointers to
>>> members of the same class or when the two types are pointers
>>> to member functions of classes one of which is unambigously
>>> derived from the other (see 4.6).
>                                ^^^^^^^
>>>[...]
>>>In fact explicit casting from void (Derived::*)() to void (Base::*)()
>>>should already be rejected ...
>>
>> No. An explicit cast makes this conversion legal. That's what the
>>quoted language says: the explicit conversion is legal if one of the two
>>classes is unambiguously derived from the other.
>
>I know that sure seems like I what it says, but I don't think that's
>what was intended and I definitely don't think such casts should be
>required to work.  Here's what I wrote in my June 24 article in this
>thread:
>
> In article <20dnsjINNdjh@emx.cc.utexas.edu> I [Jamshid] wrote:
> >ARM 4.6 doesn't discuss m.f.p.'s but its commentary refers to 4.8
> >which only allows conversion from `void(Base::*)()' to
> >`void(Derived::*)()', but not vice-versa.  [...]
> >
> >Btw, I think ANSI should make 5.4 directly reference 4.8 and mention
> >its class relationship requirement otherwise people and compilers
> >might think *explicit* conversions from `void(Derived::*)()' to
> >`void(Base::*)()' are allowed.
>
>I believe the reason for making m.f.p.'s so stubborn when it comes to
>casting is to allow for size optimizations such as the optimizations
>BC++ 3.1 performs for pointers to member functions of classes which do
>not have any virtual bases.  You must use the switch "-Vmd" to get
>this optimization.  For the classes:
>
> class Base { public: virtual void f(); };
> class Derived : public virtual Base {};
> void (Base::*bp)();
> void (Derived::*dp)();
>
>`sizeof(bp)' is 4 while `sizeof(dp)' is 8, so casting `dp' to a
>`void(Base::*)()' definitely won't work.  If I'm wrong and using
>"-Vmd" makes BC++ an incorrect C++ compiler, then why bother putting
>any restrictions on the casting of m.f.p.'s since any size
>optimizations are lost?
>

 Handling the full power of pointers to member functions is expensive.
Our compiler gives you some options so that you don't have to pay this price
if you're sure that you don't need the full flexibility. If you enable those
options and you're wrong about not needing the full flexibility your code
will not work correctly. In some cases the compiler will recognize the
problem and tell you about it, and in others it won't.
 -- Pete




Author: cadi@uni-paderborn.de (Carsten Ditze)
Date: 19 Apr 1993 17:36:00 GMT
Raw View
Hi all,


perhaps it is because I'm a C++ beginner, that I cannot find an answer
to the following problem I've:

Given a C-Function

extern "C" void func( void (*)() );

and a class

class A {
 public:
   void    method();
   void    callmethod() {
       func(method); // this is what I want to do, but it does
                            // not work...
           }
};

In words: I'd like to pass A::method as argument to func, so that func
can call method.  Since func is a member of a system C-Library, I've
also no chance to hack around this problem. To pass method by
A::method or &A::method does not solve the problem.


Is this a problem to C++, or is it just because I'm a beginner.

Thanks, for your reply,

Carsten
--

+------------------------------------------------------------------------+
| Carsten Ditze                   | e-mail: cadi@uni-paderborn.de        |
| University of Paderborn         | or:     cadi@pbinfo.uucp             |
| FB 17 (Dept. of Math. & CS)     | or:     ...!uunet!unido!pbinfo!cadi  |
| Warburger Str. 100              | voice:  +49 +5251 60-2074            |
| 4790 Paderborn, Germany         | fax:    +49 +5251 60-3427            |
+------------------------------------------------------------------------+