Conflicting declarations
Sofern nicht anders angegeben, können zwei Deklarationen nicht dieselbe Entität (wieder)einführen. Das Programm ist fehlerhaft, wenn solche Deklarationen existieren.
Inhaltsverzeichnis |
Entsprechende Deklarationen
Zwei Deklarationen korrespondieren , wenn sie denselben Namen (wieder)einführen, beide Konstruktoren deklarieren oder beide Destruktoren deklarieren, es sei denn
- entweder ist es eine using Deklaration ,
- eine deklariert einen Typ (keinen typedef-Namen ) und die andere deklariert eine Variable, ein nicht-statisches Datenelement außer eines anonymen Unions , einen Enumerator, eine Funktion oder eine Funktionsvorlage, oder
- jede deklariert eine Funktion oder Funktionsvorlage und sie deklarieren keine entsprechenden Überladungen.
Entsprechende Funktionsüberladungen
Zwei Funktionsdeklarationen deklarieren entsprechende Überladungen wenn beide Funktionen deklarieren, die alle folgenden Bedingungen erfüllen:
- Sie haben dieselbe parameter-type-list , wobei die Typen der explicit object parameters ausgelassen werden (since C++23) .
|
(seit C++20) |
- Wenn beide von ihnen nicht-statische Memberfunktionen sind, müssen sie zusätzlich eine der folgenden Anforderungen erfüllen:
|
(seit C++23) |
-
- Ihre Objektparameter haben denselben Typ.
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 Parameter-Typ-Listen , unter Auslassung der Typen von expliziten Objektparametern (seit C++23) .
- Sie haben äquivalente Rückgabetypen.
|
(seit C++20) |
- Wenn beide nicht-statische Member-Funktionstemplates 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() {} // entspricht #1 und definiert es }; typedef int Int; enum E : int { a }; void f(int); // #2 void f(Int) {} // definiert #2 void f(E) {} // OK, weitere Überladung struct X { static void f(); void f() const; // Fehler: Neudeklaration void g(); void g() const; // OK void g() &; // Fehler: Neudeklaration void h(this X&, int); void h(int) &&; // OK, weitere Überladung void j(this const X&); void j() const &; // Fehler: Neudeklaration void k(); void k(this X&); // Fehler: Neudeklaration };
Mehrfache Deklarationen derselben Entität
|
Eine Deklaration ist namensunabhä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 Aufzählungsnamen für Linkage-Zwecke einführen (falls vorhanden):
- Sie entsprechen einander.
- Sie haben denselben target scope , der kein function parameter scope oder template parameter scope ist.
|
(since C++26) |
- Eine der folgenden Bedingungen ist erfüllt:
-
- Sie erscheinen in derselben Übersetzungseinheit.
|
(seit C++20) |
-
- Sie deklarieren beide Namen mit external linkage .
Eine Deklaration eines Entitäts- oder Typedef-Namens
X
ist eine
Neudeklaration
von
X
, wenn eine andere Deklaration von
X
von ihr aus erreichbar ist; andernfalls ist es eine
Erstdoklaration
von
X
.
Einschränkungen
Wenn zwei Deklarationen einer Entität
E
die entsprechende nachfolgende Einschränkung verletzen, ist das Programm fehlerhaft:
-
Wenn man
Eals Variable deklariert, muss der andere ebenfallsEals Variable desselben Typs deklarieren. -
Wenn man
Eals eine Funktion deklariert, muss der andere ebenfallsEals Funktion desselben Typs deklarieren. -
Wenn man
Eals einen Enumerator deklariert, muss der andere ebenfallsEals Enumerator deklarieren. -
Wenn man
Eals einen Namespace deklariert, muss der andere ebenfallsEals Namespace deklarieren. -
Wenn man
Eals einen Klassentyp deklariert, muss der andere ebenfallsEals Klassentyp deklarieren. -
Wenn man
Eals einen Aufzählungstyp deklariert, muss der andere ebenfallsEals Aufzählungstyp deklarieren. -
Wenn man
Eals eine Klassenvorlage deklariert, muss der andere ebenfallsEals Klassenvorlage mit einer äquivalenten Template-Parameterliste deklarieren (siehe Funktionsvorlagen-Überladung ). -
Wenn man
Eals eine Funktionsvorlage deklariert, muss der andere ebenfallsEals Funktionsvorlage mit einer äquivalenten Template-Parameterliste und Typ deklarieren.
|
(seit C++11) |
|
(seit C++14) |
|
(seit C++20) |
Typen werden nach allen Anpassungen der 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 Hauptarray-Grenze unterscheiden. Es ist keine Diagnose erforderlich, wenn keine der Deklarationen von der anderen aus erreichbar ist.
void g(); // #1 void g(int); // OK, andere Entität als #1 (sie entsprechen sich nicht) int g(); // Fehler: dieselbe Entität wie #1 mit anderem Typ void h(); // #2 namespace h {} // Fehler: dieselbe Entität wie #2, aber keine Funktion
Wenn eine Deklaration
H
, die einen Namen mit
internal linkage
deklariert, einer Deklaration
D
in einer anderen Übersetzungseinheit
U
vorausgeht und dieselbe Entität wie
D
deklarieren würde, wenn sie in
U
erschiene, ist das Programm fehlerhaft.
Potenziell widersprüchliche Deklarationen
Zwei Deklarationen potentially conflict wenn sie korrespondieren aber unterschiedliche Entitäten deklarieren.
Wenn in einem beliebigen Gültigkeitsbereich ein Name an zwei Deklarationen
A
und
B
gebunden wird, die potenziell in Konflikt stehen
,
B
nicht namensunabhängig ist
(seit C++26)
, und
A
vor
B
steht, ist das Programm fehlerhaft:
void f() { int x, y; void x(); // Fehler: verschiedene Entität für x int y; // Fehler: Neudefinition } enum { f }; // Fehler: verschiedene Entität für ::f namespace A {} namespace B = A; namespace B = A; // OK, keine Auswirkung namespace B = B; // OK, keine Auswirkung namespace A = B; // OK, keine Auswirkung namespace B {} // Fehler: verschiedene Entität für B void g() { int _; _ = 0; // OK int _; // OK seit C++26, namensunabhängige Deklaration _ = 0; // Fehler: zwei Nicht-Funktionsdeklarationen im Lookup-Set } void h () { int _; // #1 _ ++; // OK static int _; // Fehler: Konflikt mit #1 weil // statische Variablen nicht namensunabhängig sind }
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrektes Verhalten |
|---|---|---|---|
|
CWG 279
( P1787R6 ) |
C++98 |
es war unklar, ob eine unbenannte Klasse oder Enumeration
erneut deklariert werden kann, wenn sie einen Typnamen für Verbindungszwecke hat |
sie kann erneut deklariert werden |
|
CWG 338
( P1787R6 ) |
C++98 |
es war unklar, ob eine unbenannte Enumeration erneut
deklariert werden kann, wenn sie einen Enumerator als Namen für Verbindungszwecke hat |
sie kann erneut deklariert werden |
|
CWG 1884
( P1787R6 ) |
C++98 |
die Einschränkungen für mehrere
Deklarationen derselben Entität waren unklar |
klargestellt |