Conflicting declarations
Sauf indication contraire, deux déclarations ne peuvent pas (ré)introduire la même entité. Le programme est mal formé si de telles déclarations existent.
Table des matières |
Déclarations correspondantes
Deux déclarations correspondent si elles (ré)introduisent le même nom, déclarent toutes deux des constructeurs, ou déclarent toutes deux des destructeurs, sauf si
- soit c'est une using déclaration ,
- l'un déclare un type (pas un typedef name ) et l'autre déclare une variable, un membre de données non statique autre que d'une union anonyme , un énumérateur, une fonction ou un modèle de fonction, ou
- chacun déclare une fonction ou un modèle de fonction et ils ne déclarent pas de surcharges correspondantes.
Surcharges de fonctions correspondantes
Deux déclarations de fonction déclarent des surcharges correspondantes si toutes deux déclarent des fonctions satisfaisant toutes les conditions suivantes :
- Ils ont la même parameter-type-list , en omettant les types des explicit object parameters (depuis C++23) .
|
(depuis C++20) |
- Si les deux sont des fonctions membres non statiques, elles doivent en outre satisfaire à l'une des exigences suivantes :
|
(depuis C++23) |
-
- Leurs paramètres d'objet ont le même type.
Surcharges correspondantes de modèles de fonction
Deux déclarations de modèles de fonction déclarent des surcharges correspondantes si les deux déclarent des modèles de fonction satisfaisant toutes les conditions suivantes :
- Leurs listes de paramètres de template ont la même longueur.
- Leurs paramètres de template correspondants sont équivalents .
- Ils ont des listes-de-types-de-paramètres équivalentes , en omettant les types des paramètres objet explicites (depuis C++23) .
- Ils ont des types de retour équivalents.
|
(depuis C++20) |
- Si les deux sont des modèles de fonctions membres non statiques, ils doivent en outre satisfaire à l'une des exigences suivantes :
|
(depuis C++23) |
-
- Leurs paramètres d'objet ont des types équivalents.
struct A { friend void c(); // #1 }; struct B { friend void c() {} // correspond à, et définit, #1 }; typedef int Int; enum E : int { a }; void f(int); // #2 void f(Int) {} // définit #2 void f(E) {} // OK, une autre surcharge struct X { static void f(); void f() const; // erreur : redéclaration void g(); void g() const; // OK void g() &; // erreur : redéclaration void h(this X&, int); void h(int) &&; // OK, une autre surcharge void j(this const X&); void j() const &; // erreur : redéclaration void k(); void k(this X&); // erreur : redéclaration };
Déclarations multiples de la même entité
|
Une déclaration est indépendante du nom si son nom est _ et qu'elle déclare
|
(depuis C++26) |
Sauf indication contraire, deux déclarations d'entités déclarent la même entité si toutes les conditions suivantes sont satisfaites, en considérant que les déclarations de types anonymes introduisent leurs typedef names et enumeration names pour les besoins de liaison (s'il en existe) :
- Ils correspondent.
- Ils ont la même portée cible , qui n'est pas une portée de paramètre de fonction ou une portée de paramètre de modèle .
|
(depuis C++26) |
- L'une des conditions suivantes est satisfaite :
-
- Ils apparaissent dans la même unité de traduction.
|
(depuis C++20) |
-
- Ils déclarent tous deux des noms avec external linkage .
Une déclaration d'une entité ou d'un nom typedef
X
est une
redéclaration
de
X
si une autre déclaration de
X
est accessible depuis celle-ci ; sinon, il s'agit d'une
première déclaration
de
X
.
Restrictions
Si deux déclarations d'une entité
E
violent la restriction correspondante ci-dessous, le programme est mal formé :
-
Si l'un déclare
Ecomme variable, l'autre doit également déclarerEcomme variable du même type. -
Si l'un déclare
Ecomme fonction , l'autre doit également déclarerEcomme fonction du même type. -
Si l'un déclare
Ecomme énumérateur , l'autre doit également déclarerEcomme énumérateur. -
Si l'un déclare
Ecomme espace de noms , l'autre doit également déclarerEcomme espace de noms. -
Si l'un déclare
Ecomme type classe , l'autre doit également déclarerEcomme type classe. -
Si l'un déclare
Ecomme type énumération , l'autre doit également déclarerEcomme type énumération. -
Si l'un déclare
Ecomme modèle de classe , l'autre doit également déclarerEcomme modèle de classe avec une liste de paramètres de modèle équivalente (voir surcharge de modèle de fonction ). -
Si l'un déclare
Ecomme modèle de fonction , l'autre doit également déclarerEcomme modèle de fonction avec une liste de paramètres de modèle et un type équivalents.
|
(depuis C++11) |
|
(depuis C++14) |
|
(depuis C++20) |
Les types sont comparés après tous les ajustements de types (au cours desquels typedefs sont remplacés par leurs définitions). Les déclarations pour un objet tableau peuvent spécifier des types de tableau qui diffèrent par la présence ou l'absence d'une limite majeure de tableau. Aucun diagnostic n'est requis si aucune déclaration n'est accessible depuis l'autre.
void g(); // #1 void g(int); // OK, entité différente de #1 (elles ne correspondent pas) int g(); // Erreur : même entité que #1 avec un type différent void h(); // #2 namespace h {} // Erreur : même entité que #2, mais pas une fonction
Si une déclaration
H
qui déclare un nom avec une
liaison interne
précède une déclaration
D
dans une autre unité de traduction
U
et déclarerait la même entité que
D
si elle apparaissait dans
U
, le programme est mal formé.
Déclarations potentiellement conflictuelles
Deux déclarations entrent potentiellement en conflit si elles correspondent mais déclarent des entités différentes.
Si, dans une portée quelconque, un nom est lié à deux déclarations
A
et
B
qui entrent potentiellement en conflit
,
B
n'est pas indépendant du nom
(depuis C++26)
, et
A
précède
B
, le programme est mal formé :
void f() { int x, y; void x(); // Erreur : entité différente pour x int y; // Erreur : redéfinition } enum { f }; // Erreur : entité différente pour ::f namespace A {} namespace B = A; namespace B = A; // OK, sans effet namespace B = B; // OK, sans effet namespace A = B; // OK, sans effet namespace B {} // Erreur : entité différente pour B void g() { int _; _ = 0; // OK int _; // OK depuis C++26, déclaration indépendante du nom _ = 0; // Erreur : deux déclarations non-fonction dans l'ensemble de recherche } void h () { int _; // #1 _ ++; // OK static int _; // Erreur : conflit avec #1 car // les variables statiques ne sont pas indépendantes du nom }
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| DR | Appliqué à | Comportement publié | Comportement corrigé |
|---|---|---|---|
|
CWG 279
( P1787R6 ) |
C++98 |
il n'était pas clair si une classe ou énumération sans nom
pouvait être redéclarée si elle possède un nom typedef pour la liaison |
elle peut être redéclarée |
|
CWG 338
( P1787R6 ) |
C++98 |
il n'était pas clair si une énumération sans nom pouvait être
redéclarée si elle possède un énumérateur comme nom pour la liaison |
elle peut être redéclarée |
|
CWG 1884
( P1787R6 ) |
C++98 |
les restrictions appliquées aux déclarations multiples
de la même entité n'étaient pas claires |
clarifiées |