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).