Topic: Is this cast of pointer-to-member legal?


Author: paul.black@vf.vodafone.co.uk
Date: 1996/10/03
Raw View
Kevin Cline <kcline@i2.com> wrote:
> But what about the opposite case:
>
>    struct B { };
>    struct D : B { };
>
>    struct C {
>     typedef void (C::*action)( D& );
>
>     void mb( B& ) { }
>     void md( D& ) { }
>    };
>
>    void f( action ) { }
>
> It seems that
>  f(&C::mb )
> should be a legal call, with no cast required.  Is it?

It shouldn't be legal, it doesn't always work in the presence of multiple
inheritance. For example:

    struct A { };
    struct B { };
    struct D : A, B { };

Paul



[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Kevin Cline <kcline@i2.com>
Date: 1996/10/01
Raw View
"Marco Dalla Gasperina" <marcodg@hp-vcd.vcd.hp.com> writes:

>
> Paul J. Lucas <grumpy@wizard.arc.nasa.gov> wrote in article <pjl.843754146@wizard>...
> >  Given:
> >
> >   struct B { };
> >   struct D : B { };
> >
> >   struct C {
> >    typedef void (C::*action)( B& );
> >
> >    void mb( B& ) { }
> >    void md( D& ) { }
> >   };
> >
> >   void f( action ) { }
> >
> >  Is:
> >
> >   f( (C::action)&C::md );
> >
> >  a legal cast?  The pointer-to-member is of the same class and 2
> >  out of 3 C++ compilers agree that the cast is legal.  Is the
> >  3rd one wrong?
>
> So, I think, it is legal. But not very smart...
>
> Consider a definition of f():
>
> void f( C::action mf )
> {
>     C c;
>     B b;
>     c.*mf(b); // this will call C::md with a 'B' parameter.  The
>          // member probably assumes the extra capabilities of
>               // a 'D' object but won't get them.
> }
>
> As usual, when one thinks they know more than the compiler, the compiler
> will exact a revenge.
>

But what about the opposite case:

   struct B { };
   struct D : B { };

   struct C {
    typedef void (C::*action)( D& );

    void mb( B& ) { }
    void md( D& ) { }
   };

   void f( action ) { }

It seems that
 f(&C::mb )
should be a legal call, with no cast required.  Is it?
--
Kevin Cline, i2 Technologies
--
Kevin Cline, i2 Technologies
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Chelly Green <chelly@eden.com>
Date: 1996/10/02
Raw View
Kevin Cline wrote:
...
> But what about the opposite case:
>
>                 struct B { };
>                 struct D : B { };
>
>                 struct C {
>                         typedef void (C::*action)( D& );
>
>                         void mb( B& ) { }
>                         void md( D& ) { }
>                 };
>
>                 void f( action ) { }
>
> It seems that
>
>         f(&C::mb )
>
> should be a legal call, with no cast required.  Is it?

I guess this should be legal too?

    typedef void (*action)( int, int );

    void f( double, double );
    void g( int, long );
    void h( int, int, int = 0 );

    action a = f;
    action b = g;
    action c = h;

Hey, the compiler could do type conversion and even provide default
arguments. But this requires hidden run-time functions, and possibly
complex rules. I think anything other than an exact match is going in
this direction. Pointer-to-members are just like other function pointers
in this regard.

I bet you could define a template function to do this (my compiler
doesn't support templates enough to do that, though... I tried!).
--
Chelly Green | chelly@eden.com | C++ - http://www.eden.com/~chelly


[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Marco Dalla Gasperina" <marcodg@hp-vcd.vcd.hp.com>
Date: 1996/10/02
Raw View
Kevin Cline <kcline@i2.com> wrote in article
<l5hgoept2g.fsf@sc.i-have-a-misconfigured-system-so-shoot-me>...
>
> But what about the opposite case:
>
>    struct B { };
>    struct D : B { };
>
>    struct C {
>     typedef void (C::*action)( D& );
>
>     void mb( B& ) { }
>     void md( D& ) { }
>    };
>
>    void f( action ) { }
>
> It seems that
>  f(&C::mb )
> should be a legal call, with no cast required.  Is it?



Author: "Paul J. Lucas" <grumpy@wizard.arc.nasa.gov>
Date: 1996/09/26
Raw View
 Given:

  struct B { };
  struct D : B { };

  struct C {
   typedef void (C::*action)( B& );

   void mb( B& ) { }
   void md( D& ) { }
  };

  void f( action ) { }

 Is:

  f( (C::action)&C::md );

 a legal cast?  The pointer-to-member is of the same class and 2
 out of 3 C++ compilers agree that the cast is legal.  Is the
 3rd one wrong?

 - Paul J. Lucas
   NASA Ames Research Center  Caelum Research Corporation
   Moffett Field, California  San Jose, California


[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Marco Dalla Gasperina" <marcodg@hp-vcd.vcd.hp.com>
Date: 1996/09/27
Raw View
Paul J. Lucas <grumpy@wizard.arc.nasa.gov> wrote in article <pjl.843754146@wizard>...
>  Given:
>
>   struct B { };
>   struct D : B { };
>
>   struct C {
>    typedef void (C::*action)( B& );
>
>    void mb( B& ) { }
>    void md( D& ) { }
>   };
>
>   void f( action ) { }
>
>  Is:
>
>   f( (C::action)&C::md );
>
>  a legal cast?  The pointer-to-member is of the same class and 2
>  out of 3 C++ compilers agree that the cast is legal.  Is the
>  3rd one wrong?

>From the April DWP:

|  5.4  Explicit type conversion (cast notation)              [expr.cast]
|
|1 The result of the expression (T) cast-expression is  of  type  T.   An
|  explicit  type  conversion  can be expressed using functional notation
|  (_expr.type.conv_),  a   type   conversion   operator   (dynamic_cast,
|  static_cast, reinterpret_cast, const_cast), or the cast notation.
|          cast-expression:
|                  unary-expression
|                  ( type-id ) cast-expression
|
|2 Types shall not be defined in casts.
|
|3 Any  type conversion not mentioned below and not explicitly defined by
|  the user (_class.conv_) is ill-formed.
|
|4 The conversions performed by static_cast  (_expr.static.cast_),  rein
|  terpret_cast           (_expr.reinterpret.cast_),           const_cast
|  (_expr.const.cast_), or any sequence thereof, can be  performed  using
|  the  cast  notation  of  explicit  type conversion.  The same semantic
|  restrictions and behaviors apply.  If a given conversion can  be  per
|  formed  using  either static_cast or reinterpret_cast, the static_cast

To me, this says that if it can be done by reinterpret_cast<>() it is legal.
Again from the April DWP

|  5.2.9  Reinterpret cast                        [expr.reinterpret.cast]
|
|1 The  result  of the expression reinterpret_cast<T>(v) is the result of
|  converting the expression v to type T.  If T is a reference type,  the
|  result  is an lvalue; otherwise, the result is an rvalue.  Types shall
|  not be defined in a reinterpret_cast.  Conversions that  can  be  per
|  formed  explicitly  using reinterpret_cast are listed below.  No other
|  conversion can be performed explicitly using reinterpret_cast.

[2-9 elided]

|10An rvalue of type "pointer to member of X of type T1", can be  explic
|  itly  converted  to  an rvalue of type "pointer to member of Y of type
|  T2", if T1 and T2 are both function types or both data  member  types.

So, I think, it is legal. But not very smart...

Consider a definition of f():

void f( C::action mf )
{
    C c;
    B b;
    c.*mf(b); // this will call C::md with a 'B' parameter.  The
         // member probably assumes the extra capabilities of
              // a 'D' object but won't get them.
}

As usual, when one thinks they know more than the compiler, the compiler
will exact a revenge.

marco
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: paul.black@vf.vodafone.co.uk
Date: 1996/09/27
Raw View
Paul J. Lucas <grumpy@wizard.arc.nasa.gov> wrote:
>  Given:
>
>   struct B { };
>   struct D : B { };
>
>   struct C {
>    typedef void (C::*action)( B& );
>
>    void mb( B& ) { }
>    void md( D& ) { }
>   };
>
>   void f( action ) { }
>
>  Is:
>
>   f( (C::action)&C::md );
>
>  a legal cast?  The pointer-to-member is of the same class and 2
>  out of 3 C++ compilers agree that the cast is legal.  Is the
>  3rd one wrong?
>
>  - Paul J. Lucas
>    NASA Ames Research Center  Caelum Research Corporation
>    Moffett Field, California  San Jose, California

I'm not sure about legal, but the program is not working as you expect it it
does compile. Consider the following:

#include <iostream.h>

struct A { int a; };
struct B { int b; };
struct D : A, B { int d; };
struct C
{
    typedef void (C::*action)( B& );
    void mb( B& b) { cout << "B::b" << b.b << endl; }
    void md( D& d)
    {
        cout << "D::b " << d.b << endl;
        cout << "D::d " << d.d << endl;
    }
};

void f( C::action a)
{
    C   c;
    D   d;

    d.a = 1;
    d.b = 2;
    d.d = 3;

    (c.*a)(d);
}

int main()
{
    f( (C::action)&C::md );

    return (0);
}

The output of the above program is (HP v3.72 C++, gcc 2.7.2):
D::b 3
D::d 0

At "(c.*a)(d)" the compiler believes that it has a "(C::*action)( B& )" and
adjusts the "d" that is passed (performing a "(B &)d"). This means that when
"void md( D& d)" is called, the "d" actually references a "B" not a "D"

Paul
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Alexandre Oliva <oliva@dcc.unicamp.br>
Date: 1996/09/27
Raw View
>>>>> In  article       <pjl.843754146@wizard>,     "Paul  J.   Lucas"
>>>>> <grumpy@wizard.arc.nasa.gov> writes:

>   struct B { };
>   struct D : B { };

>   struct C {
>    typedef void (C::*action)( B& );
>    void md( D& ) { }
>   };
>   void f( C::action ) { }

>  Is:
>   f( (C::action)&C::md );
>  a legal cast?

This cast  is  not a valid  static_cast,  so the compiler would  use a
reinterpret_cast, that  is, the  resulting pointer-to-member  might be
unusable --- the result is implementation defined.  This means that:

// 1) conforming compilers should flag an error:
f( static_cast<C::action>(&C::md) );
// 2) implementation-defined results:
f( reinterpret_cast<C::action>(&C::md) );
// 3) equivalent to 2, since 1 is invalid
f( (C::action)(&C::md) );

--
Alexandre Oliva
mailto:oliva@dcc.unicamp.br
Universidade Estadual de Campinas, SP, Brasil


[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]