Konfligierende Deklarationen
Sofern nicht anders angegeben, können zwei Deklarationen nicht dieselbe Entität (neu) einführen. Das Programm ist fehlerhaft, wenn solche Deklarationen existieren.
Inhalt |
[bearbeiten] Entsprechende Deklarationen
Zwei Deklarationen korrespondieren, wenn sie denselben Namen (neu) einführen, beide Konstruktoren deklarieren oder beide Destruktoren deklarieren, es sei denn,
- eine ist eine using-Deklaration,
- eine deklariert einen Typ (keinen typedef-Namen) und die andere deklariert eine Variable, einen nicht-statischen Datenmember (außer in einer anonymen Union), einen Enumerator, eine Funktion oder ein Funktions-Template,
- oder beide deklarieren eine Funktion oder ein Funktions-Template und sie deklarieren keine entsprechenden Überladungen.
[bearbeiten] Entsprechende Funktionsüberladungen
Zwei Funktionsdeklarationen deklarieren entsprechende Überladungen, wenn beide Funktionen deklarieren, die alle folgenden Bedingungen erfüllen
- Sie haben dieselbe Parameterliste, wobei die Typen von expliziten Objektparametern weggelassen werden(seit C++23).
|
(seit C++20) |
- Wenn beide Nicht-Statische Memberfunktionen sind, müssen sie zusätzlich eine der folgenden Anforderungen erfüllen
|
(seit C++23) |
- Ihre Objektparameter haben denselben Typ.
[bearbeiten] Entsprechende Funktions-Template-Überladungen
Zwei Funktions-Template-Deklarationen deklarieren entsprechende Überladungen, wenn beide Funktions-Templates deklarieren, die alle folgenden Bedingungen erfüllen
- Ihre Template-Parameterlisten haben die gleiche Länge.
- Ihre entsprechenden Template-Parameter sind äquivalent.
- Sie haben äquivalente Parameterlisten, wobei die Typen von expliziten Objektparametern weggelassen werden(seit C++23).
- Sie haben äquivalente Rückgabetypen.
|
(seit C++20) |
- Wenn beide Nicht-Statische Memberfunktions-Templates sind, müssen sie zusätzlich eine der folgenden Anforderungen erfüllen
|
(seit C++23) |
- Ihre Objektparameter haben äquivalente Typen.
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 };
[bearbeiten] Mehrfache Deklarationen derselben Entität
|
Eine Deklaration ist namenunabhängig, wenn ihr Name _ ist und sie deklariert
|
(seit C++26) |
Sofern nicht anders angegeben, deklarieren zwei Deklarationen von Entitäten dieselbe Entität, wenn alle folgenden Bedingungen erfüllt sind, wobei Deklarationen unbenannter Typen ihre typedef-Namen und Enumerationsnamen zu Linkage-Zwecken (falls vorhanden) einführen
- Sie korrespondieren.
- Sie haben denselben Ziel-Scope, der kein Funktionsparameter-Scope oder Template-Parameter-Scope ist.
|
(seit C++26) |
- Eine der folgenden Bedingungen ist erfüllt
- Sie erscheinen in derselben Translation Unit.
|
(seit C++20) |
- Sie deklarieren beide Namen mit externer Linkage.
Eine Deklaration einer Entität oder eines Typedef-Namens X ist eine Wiederdeklaration von X, wenn eine andere Deklaration von X von ihr erreichbar ist; andernfalls ist es eine erste Deklaration von X.
[bearbeiten] Beschränkungen
Wenn zwei Deklarationen einer Entität E die entsprechende Beschränkung unten verletzen, ist das Programm fehlerhaft
- Wenn eine
Eals Variable deklariert, muss die andereEauch als Variable desselben Typs deklarieren. - Wenn eine
Eals Funktion deklariert, muss die andereEauch als Funktion desselben Typs deklarieren. - Wenn eine
Eals Enumerator deklariert, muss die andereEauch als Enumerator deklarieren. - Wenn eine
Eals Namespace deklariert, muss die andereEauch als Namespace deklarieren. - Wenn eine
Eals Klassentyp deklariert, muss die andereEauch als Klassentyp deklarieren. - Wenn eine
Eals Enumerationstyp deklariert, muss die andereEauch als Enumerationstyp deklarieren. - Wenn eine
Eals Klassentemplate deklariert, muss die andereEauch als Klassentemplate mit einer äquivalenten Template-Parameterliste deklarieren (siehe Funktions-Template-Überladung). - Wenn eine
Eals Funktions-Template deklariert, muss die andereEauch als Funktions-Template mit einer äquivalenten Template-Parameterliste und einem äquivalenten Typ deklarieren.
|
(seit C++11) |
|
(seit C++14) |
|
(seit C++20) |
Typen werden nach allen Anpassungen von Typen verglichen (wobei typedefs durch ihre Definitionen ersetzt werden). Deklarationen für ein Array-Objekt können Array-Typen angeben, die sich durch das Vorhandensein oder Fehlen einer Haupt-Array-Grenze unterscheiden. Keine Diagnose ist erforderlich, wenn keine der Deklarationen von der anderen erreichbar ist.
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
Wenn eine Deklaration H, die einen Namen mit interner Linkage deklariert, einer Deklaration D in einer anderen Translation Unit U vorausgeht und dieselbe Entität wie D deklarieren würde, wenn sie in U erscheinen würde, ist das Programm fehlerhaft.
[bearbeiten] Potenziell konfliktreiche Deklarationen
Zwei Deklarationen potenziell konfliktieren, wenn sie korrespondieren, aber verschiedene Entitäten deklarieren.
Wenn in irgendeinem Scope ein Name an zwei Deklarationen A und B gebunden ist, die potenziell konfliktieren, B nicht namensunabhängig ist(seit C++26) und A vor B liegt, ist das Programm fehlerhaft
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 }
[bearbeiten] Fehlerberichte
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| CWG 279 (P1787R6) |
C++98 | Es war unklar, ob eine unbenannte Klasse oder Aufzählung wiederdeklariert werden kann, wenn sie einen typedef-Namen für Linkage-Zwecke hat |
sie kann wiederdeklariert werden |
| CWG 338 (P1787R6) |
C++98 | Es war unklar, ob eine unbenannte Aufzählung wiederdeklariert werden kann, wenn sie einen Enumerator als Namen für Linkage-Zwecke hat |
sie kann wiederdeklariert werden |
| CWG 1884 (P1787R6) |
C++98 | Die Beschränkungen für mehrere Deklarationen derselben Entität waren unklar |
wurde klargestellt |