衝突宣告
來自 cppreference.com
除非另有規定,兩個宣告不能(重新)引入相同的實體。如果存在這樣的宣告,程式將是非良構的。
目錄 |
[編輯] 對應宣告
如果兩個宣告(重新)引入相同的名稱,都宣告建構函式,或都宣告解構函式,則它們是*對應的*,除非
- 其中一個為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 | 適用於同一實體的多個 宣告的限制尚不明確。 |
已明確 |