Both clang and gcc accept the following code and choose A::operator B*
.
struct B
{
};
struct A : B
{
operator A*();
operator B*();
};
A a;
void* x = a;
My reading of the standard - specifically sentences highlighted below in bold - suggests that this conversion should be ambiguous.
Both A::operator A*
and A::operator B*
are candidates for overload resolution because A*
and B*
are both convertible to void*
via a standard conversion. Because the implied object parameter A&
is the only argument, only the conversion sequence that converts from the implied object argument to the implied object parameter is considered - the type yielded by the conversion function is ignored. In both cases, the implied object argument is the initializer expression's type A
, and the implied object parameter is A&
. If both conversion sequences are identical, there is no way to distinguish between the two candidates.
8.5 Initializers [dcl.init]
The semantics of initializers are as follows. The destination type is the type of the object or reference being initialized and the source type is the type of the initializer expression.
— If the destination type is a [reference/array/class...] [deleted details not applicable to this scenario]
— Otherwise, if the source type is a (possibly cv-qualified) class type, conversion functions are considered. The applicable conversion functions are enumerated (13.3.1.5), and the best one is chosen through overload resolution (13.3). The user-defined conversion so selected is called to convert the initializer expression into the object being initialized. If the conversion cannot be done or is ambiguous, the initialization is ill-formed.
13.3.1.5 Initialization by conversion function [over.match.conv]
Under the conditions specified in 8.5, as part of an initialization of an object of nonclass type, a conversion function can be invoked to convert an initializer expression of class type to the type of the object being initialized. Overload resolution is used to select the conversion function to be invoked. Assuming that “cv1 T” is the type of the object being initialized, and “cv S” is the type of the initializer expression, with S a class type, the candidate functions are selected as follows:
— The conversion functions of S and its base classes are considered. Those non-explicit conversion functions that are not hidden within S and yield type T or a type that can be converted to type T via a standard conversion sequence (13.3.3.1.1) are candidate functions. For direct-initialization, those explicit conversion functions that are not hidden within S and yield type T or a type that can be converted to type T with a qualification conversion (4.4) are also candidate functions. Conversion functions that return a cv-qualified type are considered to yield the cv-unqualified version of that type for this process of selecting candidate functions. Conversion functions that return “reference to cv2 X” return lvalues or xvalues, depending on the type of reference, of type “cv2 X” and are therefore considered to yield X for this process of selecting candidate functions.
The argument list has one argument, which is the initializer expression. [ Note: This argument will be compared against the implicit object parameter of the conversion functions. —end note ]
Is this ambiguous according to the standard?
EDIT: note that this is a similar question, but not the same as Distinguishing between user-defined conversion sequences by the initial standard conversion sequence
The difference being that in my example both conversion functions have the same qualification.