3
votes

According to c++ standard,

[over.best.ics]

4 However, if the target is

(4.1) — the first parameter of a constructor or

(4.2) — the implicit object parameter of a user-defined conversion function

      and the constructor or user-defined conversion function is a candidate by

(4.3) — 13.3.1.3, when the argument is the temporary in the second step of a class copy-initialization, or

(4.4) — 13.3.1.4, 13.3.1.5, or 13.3.1.6 (in all cases),

user-defined conversion sequences are not considered. [ Note: These rules prevent more than one user-defined conversion from being applied during overload resolution, thereby avoiding infinite recursion. — end note ]

struct Y { Y(int); };
struct A{operator Y();};
Y y1 = A(); //[[ 1 ]]but this compiles, why this use-defined conversion sequence is considered?

in line [[ 1 ]], it's obvious that a "A->A->Y->Y" user defined conversion sequence is used here. A->A is identity conversion A->Y is conversion function, Y->Y is identity conversion.

1
Why do you think it is prohibited by the paragraph you quote? - T.C.
The standard says that user-defined conversion sequences are not considered, but line [[1]] actually uses user-defined conversion. - Jack Chin
OK, why do you believe that this case falls within the scenarios in which this paragraph is applicable? Which bullets do you think apply, and why? - T.C.
In line [[1]], the compile will call copy constructor Y(const Y&) to initialize y1, but A() is of type A, so it will be converted to type Y. According to 13.3.1.4 [over.match.copy] Copy-initialization of class by user-defined conversion, it is apparently a copy-initialization of Y by user-defined conversion(A::operator Y()). So bullet 4.4 apply here. - Jack Chin

1 Answers

1
votes

I assume you saw the first example (and modified it):

struct Y { Y(int); };
struct A { operator int(); };
Y y1 = A(); // error: A::operator int() is not a candidate

The crux is that invoking the converting constructor for int -> Y constitutes a user-defined conversion, but Y -> Y [const&] does not. [over.best.ics]/6:

When the parameter has a class type and the argument expression has the same type, the implicit conversion sequence is an identity conversion.

I.e. in your code, there is one sole user-defined conversion sequence, not two; It consists of two standard conversion sequences (being identity conversions) and the intermediate user-defined conversion A -> Y. You could also have returned a subclass:

struct X{}; struct Y : X {};
struct A { operator Y(); };
X y = A();

…now the second standard conversion sequence has Conversion Rank - [over.best.ics]/6 again:

When the parameter has a class type and the argument expression has a derived class type, the implicit conversion sequence is a derived-to-base Conversion from the derived class to the base class. […] A derived-to-base Conversion has Conversion rank (13.3.3.1.1).