命名空間
變體
動作

宣告

出自 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)
儲存期指定符
初始化
 
 

宣告 (Declarations) 是將名稱引入(或重新引入)C++ 程式的方式。並非所有的宣告都能宣告具體事物,且每種類型的實體(entity)宣告方式皆有所不同。定義 (Definitions) 是足以用來使用該名稱所標識實體的宣告。

宣告包含以下幾種:

  • 屬性宣告 (attr ;)
(C++11 起)
  • 空宣告 (Empty declaration) (;)
  • 不含 decl-specifier-seq 的函式宣告
attr (optional) declarator ;
屬性 - (since C++11) 任意數量的 屬性序列
宣告子 (declarator) - 一個函式宣告子 (function declarator)
此宣告必須宣告建構函式、解構函式或使用者自定義型別的轉型函式 (conversion function)。它只能作為範本宣告顯式特化或顯式實例化的一部分使用。
  • 區塊宣告 (block-declaration)(可出現於區塊內的宣告),其本身可以是下列其中之一:
(C++11 起)
(自 C++20 起)
(C++11 起)
  • 簡單宣告 (simple declaration)

目錄

[edit] 簡單宣告

簡單宣告是一種引入、建立並可選擇性初始化一個或多個識別碼(通常為變數)的語句。

decl-specifier-seq init-declarator-list (optional) ; (1)
attr decl-specifier-seq init-declarator-list ; (2) (C++11 起)
decl-specifier-seq (宣告說明符序列) - 說明符序列
初始化宣告子列表 (init-declarator-list) - 以逗號分隔的 init-declarator 列表(詳見下文)
屬性 - 任意數量的屬性序列


init-declarator-list 僅在宣告具名類別或具名列舉時可省略。

結構化綁定宣告 (structured binding declaration) 亦為簡單宣告。

(自 C++17 起)


init-declarator 的語法定義如下:

declarator initializer (1)
declarator requires-clause (optional) contract-specs (optional) (2)
1) 帶有初始化的宣告子。
2) 不帶初始化的宣告子。
宣告子 (declarator) - 一個 宣告子
初始化式 (initializer) - 一個 初始化式
requires-clause - (since C++20) 一個 requires 子句
contract-specs - (since C++26) 一個 函式合約說明符 (function contract specifiers) 列表


requires-clause 僅當 declarator 宣告的是一個範本化函式 (templated function) 時才可出現。

(自 C++20 起)

contract-specs 僅當 declarator 宣告的是一個函式或函式範本時才可出現。

(C++26 起)

[edit] 說明符

宣告說明符 (Declaration specifiers) (decl-specifier-seq) 是下列以空白分隔的說明符序列,順序不拘:

  • inline 說明符也允許用於變數宣告。
(自 C++17 起)
  • friend 說明符,允許用於類別和函式宣告。
  • constexpr 說明符,僅允許用於變數定義、函式和函式範本宣告,以及字面值型別的靜態資料成員宣告。
(C++11 起)
  • consteval 說明符,僅允許用於函式和函式範本宣告。
  • constinit 說明符,僅允許用於靜態或執行緒儲存期的變數宣告。在 decl-specifier-seq 中,constexprconstevalconstinit 說明符最多只能出現一個。
(自 C++20 起)
  • 儲存類別說明符 (storage class specifier) (register, (until C++17) static, thread_local, (since C++11) extern, mutable)。僅允許一個儲存類別說明符,例外情況為 thread_local 可與 externstatic 同時出現(since C++11)
  • 型別說明符 (Type specifiers) (type-specifier-seq),是一個命名型別的說明符序列。該宣告所引入的每個實體,其型別均為此型別,並可由宣告子選擇性地修改(見下文)。此說明符序列亦由 type-id 使用。只有下列說明符屬於 type-specifier-seq,順序不拘:
(C++11 起)
(C++26 起)
(自 C++17 起)
在 decl-specifier-seq 中僅允許出現一個型別說明符,但以下情況除外:
  • const 可與任何其他型別說明符組合(自身除外)。
  • volatile 可與任何其他型別說明符組合(自身除外)。
  • signedunsigned 可與 char, long, shortint 組合。
  • shortlong 可與 int 組合。
  • long 可與 double 組合。
  • long 可與 long 組合。
(C++11 起)

屬性可出現在 decl-specifier-seq 中,在此情況下,它們適用於由前面說明符所決定的型別。

decl-specifier-seq 中重複使用任何說明符(例如 const static constvirtual inline virtual)均為錯誤,例外情況為 long 允許出現兩次(since C++11)

[edit] 宣告子 (Declarators)

init-declarator-list 中的每個 init-declarator(形式為 S D1, D2, D3;)的處理方式,皆如同將其視為帶有相同說明符的獨立宣告:S D1; S D2; S D3;

每個宣告子引入恰好一個物件、參考、函式或(對於 typedef 宣告)型別別名,其型別由 decl-specifier-seq 提供,並可選由宣告子中的運算子(如 &(參考至)、[](陣列)或 ()(函式回傳值)進行修改。這些運算子可遞迴應用,如下所示。

宣告子 (declarator) 為以下其中之一:

unqualified-id attr (optional) (1)
qualified-id attr (optional) (2)
... identifier attr (optional) (3) (C++11 起)
* attr (optional) cv (optional) declarator (4)
nested-name-specifier * attr (optional) cv (optional) declarator (5)
& attr (optional) declarator (6)
&& attr (optional) declarator (7) (C++11 起)
noptr-declarator [ constexpr (optional) ] attr (optional) (8)
noptr-declarator ( parameter-list ) cv (optional) ref  (optional) except (optional) attr (optional) (9)
1) 所宣告的 名稱
2) 使用 限定識別碼 (qualified-id) 的宣告子,用於定義或重新宣告先前已宣告的 命名空間成員類別成員
3) 參數包,僅出現在 參數宣告中。
4) 指標宣告子:宣告 S * D;D 宣告為指向由 decl-specifier-seq S 所決定型別的指標。
5) 指向成員的指標宣告:宣告 S C::* D;D 宣告為指向 C 的成員指標,該成員型別由 decl-specifier-seq S 決定。nested-name-specifier名稱與範疇解析運算子 :: 的序列
6) 左值參考宣告子:宣告 S & D;D 宣告為指向由 decl-specifier-seq S 所決定型別的左值參考。
7) 右值參考宣告子:宣告 S && D;D 宣告為指向由 decl-specifier-seq S 所決定型別的右值參考。
8) 陣列宣告子noptr-declarator 可為任何有效宣告子,但若其以 *、& 或 && 開頭,則必須以括號括起。
9) 函式宣告子noptr-declarator 可為任何有效宣告子,但若其以 *、& 或 && 開頭,則必須以括號括起。其結尾可包含選用的後置回傳型別。(since C++11)

在所有情況下,attr 皆為選用的屬性序列。當其緊接在識別碼後出現時,它適用於正在被宣告的物件。

(C++11 起)

cv const 和 volatile 限定詞的序列,其中每個限定詞在序列中至多可出現一次。

[edit] 附註

區塊宣告出現在區塊內,且由宣告引入的識別碼先前已在外層區塊中宣告,則外層宣告會在該區塊剩餘部分中被隱藏

如果一個宣告引入了具有自動儲存期的變數,則該變數會在執行其宣告語句時進行初始化。所有在區塊內宣告的自動變數都會在離開該區塊時被銷毀(無論離開方式為何:透過例外goto,或是到達區塊結尾),銷毀順序與其初始化順序相反。

[edit] 範例

注意:此範例示範了一些複雜宣告如何根據語言語法進行解析。其他常見的記憶法包括:螺旋規則 (the spiral rule)由內而外讀取,以及宣告反映用法 (declaration mirrors use)。此外,網址 https://cdecl.org 提供了一個自動化解析器。

#include <type_traits>
 
struct S
{
    int member;
    // decl-specifier-seq is "int"
    // declarator is "member"
} obj, *pObj(&obj);
// decl-specifier-seq is "struct S { int member; }"
// declarator "obj" declares an object of type S
// declarator "*pObj" declares a pointer to S,
//     and initializer "(&obj)" initializes it
 
int i = 1, *p = nullptr, f(), (*pf)(double);
// decl-specifier-seq is "int"
// declarator "i" declares a variable of type int,
//     and initializer "= 1" initializes it
// declarator "*p" declares a variable of type int*,
//     and initializer "= nullptr" initializes it
// declarator "f()" declares (but doesn't define)
//     a function taking no arguments and returning int
// declarator "(*pf)(double)" declares a pointer to function
//     taking double and returning int
 
int (*(*var1)(double))[3] = nullptr;
// decl-specifier-seq is "int"
// declarator is "(*(*var1)(double))[3]"
// initializer is "= nullptr"
 
// 1. declarator "(*(*var1)(double))[3]" is an array declarator:
//    Type declared is: "(*(*var1)(double))" array of 3 elements
// 2. declarator "(*(*var1)(double))" is a pointer declarator:
//    Type declared is: "(*var1)(double)" pointer to array of 3 elements
// 3. declarator "(*var1)(double)" is a function declarator:
//    Type declared is: "(*var1)" function taking "(double)",
//    returning pointer to array of 3 elements.
// 4. declarator "(*var1)" is a pointer declarator:
//    Type declared is: "var1" pointer to function taking "(double)",
//    returning pointer to array of 3 elements.
// 5. declarator "var1" is an identifier.
// This declaration declares the object var1 of type "pointer to function
// taking double and returning pointer to array of 3 elements of type int"
// The initializer "= nullptr" provides the initial value of this pointer.
 
// C++11 alternative syntax:
auto (*var2)(double) -> int (*)[3] = nullptr;
// decl-specifier-seq is "auto"
// declarator is "(*var2)(double) -> int (*)[3]"
// initializer is "= nullptr"
 
// 1. declarator "(*var2)(double) -> int (*)[3]" is a function declarator:
//    Type declared is: "(*var2)" function taking "(double)", returning "int (*)[3]"
// ...
 
int main()
{
    static_assert(std::is_same_v<decltype(var1), decltype(var2)>);
}

[edit] 缺陷報告

下列更改行為的缺陷報告追溯應用於之前的 C++ 標準。

DR 應用於 出版時的行為 正確的行為
CWG 482 C++98 重新宣告的宣告子無法使用限定 (qualified) 允許使用限定宣告子
CWG 569 C++98 單獨的分號不是有效的宣告 它被定義為空宣告,
沒有任何副作用
CWG 1830 C++98 decl-specifier-seq 中重複函式說明符是被允許的 禁止重複

[edit] 參見

C 語言文件 關於 宣告
English Deutsch 日本語 中文(简体) 中文(繁體)