Namespaces
Variants

Identifiers

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

一个 标识符 是由数字、下划线、小写和大写拉丁字母以及大多数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 标签及其他实体,但存在以下例外情况:

  • 标识符中属于 关键字 的部分不能用于其他用途。
  • 它们唯一能作为非关键字使用的场景是在 属性标记 中(例如 [ [ private ] ] 是有效的 属性 )。
(C++11 起)
  • 具有特殊含义的标识符( final import module (自 C++20 起) override )在特定上下文中被显式使用,而非作为常规标识符。
    • 除非另有说明,对于给定标识符是否具有特殊含义的任何歧义,均按将标记解释为常规标识符的方式解决。
(自 C++11 起)
  • 以下形式之一作为标记或预处理标记出现的标识符(即不在 用户定义字符串字面量 中,如 operator "" id )被保留:
    • 在全局命名空间中,以下划线开头的标识符
    • 包含双下划线或以下划线后接大写字母开头的标识符,但以下标识符除外:
(自 C++11 起)
  • 标准库中定义的以下宏:
  • C 兼容性宏 __alignas_is_defined __alignof_is_defined (定义于 <stdalign.h>
  • C 兼容性宏 __bool_true_false_are_defined (定义于 <stdbool.h>
(自 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 起) )。

类型

标识符表达式的类型与其命名实体的类型相同。

存在以下例外情况:

  • 若由(非限定)标识符命名的实体是局部实体,且若在声明该标识符的区域中,在未求值操作数之外命名该实体将导致介入的 lambda 表达式 以复制方式捕获它,则该表达式的类型是 类成员访问表达式 的类型,该表达式命名了在最内层此类介入 lambda 表达式的闭包对象中为此类捕获声明的非静态数据成员。
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&
    };
}
  • 若命名的实体是类型为 T 的模板参数的 模板参数对象 ,则该表达式的类型为 const T
(since C++20)
(since C++11)

非限定标识符

除了适当声明的标识符外,以下内容可在表达式中以相同角色使用:

(自 C++11 起)
  • 一个 模板 名称后跟其参数列表,例如 MyTemplate < int >
  • 字符 ~ 后跟一个类名,例如 ~MyClass
  • 字符 ~ 后接 decltype 说明符,例如 ~decltype ( str )
(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
  • 用户定义字面量运算符名称 ( operator "" _km )
(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 文档 关于 标识符