I was going through the C++ standard n4713.pdf. Consider below code:
#include <iostream>
#include <type_traits>
enum UEn
{
EN_0,
EN_1,
EN_L = 0x7FFFFFFFFFFFFFFF // EN_L has type "long int"
}; // UEn has underlying type "unsigned long int"
int main()
{
long lng = 0x7FFFFFFFFFFFFFFF;
std::cout << std::boolalpha;
std::cout << "typeof(unsigned long == UEn):" << std::is_same<unsigned long, std::underlying_type<UEn>::type>::value << std::endl; // Outputs "true"
std::cout << "sizeof(EN_L):" << sizeof(EN_L) << std::endl;
std::cout << "sizeof(unsigned):" << sizeof(unsigned) << std::endl;
std::cout << "sizeof(unsigned long):" << sizeof(unsigned long) << std::endl;
std::cout << "sizeof(unsigned long):" << sizeof(unsigned long long) << std::endl;
lng = EN_L + 1; // Invokes UB as EN_L is 0x7FFFFFFFFFFFFFFF and has type "long int"
return 0;
}
The above code outputs (tested on g++-8.1, Clang):
typeof(unsigned long == UEn):true sizeof(EN_L):8 sizeof(unsigned):4 sizeof(unsigned long):8 sizeof(unsigned long):8
As per Section 10.2p5 (10.2 Enumeration declarations):
Following the closing brace of an enum-specifier, each enumerator has the type of its enumeration...If the underlying type is not fixed, the type of each enumerator prior to the closing brace is determined as follows:
If an initializer is specified for an enumerator, the constant-expression shall be an integral constant expression (8.6). If the expression has unscoped enumeration type, the enumerator has the underlying type of that enumeration type, otherwise it has the same type as the expression.
If no initializer is specified for the first enumerator, its type is an unspecified signed integral type.
Otherwise the type of the enumerator is the same as that of the preceding enumerator unless the incremented value is not representable in that type, in which case the type is an unspecified integral type sufficient to contain the incremented value. If no such type exists, the program is ill-formed.
Further, section 10.2p7 states:
For an enumeration whose underlying type is not fixed, the underlying type is an integral type that can represent all the enumerator values defined in the enumeration. If no integral type can represent all the enumerator values, the enumeration is ill-formed. It is implementation-defined which integral type is used as the underlying type except that the underlying type shall not be larger than int unless the value of an enumerator cannot fit in an int or unsigned int.
Thus I have following questions:
- Why is the underlying type of enum
UEnanunsigned longwhen0x7FFFFFFFFFFFFFFFis an integer constant of typelong intand thus type ofEN_Lis alsolong int. Is this a compiler bug or well defined behaviour? - When the standard says
each enumerator has the type of its enumeration, shouldn't it imply that the integral types of enumerator and enumeration should also match? What could be the reason in having these two different from each other?
Aucun commentaire:
Enregistrer un commentaire