命名空间
变体
操作

冲突声明

来自 cppreference.cn
< 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 适用于同一实体的多个
声明的限制尚不明确。
已明确