引用N3797的7.3.1 / 8:
内联命名空间的成员可以在大多数方面使用,就好像 他们是封闭命名空间的成员。
请考虑以下代码段:
namespace M
{
int j = 7;
inline namespace MM
{
int j = 8;
}
}
我认为该示例违反了ODR
。但事实并非如此,它正在编制成功。你能解释一下这种行为吗?
答案 0 :(得分:3)
7.3p1
命名空间[basic.namespace]
命名空间是可选命名的声明性区域。命名空间的名称可用于访问在该命名空间中声明的实体;也就是命名空间的成员。与其他声明性区域不同,命名空间的定义可以分为一个或多个翻译单元的几个部分。
命名空间内的声明实体属于该命名空间,即。无论命名空间是否为 inline ,它都是该特定命名空间的成员。
您的示例代码段不违反 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.对此帖的评论可以提供更多详细信息。功能