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

时间:2014-06-14 12:53:37

标签: c++ namespaces inline language-lawyer

引用N3797的7.3.1 / 8:

  

内联命名空间的成员可以在大多数方面使用,就好像   他们是封闭命名空间的成员。

请考虑以下代码段:

namespace M
{
    int j = 7;
    inline namespace MM
    {
        int j = 8;
    }
}

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

1 个答案:

答案 0 :(得分:3)

简介

  

7.3p1 命名空间 [basic.namespace]

     
    

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

  

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


ODR VIOLATION = N0NE

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

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

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

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

  

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-directive引入的内联命名空间的成员,即使在封闭命名空间中存在名称声明。

  

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


  

注意:依赖编译器根据ODR违规发布诊断是不安全的,主要是因为标准明确指出“无需诊断[是] “如果某个应用程序违反[basic.def.odr].设置的规则,则Matthieu M.对此帖的评论可以提供更多详细信息。功能