Title
Ambiguity assigning class object to built-in type
Status
dup
Section
12.5 [over.built]
Submitter
Steve Adamczyk

Created on 2005-03-09.00:00:00 last changed 173 months ago

Messages

Date: 2010-08-15.00:00:00

Rationale (August, 2010):

Duplicate of issue 260.

Date: 2008-05-15.00:00:00

Additional note (May, 2008):

Here is another example that is somewhat similar:

    enum En { ec };

    struct S {
       operator int();
       operator En();
    };

    void foo () {
       S() == 0;   // ambiguous?
    }

According to 12.5 [over.built] paragraph 12, the candidate functions are

    bool operator==(L, R);

where R is int and L is every promoted arithmetic type. Overload resolution proceeds in two steps: first, for each candidate function, determine which implicit conversion sequence is used to convert from the argument type to the parameter type; then compare the candidate functions on the basis of the relative costs of those conversion sequences.

In the case of operator==(int, int) there is a clear winner: S::operator int() is chosen because the identity conversion int -> int is better than the promotion En -> int. For all the other candidates, the conversion for the first parameter is ambiguous: both S::operator int() and S::operator En() require either an integral conversion (for integral L) or a floating-integral conversion (for floating point L) and are thus indistinguishable.

These additional candidates are not removed from the set of viable functions, however; because of 12.2.4.2 [over.best.ics] paragraph 10, they are assigned the “ambiguous conversion sequence,” which “is treated as a user-defined sequence that is indistinguishable from any other user-defined conversion sequence.” As a result, all the viable functions are indistinguishable and the call is ambiguous. Like the earlier example, one might naively think that the exact match with S::operator int() and bool operator==(int, int) would be selected, but that is not the case.

Date: 2010-08-23.00:00:00

The following example is ambiguous according to the Standard:

    struct Y {
      operator int();
      operator double();
    };
    void f(Y y) {
      double d;
      d = y;    // Ambiguous: Y::operator int() or Y::operator double()?
    }

The reason for the ambiguity is that 12.5 [over.built] paragraph 18 says that there are candidate functions double& operator=(double&, int) and double& operator=(double&, double) (among others). In each case, the second argument is converted by a user-defined conversion sequence (12.2.4.2.3 [over.ics.user]) where the initial and final standard conversion sequences are the identity conversion — i.e., the conversion sequences for the second argument are indistinguishable for each of these candidate functions, and they are thus ambiguous.

Intuitively one might expect that, because it converts directly to the target type in the assignment, Y::operator double() would be selected, and in fact, most compilers do select it, but there is currently no rule to distinguish between these user-defined conversions. Should there be?

History
Date User Action Args
2010-08-23 00:00:00adminsetmessages: + msg2962
2010-08-23 00:00:00adminsetstatus: open -> dup
2008-06-29 00:00:00adminsetmessages: + msg1711
2005-03-09 00:00:00admincreate