Reputation: 733
Consider this example program:
#include <iostream>
typedef enum { A, B, C } MyEnum;
struct S
{
S(int) { std::cout << "int" << std::endl; }
S(MyEnum) { std::cout << "MyEnum" << std::endl; }
};
S f()
{
return A;
}
int main()
{
S const s = f();
}
Compiled with both clang and gcc this produces an executable that prints "MyEnum" when run. Is this behavior guaranteed by the C++ standard?
Upvotes: 4
Views: 202
Reputation: 172924
Yes, S::S(MyEnum)
wins in overload resolution because it's an exact match. While S::S(int)
requires one more implicit conversion (integral promotion) from enum to int
.
Each type of standard conversion sequence is assigned one of three ranks:
- Exact match: no conversion required, lvalue-to-rvalue conversion, qualification > conversion, function pointer conversion, (since C++17) user-defined conversion of class type to the same class
- Promotion: integral promotion, floating-point promotion
- Conversion: integral conversion, floating-point conversion, floating-integral conversion, pointer conversion, pointer-to-member conversion, boolean conversion, user-defined conversion of a derived class to its base
A standard conversion sequence S1 is better than a standard conversion sequence S2 if
a) S1 is a subsequence of S2, excluding lvalue transformations. The identity conversion sequence is considered a subsequence of any other conversion
b) Or, if not that, the rank of S1 is better than the rank of S2
F1 is determined to be a better function than F2 if implicit conversions for all arguments of F1 are not worse than the implicit conversions for all arguments of F2, and
- there is at least one argument of F1 whose implicit conversion is better than the corresponding implicit conversion for that argument of F2
These pair-wise comparisons are applied to all viable functions. If exactly one viable function is better than all others, overload resolution succeeds and this function is called. Otherwise, compilation fails.
Upvotes: 5
Reputation: 19123
Yes, of course. return
statement allows implicit construction and S(MyEnum)
is the exact match.
Same would work with return {A};
But if you were to make S(MyEnum)
explicit, then:
return A;
will call S(int)
as a fallback because MyEnum
is implicitly convertible to integers. But this is worse overload candidate than S(MyEnum)
due to the extra conversion, chosen only from necessity.return {A};
represents copy-list initialization. It will fail because it forbids explicit constructors and implicit conversions.return S{A};
represents direct-list initialization, it will call S(MyEnum)
, although it limits some implicit conversion, it does not impact this example and S(int)
would be called had S(MyEnum)
was removed.return S(A);
is essentially the same as return A;
given the specified return type S
.Upvotes: 4