Itachi Uchiwa
Itachi Uchiwa

Reputation: 3164

C++ primer enums and implicit conversion

Hello I have this from C++ primer 5th edition:

// unscoped enumeration; the underlying type is machine dependent

enum Tokens {INLINE = 128, VIRTUAL = 129};

void newf(unsigned char);

void newf(int);

unsigned char uc = VIRTUAL;

newf(VIRTUAL); // calls newf(int)

newf(uc); // calls newf(unsigned char)

The enum Tokens has only two enumerators, the larger of which has the value 129. That value can be represented by the type unsigned char, and many compilers will use unsigned char as the underlying type for Tokens. Regardless of its underlying type, objects and the enumerators of Tokens are promoted to int. Enumerators and values of an enum type are not promoted to unsigned char, even if the values of the enumerators would fit.

So as you can see the enumerator value tue is not promoted to int and I get the version of foo(unsigned char) and not foo(int).

Upvotes: 1

Views: 247

Answers (1)

Nathan Pierson
Nathan Pierson

Reputation: 5565

From cppreference's description of enums:

Values of unscoped enumeration type are implicitly-convertible to integral types. If the underlying type is not fixed, the value is convertible to the first type from the following list able to hold their entire value range: int, unsigned int, long, unsigned long, long long, or unsigned long long, extended integer types with higher conversion rank (in rank order, signed given preference over unsigned) (since C++11). If the underlying type is fixed, the values can be converted to their underlying type (preferred in overload resolution), which can then be promoted.

So you're right about which overload of foo will be selected, but you're wrong that there's no implicit conversion taking place. A days is still a different type from an unsigned char, but it will implicitly convert to one.

You're also wrong that, in the event that the implementation happens to select unsigned char as the underlying type for enum Tokens, it will therefore implicitly convert to unsigned char. Implicit conversion to a narrower underlying type than int only occurs if you fix the underlying type yourself instead of letting the implementation decide.

The text from the Primer you quoted is only describing the situation when you don't explicitly specify an underlying type.

Quotes from the draft standard, expr.conv.prom:

A prvalue of an unscoped enumeration type whose underlying type is not fixed can be converted to a prvalue of the first of the following types that can represent all the values of the enumeration ([dcl.enum]): int, unsigned int, long int, unsigned long int, long long int, or unsigned long long int. If none of the types in that list can represent all the values of the enumeration, a prvalue of an unscoped enumeration type can be converted to a prvalue of the extended integer type with lowest integer conversion rank ([conv.rank]) greater than the rank of long long in which all the values of the enumeration can be represented. If there are two such extended types, the signed one is chosen.

A prvalue of an unscoped enumeration type whose underlying type is fixed ([dcl.enum]) can be converted to a prvalue of its underlying type. Moreover, if integral promotion can be applied to its underlying type, a prvalue of an unscoped enumeration type whose underlying type is fixed can also be converted to a prvalue of the promoted underlying type.

And from over.ics.rank:

A conversion that promotes an enumeration whose underlying type is fixed to its underlying type is better than one that promotes to the promoted underlying type, if the two are different.

Upvotes: 3

Related Questions