标识符

< cpp‎ | language

标识符是一个由数字,下划线,大小写拉丁字母和大多数 Unicode 字符(见下文的详细说明)组成的任意长度的序列。有效的标识符必须以一个非数字字符(拉丁字母,下划线或 Unicode 非数字字符)开头。标识符区分大小写(小写和大写字母是不同的),而且每一个字符都是起作用的。

注意:C++ 的文法中形式上要求 Unicode 字符以 \u\U 进行转义,但根据翻译阶段 1 ,这只不过是将源代码中的原始 Unicode 字符呈现给编译器的方式。还要注意的是,对这个功能特性的支持可能是有限的,比如 gcc

在声明中

可以用标识符来命名对象、引用、函数、枚举项、类型、类成员、命名空间、模板、模板特化、形参包、goto 标号,以及其他实体,但有以下例外:

  • 关键词标识符不能用于其他目的;
    • 关键词只有在属性记号中可做他用。(例如 [[private]] 是一个合法属性(C++11 起)
  • 作为特定运算符与标点符的代用表示不能用于其他目的;
  • 拥有特殊含义的标识符(finalimportmodule (C++20 起)override)在特定语境不作为常规标识符使用,而是表达它们的特定含义;
    • 在没有特别指明的情况下,这些标识符在既能作为常规标识符也能表达特定含义的场合均被视为常规标识符。
(C++11 起)
  • 其中任何位置带有双下划线的标识符都是被保留的;
  • 以一个下划线跟着一个大写字母开头的标识符是被保留的;
  • 以一个下划线开头的标识符在全局命名空间中是被保留的。

这里“被保留”的意思是,标准库的头文件可能 #define 或者声明这样的标识符以便其内部使用,编译器可能会预先定义这种非标准的标识符,而且名字重整算法可能会假定某些这样的标识符是没有被使用的。如果程序员使用了这样的标识符的话,其行为是未定义的。

此外,在一个翻译单元 #define#undef 特定名字是未定义行为,详情请见保留宏名

僵尸标识符

某些标识符只存在于以往的 C++ 标准,换而言之,它们已经被移除。但是在特定语境中,它们为兼容早期标准而被保留。

保留语境 类别/作为成员 名字
在命名空间 std 内保留 智能指针 auto_ptr
auto_ptr_ref
函数对象工具 binary_function
binary_negate
bind1st
bind2nd
binder1st
binder2nd
const_mem_fun1_ref_t
const_mem_fun1_t
const_mem_fun_ref_t
const_mem_fun_t
mem_fun1_ref_t
mem_fun1_t
mem_fun_ref_t
mem_fun_ref
mem_fun_t
mem_fun
not1
not2
pointer_to_binary_function
pointer_to_unary_function
ptr_fun
unary_function
unary_negate
未初始化存储 get_temporary_buffer
raw_storage_iterator
return_temporary_buffer
错误处理 get_unexpected
set_unexpected
uncaught_exception
unexpected
unexpected_handler
C风格 I/O gets
类型特性 is_literal_type
is_literal_type_v
result_of
result_of_t
算法 random_shuffle
作为成员类型保留
(不得作为仿对象宏的名字在可移植代码中出现)
std::function argument_type
first_argument_type
second_argument_type
std::ios_base io_state
open_mode
seek_dir
作为成员函数保留
(不得作为仿函数宏的名字在可移植代码中出现)
std::basic_stringbuf stossc

在表达式中

命名某个变量、函数概念的特化 (C++20 起)或枚举项的标识符可以作为表达式使用。仅由这个标识符组成的表达式的结果,是该标识符所命名的实体。若该标识符命名的是某个函数、变量、模板形参对象 (C++20 起)或数据成员,则表达式的值类别左值,否则为纯右值(例如枚举项是纯右值表达式,概念的特化是 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& 类型
  };
}
(C++11 起)
  • 若所命名的实体是某个 T 类型模板形参的模板形参对象,则表达式的类型为 const T
(C++20 起)
  • 否则,表达式的类型与被命名的实体的类型相同。

在非静态成员函数内,命名非静态成员的每个标识符 member 都隐式变换成一个类成员访问表达式 this->member

无限定的标识符

除了适当声明了的标识符之外,以下各项也可以以相同方式用在表达式中:

这些和标识符一起,被称作无限定的标识表达式

有限定的标识符

有限定的标识表达式是在无限定的标识表达式前面带上作用域解析运算符 ::,以及可选地带上一系列以作用域解析运算符分隔的 枚举、 (C++11 起)类或命名空间的名字,或者 decltype 表达式 (C++11 起)。例如表达式 std::string::npos 是命名在命名空间 std 内的类 string 中的静态成员 npos 的表达式。表达式 ::tolower 命名的是全局命名空间内的函数 tolower 。表达式 ::std::cout 指名 std 命名空间(顶层命名空间)中的全局变量 cout 。表达式 boost::signals2::connection 指名的是声明于 signals2 命名空间中的类型 connection ,前者则声明于命名空间 boost

有限定标识符中,可能会需要以关键词 template 来消除待决模板名的歧义。

关于为有限定的标识符进行的名字查找的细节,请参见有限定的名字查找

名字

名字是以下各项之一,用来代表某个实体或者某个标号:

  • 标识符;
  • 函数写法的重载运算符的名字( operator+operator new);
  • 用户定义的转换函数的名字( operator bool);
  • 用户定义的字面量运算符的名字( operator "" _km);
  • 模板的名字后随其实参列表( MyTemplate<int>)。

每个代表实体的名字都是由声明引入到程序中来的。代表标号的名字则既可以通过 goto 语句,也可以通过带标号语句引入到程序中来。在多个翻译单元中使用的相同名字,可以根据其连接代表相同或者不同的实体。

每当编译器在程序中遇到一个未知的名字时,它就会通过进行名字查找来将其与引入这个名字的声明联系起来,但对模板的声明和定义中的待决名不会这样做。(对于这些名字,编译器需要确定它们命名的是类型、模板还是某些其他实体,这可能需要显式消歧义

标识符中的 Unicode 字符

允许在标识符中使用下列 Unicode 字符范围:

代码点 说明 字符
U+00A8 分音符 ¨
U+00AA 阴性顺序指示符 ª
U+00AD 软连字符 ­
U+00AF 长音符 ¯
U+00B2 - U+00B5 上标二 - 微符 ²³´µ
U+00B7 - U+00BA 中间点 - 阳性顺序指示符 ·¸¹º
U+00BC - U+00BE 普通分数四分之一 - 普通分数四分之三 ¼½¾
U+00C0 - U+00D6 带抑音符的拉丁文大写字母 A - 带分音符的拉丁文大写字母 O ÀÁÂ...ÔÕÖ
U+00D8 - U+00F6 带粗线的拉丁文大写字母 O - 带分音符的拉丁文小写字母 O ØÙÚ...ôõö
U+00F8 - U+167F 带粗线的拉丁文小写字母 O - 加拿大印第安方言领音 W (阿尔滚琴语) øùú...ᙽᙾᙿ
U+1681 - U+180D 欧甘文字母 Beith - 蒙古语自由变体选择符三 ᚁᚂᚃ...᠋᠌᠍
U+180F - U+1FFE 叙利亚文字母 Beth - 希腊文 Dasia ᠏ܒܓ...´῾🿾
U+200B - U+200D 零宽间隔 - 零宽连接符 ​‌‍
U+202A - U+202E 从左至右嵌入 - 从右至左强制
U+203F - U+2040 下连接 - 字符连接 ‿⁀
U+2054 竖翻下连接
U+2060 - U+218F 文字连接符 - 倒转数字三 ...↉↊↋
U+2460 - U+24FF 带圆圈数字一 - 反白带圆圈数字〇 ①②③...⓽⓾⓿
U+2776 - U+2793 丁贝符反白带圆圈数字一 - 丁贝符反白带圆圈无衬线数字十 ❶❷❸...➑➒➓
U+2C00 - U+2DFF 格来哥里大写字母 Azu - 组合用西里尔文字母 lota 化的大 Yus ⰀⰁⰂ...
U+2E80 - U+2FFF 中日韩字根重复 - 象形字重叠结构 ⺀⺁⺂...⿹⿺⿻
U+3004 - U+3007 日本工业标准符号 - 象形字数字 0 〄々〆〇
U+3021 - U+302F 杭州数字(苏州码子)一 - 朝鲜文双点音调标志 〡〢〣...
U+3031 - U+D7FF 竖假名重复标志 - 朝鲜文 PHIEUPH-THIEUTH ...
U+F900 - U+FD3D 中日韩兼容象形文字-F900 - 带 Fathatan 独立形式的阿拉伯文连字 Alef 豈更車...ﴻﴼﴽ
U+FD40 - U+FDCF 带 Jeem 的阿拉伯文连字 Te,还带有 Meem 词首形式 -
带 Jeem 的阿拉伯文连字 Noon,还带有 Yeh 词尾形式
U+FDF0 - U+FE44 阿拉伯文连字 Salla 用于可兰经的句号标记独立形式 -
变形显现形式垂直右空心角括号
...﹂﹃﹄
U+FE47 - U+FFFD 变形显现形式垂直左方括号 - 替换字符 ﹇﹈﹉...�
U+10000 - U+1FFFD 线性文字 B 音节 B008 A - 楔形奶酪 (U+1F9C0)
U+20000 - U+2FFFD <中日韩象形文字扩展 B , 第一个> - 中日韩兼容象形文字-2FA1D (U+2FA1D)
U+30000 - U+3FFFD
U+40000 - U+4FFFD
U+50000 - U+5FFFD
U+60000 - U+6FFFD
U+70000 - U+7FFFD
U+80000 - U+8FFFD
U+90000 - U+9FFFD
U+A0000 - U+AFFFD
U+B0000 - U+BFFFD
U+C0000 - U+CFFFD
U+D0000 - U+DFFFD
U+E0000 - U+EFFFD 语言标记 (U+E0001) - 变体选择符-256 (U+E01EF)


不允许以下列 Unicode 字符的范围为标识符的开头:

代码点 说明 字符
U+0300 - U+036F 组合用抑音符 - 组合用拉丁文小写字母 X
U+1DC0 - U+1DFF 组合用带点抑音符 - 组合用下右箭头尖和向下箭头尖
U+20D0 - U+20FF 组合用上左鱼叉 - 组合用上星号
U+FE20 - U+FE2F 组合用连字左半 - 组合用西里尔文 Titlo 右半

参阅