ここでのこの質問は、私の興味を少し刺激しました。クラス内のすべての宣言を、付随するメンバー関数の実装の前に解析する必要があることを指定している C++ 標準の場所はありますか? これに似た他のいくつかの質問を見てきましたが、どの回答にも標準への言及はありません。
3 に答える
[class.mem] 言います:
}
-2- クラスは、class-specifierの終了時に、完全に定義されたオブジェクト型 (3.9) (または完全な型) と見なされます。class member-specification内では、クラスは、関数本体、デフォルト引数、および非静的データ メンバーの波括弧または等号初期化子(ネストされたクラス内のそのようなものを含む) 内で完全であると見なされます。それ以外の場合、独自のクラスmember-specification内で不完全と見なされます。
クラスが関数本体内で完全であるためには、一般にすべての宣言を解析する必要があります。すべての宣言を完全に解析しないと、解析されなかった何かが意味を変えるかどうかを知ることができません。ただし、おそらくそれに関連するのは [basic.scope.class]/1 です。
3) クラス内のメンバー宣言を並べ替えて、(1) および (2) の下で別の有効なプログラムが得られる場合、そのプログラムは不正な形式であり、診断は必要ありません。
これは、クラス全体を解析せずに特定の宣言を使用できることを意味します。これは、後の別の宣言によって意味が変更された場合、プログラムの形式が正しくないためです。
もちろん、"as if" ルールにより、ユーザーが違いを見分けられない限り、コンパイラーは任意の実装を選択できます。そのため、コンパイラーは関数本体を解析してから、必要に応じて定義を解析することを選択できるかもしれませんが、それは難しいでしょう。メンバー関数の定義を処理するために何が必要かを伝える (おそらく enable_if 型のトリックを含む、いくつかのオーバーロードされた関数の 1 つを呼び出す可能性のある関数呼び出しを考えてみてください)。
標準では、コンパイラが翻訳単位を解析する方法を指定していません。代わりに、任意の識別子を使用して宣言を参照することが有効ではない場所を指定します。
3.3.2p5:
クラス メンバーの宣言後、そのクラスのスコープ内でメンバー名を検索できます。[ 注: これは、クラスが不完全なクラスであっても当てはまります。]
3.3.7p1:
次の規則は、クラスで宣言された名前のスコープを示しています。
- クラスで宣言された名前の潜在的なスコープは、名前の宣言ポイントに続く宣言領域だけでなく、すべての関数本体、非静的データ メンバーのブレースまたはイコール初期化子、およびその中のデフォルト引数からも構成されます。クラス(ネストされたクラスのそのようなものを含む)。
N
クラスで使用される名前S
は、そのコンテキスト内で同じ宣言を参照し、 の完全なスコープで再評価される必要がありS
ます。この規則違反の診断は必要ありません。- クラス内のメンバー宣言の順序を変更すると、(1) および (2) の下で別の有効なプログラムが生成される場合、そのプログラムは不正な形式であり、診断は必要ありません。
- メンバー関数内で宣言された名前は、スコープがメンバー関数のクラスの最後またはそれを超えて拡張されている同じ名前の宣言を非表示にします。
- クラス定義の末尾まで、またはそれを超えて拡張される宣言の潜在的なスコープは、メンバーがクラスの外部で語彙的に定義されている場合でも、そのメンバー定義によって定義された領域に拡張されます (これには、静的データ メンバー定義、ネストされたクラス定義、およびクラス定義が含まれます)。メンバー関数の定義 (メンバー関数の本体、およびdeclarator-idに続くそのような定義の宣言子部分の任意の部分を含み、 parameter-declaration-clause および任意のデフォルト引数 (8.3.6) を含む)。