The conditional operator checks conversions in both directions. In this case, since your constructor is explicit (so the ?:
is not ambiguous), the conversion from Foo
to int
is used, using your conversion function that converts to double
: That works, because after applying the conversion function, a standard conversion that converts the double
to int
(truncation) follows. The result of ?:
in your case is int
, and has the value 6
.
In the second case, since the operand has type double
, no such trailing conversion to int
takes place, and thus the result type of ?:
has type double
with the expected value.
To understand the "unnecessary" conversions, you have to understand that expressions like your ?:
are evaluated "context-free": When determining the value and type of it, the compiler doesn't consider that it's the operand of a return
for a function returning a double
.
Edit: What happens if your constructor is implicit? The ?:
expression will be ambiguous, because you can convert an int
to an rvalue of type Foo
(using the constructor), and a Foo
to an rvalue of type int
(using the conversion function). The Standard says
Using this process, it is determined whether the second operand can be converted to match the third operand, and whether the third operand can be converted to match the second operand. If both can be converted, or one can be converted but the conversion is ambiguous, the program is ill-formed.
Paragraphs explaining how your Foo
is converted to int
:
5.16/3
about condition ? E1 : E2
:
Otherwise, if the second and third operand have different types, and either has (possibly cv-qualified) class type, an attempt is made to convert each of those operands to the type of the other. [...] E1 can be converted to match E2 if E1 can be implicitly converted to the type that expression E2 would have if E2 were converted to an rvalue (or the type it has, if E2 is an rvalue).
4.3
about "implicitly converted":
An expression e can be implicitly converted to a type T if and only if the declaration T t = e;
is well-formed, for some invented temporary variable t.
8.5/14
about copy initialization ( T t = e;
)
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
about the conversion function candidates
The conversion functions of S and its base classes are considered. Those 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.