将命名空间的重定义成员放入嵌套的内联命名空间

5 c++ namespaces inline language-lawyer

引用了N3797的7.3.1/8:

内联命名空间的成员可以在大多数方面使用,就像它们是封闭命名空间的成员一样.

请考虑以下代码段:

namespace M
{
    int j = 7;
    inline namespace MM
    {
        int j = 8;
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为这个例子违反了ODR.但事实并非如此,它正在编制成功.你能解释一下这种行为吗?

Fil*_*efp 3

介绍

7.3p1 命名空间 [basic.namespace]

命名空间是一个可选命名的声明性区域。命名空间的名称可用于访问在该命名空间中声明的实体;即命名空间的成员。与其他声明性区域不同,名称空间的定义可以分为一个或多个翻译单元的多个部分。

命名空间内声明的实体属于该命名空间,即。它是该特定命名空间的成员,无论该命名空间是否内联。


ODR 违规 = N0NE

您的示例代码片段不违反ODR 主要是因为您有 2 个不同的实体名为j

namespace N {
  int j = 0;            // 1st

  inline namespace M {
    int j = 1;          // 2nd
  }
}
Run Code Online (Sandbox Code Playgroud)

正如 中进一步指出的[namespace.def]p8,封闭命名空间中的名称查找将包括在任何inline命名空间中找到的名称,但嵌套内联命名空间的成员仍然是它们自己的实体。

7.3.1p8 命名空间定义 [namespace.def]

具体来说,内联命名空间及其封闭命名空间都被添加到参数相关的 lokoup (3.4.2) 中使用的一组关联命名空间中,只要其中一个是,以及命名内联命名空间的使用方向 (7.3.4)与未命名的命名空间 (7.3.1.1) 一样,隐式插入到封闭的命名空间中。

此外,内联命名空间的每个成员随后都可以显式实例化(14.7.2)或显式专门化(14.7.3),就好像它是封闭命名空间的成员一样。最后,通过显式限定(3.4.3.2)在封闭命名空间中查找名称将包括由 using 指令引入的内联命名空间的成员,即使封闭命名空间中存在该名称的声明。

添加的名称不会被视为先前声明的实体的重新声明,它们是嵌套声明区域中的附加名称,在名称查找期间被带入封闭的命名空间。


注意:依靠编译器发出 ODR 违规诊断并不安全,主要是因为标准明确规定,如果应用程序违反了所设置的规则,则“不需要诊断”。[basic.def.odr].

更多详细信息可在Matthieu M.对这篇文章的评论。