标识符
标识符 是一个任意长度的数字、下划线、小写和大写拉丁字母以及大多数 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 起) |
- 以下形式之一的标识符,作为标记或预处理标记出现(即,不在 user-defined-string-literal 中,例如 operator ""id)(自 C++11 起)是保留的
- 在全局命名空间中,以下划线开头的标识符
- 包含双下划线或以下划线后跟大写字母开头的标识符,但以下标识符除外
(自 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 has type float decltype((x)) y2 = y1; // y2 has type float const& because this lambda // is not mutable and x is an lvalue decltype(r) r1 = y1; // r1 has type float& decltype((r)) r2 = y2; // r2 has type float const& }; }
|
(自 C++11 起) |
[编辑] 非限定标识符
除了适当声明的标识符外,以下内容也可以在表达式中扮演相同的角色
- 函数表示法中的重载运算符名称,例如 operator+ 或 operator new;
- 用户定义的转换函数名称,例如 operator bool;
|
(自 C++11 起) |
- 模板名称后跟其参数列表,例如 MyTemplate<int>;
- 字符 ~ 后跟类名,例如 ~MyClass;
|
(自 C++11 起) |
|
(自 C++26 起) |
它们与标识符一起被称为非限定标识符表达式。
[编辑] 限定标识符
限定标识符表达式是一个非限定标识符表达式,前面加上作用域解析运算符 ::,以及可选地,由作用域解析运算符分隔的以下任何序列
- 命名空间名称;
- 类名称;
|
(自 C++11 起) |
|
(自 C++26 起) |
例如,表达式 std::string::npos 是一个表达式,它命名命名空间 std 中类 string 中的静态成员 npos。表达式 ::tolower 命名全局命名空间中的函数 tolower。表达式 ::std::cout 命名命名空间 std 中的全局变量 cout,它是顶层命名空间。表达式 boost::signals2::connection 命名命名空间 signals2 中声明的类型 connection,该命名空间在命名空间 boost 中声明。
关键字 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; // OK, will be transformed into this->d b; // OK, will be transformed into this->b x; // Error: this->x is ill-formed d.x; // OK, will be transformed into this->d.x // instead of d.this->x or this->d.this->x } };
[编辑] 名称
名称是使用以下之一来引用实体
- 标识符
- 函数表示法中的重载运算符名称(operator+、operator new)
- 用户定义的转换函数名称(operator bool)
|
(自 C++11 起) |
- 模板名称后跟其参数列表(MyTemplate<int>)
每个名称都通过声明引入程序。在多个翻译单元中使用的名称可能引用相同或不同的实体,具体取决于链接。
当编译器在程序中遇到未知名称时,它会通过名称查找将其与引入该名称的声明相关联,模板声明和定义中的依赖名称除外(对于这些名称,编译器确定它们是命名类型、模板还是其他实体,这可能需要显式消除歧义)。
[编辑] 缺陷报告
以下行为变更的缺陷报告已追溯应用于以前发布的 C++ 标准。
DR | 应用于 | 已发布行为 | 正确行为 |
---|---|---|---|
CWG 1440 | C++11 | :: 前面的 decltype 表达式可以表示任何类型 |
只能表示类 或枚举类型 |
CWG 1963 | C++11 | 实现定义的字符,数字、非数字之外的字符 和通用字符名称可以用于标识符 |
禁止 |
CWG 2521 | C++11 | 字面量运算符的 user-defined-string-literal 中的标识符 像往常一样被保留 |
规则不同 |
CWG 2771 | C++98 | 在类上下文中,&a 未转换为 &this->a | 它被转换 |
CWG 2777 | C++20 | 如果标识符表达式命名模板形参对象,则其类型不明确 如果它命名模板形参对象 |
已明确 |
CWG 2818 | C++98 | 预定义宏名称是保留的 | 它们未被保留 |
[编辑] 参见
C 文档 关于 标识符
|