命名空间
变体
操作

标识符

来自 cppreference.com
< cpp‎ | language
 
 
C++ 语言
 
 

一个标识符是任意长度的数字、下划线、小写和大写拉丁字母以及大多数 Unicode 字符的序列。

有效标识符的第一个字符必须是以下字符之一

  • 大写拉丁字母 A-Z
  • 小写拉丁字母 a-z
  • 下划线
  • 任何具有 Unicode 属性的 Unicode 字符 XID_Start

有效标识符的任何其他字符必须是以下字符之一

  • 数字 0-9
  • 大写拉丁字母 A-Z
  • 小写拉丁字母 a-z
  • 下划线
  • 任何具有 Unicode 属性的 Unicode 字符 XID_Continue

具有属性 XID_Start 和 XID_Continue 的字符列表可以在 DerivedCoreProperties.txt 中找到。

标识符区分大小写(小写和大写字母是不同的),每个字符都有意义。每个标识符都必须符合 规范形式 C

注意:大多数实现对 Unicode 标识符的支持有限,例如 gcc(直到 10)

内容

[编辑] 在声明中

标识符可以用于 命名 对象、引用、函数、枚举器、类型、类成员、命名空间、模板、模板特化, 参数包(自 C++11 起) goto 标签和其他实体,以下情况除外

  • 用作 关键字 的标识符不能用于其他目的。
  • 它们唯一可以作为非关键字使用的地方是在 attribute-token 中(例如,[[private]] 是一个有效的 属性)。
(自 C++11 起)
  • 用作某些运算符和标点符号的 备用表示 的标识符不能用于其他目的。
  • 具有特殊含义的标识符(final, import, module(自 C++20 起)override)是在特定上下文中明确使用,而不是作为常规标识符。
    • 除非另有说明,否则,对于给定标识符是否具有特殊含义的任何歧义,都将被解析为将标记解释为常规标识符。
(自 C++11 起)
  • 标识符出现在标记或预处理标记中(即,不在 user-defined-string-literal 中,例如 operator ""id)(自 C++11 起) 以下形式之一,将被保留
    • 在全局命名空间中,以下划线开头的标识符
    • 包含双下划线或以下划线后跟大写字母开头的标识符,以下标识符除外
(自 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 某些名称会导致未定义行为,有关详细信息,请参阅 保留宏名称

[edit] 僵尸标识符

从 C++14 开始,一些标识符已从 C++ 标准库中删除。它们列在 僵尸名称列表 中。

但是,这些标识符仍然在特定上下文中为以前的标准化保留。删除的成员函数名称不能用作类似函数的宏的名称,其他删除的成员名称不能用作可移植代码中类似对象的宏的名称。

[edit] 在表达式中

命名变量、函数、概念的专用化、(自 C++20 起)或枚举器的标识符可以用作 表达式。仅由标识符组成的表达式的结果是由标识符命名的实体。表达式的 值类别 如果标识符命名函数、变量模板参数对象(自 C++20 起)或数据成员,则为 左值,否则为 右值(直到 C++11)纯右值(自 C++11 起)(例如,枚举器右值(直到 C++11)纯右值(自 C++11 起)表达式,概念的专用化为 bool 纯右值(自 C++20 起))。

[edit] 类型

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

存在以下例外情况

  • 如果由(非限定)标识符命名的实体是局部实体,并且如果它在标识符出现的声明区域之外被命名,则会导致中间的 lambda 表达式 通过复制捕获它,则表达式的类型为命名非静态数据成员的 类成员访问表达式 的类型,该数据成员将在最内层此类中间 lambda 表达式的闭包对象中声明。
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&
    };
}
  • 如果命名的实体是 模板参数对象,用于类型为 T 的模板参数,则表达式的类型为 const T
(自 C++20 起)
(自 C++11 起)

[edit] 非限定标识符

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

(自 C++11 起)
  • 后跟其参数列表的 模板 名称,例如 MyTemplate<int>
  • 字符 ~ 后跟类名,例如 ~MyClass
  • 字符 ~ 后跟 decltype 说明符,例如 ~decltype(str)
(自 C++11 起)
(自 C++26 起)

它们与标识符一起被称为 非限定标识符表达式

[edit] 限定标识符

限定标识符表达式 是在非限定标识符表达式之前加上作用域解析运算符 ::,并且可选地,在作用域解析运算符之间加上一系列以下任何内容

  • 命名空间名称;
  • 类名;
(自 C++11 起)
(自 C++26 起)

例如,表达式 std::string::npos 是一个表达式,它命名了命名空间 std 中类 string 中的静态成员 npos。表达式 ::tolower 命名了全局命名空间中的函数 tolower。表达式 ::std::cout 命名了命名空间 std 中的全局变量 cout,这是一个顶层命名空间。表达式 boost::signals2::connection 命名了在命名空间 signals2 中声明的类型 connection,该命名空间在命名空间 boost 中声明。

关键字 template 可能会出现在限定标识符中,以根据需要消除 依赖模板名称 的歧义。

有关限定标识符的名称查找的详细信息,请参阅 限定查找

[edit] 隐式成员访问转换

如果标识符表达式 E 表示某个类 C 的非静态非类型成员,并且满足以下所有条件,则 E 将转换为类成员访问表达式 this->E

  • E潜在求值
  • CE 的最内层封闭类。
  • CE 的最内层封闭类的基类。

此转换不适用于模板定义上下文(请参阅 依赖名称)。

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
    }
};

[edit] 名称

名称 是使用以下内容之一来引用实体

  • 标识符
  • 函数表示法中的重载运算符名称 (operator+operator new)
  • 函数表示法中的用户定义的转换函数名称 (operator bool)
  • 函数表示法中的用户定义的字面量运算符名称 (operator ""_km)
(自 C++11 起)
  • 后跟其参数列表的模板名称 (MyTemplate<int>)

每个名称都由 声明 引入程序。在多个翻译单元中使用的名称可能引用相同或不同的实体,具体取决于 链接

当编译器在程序中遇到未知名称时,它会通过 名称查找 将其与引入该名称的声明相关联,除了模板声明和定义中的 依赖名称(对于这些名称,编译器确定它们是命名类型、模板还是其他实体,这可能需要 显式消除歧义)。

[编辑] 缺陷报告

以下行为更改的缺陷报告被追溯应用于先前发布的 C++ 标准。

DR 应用于 发布的行为 正确行为
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 文档 用于 标识符