Identifiers
一个 标识符 是由数字、下划线、小写和大写拉丁字母以及大多数Unicode字符组成的任意长度序列。
有效标识符的首字符必须是以下之一:
- 大写拉丁字母 A-Z
- 小写拉丁字母 a-z
- 下划线
- 具有 Unicode 属性 XID_Start 的任何 Unicode 字符
有效标识符的其他任何字符必须是以下之一:
- 数字 0-9
- 大写拉丁字母 A-Z
- 小写拉丁字母 a-z
- 下划线
- 任何具有 Unicode 属性 XID_Continue 的 Unicode 字符
具有 XID_Start 和 XID_Continue 属性的字符列表可在 DerivedCoreProperties.txt 中找到。
标识符区分大小写(小写字母和大写字母是不同的),且每个字符都至关重要。每个标识符必须符合 规范化形式C 。
注意:在大多数实现中对Unicode标识符的支持有限,例如 gcc (10版本之前) 。
目录 |
在声明中
标识符可用于 命名 对象、引用、函数、枚举项、类型、类成员、命名空间、模板、模板特化、 参数包 (C++11 起) 、goto 标签及其他实体,但存在以下例外情况:
- 标识符中属于 关键字 的部分不能用于其他用途。
|
(C++11 起) |
- 作为某些 运算符和标点符号替代表示 的标识符不能用于其他用途。
|
(自 C++11 起) |
-
以下形式之一作为标记或预处理标记出现的标识符(即不在
用户定义字符串字面量
中,如
operator
""
id
)被保留:
- 在全局命名空间中,以下划线开头的标识符
- 包含双下划线或以下划线后接大写字母开头的标识符,但以下标识符除外:
| (自 C++11 起) |
|
(自 C++11 起) |
| (自 C++20 起) |
“保留”在此处意味着标准库头文件会 #define 或声明这些标识符以满足其内部需求,编译器可能预定义此类非标准标识符,且名称修饰算法可假定部分此类标识符未被使用。若程序员使用此类标识符,则程序非良构,不要求诊断。
此外,在翻译单元中对特定名称进行 #define 或 #undef 操作属于未定义行为,详见 保留宏名称 说明。
僵尸标识符
自 C++14 起,部分标识符已从 C++ 标准库中移除。这些标识符列于 僵尸名称列表 中。
然而,在特定上下文中这些标识符仍为先前标准化保留。被移除的成员函数名称不可用作函数式宏的名称,而其他被移除的成员名称在可移植代码中不可用作对象式宏的名称。
在表达式中
命名变量、函数、 概念 特化 (C++20 起) 或枚举项的标识符可用作 表达式 。仅由标识符组成的表达式结果是该标识符所命名的实体。若标识符命名函数、变量 、 模板形参对象 (C++20 起) 或数据成员,则表达式的 值类别 为 左值 ,否则为 右值 (C++11 前) 纯右值 (C++11 起) (例如 枚举项 是 右值 (C++11 前) 纯右值 (C++11 起) 表达式 ,概念特化为 bool 纯右值 (C++20 起) )。
类型
标识符表达式的类型与其命名实体的类型相同。
|
存在以下例外情况:
void f() { float x, &r = x; [=] { decltype(x) y1; // y1 具有类型 float decltype((x)) y2 = y1; // y2 具有类型 float const&,因为此 lambda // 非 mutable 且 x 是左值 decltype(r) r1 = y1; // r1 具有类型 float& decltype((r)) r2 = y2; // r2 具有类型 float const& }; }
|
(since C++11) |
非限定标识符
除了适当声明的标识符外,以下内容可在表达式中以相同角色使用:
- 一个以函数表示法书写的 重载运算符 名称,例如 operator + 或 operator new ;
- 一个 用户定义转换函数 名称,例如 operator bool ;
|
(自 C++11 起) |
- 一个 模板 名称后跟其参数列表,例如 MyTemplate < int > ;
- 字符 ~ 后跟一个类名,例如 ~MyClass ;
|
(since C++11) |
|
(since C++26) |
与标识符一起,它们被称为 未限定标识符表达式 。
限定标识符
一个 限定标识符表达式 是由作用域解析运算符 :: 前置的非限定标识符表达式,并可选择性地后接由作用域解析运算符分隔的以下任意序列:
- 命名空间名称;
- 类名称;
|
(自 C++11 起) |
|
(since C++26) |
例如,表达式 std:: string :: npos 是一个命名了 std 命名空间中 string 类的静态成员 npos 的表达式。表达式 :: tolower 命名了全局命名空间中的函数 tolower 。表达式 :: std:: cout 命名了顶级命名空间 std 中的全局变量 cout 。表达式 boost :: signals2 :: connection 命名了在 boost 命名空间内声明的 signals2 命名空间中声明的类型 connection 。
关键字 template 可以在限定标识符中出现,用于消除 依赖模板名称 的二义性。
请参阅 限定查找 了解限定标识符的名称查找细节。
隐式成员访问转换
若标识符表达式
E
表示某个类
C
的非静态非类型成员,且满足以下所有条件时,
E
将被转换为类成员访问表达式
this
-
>
E
:
-
- E 是 潜在求值 的。
-
C是 E 的最内层封闭类。 -
C是 E 的最内层封闭类的基类。
此转换不适用于模板定义上下文(参见 依赖名 )。
struct X { int x; }; struct B { int b; }; struct D : B { X d; void func() { d; // 正确:将被转换为 this->d b; // 正确:将被转换为 this->b x; // 错误:this->x 格式不正确 d.x; // 正确:将被转换为 this->d.x // 而非 d.this->x 或 this->d.this->x } };
名称
一个 名称 是指使用以下方式之一来引用某个实体:
- 标识符
- 函数表示法中的重载运算符名称( operator + , operator new )
- 用户自定义转换函数名称( operator bool )
|
(since C++11) |
- 模板名称后跟其参数列表( MyTemplate < int > )
每个名称都是通过 声明 引入程序的。在多个翻译单元中使用的名称可能指向相同或不同的实体,具体取决于 链接 方式。
当编译器在程序中遇到未知名称时,它会通过 名称查找 将其与引入该名称的声明关联起来,但模板声明和定义中的 依赖名称 除外(对于这些名称,编译器需要确定它们是指代类型、模板还是其他实体,这可能需要进行 显式消歧 )。
缺陷报告
以下行为变更缺陷报告被追溯应用于先前发布的C++标准。
| 缺陷报告 | 应用于 | 发布时的行为 | 正确行为 |
|---|---|---|---|
| CWG 1440 | C++11 |
位于
::
之前的 decltype 表达式可以表示任意类型
|
只能表示类
或枚举类型 |
| CWG 1963 | C++11 |
除数字、非数字和通用字符名称外,
实现定义的字符可用于标识符 |
禁止使用 |
| CWG 2521 | C++11 |
字面量运算符的
用户定义字符串字面量
中
的标识符按常规方式保留 |
规则有所不同 |
| CWG 2771 | C++98 | 在类上下文中 & a 未转换为 & this - > a | 会进行转换 |
| CWG 2777 | C++20 |
若标识符表达式命名模板参数对象,
其类型不明确 |
已明确 |
| CWG 2818 | C++98 | 预定义宏名称被保留 | 不再保留 |
参见
|
C 文档
关于
标识符
|