名前空間
変種
操作

競合する宣言

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

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

特に指定がない限り、2つの宣言は同じエンティティを(再)導入することはできません。そのような宣言が存在する場合、プログラムは不正な形式です。

目次

[編集] 対応する宣言

2つの宣言は、それらが同じ名前を(再)導入する場合、両方ともコンストラクタを宣言する場合、または両方ともデストラクタを宣言する場合に「対応する」とみなされます。ただし、例外があります。

  • どちらかが「using 宣言」である場合。
  • 一方が型(typedef 名ではない)を宣言し、もう一方が変数、匿名共用体以外の非静的データメンバー、列挙子、関数、または関数テンプレートを宣言する場合。
  • それぞれが関数または関数テンプレートを宣言し、それらが対応するオーバーロードを宣言しない場合。

[編集] 対応する関数オーバーロード

2つの「関数宣言」は、両方とも以下のすべての条件を満たす関数を宣言する場合、「対応するオーバーロード」を宣言するとみなされます。

(C++20以降)
  • 両方が非静的メンバ関数である場合、さらに以下のいずれかの要件を満たす必要があります。
  • それらのうちちょうど一方が、リファレンス修飾子なしの「暗黙のオブジェクトメンバ関数」であり、それらのオブジェクトパラメータの型(トップレベル参照を削除した後)が同じである。
(C++23から)
  • それらのオブジェクトパラメータが同じ型を持つ。

[編集] 対応する関数テンプレートオーバーロード

2つの「関数テンプレート宣言」は、両方とも以下のすべての条件を満たす関数テンプレートを宣言する場合、「対応するオーバーロード」を宣言するとみなされます。

  • それらの対応するテンプレートパラメータは、両方とも「制約」なしで宣言されているか、または両方とも同等の制約で宣言されている。
  • それらは同等の末尾の「requires」(存在する場合)を持つ。
(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` を宣言する必要があります。
  • 一方が `E` を「エイリアステンプレート」として宣言する場合、もう一方も同等のテンプレートパラメータリストと「型id」を持つエイリアステンプレートとして `E` を宣言する必要があります。
(C++11以降)
  • 一方が `E` を(変数テンプレートの)部分特殊化として宣言する場合、もう一方も同等のテンプレートパラメータリストと型を持つ(変数テンプレートの)部分特殊化として `E` を宣言する必要があります。
(C++14以降)
  • 一方が `E` を「コンセプト」として宣言する場合、もう一方も `E` をコンセプトとして宣言する必要があります。
(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 同じエンティティの複数の
宣言に対する制限が不明確でした。
明確化された
English 日本語 中文(简体) 中文(繁體)