【问题标题】:Name lookup in using-declaration via using-directive通过 using-directive 在 using-declaration 中查找名称
【发布时间】:2015-10-16 04:59:18
【问题描述】:

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

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

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

根据 c++ 标准,这个程序是良构的还是良构的?需要对 c++ 标准的引用。

我正在尝试找出应该为哪个编译器提交错误。

【问题讨论】:

    标签: c++ language-lawyer using-directives name-lookup using-declaration


    【解决方案1】:

    格式正确。

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

    如果 qualified-idnested-name-specifier 指定了一个命名空间 (包括 nested-name-specifier:: 的情况,即 命名全局命名空间),在之后指定的名称 nested-name-specifier 在命名空间范围内查找。 [...]

    对于命名空间 X 和名称 m,命名空间限定的查找集 S(X,m)定义如下:令S'(X,m)为所有的集合 X 中的 m 声明和 X (7.3.1) 的内联命名空间集。如果 S'(X,m)不为空,S(X,m)S'(X,m);否则,S(X,m)S(Ni,m) 的联合,用于所有命名空间 Ni 提名 通过X 中的using-directives 及其内联命名空间集。

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

    我发现值得注意(虽然很明显)这个限定查找的定义是递归的:使用引号中的符号,在每个命名空间中限定查找 Ni将首先查找直接在 Ni 中进行的声明,然后,如果没有找到,将依次继续查找由 using-directives 在 Ni 中,以此类推。


    不管怎样,MSVC 也接受代码。

    【讨论】:

    【解决方案2】:

    GCC 是错误的。合格名称查找确实考虑N::i; §3.4.3.2/2 & /3:

    对于命名空间 X 和名称 m,命名空间限定的查找集 S(X, m) 定义如下:设S'(X, m) 是所有的集合 X 中的 m 声明和 X 的内联命名空间集 (7.3.1)。如果S'(X, m) 不为空,则S(X, m)S'(X, m)否则,S(X, m)S(Ni, m) 的联合,用于所有命名空间 NiX 中的 using-directives 指定 及其内联命名空间集。

    给定X::m(其中X 是用户声明的命名空间),或给定::m(其中 X 是全局命名空间),[…] 如果 S(X, m) 恰好有一个成员,或者如果 引用的上下文是使用声明 (7.3.3),S(X, m)m 所需的一组声明。

    您的程序中只有一个使用指令指定的命名空间:N。因此它包含在联合中,::i 被解析为 N::i

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

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

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

    【讨论】:

    • @bogdan 好吧,我很晚才看到这个问题(就像几分钟前一样),所以我很幸运能得到第一个 ;-)