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?
Each enum type has a corresponding integral type called the underlying type of the enum type. This underlying type shall be able to represent all the enumerator values defined in the enumeration. If the enum_base is present, it explicitly declares the underlying type.
The default underlying type of the enumeration elements is int. By default, the first enumerator has the value 0, and the value of each successive enumerator is increased by 1. Enums are enumerated data type in C#.
The type of a C++ enum is the enum itself. Its range is rather arbitrary, but in practical terms, its underlying type is an int . It is implicitly cast to int wherever it's used, though.
The only requirements in the C++03 standard are that the underlying type is an integral type that can represent all the enumerator values defined in the enumeration, and that the underlying type is not larger than int, unless the value of an enumerator cannot fit in an int or unsigned int.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With