Topic: unwanted ambiguity with user-defined conversion and built-inoperator=


Author: "Andrei Iltchenko" <iltchenko@yahoo.com>
Date: Mon, 30 Apr 2001 02:39:26 GMT
Raw View
Martin Sebor <sebor@roguewave.com> wrote in message
news:3AEA1FC4.989E2960@roguewave.com...
> scott douglass wrote:
> >
> > Hello,
> >
> > This is closely related to core issue #260
> > <http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/cwg_active.html#260> but is
not
> > resolved by the suggested resolution there.
> >
> > Given:
> >
> > struct T {
> >      operator int() const;
> >      operator double() const;
> > };
> >
> > I believe the standard requires the following assignment to be ambiguous
> > (even though I expect that would surprise the user):
> >
> > double x;
> > void f(const T& t) { x = t; }
> >
> > The problem is that both of these built-in operator=()s exist (13.6/18
> > [over.built]):
> >          double& operator=(double&, int);
> >          double& operator=(double&, double);
> >
> > Both are an exact match on the first argument and a user conversion on
the
> > second.  There is no rule that says one is a better match than the
other.
> >
> > The compilers that I have tried (even in their strictest setting) do not
> > give a peep.  I think they are not following the standard.  They pick
> > double& operator=(double&, double) and use T::operator double() const.
> >
> > Can you find a rule in the standard that makes one a better match than
the
> > other?
>
>         SCS   UDC        SCS
> UCS1: T ==> T ==> int    ==> double [Identity, UDC, Conversion]
> UCS2: T ==> T ==> double ==> double [Identity, UDC, Identity]
>
> Wouldn't 13.3.3.1.2, p2 and 13.3.3, p1, bullet 6 cover this case?
> I.e., user-defined conversion followed by an identity is a better
> conversion sequence than a UDC followed by a conversion.

No, they are not pertinent in this case. Because 'x = t' is not a
declaration-statement but is an expression-statement.
> double x;
> void f(const T& t) { x = t; }
I.e. 'x = t' is not an initialization of 'x' but is an assignment to it.
13.3.3, p1, bullet 6, which in turn refers to 13.3.1.5, speaks only about
initialization. Your reasoning would've been correct had the example
provided by Scott read:
void f(const T& t) { double x = t; }
but that is not the case.

>From the set of candidate functions for the assignment expression 'x = t',
which are all built-in candidates, the following two viable functions
double& operator=(double&, int);
double& operator=(double&, double);
provide a better match than the rest of the viable functions like:
double& operator=(double&, unsigned);

However, none of the two functions provide a better match than the other,
which renders the assignment ill-formed.

For both the functions the implicit conversion sequences are:
ICS1: the identity conversion;
ICS2: a user-defined conversion (neither followed nor preceded by any
standard conversion sequence).


Regards,

Andrei Iltchenko.



---
[ 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: "Andrei Iltchenko" <iltchenko@yahoo.com>
Date: Wed, 2 May 2001 20:28:59 GMT
Raw View
Martin Sebor <sebor@roguewave.com> wrote in message
news:3AEF7B6B.638F0A29@roguewave.com...
> Andrei Iltchenko wrote:
> >
> ...
> > > > I believe the standard requires the following assignment to be
ambiguous
> > > > (even though I expect that would surprise the user):
> > > >
> > > > double x;
> > > > void f(const T& t) { x = t; }
> > > >
> > > > The problem is that both of these built-in operator=()s exist
(13.6/18
> > > > [over.built]):
> > > >          double& operator=(double&, int);
> > > >          double& operator=(double&, double);
> > > >
> > > > Both are an exact match on the first argument and a user conversion
on
> > the
> > > > second.  There is no rule that says one is a better match than the
> > other.
> ...
> > >
> > >         SCS   UDC        SCS
> > > UCS1: T ==> T ==> int    ==> double [Identity, UDC, Conversion]
> > > UCS2: T ==> T ==> double ==> double [Identity, UDC, Identity]
> > >
> > > Wouldn't 13.3.3.1.2, p2 and 13.3.3, p1, bullet 6 cover this case?
> > > I.e., user-defined conversion followed by an identity is a better
> > > conversion sequence than a UDC followed by a conversion.
> >
> > No, they are not pertinent in this case. Because 'x = t' is not a
> > declaration-statement but is an expression-statement.
> > > double x;
> > > void f(const T& t) { x = t; }
> > I.e. 'x = t' is not an initialization of 'x' but is an assignment to it.
> > 13.3.3, p1, bullet 6, which in turn refers to 13.3.1.5, speaks only
about
> > initialization. Your reasoning would've been correct had the example
> > provided by Scott read:
> > void f(const T& t) { double x = t; }
> > but that is not the case.
>
> Hmmm, I wonder then what 13.3.3.1.2, p2 means by
>
> "Since an implicit conversion sequence is an initialization, the special
rules
> for initialization by user-defined conversion apply when selecting the
best
> user-defined conversion for a user-defined conversion sequence (see 13.3.3
and
> 13.3.3.1)."

This is again not to the point. Implicit conversion sequences will be
considered only once a set of candidate functions has been identified!
> > > > double x;
> > > > void f(const T& t) { x = t; }
And for the expression 'x = t' only built-in candidates are considered (See
the previous posting). Implicit conversion sequences will then be used to
convert each expression from the argument list to the type of the
corresponding parameter.


> > From the set of candidate functions for the assignment expression 'x =
t',
> > which are all built-in candidates, the following two viable functions
> > double& operator=(double&, int);
> > double& operator=(double&, double);
> > provide a better match than the rest of the viable functions like:
> > double& operator=(double&, unsigned);
> >
> > However, none of the two functions provide a better match than the
other,
> > which renders the assignment ill-formed.
>
> I have learned that that if most compilers (and thus their implementers)
> don't consider something ill-formed, there's a good chance it isn't (or
> it isn't intended to be, in which case Scott may have another issue to
> write up :)

Take a look at a program below.

#include <iostream>

int  main()
{
   int   export = 6;
   std::cout << export << '\n';
   return  0;
}

Can you think of a compiler that will consider it ill-formed? I wasn't able
to find one. Does that mean that the above program is well-formed and
doesn't violate the semantic rules of the language?


Cheers,

Andrei Iltchenko.



---
[ 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                ]