競合する宣言
特に指定がない限り、2つの宣言は同じエンティティを(再)導入することはできません。そのような宣言が存在する場合、プログラムは不正な形式です。
目次 |
[編集] 対応する宣言
2つの宣言は、それらが同じ名前を(再)導入する場合、両方ともコンストラクタを宣言する場合、または両方ともデストラクタを宣言する場合に「対応する」とみなされます。ただし、例外があります。
- どちらかが「using 宣言」である場合。
- 一方が型(typedef 名ではない)を宣言し、もう一方が変数、匿名共用体以外の非静的データメンバー、列挙子、関数、または関数テンプレートを宣言する場合。
- それぞれが関数または関数テンプレートを宣言し、それらが対応するオーバーロードを宣言しない場合。
[編集] 対応する関数オーバーロード
2つの「関数宣言」は、両方とも以下のすべての条件を満たす関数を宣言する場合、「対応するオーバーロード」を宣言するとみなされます。
- それらは同じ「パラメータ型リスト」を持ちます(明示的なオブジェクトパラメータの型は省略されます)。
|
(C++20以降) |
- 両方が非静的メンバ関数である場合、さらに以下のいずれかの要件を満たす必要があります。
|
(C++23から) |
- それらのオブジェクトパラメータが同じ型を持つ。
[編集] 対応する関数テンプレートオーバーロード
2つの「関数テンプレート宣言」は、両方とも以下のすべての条件を満たす関数テンプレートを宣言する場合、「対応するオーバーロード」を宣言するとみなされます。
- それらのテンプレートパラメータリストは同じ長さを持つ。
- それらの対応するテンプレートパラメータは「同等」である。
- それらは「パラメータ型リスト」が同等である(明示的なオブジェクトパラメータの型は省略されます)。
- それらは同等の戻り型を持つ。
|
(C++20以降) |
- 両方が非静的メンバ関数テンプレートである場合、さらに以下のいずれかの要件を満たす必要があります。
|
(C++23から) |
- それらのオブジェクトパラメータが同等の型を持つ。
struct A { friend void c(); // #1 }; struct B { friend void c() {} // corresponds to, and defines, #1 }; typedef int Int; enum E : int { a }; void f(int); // #2 void f(Int) {} // defines #2 void f(E) {} // OK, another overload struct X { static void f(); void f() const; // error: redeclaration void g(); void g() const; // OK void g() &; // error: redeclaration void h(this X&, int); void h(int) &&; // OK, another overload void j(this const X&); void j() const &; // error: redeclaration void k(); void k(this X&); // error: redeclaration };
[編集] 同じエンティティの複数の宣言
|
宣言が「名前非依存」であるとは、その名前が「_」であり、以下を宣言する場合です。 |
(C++26以降) |
特に指定がない限り、エンティティの2つの宣言は、以下のすべての条件が満たされる場合に「同じエンティティを宣言する」とみなされます。名前のない型を宣言する場合、その「typedef 名」および「列挙名」(存在する場合)をリンク目的で導入するとみなされます。
- それらは対応する。
- それらは同じ「ターゲットスコープ」を持ち、それは「関数パラメータスコープ」または「テンプレートパラメータスコープ」ではない。
|
(C++26以降) |
- 以下のいずれかの条件が満たされる。
- それらは同じ翻訳単位に現れる。
|
(C++20以降) |
- それらは両方とも「外部リンケージ」を持つ名前を宣言する。
エンティティまたは typedef 名 `E` の宣言は、`E` の別の宣言がそれから到達可能な場合、「`E` の再宣言」とみなされ、そうでなければ `E` の「最初の宣言」とみなされます。
[編集] 制限事項
エンティティ `E` の2つの宣言のうちいずれかが以下の対応する制限に違反した場合、プログラムは不正な形式です。
- 一方が `E` を変数として宣言する場合、もう一方も `E` を同じ型の変数として宣言する必要があります。
- 一方が `E` を「関数」として宣言する場合、もう一方も `E` を同じ型の関数として宣言する必要があります。
- 一方が `E` を「列挙子」として宣言する場合、もう一方も `E` を列挙子として宣言する必要があります。
- 一方が `E` を「名前空間」として宣言する場合、もう一方も `E` を名前空間として宣言する必要があります。
- 一方が `E` を「クラス型」として宣言する場合、もう一方も `E` をクラス型として宣言する必要があります。
- 一方が `E` を「列挙型」として宣言する場合、もう一方も `E` を列挙型として宣言する必要があります。
- 一方が `E` を「クラステンプレート」として宣言する場合、もう一方も同等のテンプレートパラメータリストを持つクラステンプレートとして `E` を宣言する必要があります(「関数テンプレートのオーバーロード」を参照)。
- 一方が `E` を「関数テンプレート」として宣言する場合、もう一方も同等のテンプレートパラメータリストと型を持つ関数テンプレートとして `E` を宣言する必要があります。
|
(C++11以降) |
|
(C++14以降) |
|
(C++20以降) |
型は、すべての型の調整(その間、typedef はその定義に置き換えられます)の後で比較されます。配列オブジェクトの宣言では、主要な配列境界の有無によって異なる配列型を指定できます。どちらの宣言ももう一方から到達可能でない場合、診断は不要です。
void g(); // #1 void g(int); // OK, different entity from #1 (they do not correspond) int g(); // Error: same entity as #1 with different type void h(); // #2 namespace h {} // Error: same entity as #2, but not a function
「内部リンケージ」を持つ名前を宣言する宣言 `H` が、別の翻訳単位 `U` の宣言 `D` の前にあり、`U` に `H` が現れた場合に `D` と同じエンティティを宣言する場合、プログラムは不正な形式です。
[編集] 競合する可能性のある宣言
2つの宣言は、それらが対応するが異なるエンティティを宣言する場合、「競合する可能性」があるとみなされます。
あるスコープで、名前が2つの宣言 `A` と `B` に束縛されており、それらが競合する可能性があり(「`B` は名前非依存ではない(C++26 以降)」)、`A` が `B` より前にあり、プログラムは不正な形式です。
void f() { int x, y; void x(); // Error: different entity for x int y; // Error: redefinition } enum { f }; // Error: different entity for ::f namespace A {} namespace B = A; namespace B = A; // OK, no effect namespace B = B; // OK, no effect namespace A = B; // OK, no effect namespace B {} // Error: different entity for B void g() { int _; _ = 0; // OK int _; // OK since C++26, name-independent declaration _ = 0; // Error: two non-function declarations in the lookup set } void h () { int _; // #1 _ ++; // OK static int _; // Error: conflicts with #1 because // static variables are not name-independent }
[編集] 欠陥レポート
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 279 (P1787R6) |
C++98 | 名前のないクラスまたは列挙子が リンク目的で typedef 名を持つ場合、再宣言できるかどうか |
再宣言できる |
| CWG 338 (P1787R6) |
C++98 | 名前のない列挙子が リンク目的で名前として列挙子を持つ場合、再宣言できるかどうか |
再宣言できる |
| CWG 1884 (P1787R6) |
C++98 | 同じエンティティの複数の 宣言に対する制限が不明確でした。 |
明確化された |