来自N3797的7.3.1/8的一句话引用如下:
内联命名空间的成员可以在大多数情况下被视为是封闭命名空间的成员。
考虑以下代码片段:
namespace M
{
int j = 7;
inline namespace MM
{
int j = 8;
}
}
我认为这个例子违反了ODR
。但实际上它是正确编译的。你能解释一下这种行为吗?
来自N3797的7.3.1/8的一句话引用如下:
内联命名空间的成员可以在大多数情况下被视为是封闭命名空间的成员。
考虑以下代码片段:
namespace M
{
int j = 7;
inline namespace MM
{
int j = 8;
}
}
我认为这个例子违反了ODR
。但实际上它是正确编译的。你能解释一下这种行为吗?
7.3p1
命名空间[basic.namespace]
命名空间是一个可选命名的声明性区域。命名空间的名称可用于访问在该命名空间中声明的实体,即命名空间的成员。与其他声明性区域不同,命名空间的定义可以分布在一个或多个翻译单元的几个部分中。
在命名空间内声明的实体属于该命名空间,即使命名空间是内联的也是如此。
您的示例片段不会违反ODR,主要是因为您有2个名为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-directive引入的内联命名空间的成员,即使在封闭命名空间中有名称的声明。
[basic.def.odr]
设置的规则,则“不需要诊断”。有关更多详细信息,请参见Matthieu M.在此帖子上的评论。
inline
函数(因此template
函数)是弱符号,链接器通常只选择一个并忽略其他符号...这可能会随着模块的改变而改变。 - Matthieu M.