宣言
宣言は名前を C++ プログラムに導入 (または再導入) します。 エンティティの種類ごとに宣言は異なります。 定義はその名前によって識別されるエンティティを使用するのに十分な宣言です。
宣言は以下のいずれかです。
- 関数定義
- テンプレート宣言 (テンプレートの部分特殊化を含む)
- テンプレートの明示的実体化
- テンプレートの明示的特殊化
- 名前空間定義
- リンケージ指定
- 属性宣言 (attr
;
) (C++11以上) - 空宣言 (
;
) (C++11以上) - decl-specifier-seq のない関数宣言。 これは以下のようなものです。
attr(オプション) declarator ;
|
|||||||||
attr (C++11以上) | - | 任意個の属性の並び |
declarator | - | 関数宣言子 |
- ブロック宣言 (ブロック内部で現れることができる宣言)。 これは以下のいずれかです。
- asm 宣言
- 型エイリアス宣言 (C++11以上)
- 名前空間エイリアス定義
- using 宣言
- using 指令
static_assert
宣言 (C++11以上)- 不透明な enum 宣言 (C++11以上)
- 単純宣言
目次 |
[編集] 単純宣言
単純宣言は、ひとつまたはいくつかの識別子 (一般的には変数) を導入、作成、およびオプショナルに初期化する文です。
decl-specifier-seq init-declarator-list(オプション) ;
|
(1) | ||||||||
attr decl-specifier-seq init-declarator-list;
|
(2) | ||||||||
attr (C++11以上) | - | 任意個の属性の並び |
decl-specifier-seq | - | 指定子の並び (後述) |
init-declarator-list | - | オプショナルな初期化子付きの宣言子のコンマ区切りのリスト。 名前付きのクラス、構造体、共用体または名前付きの列挙を宣言するとき、 init-declarator-list はオプショナルです |
構造化束縛宣言も単純宣言です。 (C++17以上)
[編集] 指定子
宣言指定子 (decl-specifier-seq) は以下の指定子のホワイトスペースで区切られた並びです (順不同)。
-
typedef
指定子。 存在する場合、宣言全体が typedef 宣言であり、それぞれの宣言子は、オブジェクトや関数ではなく、新しい型名を導入します。 - 関数指定子 (
inline
、virtual
、explicit
)。 関数宣言でのみ使用できます。
|
(C++17以上) |
-
friend
指定子。 クラスおよび関数の宣言で使用できます。
|
(C++11以上) |
(C++20以上) |
- 記憶域クラス指定子 (register、 static、 thread_local (C++11以上)、 extern、 mutable)。 ひとつの記憶域クラス指定子のみ指定できます。 ただし
thread_local
はextern
またはstatic
と一緒に使用できます。 - 型指定子 (type-specifier-seq)。 型を表す指定子の並び。 宣言によって導入されるすべてのエンティティの型はこの型であり、オプションで宣言子 (下記参照) によって変更できます。 この一連の指定子は type-id によっても使用されます。 以下の指定子のみが type-specifier-seq の一部になれます (順不同)。
(C++11以上) |
|
(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 に2回現れることが許される指定子は |
(C++17以上) |
[編集] 宣言子
init-declarator-list は1つ以上の init-declarators のコンマ区切りの並びです。 init-declarators は以下の構文を持ちます。
declarator initializer(オプション) | (1) | ||||||||
declarator requires-clause | (2) | (C++20以上) | |||||||
declarator | - | 宣言子 |
initializer | - | オプショナルな初期化子 (ただし、参照や const オブジェクトを初期化するときなどは必須です)。 詳細は初期化を参照してください |
requires-clause(C++20) | - | requires 節。 関数宣言に制約を追加します |
init-declaractor の並び S D1, D2, D3; におけるそれぞれの init-declaractor は、同じ指定子を持つ独立した宣言 S D1; S D2; S D3; であるかのように処理されます。
それぞれの宣言子はちょうどひとつのオブジェクト、参照、関数、または (typedef 宣言の場合は) 型エイリアスを導入します。 その型は 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) | ||||||||
S
によって決定される型の C
のメンバへのポインタとして D
を宣言します。 nested-name-specifier は名前とスコープ解決演算子 ::
の並びです。*
、&
、&&
で始まる場合は括弧で囲む必要があります。 最も外側の関数宣言子はオプショナルな後置戻り値型で終わっても構わないことに注意してください。 (C++11以上)すべての場合において、 attr はオプショナルな属性の並びです。 識別子の直後に現れたときは、宣言されているオブジェクトに適用されます。
cv は const および volatile 修飾子の並びです。 ただしそれぞれの修飾子は並びの中に多くとも1度だけ現れることができます。
This section is incomplete Reason: explain declaration name hiding rules; how a variable/function declaration hides a class (but not a typedef) with the same name |
[編集] ノート
ブロック宣言がブロックの内部に現れ、宣言によって導入された識別子が外側のブロックで以前に宣言されていた場合、そのブロックの残りに対して外側の宣言は隠蔽されます。
宣言が自動記憶域期間を持つ変数を導入する場合、それはその宣言文が実行されたときに初期化されます。 ブロック内で宣言されたすべての自動変数は、そのブロックから抜けるとき (例外、goto、または終端に達したなど、どのように抜けるかにかかわらず)、それらの初期化の順序の逆順で、破棄されます。
[編集] 例
#include <string> class C { std::string member; // 宣言指定子は「std::string」です。 // 宣言子は「member」です。 } obj, *pObj(&obj); // 宣言指定子は「class C { std::string member; }」です。 // 宣言子「obj」は C 型のオブジェクトを定義します。 // 宣言子「*pObj(&obj)」は C へのポインタを宣言および初期化します。 int a = 1, *p = nullptr, f(), (*pf)(double); // 宣言指定子は int です。 // 宣言子 a = 1 は int 型の変数を定義および初期化します。 // 宣言子 *p = nullptr は int* 型の変数を定義および初期化します。 // 宣言子 (f)() は int を返し引数を取らない関数を宣言します (が定義はしません)。 // 宣言子 (*pf)(double) は int を返し double を取る関数へのポインタを定義します。 int (*(*foo)(double))[3] = nullptr; // 宣言指定子は int です。 // 1. 宣言子「(*(*foo)(double))[3]」は配列宣言子です。 // 宣言された内容は「int 3個の配列 *(*foo)(double)」です。 // 2. 宣言子「*(*foo)(double)」はポインタ宣言子です。 // 宣言された内容は「int 3個の配列へのポインタ (*foo)(double)」です。 // 3. 宣言子「(*foo)(double)」は関数宣言子です。 // 宣言された内容は「int 3個の配列へのポインタを返し double を取る関数 *foo」です。 // 4. 宣言子「*foo」はポインタ宣言子です。 // 宣言された内容は「int 3個の配列へのポインタを返し double を取る関数へのポインタ foo」です。 // 5. 宣言子「foo」は識別子です。 // この宣言は「int 3個の配列へのポインタを返し double を取る関数へのポインタ」型のオブジェクト foo を宣言します。 // 初期化子「= nullptr」はこのポインタの初期値を提供します。