名前空間
変種
操作

宣言

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

宣言 (Declarations) とは、C++プログラムに名前を導入 (または再導入) する方法です。すべての宣言が実際に何かを宣言するわけではなく、エンティティの種類ごとに宣言方法が異なります。定義 (Definitions) とは、その名前で識別されるエンティティを使用するのに十分な宣言のことです。

宣言は以下のいずれかです

  • 属性宣言 (attr ;)
(C++11以降)
  • 空宣言 (;)
  • decl-specifier-seq を持たない関数宣言
attr (オプション) declarator ;
attr - (C++11以降) 任意の数の属性のシーケンス
declarator (宣言子) - 関数宣言子
この宣言は、コンストラクタ、デストラクタ、またはユーザー定義の型変換関数を宣言しなければなりません。これはテンプレート宣言明示的特殊化、または明示的インスタンス化の一部としてのみ使用できます。
  • block-declaration (ブロック内に現れることができる宣言) であり、これはさらに以下のいずれかです
(C++11以降)
(C++20以降)
(C++11以降)
  • 単純宣言

目次

[編集] 単純宣言

単純宣言とは、1つまたは複数の識別子 (通常は変数) を導入、作成し、任意で初期化する文です。

decl-specifier-seq init-declarator-list (オプション) ; (1)
attr decl-specifier-seq init-declarator-list ; (2) (C++11以降)
decl-specifier-seq (宣言指定子シーケンス) - 指定子のシーケンス
init-declarator-list (初期化子付き宣言子リスト) - init-declarator  (下記参照) のカンマ区切りリスト
attr - 任意の数の属性のシーケンス


init-declarator-list は、名前付きクラスまたは名前付き列挙体を宣言する場合にのみ省略できます。

構造化束縛宣言も単純宣言です。

(C++17以降)


init-declarator の構文は次のように定義されます

declarator initializer (1)
declarator requires-clause (オプション) contract-specs (オプション) (2)
1) 初期化子を持つ宣言子。
2) 初期化子を持たない宣言子。
declarator (宣言子) - 宣言子 (declarator)
initializer (初期化子) - 初期化子
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 指定子のうち最大1つだけが現れることができます。
(C++20以降)
  • 記憶域クラス指定子 (register, (C++17まで) static, thread_local, (C++11以降) extern, mutable)。記憶域クラス指定子は1つだけ許可されますが、thread_localextern または static と一緒に現れることができます(C++11以降)
  • 型指定子 (type-specifier-seq) は、型を名付ける指定子のシーケンスです。宣言によって導入されるすべてのエンティティの型は、この型であり、任意で宣言子 (下記参照) によって修飾されます。この指定子のシーケンスは type-id でも使用されます。type-specifier-seq に含まれるのは以下の指定子のみで、順序は任意です
(C++11以降)
(C++26以降)
(C++17以降)
  • キーワード class, struct, または union に、以前にクラス名として定義された識別子 (任意で修飾) が続くもの。
  • キーワード class, struct, または union に、以前にクラステンプレート名として定義されたテンプレート引数付きテンプレート名 (任意で修飾、任意でtemplate曖昧性解決子を使用) が続くもの。
  • キーワード enum に、以前に列挙型の名前として宣言された識別子 (任意で修飾) が続くもの。
decl-specifier-seq では、以下の例外を除き、1つの型指定子のみが許可されます
  • const は、それ自体を除く任意の型指定子と組み合わせることができます。
  • volatile は、それ自体を除く任意の型指定子と組み合わせることができます。
  • signed または unsigned は、char, long, short, または int と組み合わせることができます。
  • short または longint と組み合わせることができます。
  • longdouble と組み合わせることができます。
  • longlong と組み合わせることができます。
(C++11以降)

属性decl-specifier-seq 内に現れることができ、その場合、先行する指定子によって決定される型に適用されます。

decl-specifier-seq 内での任意の指定子の繰り返し、たとえば const static constvirtual inline virtual はエラーですが、long が2回現れることは許可されます(C++11以降)

[編集] 宣言子

init-declarator-list S D1, D2, D3; の各 init-declarator は、同じ指定子を持つスタンドアロンの宣言であるかのように処理されます: S D1; S D2; S D3;

各宣言子は、オブジェクト、参照、関数、または (typedef 宣言の場合) 型エイリアスを正確に1つ導入します。その型は decl-specifier-seq によって提供され、宣言子内の & (への参照) や [] (の配列) や () (を返す関数) のような演算子によって任意で修飾されます。これらの演算子は、以下に示すように再帰的に適用できます。

declarator (宣言子) は以下のいずれかです

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; は、Ddecl-specifier-seq S によって決定される型へのポインタとして宣言します。
5) メンバへのポインタ宣言: 宣言 S C::* D; は、DC のメンバで、型が decl-specifier-seq S によって決定されるものへのポインタとして宣言します。nested-name-specifier は、名前とスコープ解決演算子 :: のシーケンスです。
6) 左辺値参照宣言子: 宣言 S & D; は、Ddecl-specifier-seq S によって決定される型への左辺値参照として宣言します。
7) 右辺値参照宣言子: 宣言 S && D; は、Ddecl-specifier-seq S によって決定される型への右辺値参照として宣言します。
8) 配列宣言子noptr-declarator は任意の有効な宣言子ですが、*, &, または && で始まる場合は、括弧で囲む必要があります。
9) 関数宣言子noptr-declarator は任意の有効な宣言子ですが、*, &, または && で始まる場合は、括弧で囲む必要があります。オプションの後置戻り値型で終わることがあります。(C++11以降)

すべての場合において、attr属性のオプションのシーケンスです。識別子の直後に現れる場合、宣言されるオブジェクトに適用されます。

(C++11以降)

cvconst と volatile 修飾子のシーケンスで、各修飾子はシーケンス内に最大1回現れることができます。

[編集] 備考

block-declarationブロック内に現れ、宣言によって導入された識別子が以前に外側のブロックで宣言されていた場合、外側の宣言はブロックの残りの部分で隠蔽されます

宣言が自動記憶域期間を持つ変数を導入する場合、その宣言文が実行されるときに初期化されます。ブロック内で宣言されたすべての自動変数は、ブロックからの脱出時に (ブロックからの脱出方法に関わらず: 例外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++標準に遡って適用されました。

DR 適用対象 公開された動作 正しい動作
CWG 482 C++98 再宣言の宣言子は修飾できなかった 修飾された宣言子が許可された
CWG 569 C++98 単独のセミコロンは有効な宣言ではなかった それは空宣言であり、
効果はない
CWG 1830 C++98 decl-specifier-seq 内での関数指定子の繰り返しが許可されていた 繰り返しは禁止された

[編集] 関連項目

English 日本語 中文(简体) 中文(繁體)