枚举上提供的类型检查
我希望下面的代码片段会抱怨尝试将 0,1,2 之外的其他值分配给 Color 变量。 但以下内容确实可以编译,并且我得到输出
Printing:3
3
有人能解释为什么吗?枚举不应该是真正的用户定义类型吗?谢谢。
enum Color { blue=0,green=1,yellow=2};
void print_color(Color x);
int main(){
Color x=Color(3);
print_color(x);
std::cout << x << std::endl;
return 0;
}
void print_color(Color x)
{
std::cout << "Printing:" << x << std::endl;
}
I would expect the following code snippet to complain about trying to assign something other that 0,1,2 to a Color variable.
But the following does compile and I get the output
Printing:3
3
Can anybody explain why? Is enum not meant to be a true user-defined type? Thanks.
enum Color { blue=0,green=1,yellow=2};
void print_color(Color x);
int main(){
Color x=Color(3);
print_color(x);
std::cout << x << std::endl;
return 0;
}
void print_color(Color x)
{
std::cout << "Printing:" << x << std::endl;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
由于您手动将
3
转换为Color
,编译器将允许您执行此操作。如果您尝试使用普通的3
而不进行强制转换来初始化变量x
,您将得到诊断信息。请注意,枚举可以存储的值的范围不受其包含的枚举数的限制。它是可以存储枚举的所有枚举值的最小位域的值范围。也就是说,枚举类型的范围是
0..3
:因此值
3
仍在范围内,因此代码有效。如果您转换4
,则 C++ 标准将未指定结果值。实际上,实现必须为枚举选择底层整数类型。它可以选择的最小类型是
char
,但它仍然能够至少存储最大127
的值。但如前所述,编译器不需要将4
转换为4
值,因为它超出了枚举范围。我想我应该对“基础类型”和“枚举值范围”的区别发表一些解释。任何类型的值范围都是该类型的最小值和最大值。枚举的基础类型必须能够存储任何枚举器的值(当然) - 并且具有相同基础类型的两个枚举是布局兼容的(这在发生类型不匹配的情况下提供了一定的灵活性)。
因此,虽然底层类型旨在修复对象表示(对齐和大小),但枚举的值在
7.2/6
中定义如下Since you manually cast the
3
toColor
, the compiler will allow you to do that. If you tried to initialize the variablex
with a plain3
without a cast, you would get a diagnostic.Note that the range of values an enumeration can store is not limited by the enumerators it contains. It's the range of values of the smallest bitfield that can store all enumerator values of the enumeration. That is, the range of your enumeration type is
0..3
:The value
3
is thus still in range, and so the code is valid. Had you cast a4
, then the resulting value would be left unspecified by the C++ Standard.In practice, the implementation has to chose an underlying integer type for the enumeration. The smallest type it can choose is
char
, but which is still able to at least store values ranging up to127
. But as mentioned, the compiler is not required to convert a4
to a value of4
, because it's outside the range of your enumeration.I figure i should post some explanation on the difference of "underlying type" and "range of enumeration values". The range of values for any type is the smallest and largest value of that type. The underlying type of an enumeration must be able to store the value of any enumerator (of course) - and two enumerations that have the same underlying type are layout compatible (this allows some flexibility in case a type mismatch occurs).
So while the underlying type is meant to fix the object representation (alignment and size), the values of the enumeration is defined as follows in
7.2/6
Color(3)
是一个强制转换,与(Color)3
具有相同的语义,它不是构造函数。请注意,您还可以使用static_cast(3)
进行相同的转换,但不能使用Color x(3)
。Color(3)
is a cast, with the same semantic as(Color)3
, it isn't a constructor. Note that you can also usestatic_cast<Color>(3)
for the same conversion but you can't useColor x(3)
.从编译时检查的角度来看,C++ 中的枚举更像是一组命名的整数常量,而不是真正的类型。然而,C++ 标准有这样的说法 [dcl.enum]:
9 算术或枚举类型的表达式可以转换为
显式枚举类型。如果该值位于
枚举类型的枚举值范围;否则
结果枚举值未指定。
“未指定”比通常的“未定义行为”稍好一些。
Enum in C++ is more of a set of named integer constants than a true type, from compile-time checking point of view. However, the C++ standard has this to say [dcl.enum]:
9 An expression of arithmetic or enumeration type can be converted to an
enumeration type explicitly. The value is unchanged if it is in the
range of enumeration values of the enumeration type; otherwise the
resulting enumeration value is unspecified.
"Unspecified" is slightly better than the usual "undefined behavior".
C 和 C++ 标准在枚举主题上都有点令人困惑。两者都坚持认为枚举是“不同的类型”,但随后都将它们视为基础整数类型。 C++ 甚至引用了一个斜体术语“底层类型”,它只是在引入 wchar_t 时才定义的。
总之,wchar_t 和 enum 类型是“不同的”,但只是映射到实现选择的底层整型类型,毫无疑问,这是因为需要与历史枚举兼容,而历史枚举绝对只是一个 int。
现代编译器通常可以选择向枚举添加更多类似类型的行为,从而针对各种误用打开警告和错误。这些不能是默认行为,因为它们选择了不合格的行为。
Both the C and the C++ standards are kind of confusing on the subject of enums. Both insist that enums are "distinct types" but then both treat them as the underlying integral type. C++ even refers to an italic term "underlying type" which is only sort-of defined when introducing wchar_t.
In summary, wchar_t and enum types are "distinct" but simply mapped to an underlying integral type chosen by the implementation, and this is no doubt due to the need to be compatible with historical enum which was definitely just an int.
Modern compilers typically have options to add more type-like behavior to enums, turning on warnings and errors for various misuses. These can't be a default because they elect non-conforming behavior.