宣告
宣告是在 C++ 程式中引入(或重新引入)名稱的方式。並非所有宣告都實際宣告任何內容,並且每種實體都有不同的宣告方式。定義是足以使用名稱所標識實體的宣告。
宣告是以下之一:
|
(C++11 起) |
- 空宣告(
;) - 不帶decl-specifier-seq的函式宣告
attr (可選) declarator ; |
|||||||||
| 屬性 | - | (C++11 起) 任意數量的屬性序列 |
| 宣告符 | - | 一個函式宣告符 |
- block-declaration(可以出現在塊內部的宣告),它可以是以下之一
| (C++11 起) |
| (C++20 起) | |
| (C++11 起) |
- 簡單宣告
目錄 |
[編輯] 簡單宣告
簡單宣告是引入、建立並可選地初始化一個或多個識別符號(通常是變數)的語句。
decl-specifier-seq init-declarator-list (可選) ; |
(1) | ||||||||
attr decl-specifier-seq init-declarator-list ; |
(2) | (C++11 起) | |||||||
| 宣告說明符序列 | - | 說明符序列 |
| init-declarator-list | - | 逗號分隔的init-declarator列表(見下文) |
| 屬性 | - | 任意數量的屬性序列 |
只有在宣告具名類或具名列舉時才能省略init-declarator-list。
|
一個結構化繫結宣告也是一個簡單宣告。 |
(C++17 起) |
init-declarator 的語法定義如下
| declarator initializer | (1) | ||||||||
| declarator requires-clause (可選) contract-specs (可選) | (2) | ||||||||
| 宣告符 | - | 一個宣告符 |
| 初始化器 | - | 一個初始化器 |
| requires-clause | - | (C++20 起) 一個requires 子句 |
| contract-specs | - | (C++26 起) 一個函式契約說明符列表 |
|
requires-clause 只能在declarator宣告模板函式時出現。 |
(C++20 起) |
|
contract-specs 只能在declarator宣告函式或函式模板時出現。 |
(C++26 起) |
[編輯] 說明符
宣告說明符(decl-specifier-seq)是以下空白分隔說明符的序列,可以按任意順序排列
typedef說明符。如果存在,則整個宣告是typedef 宣告,每個宣告符引入一個新型別名,而不是一個物件或函式。- 函式說明符(
inline、virtual、explicit),只允許在函式宣告中使用。
|
(C++17 起) |
friend說明符,允許用於類和函式宣告。
|
(C++11 起) |
| (C++20 起) |
- 儲存類說明符(register、(C++17 前) static、thread_local、(C++11 起) extern、mutable)。只允許一個儲存類說明符,除了 thread_local 可以與 extern 或 static 一起出現(C++11 起)。
- 型別說明符(type-specifier-seq),是命名型別的說明符序列。宣告引入的每個實體的型別就是此型別,可選地由宣告符修改(見下文)。此說明符序列也用於type-id。只有以下說明符是type-specifier-seq的一部分,可以按任意順序排列
| (C++11 起) | |
| (C++26 起) |
| (C++17 起) |
-
- 在一個 decl-specifier-seq 中只允許一個型別說明符,但以下情況除外:
- const 可以與除自身以外的任何型別說明符組合。
- volatile 可以與除自身以外的任何型別說明符組合。
- signed 或 unsigned 可以與 char、long、short 或 int 組合。
- short 或 long 可以與 int 組合。
- long 可以與 double 組合。
|
(C++11 起) |
屬性可以出現在decl-specifier-seq中,在這種情況下,它們適用於由前面的說明符確定的型別。
decl-specifier-seq 中任何說明符的重複,例如 const static const 或 virtual inline virtual 都是錯誤,但 long 允許出現兩次(C++11 起)。
[編輯] 宣告符
init-declarator-list 中的每個 init-declarator S D1, D2, D3; 都被處理為如同獨立的宣告,具有相同的說明符:S D1; S D2; S D3;。
每個宣告符恰好引入一個物件、引用、函式,或(對於 typedef 宣告)類型別名,其型別由 decl-specifier-seq 提供,並可選地透過宣告符中的運算子進行修改,例如 &(引用)、[](陣列)或 ()(返回函式)。這些運算子可以遞迴應用,如下所示。
一個宣告符是以下之一
| unqualified-id attr (可選) | (1) | ||||||||
| qualified-id attr (可選) | (2) | ||||||||
... identifier attr (可選) |
(3) | (C++11 起) | |||||||
* attr (可選) cv (可選) declarator |
(4) | ||||||||
nested-name-specifier * attr (可選) cv (可選) declarator |
(5) | ||||||||
& attr (可選) declarator |
(6) | ||||||||
&& attr (可選) declarator |
(7) | (C++11 起) | |||||||
noptr-declarator [ constexpr (可選) ] attr (可選) |
(8) | ||||||||
noptr-declarator ( parameter-list ) cv (可選) ref (可選) except (可選) attr (可選) |
(9) | ||||||||
D 宣告為指向型別由 decl-specifier-seq S 確定的 C 的成員的指標。nested-name-specifier 是名稱和作用域解析運算子 :: 的序列|
在所有情況下,attr 是可選的屬性序列。當緊跟在識別符號之後時,它適用於被宣告的物件。 |
(C++11 起) |
cv 是const 和 volatile 限定符的序列,其中每個限定符在序列中最多隻能出現一次。
| 本節不完整 原因:解釋宣告名稱隱藏規則;變數/函式宣告如何隱藏同名類(但不隱藏 typedef) |
[編輯] 注意
當塊宣告出現在塊內時,如果宣告引入的識別符號先前已在外部塊中宣告,則外部宣告在塊的其餘部分被隱藏。
如果宣告引入的變數具有自動儲存期,則在其宣告語句執行時進行初始化。在一個塊中宣告的所有自動變數在該塊退出時(無論該塊如何退出:透過異常、goto,或到達其末尾)以與初始化順序相反的順序銷燬。
[編輯] 示例
注意:本示例演示瞭如何根據語言語法解析一些複雜的宣告。其他流行的助記符包括:螺旋規則,由內而外閱讀,以及宣告映象使用。還有一個自動解析器在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)>); }
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。
| 缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
|---|---|---|---|
| CWG 482 | C++98 | 重宣告的宣告符不能限定 | 允許限定宣告符 |
| CWG 569 | C++98 | 一個單獨的分號不是有效的宣告 | 它是一個空宣告, 沒有效果 |
| CWG 1830 | C++98 | 允許在decl-specifier-seq中重複函式說明符 | 禁止重複 |
[編輯] 參見
| C 文件 關於 宣告
|