冲突声明
来自 cppreference.cn
除非另有规定,两个声明不能(重新)引入相同的实体。如果存在这样的声明,程序将是非良构的。
目录 |
[编辑] 对应声明
如果两个声明(重新)引入相同的名称,都声明构造函数,或都声明析构函数,则它们是*对应的*,除非
- 其中一个为using 声明,
- 其中一个声明类型(不是typedef 名称),而另一个声明变量、非静态数据成员(不是匿名联合的成员)、枚举器、函数或函数模板,或
- 每个都声明一个函数或函数模板,并且它们不声明对应的重载。
[编辑] 对应函数重载
两个函数声明声明*对应的重载*,如果两者声明的函数满足所有以下条件:
|
(C++20 起) |
- 如果它们都是非静态成员函数,它们还需要额外满足以下要求之一
|
(C++23 起) |
- 它们的对象参数具有相同的类型。
[编辑] 对应函数模板重载
两个函数模板声明声明*对应的重载*,如果两者声明的函数模板满足所有以下条件:
|
(C++20 起) |
- 如果两者都是非静态成员函数模板,它们还需要额外满足以下要求之一
|
(C++23 起) |
- 它们的对象参数具有等价的类型。
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 };
[编辑] 同一实体的多个声明
一个声明是*名称无关的*,如果它的名称是_,并且它声明了 |
(C++26 起) |
除非另有规定,两个实体声明*声明相同的实体*,如果所有以下条件都满足,考虑到未命名类型的声明会引入它们的typedef 名称和枚举名称用于链接目的(如果存在)
|
(C++26 起) |
- 以下条件之一满足
- 它们出现在同一翻译单元中。
(C++20 起) |
- 它们都声明具有外部链接的名称。
一个实体或 typedef 名称 X
的声明是 X
的*重声明*,如果从它可到达 X
的另一个声明;否则,它是 X
的*首次声明*。
[编辑] 限制
如果实体 E
的任意两个声明违反以下相应限制,则程序是非良构的
- 如果一个声明
E
为变量,则另一个也必须声明E
为相同类型的变量。 - 如果一个声明
E
为函数,则另一个也必须声明E
为相同类型的函数。 - 如果一个声明
E
为枚举器,则另一个也必须声明E
为枚举器。 - 如果一个声明
E
为命名空间,则另一个也必须声明E
为命名空间。 - 如果一个声明
E
为类类型,则另一个也必须声明E
为类类型。 - 如果一个声明
E
为枚举类型,则另一个也必须声明E
为枚举类型。 - 如果一个声明
E
为类模板,则另一个也必须声明E
为具有等价模板参数列表的类模板(参见函数模板重载)。 - 如果一个声明
E
为函数模板,则另一个也必须声明E
为具有等价模板参数列表和类型的函数模板。
|
(C++11 起) |
|
(C++14 起) |
|
(C++20 起) |
类型在所有类型调整之后进行比较(在此期间,typedef 被其定义替换)。数组对象的声明可以指定数组类型,这些类型在主要数组边界的存在或缺失上有所不同。如果两个声明都无法从另一个可到达,则不需要诊断。
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
如果声明 H
声明一个具有内部链接的名称,并且在另一个翻译单元 U
中的声明 D
之前,如果它出现在 U
中会声明与 D
相同的实体,则程序是非良构的。
[编辑] 潜在冲突的声明
两个声明*潜在冲突*,如果它们对应但声明了不同的实体。
如果在任何作用域中,一个名称绑定到两个声明 A
和 B
,它们潜在冲突,B
不是名称无关的(C++26 起),并且 A
在 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 }
[编辑] 缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
缺陷报告 | 应用于 | 发布时的行为 | 正确的行为 |
---|---|---|---|
CWG 279 (P1787R6) |
C++98 | 关于未命名类或枚举是否可以 在具有用于链接目的的 typedef 名称时被重声明尚不明确。 |
它可以被重声明。 |
CWG 338 (P1787R6) |
C++98 | 关于未命名枚举是否可以 在具有用于链接目的的枚举器名称时被重声明尚不明确。 |
它可以被重声明。 |
CWG 1884 (P1787R6) |
C++98 | 适用于同一实体的多个 声明的限制尚不明确。 |
已明确 |