Namespaces
Variants

Conflicting declarations

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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

目次

対応する宣言

2つの宣言は、それらが同じ名前を(再)導入する場合、両方がコンストラクタを宣言する場合、または両方がデストラクタを宣言する場合、 対応する ものとされます。ただし、以下の場合を除きます。

  • いずれかが using declaration である場合、
  • 一方が型( typedef name ではない)を宣言し、他方が変数、 anonymous union 以外の非静的データメンバ、列挙子、関数、または関数テンプレートを宣言する場合、または
  • それぞれが関数または関数テンプレートを宣言し、対応するオーバーロードを宣言しない場合。

対応する関数オーバーロード

2つの 関数宣言 は、以下の条件をすべて満たす関数を宣言する場合、 対応するオーバーロード を宣言します:

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

対応する関数テンプレートのオーバーロード

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

  • 対応するテンプレートパラメータは、両方とも constraint なしで宣言されているか、または両方とも同等の制約で宣言されている。
  • 同等の末尾 requires を持つ(もしあれば)。
(C++20以降)
  • 両方が非静的メンバ関数テンプレートである場合、以下の要件のいずれかを追加で満たす必要があります:
  • それらのうち正確に1つが参照修飾子なしの 暗黙オブジェクトメンバー関数 テンプレートであり、それらのオブジェクトパラメータの型(すべての参照を除去した後)が等価である。
(C++23以降)
  • それらのオブジェクトパラメータは同等の型を持ちます。
struct A
{
    friend void c();   // #1
};
struct B
{
    friend void c() {} // #1に対応し、定義する
};
typedef int Int;
enum E : int { a };
void f(int);   // #2
void f(Int) {} // #2を定義する
void f(E) {}   // OK、別のオーバーロード
struct X
{
    static void f();
    void f() const;   // エラー:再宣言
    void g();
    void g() const;   // OK
    void g() &;       // エラー:再宣言
    void h(this X&, int);
    void h(int) &&;   // OK、別のオーバーロード
    void j(this const X&);
    void j() const &; // エラー:再宣言
    void k();
    void k(this X&);  // エラー:再宣言
};

同一エンティティの複数宣言

宣言は、その名前が _ であり、以下を宣言する場合 名前独立 である:

(C++26 以降)

特に指定がない限り、二つのエンティティ宣言は、以下の全ての条件が満たされる場合に 同じエンティティを宣言する ものとします。この際、無名型の宣言はリンケージ目的における typedef名 および enumeration名 (存在する場合)を導入するものとして考慮されます:

  • どちらも名前非依存の宣言ではない。
(since C++26)
  • 以下の条件のいずれかが満たされていること:
  • それらは同じ翻訳単位内に現れます。
(C++20以降)

エンティティまたはtypedef名 X の宣言は、それが X の別の宣言から到達可能である場合、 X 再宣言 である。そうでない場合、それは X 最初の宣言 である。

制限事項

あるエンティティ E の2つの宣言が以下の対応する制約に違反する場合、そのプログラムは不適格となります:

  • 一方が E を変数として宣言する場合、他方も同じ型の変数として E を宣言しなければならない。
  • 一方が E function として宣言する場合、他方も同じ型の関数として E を宣言しなければならない。
  • 一方が E enumerator として宣言する場合、他方も列挙子として E を宣言しなければならない。
  • 一方が E namespace として宣言する場合、他方も名前空間として E を宣言しなければならない。
  • 一方が E class type として宣言する場合、他方もクラス型として E を宣言しなければならない。
  • 一方が E enumeration type として宣言する場合、他方も列挙型として E を宣言しなければならない。
  • 一方が E class template として宣言する場合、他方も等価なテンプレートパラメータリストを持つクラステンプレートとして E を宣言しなければならない( function template overloading を参照)。
  • 一方が E function template として宣言する場合、他方も等価なテンプレートパラメータリストと型を持つ関数テンプレートとして E を宣言しなければならない。
  • 一方が E エイリアステンプレート として宣言する場合、他方も E を等価なテンプレートパラメータリストと type-id を持つエイリアステンプレートとして宣言しなければならない。
(C++11以降)
  • 一方が E を(部分特殊化された) 変数テンプレート として宣言する場合、他方も E を等価なテンプレートパラメータリストと型を持つ(部分特殊化された)変数テンプレートとして宣言しなければならない。
(C++14以降)
  • 一方が E concept として宣言する場合、他方も E をconceptとして宣言しなければならない。
(C++20以降)

型は、すべての型調整の後で比較されます(この過程で typedef はその定義に置き換えられます)。配列オブジェクトの宣言は、主要な配列境界の有無によって異なる配列型を指定できます。どちらの宣言も互いに到達可能でない場合、診断は要求されません。

void g();      // #1
void g(int);   // OK: #1とは異なるエンティティ(対応していない)
int g();       // エラー: #1と同じエンティティだが型が異なる
void h();      // #2
namespace h {} // エラー: #2と同じエンティティだが関数ではない

宣言 H 内部リンケージ を持つ名前を宣言し、別の翻訳単位 U 内の宣言 D より前に現れ、かつ U 内に現れた場合に D と同じエンティティを宣言するであろうとき、プログラムは不適格となる。

競合する可能性のある宣言

2つの宣言は、対応しているが異なるエンティティを宣言する場合、 潜在的に競合する 可能性があります。

任意のスコープにおいて、名前が2つの宣言 A B に束縛され、それらが潜在的に競合する場合 B が名前独立ではない場合 (C++26以降) )、かつ A B に先行するとき、プログラムは不適格となります:

void f()
{
    int x, y;
    void x(); // エラー: xのエンティティが異なる
    int y;    // エラー: 再定義
}
enum { f };   // エラー: ::fのエンティティが異なる
namespace A {}
namespace B = A;
namespace B = A; // OK、効果なし
namespace B = B; // OK、効果なし
namespace A = B; // OK、効果なし
namespace B {}   // エラー: Bのエンティティが異なる
void g()
{
    int _;
    _ = 0; // OK
    int _; // C++26以降OK、名前非依存宣言
    _ = 0; // エラー: ルックアップセット内に2つの非関数宣言が存在
}
void h ()
{
    int _;        // #1
    _ ++;         // OK
    static int _; // エラー: #1と競合(static変数は名前非依存ではないため)
                  // static変数は名前非依存ではないため
}

不具合報告

以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。

DR 適用対象 公開時の動作 正しい動作
CWG 279
( P1787R6 )
C++98 リンケージ目的のtypedef名を持つ無名クラスまたは列挙型が
再宣言可能かどうかが不明確であった
再宣言可能である
CWG 338
( P1787R6 )
C++98 リンケージ目的の名前として列挙子を持つ無名列挙型が
再宣言可能かどうかが不明確であった
再宣言可能である
CWG 1884
( P1787R6 )
C++98 同一エンティティの複数宣言に適用される
制限が不明確であった
明確化された