名稱空間
變體
操作

宣告

來自 cppreference.com
< cpp‎ | 語言
 
 
C++ 語言
 
 

宣告是在 C++ 程式中引入(或重新引入)名稱的方式。並非所有宣告都實際宣告任何內容,並且每種實體都有不同的宣告方式。定義是足以使用名稱所標識實體的宣告。

宣告是以下之一:

  • 屬性宣告(attr ;
(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)
1) 帶有初始化器的宣告符。
2) 不帶初始化器的宣告符。
宣告符 - 一個宣告符
初始化器 - 一個初始化器
requires-clause - (C++20 起) 一個requires 子句
contract-specs - (C++26 起) 一個函式契約說明符列表


requires-clause 只能在declarator宣告模板函式時出現。

(C++20 起)

contract-specs 只能在declarator宣告函式或函式模板時出現。

(C++26 起)

[編輯] 說明符

宣告說明符decl-specifier-seq)是以下空白分隔說明符的序列,可以按任意順序排列

  • inline 說明符也允許用於變數宣告。
(C++17 起)
  • friend 說明符,允許用於類和函式宣告。
  • constexpr 說明符,只允許用於變數定義、函式和函式模板宣告,以及字面量型別靜態資料成員的宣告。
(C++11 起)
  • consteval 說明符,只允許用於函式和函式模板宣告。
  • constinit 說明符,只允許用於具有靜態或執行緒儲存期變數的宣告。在decl-specifier-seq中,constexprconstevalconstinit 說明符中最多隻能出現一個。
(C++20 起)
  • 儲存類說明符register(C++17 前) staticthread_local(C++11 起) externmutable)。只允許一個儲存類說明符,除了 thread_local 可以與 externstatic 一起出現(C++11 起)
  • 型別說明符type-specifier-seq),是命名型別的說明符序列。宣告引入的每個實體的型別就是此型別,可選地由宣告符修改(見下文)。此說明符序列也用於type-id。只有以下說明符是type-specifier-seq的一部分,可以按任意順序排列
(C++11 起)
(C++26 起)
(C++17 起)
在一個 decl-specifier-seq 中只允許一個型別說明符,但以下情況除外:
  • const 可以與除自身以外的任何型別說明符組合。
  • volatile 可以與除自身以外的任何型別說明符組合。
  • signedunsigned 可以與 charlongshortint 組合。
  • shortlong 可以與 int 組合。
  • long 可以與 double 組合。
  • long 可以與 long 組合。
(C++11 起)

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

decl-specifier-seq 中任何說明符的重複,例如 const static constvirtual 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)
1) 被宣告的名稱
2) 使用限定識別符號qualified-id)的宣告符定義或重新宣告先前宣告的名稱空間成員類成員
3) 形參包,只出現在形參宣告中。
4) 指標宣告符:宣告 S * D;D 宣告為指向由 decl-specifier-seq S 確定的型別的指標。
5) 指向成員的指標宣告:宣告 S C::* D;D 宣告為指向型別由 decl-specifier-seq S 確定的 C 的成員的指標。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 任何有效的宣告符,但如果它以 *、& 或 && 開頭,則必須用括號括起來。它可以以可選的尾置返回型別結束。(C++11 起)

在所有情況下,attr 是可選的屬性序列。當緊跟在識別符號之後時,它適用於被宣告的物件。

(C++11 起)

cvconst 和 volatile 限定符的序列,其中每個限定符在序列中最多隻能出現一次。

[編輯] 注意

塊宣告出現在塊內時,如果宣告引入的識別符號先前已在外部塊中宣告,則外部宣告在塊的其餘部分被隱藏

如果宣告引入的變數具有自動儲存期,則在其宣告語句執行時進行初始化。在一個塊中宣告的所有自動變數在該塊退出時(無論該塊如何退出:透過異常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 文件 關於 宣告
English 日本語 中文(简体) 中文(繁體)