Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overload resolution involving old-style enums and integral types

Consider the following piece of code

#include <iostream>

using namespace std;

enum myEnum { a, b, c };

void test(myEnum e) {
  cout << "myEnum overload" << endl;
}

void test(unsigned int i) {
  cout << "unsigned int overload" << endl;
}

int main() {
  test(a);
  test(1);
  test(1u);  

  return 0;
}

(I know enum class is safer than enum for this kind of things but I am using open-source code that has old-style enums.)

When I compile this with g++ 4.4.7 and run it, I get

myEnum overload
unsigned int overload
unsigned int overload

i.e. the compiler prefers to convert int to unsigned int over converting it to myEnum. This is what I want, but I was wondering if this is always guaranteed. The standard does not specify exactly what the underlying type of myEnum should be, so I thought perhaps if it was exactly int, perhaps this would be favored over unsigned int.

But when I comment out the unsigned int overload, I get this error:

enum_overload.cpp: In function ‘int main()’:
enum_overload.cpp:17: error: invalid conversion from ‘int’ to ‘myEnum’
enum_overload.cpp:17: error:   initializing argument 1 of ‘void test(myEnum)’
enum_overload.cpp:18: error: invalid conversion from ‘unsigned int’ to ‘myEnum’
enum_overload.cpp:18: error:   initializing argument 1 of ‘void test(myEnum)’

Does that mean that old-style enums implicitly convert to their underlying types but not from those types? If that is the case, then that would answer my previous question: if integral types can't convert to myEnum, then the overload resolution is guaranteed to behave as above.

like image 808
PieterNuyts Avatar asked Nov 19 '19 13:11

PieterNuyts


2 Answers

[conv.integral]/1:

A prvalue of an unscoped enumeration type can be converted to a prvalue of an integer type.

The converse is not true. There's no implicit conversion from an integer type to an unscoped enum type:

It seems that you are confusing this with casting an integral value to an enum type: [expr.static.cast]/10

A value of integral or enumeration type can be explicitly converted to a complete enumeration type. The value is unchanged if the original value is within the range of the enumeration values ([dcl.enum]). Otherwise, the behavior is undefined. A value of floating-point type can also be explicitly converted to an enumeration type. The resulting value is the same as converting the original value to the underlying type of the enumeration ([conv.fpint]), and subsequently to the enumeration type.

(emphasis mine)

But this can only be done via an explicit cast:

E x1 = static_cast<E>(1) // yes
E x2 = E(1);             // yes
E x3 = 1;                // no
E x4(1);                 // no
like image 79
L. F. Avatar answered Oct 22 '22 13:10

L. F.


I suggest you read this link.

As mentioned,

An enumeration such as enum Color { red, white, blue }; is its own type. It is not of type int.

myEnum is neither an int nor an unsigned int.

Plus, I suggest not to use myEnum by directly casting an int to a myEnum (doing this: test(static_cast<myEnum>(0))). Indeed the compiler won't check for you if the value provided is a valid one, it can lead to unexpected behavior.

like image 3
Lucie Avatar answered Oct 22 '22 14:10

Lucie