識別符 (Identifiers)
識別符(Identifier)是任意長度的序列,由數字、底線、大小寫拉丁字母以及大多數 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 中找到。
識別符區分大小寫(小寫與大寫字母視為不同),且每個字元皆具備意義。每個識別符都必須符合 Unicode 正規化形式 C (Normalization Form 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 或宣告此類識別符,編譯器亦可預定義該類非標準識別符,且名稱修飾(name mangling)演算法可能會假設其中部分識別符未被使用。若程式設計師使用了這些識別符,程式即為病態(ill-formed),且無需診斷訊息。
此外,在轉譯單元中 #define 或 #undef 特定名稱會導致未定義行為,詳情請見保留的巨集名稱。
[編輯] 殭屍識別符
自 C++14 起,部分識別符已從 C++ 標準函式庫中移除。它們列於殭屍名稱列表中。
然而,這些識別符在特定上下文中對於先前的標準化版本仍然是保留的。被移除的成員函式名稱不得在可攜式程式碼中用作類函式巨集的名稱,其他被移除的成員名稱亦不得用作類物件巨集的名稱。
[編輯] 在運算式中
命名變數、函式、概念 (concept) 的特化、(C++20 起)或列舉元的識別符可用作運算式。僅由識別符組成的運算式,其結果為該識別符所命名的實體。若識別符命名的是函式、變數、範本參數物件(C++20 起)或資料成員,該運算式的值類別 (value category) 為左值 (lvalue);否則為右值 (rvalue)(C++11 前)純右值 (prvalue)(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(該空間宣告於 boost 命名空間中)內的類型 connection。
若有必要消除相依範本名稱的歧義,可在限定識別符中使用關鍵字 template。
關於限定識別符名稱查閱的細節,請見限定名稱查閱。
[編輯] 隱式成員存取轉換
若識別符運算式 E 表示某個類別 C 的非靜態非類型成員,且滿足下列所有條件,則 E 會被轉換為類別成員存取運算式 this->E:
- E 是潛在求值 (potentially evaluated)的。
-
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>)
每個名稱都藉由宣告被引入程式中。在多個轉譯單元中使用的名稱,根據連結 (linkage),可能參照同一個或不同的實體。
當編譯器在程式中遇到未知名稱時,會藉由名稱查閱將其與引入該名稱的宣告關聯起來;但範本宣告與定義中的相依名稱除外(對於這些名稱,編譯器需確定它們命名的是類型、範本或其他實體,這可能需要顯式釐清歧義)。
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯應用於之前的 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 文件 關於 識別符
|