public inbox for gcc-prs@sourceware.org
help / color / mirror / Atom feed
* Re: c++/3708: [2003-01-02] static_cast between classes finds ambiguous base conversion
@ 2003-05-01  1:26 P Hornby
  0 siblings, 0 replies; 4+ messages in thread
From: P Hornby @ 2003-05-01  1:26 UTC (permalink / raw)
  To: nobody; +Cc: gcc-prs

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

From: P Hornby <p.hornby@ned.dem.csiro.au>
To: Giovanni Bajo <giovannibajo@libero.it>
Cc: gcc-gnats@gcc.gnu.org, gcc-bugs@gcc.gnu.org, nobody@gcc.gnu.org,
   gcc-prs@gcc.gnu.org, nathan@gcc.gnu.org
Subject: Re: c++/3708: [2003-01-02] static_cast between classes finds ambiguous
 base conversion
Date: Thu, 01 May 2003 09:16:19 +0800

 Long ago I eliminated the template, to get
 
 class Foo
 {
 public:
      Foo() {}
      Foo(int) {}
   };
 
 class B
 {
 public:
     B() {}
 
     operator int () { return 1; }
 };
 
 class D : public B
 {
 public:
     D () {}
 
     operator Foo () { return Foo(1); };
 };
 
 int main()
 {
     D d;
     Foo foo = (Foo) d;
     return 0;
 }
 
 
 I seem to recall that D's methods are to be preferred over any of B's in 
 the event of such conflicts. I also recall something that implied that 
 such conflict resolution had a limit on the complexity, and that this 
 limit was greater than a single direct call to a method of a class. I 
 think it was in BS's C++ ANSI book, but it was so long ago that I 
 forget. In any case, the template version of the conflict is excluded on 
 the grounds that the D::operator Foo() -> Foo::Foo(const Foo&) requires 
 no template instantiation. (under the rule that the less instantiated 
 resolution yields to the more instantiated (in this case explict) 
 resolution). This would be the case if the conflict were to arise from a 
 D::operator T(), so why break the rule for B::operator T()? (I know why 
 the compiler is doing this, and it is very hard to fix. I understand why 
 you are keen to close it).
 
 As I've stated elsewhere g++ (and now Comeau) are the only compilers I 
 have encountered that do not resolve this conflict. I only ask that you 
 consider this once more before closing it. (You may run into a language 
 lawyer next time).
 
 
 
 
 
 > http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gcc&pr=3708
 > 
 > I think there is nothing wrong with this. Nathan's epurated code (for
 > reference) is:
 > -----------------------------------------
 > class Foo
 > {
 > public:
 >    Foo() {}
 >    Foo(int) {}
 > };
 > 
 > class B
 > {
 > public:
 >    B() {}
 > 
 >    template <class T>
 >    operator T () { return T (); }
 > };
 > 
 > class D : public B
 > {
 > public:
 >    D () {}
 > 
 >    operator Foo () { return Foo (); };
 > };
 > 
 > int main()
 > {
 >    D d;
 >    static_cast <Foo> (d);
 >    return 0;
 > }
 > 
 > -----------------------------------------
 > pr3708.cpp: In function `int main()':
 > pr3708.cpp:39: error: call of overloaded `Foo(D&)' is ambiguous
 > pr3708.cpp:4: note: candidates are: Foo::Foo(const Foo&)
 > pr3708.cpp:7: note:                 Foo::Foo(int)
 > 
 > It makes sense to me, because there are two ways the compiler can perform
 > the conversion:
 > 
 > 1) using D::operator Foo(), and then calling the implicit copy constructor
 > Foo::Foo(const Foo&)
 > 2) using template <class T> B::operator T(), specialized as B::operator
 > int(), and then calling the constructor Foo::Foo(int)
 > 
 > The two ways look both perfectly feasable to me, so I think this is not a
 > bug. As a further confirmation, Comeau rejects the code in the same way.
 > 
 > If no language lawyer objects, I will close this PR.
 > 
 > Giovanni Bajo
 
 
 


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: c++/3708: [2003-01-02] static_cast between classes finds ambiguous base conversion
@ 2003-05-02 11:35 giovannibajo
  0 siblings, 0 replies; 4+ messages in thread
From: giovannibajo @ 2003-05-02 11:35 UTC (permalink / raw)
  To: gcc-bugs, gcc-prs, nobody, p.hornby

Synopsis: [2003-01-02] static_cast between classes finds ambiguous base conversion

State-Changed-From-To: analyzed->closed
State-Changed-By: bajo
State-Changed-When: Fri May  2 11:35:49 2003
State-Changed-Why:
    Not a bug (agreed with the original poster). See also the
    post on comp.std.c++.
    
    http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&threadm=vb2vhkpkrg5o17%40corp.supernews.com&rnum=11&prev=/groups%3Fq%3Dcomp.std.c%252B%252B%2Bgiovanni%2Bbajo%26start%3D10%26hl%3Den%26lr%3D%26ie%3DUTF-8%26oe%3DUTF-8%26selm%3Dvb2vhkpkrg5o17%2540corp.supernews.com%26rnum%3D11

http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gcc&pr=3708


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: c++/3708: [2003-01-02] static_cast between classes finds ambiguous base conversion
@ 2003-05-01  1:56 Giovanni Bajo
  0 siblings, 0 replies; 4+ messages in thread
From: Giovanni Bajo @ 2003-05-01  1:56 UTC (permalink / raw)
  To: nobody; +Cc: gcc-prs

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 5658 bytes --]

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

From: "Giovanni Bajo" <giovannibajo@libero.it>
To: "P Hornby" <p.hornby@ned.dem.csiro.au>
Cc: <gcc-gnats@gcc.gnu.org>,
	<gcc-bugs@gcc.gnu.org>,
	<nobody@gcc.gnu.org>,
	<gcc-prs@gcc.gnu.org>,
	<nathan@gcc.gnu.org>
Subject: Re: c++/3708: [2003-01-02] static_cast between classes finds ambiguous base conversion
Date: Thu, 1 May 2003 03:55:04 +0200

 P Hornby <p.hornby@ned.dem.csiro.au> wrote:
 
 > Long ago I eliminated the template, to get
 >
 > class B
 > {
 > public:
 >     B() {}
 >
 >     operator int () { return 1; }
 > };
 >
 > class D : public B
 > {
 > public:
 >     D () {}
 >
 >     operator Foo () { return Foo(1); };
 > };
 
 Which is still ambigous for both GCC and Comeau.
 
 > I seem to recall that D's methods are to be preferred over any of B's in
 > the event of such conflicts.
 
 That would be very strange, I never heard of a situation where methods of
 the most derived class are preferred over members of a less derived class to
 resolve ambiguity.
 
 > I also recall something that implied that
 > such conflict resolution had a limit on the complexity, and that this
 > limit was greater than a single direct call to a method of a class.
 
 I am not sure about what you mean here.
 
 > forget. In any case, the template version of the conflict is excluded on
 > the grounds that the D::operator Foo() -> Foo::Foo(const Foo&) requires
 > no template instantiation. (under the rule that the less instantiated
 > resolution yields to the more instantiated (in this case explict)
 > resolution).
 
 I think you're slightly missing the point. There is no ambiguity between
 operator Foo() and template <class  T> operator T(). Let's go step by step.
 
 The compiler needs to convert "d" (of type D) to type Foo. Since Foo() has a
 constructor taking a parameter of type "int", the compiler knows that the
 conversion can be done directly (finding an user-defined conversion to Foo,
 and calling the copy constructor) or indirectly (finding an user-defined
 conversions to int and calling the custom constructor). In the standard,
 there is nothing on why a constructor might be preferred over the other, so
 the conversion to type Foo() is not "better" in any way to the conversion to
 type int, since both have an accessible constructor in Foo (the implicit
 copy constructor for the former, the explicit custom constructor for the
 latter).
 
 So, the compiler just found out it can try to convert to either Foo or int.
 It checks for custom conversion functions, and it finds two of them: a
 conversion to Foo, and a template conversion operator. One is in B and one
 is in D, but §12.3p5 says "[...]A conversion function in a derived class
 does not hide a conversion function in a base class unless the two functions
 convert to the same type[...]". So both of them are visible.
 First, let's say that the compiler tries to convert to int. The non-template
 operator obviously cannot be used, but the template operator can be
 instanciated with type int. So the compiler now know that there is an
 available conversion from D to int, through the template operator in B.
 Second, it tries to see if it's possible to convert Foo to int. In this
 case, the compiler finds that there is a non-template operator Foo() which
 can be used, but also a template operator that could be instanciated with
 type Foo. So what? Again §12.3p5: "Function overload resolution selects the
 best conversion function to perform the conversion". Thus, the compiler
 prefers the non-template version over the template one (for the usual
 overaload rules).
 
 As you see, the compiler ends up with two valid paths to perform the
 required conversion. One path goes through conversion to int (thanks to the
 custom constructor) and one path through conversion to Foo (thanks to the
 implicit copy constructor).
 
 > This would be the case if the conflict were to arise from a
 > D::operator T(), so why break the rule for B::operator T()? (I know why
 > the compiler is doing this, and it is very hard to fix. I understand why
 > you are keen to close it).
 
 No, it's wrong. Even if you move the template operator into D, there is
 still an ambiguity.
 In fact (again) the ambiguty is not about choosing between the non-template
 conversion operator and the template one. Remember that a group of
 conversion functions do not form an overload set. You seem to think as your
 code is in the same situation of:
 
 template <typename T>
 void foo(T a);
 
 void foo(int a);
 
 where the second overload is obviously preferred to the first if the
 function is called with a varible of type int. But here, the situation is
 different. There is no overload set. The ambiguity is between which
 constructor must be called! Both of them are accessible, both of them are
 reachable through custom conversion functions (which are not overloaded!
 they are different functions!), so there is no way to solve this ambiguity.
 
 To solve this as you think, there should be an explicit paragraph in the
 standard stating that, in case of ambiguity during a conversion, a
 conversion made through a non-template operator should be preferred over a
 conversion made through a template operator. But there is no such a rule.
 
 > As I've stated elsewhere g++ (and now Comeau) are the only compilers I
 > have encountered that do not resolve this conflict. I only ask that you
 > consider this once more before closing it. (You may run into a language
 > lawyer next time).
 
 Sure, there is no hurry. In case nobody helps us here, I'll bring the issue
 to comp.std.c++ soon.
 
 Giovanni Bajo
 


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: c++/3708: [2003-01-02] static_cast between classes finds ambiguous base conversion
@ 2003-04-30 21:16 Giovanni Bajo
  0 siblings, 0 replies; 4+ messages in thread
From: Giovanni Bajo @ 2003-04-30 21:16 UTC (permalink / raw)
  To: nobody; +Cc: gcc-prs

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

From: "Giovanni Bajo" <giovannibajo@libero.it>
To: <p.hornby@ned.dem.csiro.au>,
	<gcc-gnats@gcc.gnu.org>,
	<gcc-bugs@gcc.gnu.org>,
	<nobody@gcc.gnu.org>,
	<gcc-prs@gcc.gnu.org>
Cc: <nathan@gcc.gnu.org>
Subject: Re: c++/3708: [2003-01-02] static_cast between classes finds ambiguous base conversion
Date: Wed, 30 Apr 2003 23:07:22 +0200

 http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gcc&pr=3708
 
 I think there is nothing wrong with this. Nathan's epurated code (for
 reference) is:
 -----------------------------------------
 class Foo
 {
 public:
    Foo() {}
    Foo(int) {}
 };
 
 class B
 {
 public:
    B() {}
 
    template <class T>
    operator T () { return T (); }
 };
 
 class D : public B
 {
 public:
    D () {}
 
    operator Foo () { return Foo (); };
 };
 
 int main()
 {
    D d;
    static_cast <Foo> (d);
    return 0;
 }
 
 -----------------------------------------
 pr3708.cpp: In function `int main()':
 pr3708.cpp:39: error: call of overloaded `Foo(D&)' is ambiguous
 pr3708.cpp:4: note: candidates are: Foo::Foo(const Foo&)
 pr3708.cpp:7: note:                 Foo::Foo(int)
 
 It makes sense to me, because there are two ways the compiler can perform
 the conversion:
 
 1) using D::operator Foo(), and then calling the implicit copy constructor
 Foo::Foo(const Foo&)
 2) using template <class T> B::operator T(), specialized as B::operator
 int(), and then calling the constructor Foo::Foo(int)
 
 The two ways look both perfectly feasable to me, so I think this is not a
 bug. As a further confirmation, Comeau rejects the code in the same way.
 
 If no language lawyer objects, I will close this PR.
 
 Giovanni Bajo
 


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2003-05-02 11:35 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-05-01  1:26 c++/3708: [2003-01-02] static_cast between classes finds ambiguous base conversion P Hornby
  -- strict thread matches above, loose matches on Subject: below --
2003-05-02 11:35 giovannibajo
2003-05-01  1:56 Giovanni Bajo
2003-04-30 21:16 Giovanni Bajo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).