将名称空间的成员重新定义为嵌套的内联名称空间

Redefinition member of the namespace into the nested inline namespace

本文关键字:空间 嵌套 定义 新定义 成员      更新时间:2023-10-16

有一个N3797的7.3.1/8的报价:

内联命名空间的成员在大多数情况下都可以像这样使用它们是封闭命名空间的成员。

考虑下面的代码片段:
namespace M
{
    int j = 7;
    inline namespace MM
    {
        int j = 8;
    }
}

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

简介

7.3p1 Namespaces [basic.namespace]

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

名称空间中的声明实体属于该名称空间。它是该特定名称空间的成员,无论该名称空间是否为inline


ODR VIOLATION = no0ne

你的例子片段没有违反ODR,主要是因为你有两个不同的实体命名为j;

namespace N {
  int j = 0;            // 1st
  inline namespace M {
    int j = 1;          // 2nd
  }
}

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

<一口>

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

具体来说,内联命名空间和它的封闭命名空间都被添加到参数依赖查找(3.4.2)中使用的关联命名空间集中,并且将命名内联命名空间的using-direction(7.3.4)隐式插入到封闭命名空间中,就像未命名命名空间(7.3.1.1)一样。

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

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


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

进一步的细节可以在Matthieu M.对这篇文章的评论中找到。