根据c ++标准,这是不正确的还是格式良好的?
namespace M { struct i {}; }
namespace N { static int i = 1; }
using M::i;
using N::i;
int main() { sizeof (i); }
Clang拒绝它并且GCC接受它。
根据[namespace.udir-6](http://eel.is/c++draft/basic.namespace#namespace.udir-6):
如果名称查找找到两个不同的名称声明 名称空间,并且声明不会声明相同的实体 没有声明功能,名称的使用是不正确的。
我们该怎么解释这个?请记住,每个using声明都是通过[namespace.udecl] p1(http://eel.is/c++draft/namespace.udecl#1)声明一个名称:
using声明在声明区域中引入了一个名称 其中出现了使用声明。
using声明:
using typename
opt nested-name-specifier unqualified-id;
在using声明中指定的成员名称在 声明区域,其中出现using声明。 [ 注意: 只声明了指定的名称;指定枚举名称 在using声明中没有声明它的枚举器 using-declaration的声明区域。 - 结束说明]如果是 using-declaration命名一个构造函数([class.qual]),它是隐式的 在类中声明一组构造函数 出现using-declaration([class.inhctor]);否则这个名字 在using声明中指定的是一组的同义词 另一个命名空间或类中的声明。
所以我们有4个名字i的声明。
i
中sizeof(i)
的{{1}}的无限制名称查找中的哪一项?
它是否只找到同一命名空间(全局命名空间)中的using M::i;
和using N::i;
,以便程序格式正确?
或者它只找到位于不同名称空间的struct i {};
和static int i = 1;
,因此程序格式不正确?
或者我们还有其他选择吗?
答案 0 :(得分:1)
N4527 [7.3.3p13]:
由于 using-declaration 是声明,因此受到限制 同一声明区域中的同名声明(3.3) 也适用于使用声明。 [示例:
namespace A { int x; } namespace B { int i; struct g { }; struct x { }; void f(int); void f(double); void g(char); // OK: hides struct g } void func() { int i; using B::i; // error: i declared twice void f(char); using B::f; // OK: each f is a function f(3.5); // calls B::f(double) using B::g; g(’a’); // calls B::g(char) struct g g1; // g1 has class type B::g using B::x; using A::x; // OK: hides struct B::x x = 99; // assigns to A::x struct x x1; // x1 has class type B::x }
- 示例]
请注意两个不同x
的 using-declarations - 它与您的示例相同。
您的第一个引用是指 using-directives ,而不是 using-declarations 。
i
中sizeof(i)
的非限定名称查找在全局命名空间中找到i
。由于它们是相同范围内的声明,根据[3.3.10p2](下面引用),变量i
隐藏了struct
。
可以通过名称隐藏类名(9.1)或枚举名称(7.2) 在...中声明的变量,数据成员,函数或枚举器 相同的范围。如果是类或枚举名称和变量,则为数据 成员,函数或枚举器在同一范围内声明(在任何范围内) order)具有相同的名称,隐藏类或枚举名称 变量,数据成员,函数或枚举器名称的位置 可见。
因此,代码格式正确,Clang拒绝它是错误的。
MSVC(12和14)接受了这个例子。
基本上,将 using-declaration 引入的名称视为某个实体的另一个名称,该名称也在其他地方命名(由 nested-name-specifier指定的位置使用声明中 qualified-id 的。这与 using-directive 的作用不同;我倾向于将 using-directives 视为"名称查找调整"。
答案 1 :(得分:1)
anonymous struct已经有了答案,但为了建立你的直觉不正确的原因,你引用了:
如果名称查找在两个不同的名称空间中找到名称的声明,并且声明没有声明相同的实体而且没有声明函数,则名称的使用是错误的。 / p>
但是在这个例子中,我们有:
namespace M {
struct i {}; // declares M::i, entity class type
}
namespace N {
static int i = 1; // declares N::i, entity variable
}
using M::i; // declares ::i, synonym of M::i
using N::i; // declares ::i, synonym of N::i
// hides (*) the other ::i
int main() {
sizeof (i);
}
要详细说明(*)
,我们在全局命名空间i
中有两个::
声明。来自[basic.scope.hiding]:
类名(9.1)或枚举名(7.2)可以通过变量名称,数据成员隐藏, 在同一范围内声明的函数或枚举器。如果是类或枚举名称和变量,则为数据 成员,函数或枚举器在同一范围内(以任何顺序)声明具有相同的名称,即 在变量,数据成员,函数或枚举器名称所在的位置隐藏类或枚举名称 可见。
因此,在同一范围内的两个i
中,该类被隐藏(无关 using-declarations 的排序!),以及sizeof(i)
指::i
,它是N::i
的同义词。这两个i
都位于相同的名称空间(::
)中,这就是您的报价不适用的原因。这与您的bogdan不同,后者您使用 using-directives :
using namespace M;
using namespace N;
在两个不同的名称空间中可以找到i
,指的是两个不同的非功能实体。因此,错误。在这里,Clang错了,GCC是正确的。