Topic: Proposal: member function pointer conversions


Author: bill@gibbons.org (Bill Gibbons)
Date: Mon, 10 Dec 2001 17:08:09 GMT
Raw View
In article <9uqbap$ha4$1@bob.news.rcn.net>, "David Abrahams"
<david.abrahams@rcn.com> wrote:

> Just as we have implicit conversions from "pointer to member of Base" to
> "pointer to member of Derived", it seems to me we should have an implicit
> conversion from "pointer to cv-qualified member function" to "pointer to
> cv-unqualified member function". In other words,
>
> struct X
> {
>     void f() const;
> };
>
> int g(void(X::*)());
>
> z = g(X::f); // currently illegal -- should it be?
>
> It seems to me that X::f can be safely applied anywhere a pointer to
> non-const member function is applicable.
>
> Having these conversions would save lots of code in libraries that traffic
> in member function pointers.

This seems reasonable, but it is a more significant change than it appears
to be.  The "const" attribute of a member function is not "const qualification"
in the sense of other const qualification.  For example:

   typedef void F();
   struct X {
      X f1;        // OK
      const X f2;  // ill-formed
   };

Rather, the "const" in a "const member function" declaration is an internal
attribute of the type, as if it had been added to the hidden "this" parameter
declaration.

So the proposed change is not a matter of just considering one more corner
case of const qualification because the conversion involves the function type
itself, not its qualification.  It is more like the special case of using a
pointer to member with an object pointer referring to an object of a type
derived from the PMF's type.

Both conversions could be considered to be relaxation of the rules on
conversion of pointers to functions.  If the "this" parameter were explicit,
the conversions would look like:

   struct B {
      void f(B *this};
   struct D : B {
      void g(const D *this);
   };

   // Would be allowed under 5.2.9/9 if "this" were explicit
   // The type of "this" changes from "B*" to "D*".
   void (D::*pf)(D *) = &B::f;

   // Proposed, if "this" were explicit.
   // The type of "this" changes from "const D*" to "D*".
   void (D::*pg)(D *) = &D::g;

(Note that the proposed change for the second case involves the opposite of
the usual implicit conversion, just as the rule for the first case involves
the opposite of the usual derived-to-base conversion.  This is the correct
rule for type safety.)

So one might argue that the proposed change simply adds the missing conversion
implied by 5.2.9/9.


But this would likely open the issue of whether to extend the conversion to
other function parameters:

   void f(const int *);
   void (*pf)(int *) = &f;

This seem harmless, but what about:

   void g(B *);
   void (*pg)(D *) = &g;

Now the use of "pg" involves converting the "D*" argument to "B*" at the
point of call.  For multiple inheritance this may require an offset
adjustment.  This quickly becomes impractical, especially when you consider
conversions involving multiple parameters.

So this looks like yet another subjective issue about how far to go down
this path:

   base => derived in PMF
                                      -- currently only the above is allowed
   non-const => const in PMF
                                      -- proposal moves the line to here
   non-const => const in fct params
                                      -- this is practical
   base => derived in fct params
                                      -- this is impractical

I think that only the original proposal deserves consideration.


(One last nit - "X::f" is not a pointer to member function; you must write this
as "&X::f".  At least one popular compiler accepts the former as an extension,
but conforming code must use the latter.)


-- Bill Gibbons
   bill@gibbons.org

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "David Abrahams" <david.abrahams@rcn.com>
Date: Fri, 7 Dec 2001 17:44:57 GMT
Raw View
Just as we have implicit conversions from "pointer to member of Base" to
"pointer to member of Derived", it seems to me we should have an implicit
conversion from "pointer to cv-qualified member function" to "pointer to
cv-unqualified member function". In other words,

struct X
{
    void f() const;
};

int g(void(X::*)());

z = g(X::f); // currently illegal -- should it be?

It seems to me that X::f can be safely applied anywhere a pointer to
non-const member function is applicable.

Having these conversions would save lots of code in libraries that traffic
in member function pointers.

-Dave

--
===================================================
  David Abrahams, C++ library designer for hire
 resume: http://users.rcn.com/abrahams/resume.html

        C++ Booster (http://www.boost.org)
          email: david.abrahams@rcn.com
===================================================



---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]