This is the mail archive of the
gcc-prs@gcc.gnu.org
mailing list for the GCC project.
Re: c++/561
- To: nobody at gcc dot gnu dot org
- Subject: Re: c++/561
- From: Martin Sebor <sebor at roguewave dot com>
- Date: 25 Sep 2000 14:56:01 -0000
- Cc: gcc-prs at gcc dot gnu dot org,
- Reply-To: Martin Sebor <sebor at roguewave dot com>
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--