識別符號
一個 識別符號 是由任意長度的數字、下劃線、小寫和大寫拉丁字母,以及大多數 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 起) |
- 以下形式的識別符號 (以 token 或預處理 token 形式出現,即不在 user-defined-string-literal 中,如 operator ""id)(C++11 起) 是保留的:
- 在全域性名稱空間中,以下劃線開頭的識別符號
- 包含雙下劃線或以下劃線後跟大寫字母開頭的識別符號,除了以下識別符號:
(C++11 起) |
|
(C++11 起) |
(C++20 起) |
這裡的“保留”意味著標準庫標頭檔案 #define 或宣告此類識別符號用於其內部需求,編譯器可以預定義此類非標準識別符號,並且名稱重整演算法可能假定其中一些識別符號未被使用。如果程式設計師使用此類識別符號,則程式格式錯誤,不需要診斷。
此外,在翻譯單元中 #define 或 #undef 某些名稱是未定義行為,詳見 保留宏名稱。
[編輯] 殭屍識別符號
從 C++14 起,一些識別符號已從 C++ 標準庫中刪除。它們列在 殭屍名稱列表 中。
然而,這些識別符號在特定上下文中仍為之前的標準化所保留。已刪除的成員函式名不能用作函式式宏的名稱,而其他已刪除的成員名不能用作可移植程式碼中物件式宏的名稱。
[編輯] 在表示式中
命名變數、函式、概念的特化(C++20 起)或列舉器的識別符號可以用作表示式。僅由識別符號組成的表示式的結果是識別符號命名的實體。表示式的值類別是 lvalue,如果識別符號命名的是函式、變數、模板引數物件(C++20 起)或資料成員,否則為 rvalue(C++11 前)prvalue(C++11 起)(例如,列舉器是 rvalue(C++11 前)prvalue(C++11 起)表示式,概念的特化是布林 prvalue(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,而 signals2 宣告在名稱空間 boost 中。
關鍵字 template 可能出現在限定識別符號中,以消除依賴模板名稱的歧義。
有關限定識別符號名稱查詢的詳細資訊,請參閱限定查詢。
[編輯] 隱式成員訪問轉換
如果識別符號表示式 E 表示類 C
的某個非靜態非型別成員,並且滿足以下所有條件,則 E 被轉換為類成員訪問表示式 this->E
- E 可能被求值。
-
C
是 E 處最內層的 enclosing class。 -
C
是 E 處最內層 enclosing class 的基類。
此轉換不適用於模板定義上下文(請參見依賴名稱)。
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++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
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 文件 關於 識別符號
|