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

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 :

(depuis C++20)
  • Si les deux sont des fonctions membres non statiques, elles doivent en outre satisfaire à l'une des exigences suivantes :
  • Exactement l'un d'entre eux est une fonction membre d'objet implicite sans ref-qualifier et les types de leurs paramètres objet, après suppression des références de plus haut niveau, sont identiques.
(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 paramètres de template correspondants sont soit tous deux déclarés sans contrainte , soit tous deux déclarés avec des contraintes équivalentes.
  • Ils ont des clauses requires finales équivalentes (si présentes).
(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) :

  • Aucune n'est une déclaration indépendante du nom.
(depuis C++26)
  • L'une des conditions suivantes est satisfaite :
  • Ils apparaissent dans la même unité de traduction.
(depuis C++20)

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 E comme variable, l'autre doit également déclarer E comme variable du même type.
  • Si l'un déclare E comme fonction , l'autre doit également déclarer E comme fonction du même type.
  • Si l'un déclare E comme énumérateur , l'autre doit également déclarer E comme énumérateur.
  • Si l'un déclare E comme espace de noms , l'autre doit également déclarer E comme espace de noms.
  • Si l'un déclare E comme type classe , l'autre doit également déclarer E comme type classe.
  • Si l'un déclare E comme type énumération , l'autre doit également déclarer E comme type énumération.
  • Si l'un déclare E comme modèle de classe , l'autre doit également déclarer E comme 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 E comme modèle de fonction , l'autre doit également déclarer E comme modèle de fonction avec une liste de paramètres de modèle et un type équivalents.
  • Si l'on déclare E comme étant un alias template , l'autre doit également déclarer E comme un alias template avec une liste de paramètres de template équivalente et un type-id équivalent.
(depuis C++11)
  • Si l'on déclare E comme étant une (spécialisation partielle d'une) variable template , l'autre doit également déclarer E comme une (spécialisation partielle d'une) variable template avec une liste de paramètres de template et un type équivalents.
(depuis C++14)
  • Si l'on déclare E comme étant un concept , l'autre doit également déclarer E comme un concept.
(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