12

C++11 introduced strongly typed enums, with the syntax enum class. These are not compatible with integer types and require explicit casts to obtain their numeric value. C++11 also introduces the ability to specify the storage class for weakly typed enums with the form enum name : type {}. This is fine up to here.

But it looks like even if an weakly typed enum has a given storage class, the type of its items is still int. I tried with Visual Studio 2012, November CTP release. Consider the following code:

enum charEnum : char { A = 'A' };
enum longEnum : long long { Tera = 1000000000000 };

void fct(char val) {}
void fct(int val) {}
void fct(long long val) {}

int main() 
{
    static_assert(sizeof(A) == sizeof(char), "check charEnum size");
    static_assert(sizeof(Tera) == sizeof(long long), "check longEnum size");
    fct('A');  // calls fct(char)
    fct(1);    // calls fct(int)
    fct(2ll);  // calls fct(long long)
    fct(A);    // calls fct(int) !
    fct(Tera); // calls fct(int), with truncation !
    fct((long long)Tera);  // calls fct(long long)
    return 0;
}

The overloaded function called for an enumeration value is always fct(int), even if this results in a truncation of the value. Of course, with an explicit cast, we can call the overloaded function, but this was also possible in traditional C++03 syntax.

Am I missing something obvious? Why is that? Is there a better workaround than an explicit cast?

prapin
  • 6,395
  • 5
  • 26
  • 44
  • Probably because enums are only implicitly convertible to int. – Andrei Tita Jan 06 '13 at 18:33
  • Where did you get your certainty? From the behaviour of a particular compiler? If so, which compiler did you use? Did you try another compiler? – Walter Jan 06 '13 at 18:35
  • Maybe backwards compatibility? A definite answer would be interesting. – vobject Jan 06 '13 at 18:37
  • 1
    @Walter You are right, I only tried with Visual Studio 2012 CTP. Maybe I have wrongly extrapolated to the standard itself. – prapin Jan 06 '13 at 18:37
  • This behaviour is wrong, the standard says no implicit conversion from enum type to `int` is provided for scoped enumerations. – Seth Carnegie Jan 06 '13 at 18:40
  • 1
    @SethCarnegie: those are not scoped enumerations you are looking for. Scoped enumerations have a word `class` or `struct` in them (these keywords introduce a scope; `int` does not). – n. m. could be an AI Jan 06 '13 at 18:43
  • If you would, please open a bug on [Microsoft Connect](http://connect.microsoft.com/visualstudio) and post the link in a comment here for future reference. – James McNellis Jan 06 '13 at 19:04
  • 1
    @McNellis Done. Here is the link: https://connect.microsoft.com/VisualStudio/feedback/details/775916/ – prapin Jan 06 '13 at 20:05
  • @prapin: I hope you saw th additional question yours spawned; apparently the `char` case is a core issue with high contention on what should happen! – GManNickG Jan 09 '13 at 20:53

1 Answers1

9

It's a compiler bug. According to §7.2/9 and §4.5/4:

§7.2/9:
The value of an enumerator or an object of an unscoped enumeration type is converted to an integer by integral promotion (4.5)

§4.5/4:
A prvalue of an unscoped enumeration type whose underlying type is fixed (7.2) 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.

The last one should convert to long long, not int. The char case is a point of contention. (!)


Test program:

#include <iostream>

enum charEnum : char      { A = 'A' };
enum longEnum : long long { Tera = 1000000000000 };

void fct(char val)      { std::cout << "fct(char)"      << std::endl; }
void fct(int val)       { std::cout << "fct(int)"       << std::endl; }
void fct(long long val) { std::cout << "fct(long long)" << std::endl; }

int main() 
{
    static_assert(sizeof(A)    == sizeof(char),      "check charEnum size");
    static_assert(sizeof(Tera) == sizeof(long long), "check longEnum size");

    fct('A');
    fct(1);
    fct(2ll);
    fct(A);
    fct(Tera);
    fct((long long)Tera);
}

MSVC2012NovCTP output:

fct(char)
fct(int)
fct(long long)
fct(int)
fct(int)
fct(long long)

g++ 4.7.1:

fct(char)
fct(int)
fct(long long)
fct(int)
fct(long long)
fct(long long)

Community
  • 1
  • 1
GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • You are right! I tried with GCC 4.5.3 and it calls `long long` for `fct(Tera)` ! I think I will file the bug to Microsoft. But I still don't understand why `fct(A)` calls `fct(int)` instead of `fct(char)`. – prapin Jan 06 '13 at 18:59
  • "Can be converted" means very little here. `char` can be converted to any integral type, but given a choice between `f(int)` and `f(char)`, the latter will be called. – n. m. could be an AI Jan 06 '13 at 19:20
  • @n.m.: `char`, yes, but apparently not an enum with `char` as an underlying type. – GManNickG Jan 06 '13 at 19:24
  • @prapin: I don't know either, per the quotes it should either call the `char` overload or be ambiguous between all three. – GManNickG Jan 06 '13 at 19:25
  • @GManNickG: yes, that's what I mean. – n. m. could be an AI Jan 06 '13 at 19:30
  • @prapin "why fct(A) calls fct(int) instead of fct(char)" — because an integral promotion is applied, and the result of an integral promotion is an `int` or a longer type, never a `char`. – n. m. could be an AI Jan 06 '13 at 19:43
  • @n.m.: That's what I think too, but I don't see the text for it. The section I quoted says `A` will be promoted to `char` (and if needed, can also be promoted to anything `char` can be promoted to). What states that the result is recursively promoted? – GManNickG Jan 06 '13 at 19:46
  • @GManNickG: this looks like a problem. Two promotions can be applied to the same type. I don't know what to do with it. Perhaps `fct(A)` should be ambiguous. – n. m. could be an AI Jan 06 '13 at 20:30
  • @n.m.: [I've asked a separate question](http://stackoverflow.com/questions/14206403/why-does-a-value-of-an-enum-with-a-fixed-underlying-type-of-char-resolve-to-fct). – GManNickG Jan 08 '13 at 00:24