命名空间
变体
操作

冲突的声明

来自 cppreference.com
< cpp‎ | 语言
 
 
C++ 语言
 
 

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

目录

[编辑] 对应声明

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

  • 其中一个是 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 的另一个声明。

[编辑] 限制

如果实体 E 的任何两个声明违反了以下相应限制,则程序是格式错误的

  • 如果一个声明 E 为变量,则另一个也必须将 E 声明为相同类型的变量。
  • 如果一个声明将 E 声明为一个 函数,则另一个声明也必须将 E 声明为相同类型的函数。
  • 如果一个声明将 E 声明为一个 枚举器,则另一个声明也必须将 E 声明为一个枚举器。
  • 如果一个声明将 E 声明为一个 命名空间,则另一个声明也必须将 E 声明为一个命名空间。
  • 如果一个声明将 E 声明为一个 类类型,则另一个声明也必须将 E 声明为一个类类型。
  • 如果一个声明将 E 声明为一个 枚举类型,则另一个声明也必须将 E 声明为一个枚举类型。
  • 如果一个声明将 E 声明为一个 类模板,则另一个声明也必须将 E 声明为一个具有等效模板参数列表的类模板(参见 函数模板重载)。
  • 如果一个声明将 E 声明为一个 函数模板,则另一个声明也必须将 E 声明为一个具有等效模板参数列表和类型的函数模板。
  • 如果一个声明将 E 声明为一个 别名模板,则另一个声明也必须将 E 声明为一个具有等效模板参数列表和 类型标识 的别名模板。
(自 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 相同的实体,则程序是格式错误的。

[编辑] 潜在冲突的声明

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

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

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