名稱空間
變體
操作

衝突宣告

來自 cppreference.com
< cpp‎ | 語言
 
 
C++ 語言
表示式
替代表示
字面量
布林字面量 - 整數字面量 - 浮點字面量
字元字面量 - 字串字面量 - nullptr (C++11)
使用者定義 (C++11)
工具
屬性 (C++11)
型別
typedef 宣告
類型別名宣告 (C++11)
型別轉換
記憶體分配
類特有的函式屬性
explicit (C++11)
static

特殊成員函式
模板
雜項
 
 

除非另有規定,兩個宣告不能(重新)引入相同的實體。如果存在這樣的宣告,程式將是非良構的。

目錄

[編輯] 對應宣告

如果兩個宣告(重新)引入相同的名稱,都宣告建構函式,或都宣告解構函式,則它們是*對應的*,除非

  • 其中一個為using 宣告
  • 其中一個宣告型別(不是typedef 名稱),而另一個宣告變數、非靜態資料成員(不是匿名聯合的成員)、列舉器、函式或函式模板,或
  • 每個都宣告一個函式或函式模板,並且它們不宣告對應的過載。

[編輯] 對應函式過載

兩個函式宣告宣告*對應的過載*,如果兩者宣告的函式滿足所有以下條件:

(C++20 起)
  • 如果它們都是非靜態成員函式,它們還需要額外滿足以下要求之一
  • 它們中的一個正好是一個不帶引用限定符的隱式物件成員函式,並且它們物件引數的型別,在移除頂層引用後,是相同的。
(C++23 起)
  • 它們的物件引數具有相同的型別。

[編輯] 對應函式模板過載

兩個函式模板宣告宣告*對應的過載*,如果兩者宣告的函式模板滿足所有以下條件:

  • 它們的對應模板引數要麼都未宣告約束,要麼都聲明瞭等價的約束。
  • 它們具有等價的尾部requires 子句(如果有)。
(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 為具有等價模板引數列表和型別的函式模板。
  • 如果一個宣告 E別名模板,則另一個也必須宣告 E 為具有等價模板引數列表和型別 ID 的別名模板。
(C++11 起)
  • 如果一個宣告 E變數模板(的偏特化),則另一個也必須宣告 E 為具有等價模板引數列表和型別的變數模板(的偏特化)。
(C++14 起)
  • 如果一個宣告 E概念,則另一個也必須宣告 E 為概念。
(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 相同的實體,則程式是非良構的。

[編輯] 潛在衝突的宣告

兩個宣告*潛在衝突*,如果它們對應但聲明瞭不同的實體。

如果在任何作用域中,一個名稱繫結到兩個宣告 AB,它們潛在衝突B 不是名稱無關的(C++26 起),並且 AB 之前,則程式是非良構的。

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 適用於同一實體的多個
宣告的限制尚不明確。
已明確