This is the mail archive of the gcc-prs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: c++/561


The following reply was made to PR c++/561; it has been noted by GNATS.

From: Martin Sebor <sebor@roguewave.com>
To: nathan@gcc.gnu.org
Cc: dmies@bluekite.com, gcc-gnats@gcc.gnu.org,
 	gudjon.gunnarsson@mscsoftware.com, nobody@gcc.gnu.org
Subject: Re: c++/561
Date: Mon, 25 Sep 2000 08:54:03 -0600

 This is a multi-part message in MIME format.
 --------------D5F3AF7BCC53F179709F993E
 Content-Type: text/plain; charset=us-ascii
 Content-Transfer-Encoding: 7bit
 
 nathan@gcc.gnu.org wrote:
 > 
 > Synopsis: Compiler Error Casting Overloaded Function Pointers
 > 
 > State-Changed-From-To: open->closed
 > State-Changed-By: nathan
 > State-Changed-When: Mon Sep 25 05:36:12 2000
 > State-Changed-Why:
 >     The code is ill-formed.
 >     [13.4]/1 enumerates when overload resolution is applied to
 >     address of member function. The last option applies here
 >     (an explicit type conversion). The paragraph states 'the
 >     function selected is the one whose type matches the target
 >     type required in the context' In this case `void (A::*)()'.
 >     Neither choice matches that type, so the diagnostic is
 >     required.
 > 
 >     You are attempting to perform both overload resolution and
 >     the downcast of a pointer-to-member in a single cast --
 >     that's too much for C++. Please let me know if the desired
 >     behaviour is explicitly documented as an extension in those
 >     compilers that accept it.
 
 No, it's not an extension, it's how the other implementers read the
 standard. Obviously, they're reading it differently from you. I posted a
 question to c++std-core@research.att.com to get a consensus from the
 core group of the ISO committee and apparently even they can't agree on
 the same interpretation (read the attachments). The resolution of the
 problem will be the subject of a new core issue.
 
 Regards
 Martin
 
 > 
 > http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view&pr=561&database=gcc
 --------------D5F3AF7BCC53F179709F993E
 
 Received: from blowfish.cvo.roguewave.com (ext-mail.roguewave.com [172.17.40.67]) by cvo-exchange.cvo.roguewave.com with SMTP (Microsoft Exchange Internet Mail Service Version 5.5.2650.21)
 	id Q1JNLLBH; Fri, 22 Sep 2000 13:54:35 -0700
 Received: from mail-blue.research.att.com (mail-blue.research.att.com [135.207.30.102])
 	by blowfish.cvo.roguewave.com (8.11.0/8.11.0) with ESMTP id e8ML4iJ35152
 	for <c++std@roguewave.com>; Fri, 22 Sep 2000 14:04:45 -0700 (PDT)
 Received: from raptor.research.att.com (raptor.research.att.com [135.207.23.32])
 	by mail-blue.research.att.com (Postfix) with ESMTP id BE04F4CE09
 	for <c++std@roguewave.com>; Fri, 22 Sep 2000 17:01:18 -0400 (EDT)
 Received: from research.att.com (daemon@localhost)
 	by raptor.research.att.com (980427.SGI.8.8.8/8.8.7) with UUCP id RAA62675
 	for c++std@roguewave.com; Fri, 22 Sep 2000 17:01:18 -0400 (EDT)
 Received: from mail-blue.research.att.com (mail-blue.research.att.com [135.207.30.102])
 	by raptor.research.att.com (980427.SGI.8.8.8/8.8.7) with ESMTP id RAA64163
 	for <c++std-core@raptor.research.att.com>; Fri, 22 Sep 2000 17:00:12 -0400 (EDT)
 Received: by mail-blue.research.att.com (Postfix)
 	id 99BCE4CE15; Fri, 22 Sep 2000 17:00:12 -0400 (EDT)
 Received: from relay.ondisplay.com (relay.ondisplay.com [38.170.243.52])
 	by mail-blue.research.att.com (Postfix) with ESMTP id 3FB794CE7D
 	for <c++std-core@research.att.com>; Fri, 22 Sep 2000 17:00:11 -0400 (EDT)
 Received: from wmmVAIO ([10.37.1.190])
 	by relay.ondisplay.com (Switch-2.0.0/Switch-2.0.0) with SMTP id e8MKx0R01761
 	for <c++std-core@research.att.com>; Fri, 22 Sep 2000 13:59:01 -0700
 From: "William M Miller" <wmm@fastdial.net>
 Errors-To: c++std-postmaster@research.att.com
 Reply-To: c++std-core@research.att.com
 Sender: c++std=core@research.att.com
 Precedence: list
 Transport-Options: /ignore
 Delivered-To: c++std-core@research.att.com
 Message-ID: <011401c024d8$3abd6340$be01250a@ondisplay>
 References: <39CBBDD4.C7389B2C@roguewave.com>
 Subject: Re: question about pointer-to-member conversions
 Date: Fri, 22 Sep 2000 17:00:59 -0400
 MIME-Version: 1.0
 Content-Type: text/plain;
 	charset="iso-8859-1"
 Content-Transfer-Encoding: 7bit
 X-Priority: 3
 X-MSMail-Priority: Normal
 X-Mailer: Microsoft Outlook Express 5.00.2919.6600
 X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2919.6600
 
 To: C++ core language mailing list
 Message c++std-core-8910
 
 From: "Martin Sebor" <sebor@roguewave.com>
 > Message c++std-core-8908
 > 
 > I'm wondering if everyone agrees that the program below is well formed
 > and has defined behavior due to 5.2.9, p9 (since A is a base of the the
 > class containing the member, the behavior isn't undefined).
 > 
 > I discussed this with several compiler vendors each of whom reads the
 > standard differently. The argument against the validity of the program
 > is 13.4, p1 (the target of the cast doesn't match either of the
 > overloaded functions) and  13.4, p7 (no standard conversion from (void
 > (B::*)() to (void (A::*)()).
 > 
 > This code is apparently being used in MFC and is causing portability
 > problems.
 > 
 > Thanks
 > Martin
 > 
 > class A { }; 
 > 
 > struct B : public A
 > { 
 >     void foo (); 
 >     void foo (int);
 > }; 
 > 
 > 
 > int main ()
 > {
 >     void (A::*f)() = (void (A::*)())&B::foo;
 > }
 
 I think it's well-formed.  13.4p3 says,
 
         the function type of the pointer-to-member is used to select
         the member function from the set of overloaded member functions.
 
 The class to which a member function belongs is not part of its
 "function type" -- only its return type, parameter type list, and
 cv-qualifier-seq (8.3.5p4).  Thus the cast, even though it's a pointer
 to member of the wrong class, still selects B::foo() from the overload
 set.  13.4p1 should be regarded as a general statement ("...type
 matches the target type..."), where 13.4p4 explains what it means for
 the types to match in the context of pointers to member functions.
 13.4p7 clearly doesn't apply, IMHO -- I don't see any need for a
 standard conversion inside an explicit conversion expression.
 
 (BTW, it would be well-formed even if A were not a base class of B: the
 old-style cast would simply be equivalent to a reinterpret_cast, which
 permits pointer-to-member conversions between members of unrelated
 classes; see 5.2.10p9 and 5.4p5.  The behavior would be unspecified but
 not undefined.)
 
 -- Mike Miller
 
 --------------D5F3AF7BCC53F179709F993E
 
 Received: from blowfish.cvo.roguewave.com (ext-mail.roguewave.com [172.17.40.67]) by cvo-exchange.cvo.roguewave.com with SMTP (Microsoft Exchange Internet Mail Service Version 5.5.2650.21)
 	id Q1JNLLJV; Fri, 22 Sep 2000 14:53:22 -0700
 Received: from mail-blue.research.att.com (mail-blue.research.att.com [135.207.30.102])
 	by blowfish.cvo.roguewave.com (8.11.0/8.11.0) with ESMTP id e8MM3VJ36009
 	for <c++std@roguewave.com>; Fri, 22 Sep 2000 15:03:32 -0700 (PDT)
 Received: from raptor.research.att.com (raptor.research.att.com [135.207.23.32])
 	by mail-blue.research.att.com (Postfix) with ESMTP id EF9674CE6A
 	for <c++std@roguewave.com>; Fri, 22 Sep 2000 18:00:00 -0400 (EDT)
 Received: from research.att.com (daemon@localhost)
 	by raptor.research.att.com (980427.SGI.8.8.8/8.8.7) with UUCP id SAA08594
 	for c++std@roguewave.com; Fri, 22 Sep 2000 18:00:00 -0400 (EDT)
 Received: from mail-green.research.att.com (mail-green.research.att.com [135.207.30.103])
 	by raptor.research.att.com (980427.SGI.8.8.8/8.8.7) with ESMTP id RAA95745
 	for <c++std-core@raptor.research.att.com>; Fri, 22 Sep 2000 17:59:00 -0400 (EDT)
 Received: by mail-green.research.att.com (Postfix)
 	id D955C1E025; Fri, 22 Sep 2000 17:58:55 -0400 (EDT)
 Received: from proxy4.ba.best.com (proxy4.ba.best.com [206.184.139.15])
 	by mail-green.research.att.com (Postfix) with ESMTP id 1AD911E020
 	for <c++std-core@research.att.com>; Fri, 22 Sep 2000 17:58:55 -0400 (EDT)
 Received: from [172.16.1.128] (pixo130.pixo.com [209.157.247.130])
 	by proxy4.ba.best.com (8.9.3/8.9.2/best.out) with ESMTP id OAA27218
 	for <c++std-core@research.att.com>; Fri, 22 Sep 2000 14:57:25 -0700 (PDT)
 From: Bill Gibbons <bill@gibbons.org>
 Errors-To: c++std-postmaster@research.att.com
 Reply-To: c++std-core@research.att.com
 Sender: c++std=core@research.att.com
 Precedence: list
 Transport-Options: /ignore
 Delivered-To: c++std-core@research.att.com
 Mime-Version: 1.0
 X-Sender: bgibbons@shell7.ba.best.com
 Message-Id: <v04210100b5f17cc9e5ff@[172.16.1.128]>
 In-Reply-To: <39CBBDD4.C7389B2C@roguewave.com>
 References: <39CBBDD4.C7389B2C@roguewave.com>
 Date: Fri, 22 Sep 2000 14:57:11 -0700
 Subject: Re: question about pointer-to-member conversions
 Content-Type: text/plain; charset="us-ascii"
 
 To: C++ core language mailing list
 Message c++std-core-8911
 
 >In core-8908 Martin Sebor wrote:
 >
 >I'm wondering if everyone agrees that the program below is well formed
 >and has defined behavior due to 5.2.9, p9 (since A is a base of the the
 >class containing the member, the behavior isn't undefined).
 >
 >I discussed this with several compiler vendors each of whom reads the
 >standard differently. The argument against the validity of the program
 >is 13.4, p1 (the target of the cast doesn't match either of the
 >overloaded functions) and  13.4, p7 (no standard conversion from (void
 >(B::*)() to (void (A::*)()).
 >
 >class A { }; 
 >
 >struct B : public A
 >{ 
 >    void foo (); 
 >    void foo (int);
 >}; 
 >
 >int main ()
 >{
 >    void (A::*f)() = (void (A::*)())&B::foo;
 >}
 
 This looks ill-formed to me.  The sentence in 13.4p1:
   
    The function selected is the one whose type matches the target type
    required in the context.
 
 seems to forbid the above cast.  The wording could be better since the
 phrase "target type required in the context" is not an ideal way to describe
 the fact that the type in the cast may be pointer to function, reference
 to function, or pointer to member function.
 
 One could argue that in the case of pointer to member function, the function
 type itself is independent of the class type, so there is still a match.
 But I think this is an accident due to vague wording, and was not the
 intention of the paragraph.
 
 I think the intent was:
 
    The function selected is the one which will make the effect of the cast
    be that of the identity conversion.
 
 which would certainly disallow the example code.  This is worth clarifying.
 
 
 BTW, 13.4p7 does not apply since this is not a pointer to function.
 
 
 There is an interesting situation with using-declarations.  If a base class
 member function is present in the overload set in a derived class due to a
 using-declaration, it is treated as if it were a derived class member
 function for purposes of overload resolution in a call:
 
 From 13.3.1p4:
 
   For non-conversion functions introduced by a using-declaration into a
   derived class, the function is considered to be a member of the derived
   class for the purpose of defining the type of the implicit object
   parameter
 
 There is no corresponding rule for casts. Such a rule would be practical,
 but if the base class member function were selected it would not have the
 same class as that specified in the cast.  Since base-to-derived
 pointer to member conversions are implicit conversions, it would seem
 reasonable to perform this conversion implicitly in this case, so that
 the result of the cast has the right type.  The usual ambiguity and access
 restrictions on the base-to-derived conversion would not apply since
 they do no apply to calling through the using-declaration either.
 
 On the other hand, if there is no special case for this, we end up with
 the bizzare case:
 
     struct A {
         void foo();
     };
     struct B : A {
         using A::foo;
         void foo(int);
     }
     int main() {
 	// Works because "B::foo" contains A::foo() in its overload set.
         (void (A::*)())&B::foo;
 	// Does not work because "B::foo(int)" does not match the cast.
         (void (A::*)(int))&B::foo;
     }
 
 I think the standard should be clarified by either:
 
   * Adding a note to 13.4 saying that using-declarations do not participate
     in this kind of overload resolution; or
 
   * Modifying 13.4 saying that using-declarations are treated as members
     of the derived class for matching purposes, and if selected, the
     resulting pointer to member is implicitly converted to the derived
     type with no access or ambiguity errors.  (The using-declaration itself
     has already addressed both of these areas.)
 
 
 Mike Miller replied:
 >(BTW, it would be well-formed even if A were not a base class of B: the
 >old-style cast would simply be equivalent to a reinterpret_cast, which
 >permits pointer-to-member conversions between members of unrelated
 >classes; see 5.2.10p9 and 5.4p5.  The behavior would be unspecified but
 >not undefined.)
 
 No, because reinterpret-casts do not apply in overload contexts.
 
 
 -- Bill Gibbons
 
 --------------D5F3AF7BCC53F179709F993E
 
 Received: from blowfish.cvo.roguewave.com (ext-mail.roguewave.com [172.17.40.67]) by cvo-exchange.cvo.roguewave.com with SMTP (Microsoft Exchange Internet Mail Service Version 5.5.2650.21)
 	id Q1JNLP2L; Mon, 25 Sep 2000 05:52:07 -0700
 Received: from mail-blue.research.att.com (mail-blue.research.att.com [135.207.30.102])
 	by blowfish.cvo.roguewave.com (8.11.0/8.11.0) with ESMTP id e8PD2BJ54732
 	for <c++std@roguewave.com>; Mon, 25 Sep 2000 06:02:12 -0700 (PDT)
 Received: from raptor.research.att.com (raptor.research.att.com [135.207.23.32])
 	by mail-blue.research.att.com (Postfix) with ESMTP id C0D884CEA0
 	for <c++std@roguewave.com>; Mon, 25 Sep 2000 08:58:53 -0400 (EDT)
 Received: from research.att.com (daemon@localhost)
 	by raptor.research.att.com (980427.SGI.8.8.8/8.8.7) with UUCP id IAA88775
 	for c++std@roguewave.com; Mon, 25 Sep 2000 08:58:53 -0400 (EDT)
 Received: from mail-blue.research.att.com (mail-blue.research.att.com [135.207.30.102])
 	by raptor.research.att.com (980427.SGI.8.8.8/8.8.7) with ESMTP id IAA44015
 	for <c++std-core@raptor.research.att.com>; Mon, 25 Sep 2000 08:57:47 -0400 (EDT)
 Received: by mail-blue.research.att.com (Postfix)
 	id 9879A4CE9C; Mon, 25 Sep 2000 08:57:47 -0400 (EDT)
 Received: from relay.ondisplay.com (relay.ondisplay.com [38.170.243.52])
 	by mail-blue.research.att.com (Postfix) with ESMTP id B34CB4CE9A
 	for <c++std-core@research.att.com>; Mon, 25 Sep 2000 08:57:38 -0400 (EDT)
 Received: from wmmVAIO ([10.37.1.118])
 	by relay.ondisplay.com (Switch-2.0.0/Switch-2.0.0) with SMTP id e8PCuQR18211
 	for <c++std-core@research.att.com>; Mon, 25 Sep 2000 05:56:31 -0700
 From: "William M Miller" <wmm@fastdial.net>
 Errors-To: c++std-postmaster@research.att.com
 Reply-To: c++std-core@research.att.com
 Sender: c++std=core@research.att.com
 Precedence: list
 Transport-Options: /ignore
 Delivered-To: c++std-core@research.att.com
 Message-ID: <016d01c026f0$5a14e820$be01250a@ondisplay>
 References: <39CBBDD4.C7389B2C@roguewave.com> <v04210100b5f17cc9e5ff@[172.16.1.128]>
 Subject: Re: question about pointer-to-member conversions
 Date: Mon, 25 Sep 2000 08:58:41 -0400
 MIME-Version: 1.0
 Content-Type: text/plain;
 	charset="iso-8859-1"
 Content-Transfer-Encoding: 7bit
 X-Priority: 3
 X-MSMail-Priority: Normal
 X-Mailer: Microsoft Outlook Express 5.00.2919.6600
 X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2919.6600
 
 To: C++ core language mailing list
 Message c++std-core-8913
 
 From: "Bill Gibbons" <bill@gibbons.org>
 > Message c++std-core-8911
 >
 > This looks ill-formed to me.  The sentence in 13.4p1:
 >
 >    The function selected is the one whose type matches the target type
 >    required in the context.
 >
 > seems to forbid the above cast.  The wording could be better since the
 > phrase "target type required in the context" is not an ideal way to
 describe
 > the fact that the type in the cast may be pointer to function, reference
 > to function, or pointer to member function.
 >
 > One could argue that in the case of pointer to member function, the
 function
 > type itself is independent of the class type, so there is still a match.
 > But I think this is an accident due to vague wording, and was not the
 > intention of the paragraph.
 >
 > I think the intent was:
 >
 >    The function selected is the one which will make the effect of the cast
 >    be that of the identity conversion.
 >
 > which would certainly disallow the example code.  This is worth
 clarifying.
 
 I wasn't involved in the creation of this wording, so I can't speak to
 the intent.  However, the "identity conversion" reading seems to me to
 be overly restrictive.  It would lead to the following:
 
         struct B {
             void f();
             void f(int);
         };
         struct D: B { };
         void (D::* p1)() = &D::f;                   // ill-formed
         void (D::* p2)() = (void (B::*)()) &D::f;   // okay
 
 I would find the need for an explicit cast here surprising, since the
 downcast is a standard conversion and since the declaration of "p1"
 certainly has enough information to disambiguate the overload set.
 (This also relates with the issue we have open about whether the type
 of an address-of-member function should reflect the class in which the
 member is declared or the nested-name-specifier used in the expression.)
 
 I think this example supplies a rationale for the use of the "function
 type" (as opposed to just "type") wording in 13.4p3, i.e., that it could
 be deliberate and not just "an accident due to vague wording."
 
 I'll open an issue.
 
 > There is an interesting situation with using-declarations.  If a base
 class
 > member function is present in the overload set in a derived class due to a
 > using-declaration, it is treated as if it were a derived class member
 > function for purposes of overload resolution in a call:
 >
 > >From 13.3.1p4:
 >
 >   For non-conversion functions introduced by a using-declaration into a
 >   derived class, the function is considered to be a member of the derived
 >   class for the purpose of defining the type of the implicit object
 >   parameter
 >
 > There is no corresponding rule for casts. Such a rule would be practical,
 > but if the base class member function were selected it would not have the
 > same class as that specified in the cast.  Since base-to-derived
 > pointer to member conversions are implicit conversions, it would seem
 > reasonable to perform this conversion implicitly in this case, so that
 > the result of the cast has the right type.  The usual ambiguity and access
 > restrictions on the base-to-derived conversion would not apply since
 > they do no apply to calling through the using-declaration either.
 >
 > On the other hand, if there is no special case for this, we end up with
 > the bizzare case:
 >
 >     struct A {
 >         void foo();
 >     };
 >     struct B : A {
 >         using A::foo;
 >         void foo(int);
 >     }
 >     int main() {
 > // Works because "B::foo" contains A::foo() in its overload set.
 >         (void (A::*)())&B::foo;
 > // Does not work because "B::foo(int)" does not match the cast.
 >         (void (A::*)(int))&B::foo;
 >     }
 >
 > I think the standard should be clarified by either:
 >
 >   * Adding a note to 13.4 saying that using-declarations do not
 participate
 >     in this kind of overload resolution; or
 
 I would find this _very_ counterintuitive -- that you could call it via
 the derived class but not take its address in the derived class.
 
 >   * Modifying 13.4 saying that using-declarations are treated as members
 >     of the derived class for matching purposes, and if selected, the
 >     resulting pointer to member is implicitly converted to the derived
 >     type with no access or ambiguity errors.  (The using-declaration
 itself
 >     has already addressed both of these areas.)
 
 I didn't follow this completely.  What is the purpose of the implicit
 conversion to the derived type?  You said above "so that the result of
 the cast has the right type," but I would have expected the result of the
 cast to have the right type (the type specified in the cast) anyway.
 (I'm afraid this would exacerbate the confusion that already exists
 regarding the type of an address-of-member expression.)
 
 > Mike Miller replied:
 > >(BTW, it would be well-formed even if A were not a base class of B: the
 > >old-style cast would simply be equivalent to a reinterpret_cast, which
 > >permits pointer-to-member conversions between members of unrelated
 > >classes; see 5.2.10p9 and 5.4p5.  The behavior would be unspecified but
 > >not undefined.)
 >
 > No, because reinterpret-casts do not apply in overload contexts.
 
 Could you point me to the reference for this?  Or is it an implication
 of the "identity conversion" interpretation?
 
 -- Mike Miller
 
 
 --------------D5F3AF7BCC53F179709F993E--
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]