命名空间
变体
操作

冲突声明

来自 cppreference.cn
< cpp‎ | language
 
 
C++ 语言
通用主题
流程控制
条件执行语句
if
迭代语句(循环)
for
range-for (C++11)
跳转语句
函数
函数声明
Lambda 函数表达式
inline 说明符
动态异常规范 直到 C++17*
noexcept 说明符 (C++11)
异常
命名空间
类型
说明符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
存储期说明符
初始化
 
 

除非另有说明,否则两个声明不能(重新)引入相同的实体。如果存在此类声明,则程序是非良构的。

目录

[编辑] 对应声明

如果两个声明(重新)引入相同的名称,都声明构造函数,或都声明析构函数,则它们对应,除非

  • 其中一个是 using 声明
  • 一个声明类型(不是 typedef 名称),另一个声明变量、非静态数据成员(匿名联合体除外)、枚举器、函数或函数模板,或者
  • 每个都声明一个函数或函数模板,并且它们不声明对应的重载。

[编辑] 对应函数重载

如果两个 函数声明 都声明了满足以下所有条件的函数,则它们声明对应的重载

(自 C++20 起)
  • 如果它们都是非静态成员函数,则它们还需要满足以下要求之一
  • 其中一个是 隐式对象成员函数,没有 ref-qualifier,并且在移除顶层引用后,其对象参数的类型相同。
(自 C++23 起)
  • 它们的对象参数具有相同的类型。

[编辑] 对应函数模板重载

如果两个 函数模板声明 都声明了满足以下所有条件的函数模板,则它们声明对应的重载

  • 它们的模板参数列表具有相同的长度。
  • 它们对应的模板参数是 等价的
  • 它们具有等价的 参数类型列表,省略了 显式对象参数 的类型(自 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 为具有等价模板参数列表和 type-id 的别名模板。
(自 C++11 起)
  • 如果一个声明 E变量模板(或变量模板的部分特化),则另一个也必须声明 E 为具有等价模板参数列表和类型的变量模板(或变量模板的部分特化)。
(自 C++14 起)
  • 如果一个声明 E概念,则另一个也必须声明 E 为概念。
(自 C++20 起)

类型在所有类型调整后进行比较(在此期间 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

如果声明具有 内部链接 的名称的声明 H 在另一个翻译单元 U 中的声明 D 之前,并且如果它出现在 U 中将声明与 D 相同的实体,则程序是非良构的。

[编辑] 潜在冲突声明

如果两个声明对应但声明了不同的实体,则它们潜在冲突

如果在任何作用域中,名称绑定到两个潜在冲突的声明 ABB 不是名称独立的(自 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++ 标准。

DR 应用于 已发布行为 正确行为
CWG 279
(P1787R6)
C++98 尚不清楚是否可以重新声明未命名的类或枚举
如果它具有用于链接目的的 typedef 名称,则可以重新声明
它可以被重新声明
CWG 338
(P1787R6)
C++98 尚不清楚是否可以重新声明未命名的枚举
如果它具有作为链接目的名称的枚举器,则可以重新声明
它可以被重新声明
CWG 1884
(P1787R6)
C++98 应用于多次的限制
同一实体的声明不清楚
已明确