Home > Blockchain >  Does C guarantee this enum vs int constructor overload resolution?
Does C guarantee this enum vs int constructor overload resolution?

Time:11-05

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?

CodePudding user response:

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:

  1. 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
  2. Promotion: integral promotion, floating-point promotion
  3. 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

CodePudding user response:

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.
  • Related