通过 using-directive 在 using-declaration 中查找名称

Name lookup in using-declaration via using-directive

根据 c++ 标准,下面的程序是良构还是病构的?

namespace N { int i; }
using namespace N;
using ::i;
int main() {}

我用不同的编译器得到不同的结果:

根据 c++ 标准,这个程序是良构的还是病态的?需要参考 c++ 标准。

我想弄清楚我应该为哪个编译器提交错误。

GCC 错误。限定名称查找确实考虑 N::i; §3.4.3.2/2 & /3:

For a namespace X and name m, the namespace-qualified lookup set S(X, m) is defined as follows: Let S'(X, m) be the set of all declarations of m in X and the inline namespace set of X (7.3.1). If S'(X, m) is not empty, S(X, m) is S'(X, m); otherwise, S(X, m) is the union of S(Ni, m) for all namespaces Ni nominated by using-directives in X and its inline namespace set.

Given X::m (where X is a user-declared namespace), or given ::m (where X is the global namespace), […] if S(X, m) has exactly one member, or if the context of the reference is a using-declaration (7.3.3), S(X, m) is the required set of declarations of m.

您的程序中只有一个由 using 指令指定的名称空间:N。因此它包含在联合中并且 ::i 被解析为 N::i.

请注意,GCC 与其查找不一致:在另一个上下文中使用 ::i 没问题。

namespace N { int i; }
using namespace N;

int main() {
    ::i = 5;
}

这个compiles。 using 声明作为上下文的唯一区别显示在上面的引用中,并且不会影响既定的结论。

格式正确。

using-directive 没有在全局命名空间中引入名称 i,但在查找期间使用它。 using-declaration 使用限定查找来查找 iusing-directives 存在的合格查找在 [3.4.3.2 p1, p2] 中指定(引自 N4527,当前工作草案):

If the nested-name-specifier of a qualified-id nominates a namespace (including the case where the nested-name-specifier is ::, i.e., nominating the global namespace), the name specified after the nested-name-specifier is looked up in the scope of the namespace. [...]

For a namespace X and name m, the namespace-qualified lookup set S(X,m) is defined as follows: Let S'(X,m) be the set of all declarations of m in X and the inline namespace set of X (7.3.1). If S'(X,m) is not empty, S(X,m) is S'(X,m); otherwise, S(X,m) is the union of S(Ni,m) for all namespaces Ni nominated by using-directives in X and its inline namespace set.

因此,对于合格的查找,第一步是查找直接在 nested-name-specifier (:: 在这种情况下)。没有这样的声明,所以 lookup 然后进行到第二步,即在 using-directives[=47] 指定的所有名称空间中通过合格查找找到的 i 的所有声明形成集合=] 在全局命名空间中。该集合由 N::i 组成,这是名称查找的结果,并通过 using 声明作为名称引入全局命名空间。

我发现值得注意(虽然很明显)限定查找的定义是递归的:使用引号中的符号,每个命名空间中的限定查找 Ni 将首先查找直接在 Ni 中进行的声明,然后,如果找到 none,将依次查看 using-directivesNi 中指定的命名空间,等等上。


就其价值而言,MSVC 也接受该代码。