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