枚举声明

枚举声明

C++

编译器支持

自由(freestanding)与宿主(hosted)

语言

标准库

标准库头文件

具名要求

特性测试宏 (C++20)

语言支持库

概念库 (C++20)

诊断库

内存管理库

元编程库 (C++11)

通用工具库

容器库

迭代器库

范围库 (C++20)

算法库

字符串库

文本处理库

数值库

日期和时间库

输入/输出库

文件系统库 (C++17)

并发支持库 (C++11)

执行控制库 (C++26)

技术规范

符号索引

外部库

[编辑] C++ 语言

通用主题

预处理器

注释

关键词

转义序列

流程控制

条件执行语句

if

switch

迭代语句(循环)

for

range-for (C++11)

while

do-while

跳转语句

continue - break

goto - return

函数

函数声明

Lambda 函数表达式

inline 说明符

动态异常规范 (直到 C++17*)

noexcept 说明符 (C++11)

异常

throw 表达式

try 块

catch 处理程序

命名空间

命名空间声明

命名空间别名

类型

基本类型

枚举类型

函数类型

类/结构体类型

联合类型

说明符

const/volatile

decltype (C++11)

auto (C++11)

constexpr (C++11)

consteval (C++20)

constinit (C++20)

存储期说明符

初始化

默认初始化

值初始化

零初始化

复制初始化

直接初始化

聚合初始化

列表初始化 (C++11)

常量初始化

引用初始化

表达式

值类别

求值顺序

运算符

运算符优先级

替代表示

字面量

布尔字面量 - 整数字面量 - 浮点字面量

字符字面量 - 字符串字面量 - nullptr (C++11)

用户定义 (C++11)

工具

属性 (C++11)

类型

typedef 声明

类型别名声明 (C++11)

类型转换

隐式转换

static_cast

const_cast

显式转换

dynamic_cast

reinterpret_cast

内存分配

new 表达式

delete 表达式

类声明

构造函数

this 指针

访问说明符

friend 说明符

类特有的函数属性

虚函数

override 说明符 (C++11)

final 说明符 (C++11)

explicit (C++11)

static

特殊成员函数

默认构造函数

复制构造函数

移动构造函数 (C++11)

复制赋值

移动赋值 (C++11)

析构函数

模板

类模板

函数模板

模板特化

参数包 (C++11)

杂项

内联汇编

C++ 历史

[编辑] 声明

概览

声明语法

声明说明符序列

声明符

冲突声明

说明符

typedef

inline

virtual 函数说明符

explicit 函数说明符

friend

constexpr(C++11)

consteval(C++20)

constinit(C++20)

存储类说明符

翻译单元局部 (C++20)

class/struct

union

enum

decltype(C++11)

auto(C++11)

alignas(C++11)

constvolatile

包索引说明符 (C++26)

细化类型说明符

属性 (C++11)

声明符

引用

指针

数组

块声明

简单声明

→结构化绑定声明 (C++17)

别名声明 (C++11)

命名空间别名定义

using 声明

using 指令

static_assert 声明 (C++11)

asm 声明

不透明枚举声明 (C++11)

其他声明

命名空间定义

函数声明

类模板声明

函数模板声明

显式模板实例化 (C++11)

显式模板特化

链接规范

属性声明 (C++11)

空声明

[编辑]

“枚举”是一种独特的类型,其值被限制在一定范围之内(详情见下文),该范围可能包含若干显式命名的常量(“枚举器”)。

常量的数值是整数类型的值,这种整数类型被称为枚举的“底层类型”。枚举的大小、值表示和对齐要求与其底层类型相同。此外,枚举的每个值与底层类型的对应值具有相同的表示。

枚举通过以下语法进行(重)声明:

enum-key attr (可选) enum-head-name (可选) enum-base (可选){ enumerator-list (可选) }

(1)

enum-key attr (可选) enum-head-name (可选) enum-base (可选){ enumerator-list , }

(2)

enum-key attr (可选) enum-head-name enum-base (可选) ;

(3)

(C++11 起)

1) enum-specifier,出现在声明语法中的 decl-specifier-seq:定义枚举类型及其枚举器。

2) 可以在 enumerator-list 后加一个尾随逗号。

3) 不透明枚举声明:定义枚举类型但不定义其枚举器:在此声明之后,该类型是完整类型且其大小已知。

enum-key

-

enum

(C++11 前)

enum、enum class 或 enum struct 之一

(C++11 起)

属性

-

(C++11 起) 可选的任意数量属性序列

enum-head-name

-

正在声明的枚举的名称,可以省略。

(C++11 前)

正在声明的枚举的名称,可选地前面带有一个 nested-name-specifier:由名称和作用域解析运算符 :: 组成的序列,以作用域解析运算符结尾。它只能在无作用域的非不透明枚举声明中省略。

仅当枚举名称存在且此声明是重新声明时,才允许出现 nested-name-specifier。对于不透明枚举声明,nested-name-specifier 只能在显式特化声明中枚举名称之前出现。如果存在 nested-name-specifier,则 enum-specifier 不能引用仅通过继承或using declaration引入的枚举,并且 enum-specifier 只能出现在包含先前声明的命名空间中。在这种情况下,nested-name-specifier 不能以 decltype 说明符开头。

(C++11 起)

enum-base

-

(C++11 起) 冒号 (:),后跟一个 type-specifier-seq,它指定一个整数类型(如果它是 cv 限定的,则忽略限定符),该整数类型将作为此枚举类型的固定底层类型

enumerator-list

-

逗号分隔的枚举器定义列表,每个定义要么是唯一的 identifier,成为枚举器的名称,要么是带常量表达式的唯一标识符:identifier = constant-expression。在这两种情况下,identifier 之后都可以直接跟着一个可选的属性说明符序列。(C++17 起)

有两种不同种类的枚举:无作用域枚举(用 enum-key enum 声明)和 有作用域枚举(用 enum-key enum class 或 enum struct 声明)。

目录

1 无作用域枚举

1.1 用于链接的枚举名称

2 有作用域枚举

3 using enum 声明

4 注意

5 关键词

6 示例

7 缺陷报告

8 参考

9 参阅

[编辑] 无作用域枚举

enum name (可选) { enumerator = constant-expression , enumerator = constant-expression , ... }

(1)

enum name (可选) : type { enumerator = constant-expression , enumerator = constant-expression , ... }

(2)

(C++11 起)

enum name : type ;

(3)

(C++11 起)

1) 声明一个无作用域枚举类型,其底层类型不固定(在这种情况下,底层类型是一个实现定义的整数类型,可以表示所有枚举器值;除非某个枚举器的值无法放入 int 或 unsigned int 中,否则该类型不会大于 int。如果 enumerator-list 为空,则底层类型就好像枚举有一个值为 ​0​ 的枚举器。如果没有整数类型可以表示所有枚举器值,则枚举是病态的)。

2) 声明一个无作用域枚举类型,其底层类型是固定的。

3) 无作用域枚举的不透明枚举声明必须指定名称和底层类型。

每个 enumerator 都会成为枚举类型(即 name)的一个命名常量,在包含作用域中可见,并且可以在需要常量时使用。

enum Color { red, green, blue };

Color r = red;

switch(r)

{

case red : std::cout << "red\n"; break;

case green: std::cout << "green\n"; break;

case blue : std::cout << "blue\n"; break;

}

每个枚举器都与底层类型的一个值相关联。当 enumerator-list 中提供了 = 时,枚举器的值由那些关联的 constant-expression 定义。如果第一个枚举器没有 =,则关联值为零。对于任何其他没有 = 定义的枚举器,关联值为前一个枚举器的值加一。

enum Foo { a, b, c = 10, d, e = 1, f, g = f + c };

//a = 0, b = 1, c = 10, d = 11, e = 1, f = 2, g = 12

无作用域枚举的 name 可以省略:这样的声明只将枚举器引入到包含作用域中。

enum { a, b, c = 0, d = a + 2 }; // defines a = 0, b = 1, c = 0, d = 2

当无作用域枚举是类成员时,其枚举器可以使用类成员访问运算符 . 和 -> 访问

struct X

{

enum direction { left = 'l', right = 'r' };

};

X x;

X* p = &x;

int a = X::direction::left; // allowed only in C++11 and later

int b = X::left;

int c = x.left;

int d = p->left;

在声明说明符中,对于成员声明,序列

enum enum-head-name :

总是解析为枚举声明的一部分

struct S

{

enum E1 : int {};

enum E1 : int {}; // error: redeclaration of enumeration,

// NOT parsed as a zero-length bit-field of type enum E1

};

enum E2 { e1 };

void f()

{

false ? new enum E2 : int(); // OK: 'int' is NOT parsed as the underlying type

}

(C++11 起)

[编辑] 用于链接的枚举名称

对于链接目的,没有用于链接目的的 typedef 名称且具有枚举器的未命名枚举,由其底层类型和其第一个枚举器表示;这样的枚举据说具有一个枚举器作为“用于链接目的的名称”。

[编辑] 有作用域枚举

enum struct|class name { enumerator = constant-expression , enumerator = constant-expression , ... }

(1)

enum struct|class name : type { enumerator = constant-expression , enumerator = constant-expression , ... }

(2)

enum struct|class name ;

(3)

enum struct|class name : type ;

(4)

1) 声明一个有作用域的枚举类型,其底层类型为 int(关键字 class 和 struct 完全等价)

2) 声明一个有作用域的枚举类型,其底层类型为 type

3) 声明一个有作用域的枚举类型的不透明枚举,其底层类型为 int

4) 声明一个有作用域的枚举类型的不透明枚举,其底层类型为 type

每个 enumerator 成为枚举类型(即 name)的命名常量,包含在枚举的作用域内,并且可以使用作用域解析运算符访问。没有从有作用域枚举器值到整数类型的隐式转换,尽管可以使用 static_cast 获取枚举器的数值。

运行此代码

#include

int main()

{

enum class Color { red, green = 20, blue };

Color r = Color::blue;

switch(r)

{

case Color::red : std::cout << "red\n"; break;

case Color::green: std::cout << "green\n"; break;

case Color::blue : std::cout << "blue\n"; break;

}

// int n = r; // error: no implicit conversion from scoped enum to int

int n = static_cast(r); // OK, n = 21

std::cout << n << '\n'; // prints 21

}

(C++11 起)

如果满足以下所有条件,则可以使用列表初始化从整数初始化枚举,无需强制转换:

初始化是直接列表初始化。初始化列表只有一个元素。枚举是有作用域的,或无作用域且底层类型固定。转换是非收缩的。

这使得可以引入新的整数类型(例如 `SafeInt`),即使在惩罚通过值传递/返回结构的 ABI 上,它们也享有与其底层整数类型相同的现有调用约定。

enum byte : unsigned char {}; // byte is a new integer type; see also std::byte (C++17)

byte b{42}; // OK as of C++17 (direct-list-initialization)

byte c = {42}; // error

byte d = byte{42}; // OK as of C++17; same value as b

byte e{-1}; // error

struct A { byte b; };

A a1 = {{42}}; // error (copy-list-initialization of a constructor parameter)

A a2 = {byte{42}}; // OK as of C++17

void f(byte);

f({42}); // error (copy-list-initialization of a function parameter)

enum class Handle : std::uint32_t { Invalid = 0 };

Handle h{42}; // OK as of C++17

(C++17 起)

using enum 声明

using enum using-enum-declarator ;

(C++20 起)

声明符

-

一个(可能合格的)标识符或简单模板标识符

declarator 必须命名一个非依赖枚举类型。枚举声明通过仅限类型的普通限定或非限定查找找到,具体取决于 declarator 是否限定。

enum E { x };

void f()

{

int E;

using enum E; // OK

}

using F = E;

using enum F; // OK

template

using EE = T;

void g()

{

using enum EE; // OK

}

一个 using enum 声明引入命名枚举的枚举器名称,如同通过每个枚举器的using 声明一样。当在类作用域中时,using enum 声明将命名枚举的枚举器作为成员添加到作用域中,使其可用于成员查找。

enum class fruit { orange, apple };

struct S

{

using enum fruit; // OK: introduces orange and apple into S

};

void f()

{

S s;

s.orange; // OK: names fruit::orange

S::orange; // OK: names fruit::orange

}

两个 using enum 声明如果引入了两个同名的枚举器,则会发生冲突。

enum class fruit { orange, apple };

enum class color { red, orange };

void f()

{

using enum fruit; // OK

// using enum color; // error: color::orange and fruit::orange conflict

}

(C++20 起)

[编辑] 注意

无作用域枚举类型的值可以提升或转换为整数类型

enum color { red, yellow, green = 20, blue };

color col = red;

int n = blue; // n == 21

整数、浮点和枚举类型的值可以通过使用 static_cast 转换为任何枚举类型。请注意,这种转换后的值不一定等于为枚举定义的任何命名枚举器

enum access_t { read = 1, write = 2, exec = 4 }; // enumerators: 1, 2, 4 range: 0..7

access_t rwe = static_cast(7);

assert((rwe & read) && (rwe & write) && (rwe & exec));

access_t x = static_cast(8.0); // undefined behavior since CWG 1766

access_t y = static_cast(8); // undefined behavior since CWG 1766

enum foo { a = 0, b = UINT_MAX }; // range: [0, UINT_MAX]

foo x = foo(-1); // undefined behavior since CWG 1766,

// even if foo's underlying type is unsigned int

功能测试宏

标准

特性

__cpp_enumerator_attributes

201411L

(C++17)

枚举器的属性

__cpp_using_enum

201907L

(C++20)

using enum

[编辑] 关键词

enum, struct, class, using

[编辑] 示例

运行此代码

#include

#include

// enum that takes 16 bits

enum smallenum: std::int16_t

{

a,

b,

c

};

// color may be red (value 0), yellow (value 1), green (value 20), or blue (value 21)

enum color

{

red,

yellow,

green = 20,

blue

};

// altitude may be altitude::high or altitude::low

enum class altitude: char

{

high = 'h',

low = 'l', // trailing comma only allowed after CWG 518

};

// the constant d is 0, the constant e is 1, the constant f is 3

enum

{

d,

e,

f = e + 2

};

// enumeration types (both scoped and unscoped) can have overloaded operators

std::ostream& operator<<(std::ostream& os, color c)

{

switch(c)

{

case red : os << "red"; break;

case yellow: os << "yellow"; break;

case green : os << "green"; break;

case blue : os << "blue"; break;

default : os.setstate(std::ios_base::failbit);

}

return os;

}

std::ostream& operator<<(std::ostream& os, altitude al)

{

return os << static_cast(al);

}

// The scoped enum (C++11) can be partially emulated in earlier C++ revisions:

enum struct E11 { x, y }; // since C++11

struct E98 { enum { x, y }; }; // OK in pre-C++11

namespace N98 { enum { x, y }; } // OK in pre-C++11

struct S98 { static const int x = 0, y = 1; }; // OK in pre-C++11

void emu()

{

std::cout << (static_cast(E11::y) + E98::y + N98::y + S98::y) << '\n'; // 4

}

namespace cxx20

{

enum class long_long_long_name { x, y };

void using_enum_demo()

{

std::cout << "C++20 `using enum`: __cpp_using_enum == ";

switch (auto rnd = []{return long_long_long_name::x;}; rnd())

{

#if defined(__cpp_using_enum)

using enum long_long_long_name;

case x: std::cout << __cpp_using_enum << "; x\n"; break;

case y: std::cout << __cpp_using_enum << "; y\n"; break;

#else

case long_long_long_name::x: std::cout << "?; x\n"; break;

case long_long_long_name::y: std::cout << "?; y\n"; break;

#endif

}

}

}

int main()

{

color col = red;

altitude a;

a = altitude::low;

std::cout << "col = " << col << '\n'

<< "a = " << a << '\n'

<< "f = " << f << '\n';

cxx20::using_enum_demo();

}

可能的输出

col = red

a = l

f = 3

C++20 `using enum`: __cpp_using_enum == 201907; x

[编辑] 缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告

应用于

发布时的行为

正确的行为

CWG 377

C++98

当没有整数类型可以表示所有枚举器值时,行为未指定在这种情况下,枚举是不完善的

在这种情况下,枚举是病态的在这种情况下,枚举是病态的

CWG 518

C++98

枚举器列表后不允许尾随逗号

允许

CWG 1514

C++11

固定底层类型的枚举的重新定义可能被解析为类成员声明中的位域

总是解析为重新定义

CWG 1638

C++11

不透明枚举声明的语法禁止用于模板特化

nested-name-specifier允许

CWG 1766

C++98

将超出范围的值转换为没有固定底层类型的枚举其结果未指定

行为未定义

CWG 1966

C++11

CWG 问题 1514 的解决方案使得条件表达式中的 :成为 enum-base 的一部分

仅将解决方案应用于成员声明说明符

CWG 2156

C++11

枚举定义可以通过 using-声明来定义枚举类型枚举类型可以通过 using-声明来定义

已禁止

CWG 2157

C++11

CWG 问题 1966 的解决方案未涵盖限定枚举名称

已涵盖

CWG 2530

C++98

一个枚举器列表可能包含多个具有相同标识符的枚举器

已禁止

CWG 2590

C++98

枚举的大小、值表示和对齐要求不依赖于其底层类型

所有这些都与底层类型相同

CWG 2621

C++20

using enum 声明中使用的枚举名称查找不明确using enum 声明中使用的枚举名称查找不明确

已明确

CWG 2877

C++20

using enum 声明中使用的枚举名称查找不明确using enum 声明并非仅限于类型

已改为仅限类型

[编辑] 参考

C++23 标准 (ISO/IEC 14882:2024)

9.7.1 枚举声明 [dcl.enum]

C++20 标准 (ISO/IEC 14882:2020)

9.7.1 枚举声明 [dcl.enum]

C++17 标准 (ISO/IEC 14882:2017)

10.2 枚举声明 [dcl.enum]

C++14 标准 (ISO/IEC 14882:2014)

7.2 枚举声明 [dcl.enum]

C++11 标准 (ISO/IEC 14882:2011)

7.2 枚举声明 [dcl.enum]

C++03 标准 (ISO/IEC 14882:2003)

7.2 枚举声明 [dcl.enum]

C++98 标准 (ISO/IEC 14882:1998)

7.2 枚举声明 [dcl.enum]

[编辑] 参见

is_enum(C++11)

检查一个类型是否是枚举类型 (类模板) [编辑]

is_scoped_enum(C++23)

检查一个类型是否是有作用域的枚举类型 (类模板) [编辑]

underlying_type(C++11)

获取给定枚举类型的底层整数类型 (类模板) [编辑]

to_underlying(C++23)

将枚举转换为其底层类型 (函数模板) [编辑]

C 文档 关于 枚举

💡 关键要点

C++ 编译器支持 自由(freestanding)与宿主(hosted) 语言 标准库 标准库头文件 具名要求 特性测试宏 (C++20) 语言支持库 概念库 (C++20) 诊断库 内存

更多疯狂内容

spotter 是什麼意思?

spotter 是什麼意思?

🔥 244 📅 07-07
魅族天猫要多久发货 魅族商城发货要多久
新手教程:如何使用手机版网盘