命名空間
變體
動作

識別符 (Identifiers)

出自 cppreference.com
< cpp‎ | language
 
 
C++ 語言
一般主題
流程控制
條件執行陳述式
if
疊代陳述式 (迴圈)
for
範圍 for (C++11)
跳躍陳述式
函式
函式宣告
Lambda 函式運算式
inline 指定符
動態例外規範 (直到 C++17*)
noexcept 指定符 (C++11)
例外
命名空間
型別
指定符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
儲存期指定符
初始化
 
 

識別符(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 標籤及其他實體,但有下列例外:

  • 作為關鍵字的識別符不能用於其他用途。
  • 它們唯一能以非關鍵字形式使用的場合是在 屬性標記 (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 或宣告此類識別符,編譯器亦可預定義該類非標準識別符,且名稱修飾(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 起))。

[編輯] 類型

識別符運算式的類型與其所命名實體的類型相同。

存在下列例外:

  • 若由(非限定)識別符命名的實體是區域實體,且若該識別符出現在宣告區域中的非求值運算元之外時,會導致插入的 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 起)

[編輯] 非限定識別符

除適當宣告的識別符外,下列項目亦可在運算式中擔任相同角色:

(C++11 起)
  • 後接引數列表的範本名稱,例如 MyTemplate<int>
  • 後接類別名稱的字元 ~,例如 ~MyClass
  • 後接 decltype 指定符的字元 ~,例如 ~decltype(str)
(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

此轉換不適用於範本定義內容(參見相依名稱)。

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)
  • 使用者自訂實字運算子名稱 (operator ""_km)
(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 文件 關於 識別符
English Deutsch 日本語 中文(简体) 中文(繁體)