Conflicting declarations
Unless otherwise specified, two declarations cannot (re)introduce the same entity. The program is ill-formed if such declarations exist.
Corresponding declarations
Two declarations correspond if they (re)introduce the same name, both declare constructors, or both declare destructors, unless
- either is a using declaration,
- one declares a type (not a typedef name) and the other declares a variable, non-static data member other than of an anonymous union
- each declares a function or function template and they do not declare corresponding overloads.
Corresponding function overloads
Two function declarations declare corresponding overloads if both declare functions satisfying all following conditions:
- They have the same parameter-type-list , omitting the types of explicit object parameters (since C++23)
|
(since C++20) |
- If both of them are non-static member functions, they need to additionally satisfy one of the following requirements:
|
(since C++23) |
- Their object parameters have the same type.
Corresponding function template overloads
Two function template declarations declare corresponding overloads if both declare function templates satisfying all following conditions:
- Their template parameter lists have the same length.
- Their corresponding template parameters are equivalent.
- They have equivalent parameter-type-lists , omitting the types of explicit object parameters (since C++23)
- They have equivalent return types.
|
(since C++20) |
- If both are non-static members function templates, they need to additionally satisfy one of the following requirements:
|
(since C++23) |
- Their object parameters have equivalent types.
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 };
Multiple declarations of the same entity
A declaration is name-independent if its name is _ and it declares
|
(since C++26) |
Unless otherwise specified, two declarations of entities declare the same entity if all following conditions are satisfied, considering declarations of unnamed types to introduce their typedef names and enumeration names
- They correspond.
- They have the same target scope, which is not a function parameter scope or a template parameter scope
|
(since C++26) |
- One of the following conditions is satisfied:
- They appear in the same translation unit.
|
(since C++20) |
- They both declare names with external linkage.
A declaration of an entity or typedef name X
is a redeclaration of X
if another declaration of X
is reachable from it.
Restrictions
If any two declarations of an entity E
violate the corresponding restriction below, the program is ill-formed:
- If one declares
E
to be a variable, the other must also declareE
as a variable of the same type. - If one declares
E
to be a function, the other must also declareE
as a function of the same type. - If one declares
E
to be an enumerator, the other must also declareE
as an enumerator. - If one declares
E
to be a namespace, the other must also declareE
as a namespace. - If one declares
E
to be a class type, the other must also declareE
as a class type. - If one declares
E
to be an enumeration type, the other must also declareE
as an enumeration type. - If one declares
E
to be a class template, the other must also declareE
as a class template with an equivalent template parameter list (see function template overloading - If one declares
E
to be a function template, the other must also declareE
|
(since C++11) |
|
(since C++14) |
|
(since C++20) |
Types are compared after all adjustments of types (during which typedefs
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
If a declaration H
that declares a name with internal linkage precedes a declaration D
in another translation unit U
and would declare the same entity as D
if it appeared in U
Potentially-conflicting declarations
Two declarations potentially conflict if they correspond but declare different entities.
If, in any scope, a name is bound to two declarations A
and B
that potentially conflict, B
is not name-independent(since C++26), and A
precedes B
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 }
Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 279 (P1787R6) |
C++98 | it was unclear whether an unnamed class or enumeration can be redeclared if it has a typedef name for linkage purposes |
it can be redeclared |
CWG 338 (P1787R6) |
C++98 | it was unclear whether an unnamed enumeration can be redeclared if it has an enumerator as a name for linkage purposes |
it can be redeclared |
CWG 1884 (P1787R6) |
C++98 | the restrictions applied to multiple declarations of the same entity were unclear |
made clear |