Reputation: 108
I have the following code snippet:
struct T {
T(const T&) = default;
T(const S &);
};
struct S {
operator T();
};
int main() {
S s;
T t = s; // copy-initialization of class type
return 0;
}
My question is why the compiler prefers S::operator T() for the initialization of t rather than reporting an error that the initialization is ambigious. In my opinion the following happens (correct me if i am wrong):
Both the constructor and the conversion function return a prvalue of type T which can be used to direct-initialize the variable t. That means that the second standard conversion sequence of both user-defined-conversion sequences is the identity conversion.
This would mean that both user-defined-conversion sequences are equally good. Or is there a special rule which prefers the conversion functions?
I was reading the following rules in the c++11 standard:
The initialization that occurs in the form T x = a; as well as in argument passing, function return, throwing an exception (15.1), handling an exception (15.3), and aggregate member initialization (8.5.1) is called copy-initialization.
The semantics of initializers are as follows...If the destination type is a (possibly cv-qualified) class type: If the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source type is the same class as, or a derived class of, the class of the destination, constructors are considered.... Otherwise (i.e., for the remaining copy-initialization cases), user-defined conversion sequences that can convert from the source type to the destination type or (when a conversion function is used) to a derived class thereof are enumerated as described in 13.3.1.4, and the best one is chosen through overload resolution (13.3)
User-defined conversion sequence U1 is a better conversion sequence than another user defined conversion sequence U2 if they contain the same user-defined conversion function or constructor and if the second standard conversion sequence of U1 is better than the second standard conversion sequence of U2
Maybe i am making false assumptions. I hope you can help me!
Upvotes: 3
Views: 341
Reputation: 108
I think i found the rule which clarifies this:
13.3.3.2: ... S1 and S2 are reference bindings (8.5.3), and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers.
In the member function S::operator T() the implicit object parameter has type S& which is directly bound to the lvalue s of type S. In the constructor T::T(const S&) the parameter is directly bound to the lvalue s of type S but this reference binding is more cv-qualified than in the operator function, so the operator function is preferred by overload resolution.
Do you agree with this?
Upvotes: 0
Reputation: 153840
The conversion from S
using the conversion operator is better than the conversion to T
taking an S const
as argument. If you make s
an S const
, the constructor is preferred: Your identity operation in one case, indeed, is an identity operation, in the other case it isn't. If you make the conversion operator of S
a const
member, you get an ambiguity. Below is a test program demonstrating all cases:
struct S;
struct T {
T(const T&) = default;
T(const S &);
};
struct S {
S(); // needed to allow creation of a const object
#ifdef AMBIGUOUS
operator T() const;
#else
operator T();
#endif
};
int main() {
#ifdef CONST
S const s;
#else
S s;
#endif
T t = s; // copy-initialization of class type
return 0;
}
Upvotes: 2