Answers:
让我们去探源。这是C ++ 03标准(ISO / IEC 14882:2003)文档在7.2-5(枚举声明)中所说的:
枚举的基础类型是整数类型,可以表示枚举中定义的所有枚举器值。由实现方式定义,哪种整数类型用作枚举的基础类型,除非基础类型不得大于int,除非枚举器的值不能适合int或unsigned int。
简而言之,编译器可以选择(很明显,如果某些枚举值的值为负数,它将被签名)。
您不应该依赖于它们是否已签名。如果要使它们显式签名或未签名,可以使用以下命令:
enum X : signed int { ... }; // signed enum
enum Y : unsigned int { ... }; // unsigned enum
您不应该依赖于已签名或未签名。根据标准,实现是定义哪种整数类型用作枚举的基础类型。但是,在大多数实现中,它是一个有符号整数。
在C ++ 0x中,将添加强类型枚举,这将允许您指定枚举的类型,例如:
enum X : signed int { ... }; // signed enum
enum Y : unsigned int { ... }; // unsigned enum
但是,即使到现在,也可以通过将枚举用作变量或参数类型来实现一些简单的验证,如下所示:
enum Fruit { Apple, Banana };
enum Fruit fruitVariable = Banana; // Okay, Banana is a member of the Fruit enum
fruitVariable = 1; // Error, 1 is not a member of enum Fruit
// even though it has the same value as banana.
编译器可以确定枚举是有符号的还是无符号的。
验证枚举的另一种方法是将枚举本身用作变量类型。例如:
enum Fruit
{
Apple = 0,
Banana,
Pineapple,
Orange,
Kumquat
};
enum Fruit fruitVariable = Banana; // Okay, Banana is a member of the Fruit enum
fruitVariable = 1; // Error, 1 is not a member of enum Fruit even though it has the same value as banana.
即使是一些旧的答案也有44票赞成票,我倾向于不同意所有这些票。简而言之,我认为我们不应该关心underlying type
枚举的。
首先,C ++ 03 Enum类型是其自身的独特类型,没有符号的概念。从C ++ 03标准开始dcl.enum
7.2 Enumeration declarations
5 Each enumeration defines a type that is different from all other types....
因此,当我们谈论枚举类型的符号时,例如,使用<
运算符比较2个枚举操作数时,实际上是在隐式地将枚举类型转换为某种整数类型。重要的是这种整体类型的标志。当将枚举转换为整数类型时,此语句适用:
9 The value of an enumerator or an object of an enumeration type is converted to an integer by integral promotion (4.5).
而且,显然,枚举的基础类型与“积分提升”无关。由于该标准对积分促销的定义如下:
4.5 Integral promotions conv.prom
.. An rvalue of an enumeration type (7.2) can be converted to an rvalue of the first of the following types that can represent all the values of the enumeration
(i.e. the values in the range bmin to bmax as described in 7.2: int, unsigned int, long, or unsigned long.
因此,枚举类型是否变为signed int
或unsigned int
取决于是否signed int
可以包含已定义枚举数的所有值,而不是枚举的基础类型。
看到我相关的问题 转换为整数类型后C ++枚举类型的符号不正确
-Wsign-conversion
。我们使用它来帮助捕获代码中意外的错误。但是+1是引用标准,并指出一个枚举没有与之关联的类型(signed
vs unsigned
)。
除了其他人已经说过的关于有符号/无符号的内容之外,以下是该标准对枚举类型范围的说明:
7.2(6):“对于其中e(min)是最小的枚举数且e(max)是最大的枚举,该枚举的值是从b(min)到b(max)范围内的基础类型的值),其中b(min)和b(max)分别是可以存储e(min)和e(max)的最小位字段的最小和最大值。可以定义一个未定义值的枚举通过其任何枚举器。”
因此,例如:
enum { A = 1, B = 4};
定义一个枚举类型,其中e(min)为1,e(max)为4。如果基础类型为有符号int,则所需的最小位域为4位,并且如果实现中的int为二进制补码,则有效范围为枚举是-8到7。如果基础类型是无符号的,则它有3位,范围是0到7。如果需要,请查看编译器文档(例如,如果要将除枚举器以外的整数值强制转换为枚举类型,那么您需要知道该值是否在枚举范围内-如果不是,则未指定结果枚举值)。
这些值是否为函数的有效输入,可能不同于它们是否为枚举类型的有效值。您的检查代码可能担心前者而不是后者,因此在此示例中至少应检查> = A和<= B。
用std::is_signed<std::underlying_type
+作用域枚举检查它,默认为int
https://en.cppreference.com/w/cpp/language/enum表示:
main.cpp
#include <cassert>
#include <iostream>
#include <type_traits>
enum Unscoped {};
enum class ScopedDefault {};
enum class ScopedExplicit : long {};
int main() {
// Implementation defined, let's find out.
std::cout << std::is_signed<std::underlying_type<Unscoped>>() << std::endl;
// Guaranteed. Scoped defaults to int.
assert((std::is_same<std::underlying_type<ScopedDefault>::type, int>()));
// Guaranteed. We set it ourselves.
assert((std::is_same<std::underlying_type<ScopedExplicit>::type, long>()));
}
编译并运行:
g++ -std=c++17 -Wall -Wextra -pedantic-errors -o main main.cpp
./main
输出:
0
已在Ubuntu 16.04,GCC 6.4.0上测试。