C++ 嵌套 `namespace` `using` Name Lookup Order of Preference

标签 c++ scope namespaces nested name-lookup

我正在阅读有关 using -directives on cppreference.com 的内容,他们有一些代码我无法弄清楚名称查找的顺序偏好。

我已经阅读了 the transitive property of using -directives on paragraph 3unqualified_lookup#namespace scopescope#namespace_scope 。我还尝试在其他一些网站上搜索。

如果您认为我应该阅读更多文档,请提出建议。

他们的代码如下:

不要花太多时间阅读这段代码,因为我将在下面讨论我的改编版本。

namespace A {
    int i;
}
namespace B {
    int i;
    int j;
    namespace C {
        namespace D {
            using namespace A; // all names from A injected into global namespace
            int j;
            int k;
            int a = i; // i is B::i, because A::i is hidden by B::i
        }
        using namespace D; // names from D are injected into C
                           // names from A are injected into global namespace
        int k = 89; // OK to declare name identical to one introduced by a using
        int l = k;  // ambiguous: C::k or D::k
        int m = i;  // ok: B::i hides A::i
        int n = j;  // ok: D::j hides B::j
    }
}

我已经修改了他们的代码来打印出来:

我把编号的问题作为对我不理解的问题的评论。如果您可以解释顺序或名称查找,并且您认为我可以自己回答其余的问题,则您不必回答所有问题。

如果我的问题太令人困惑,您能否尝试解释上面 cppreference 代码中的每个变量名称查找?
#include <iostream>
using namespace std;

namespace A {
    int b = 0;
    int i = 1;
}
namespace B {
    int b = 2;
    int i = 3;
    int j = 4;
    namespace C {
        namespace D {
            // 1) Why does cppreference say A is injected into `global`
            //    and not `D` namespace?
            using namespace A; // all names from A injected into global namespace
            int j = 5;
            int k = 6;
            int a = i; // i is B::i, because A::i is hidden by B::i
        }
        using namespace D; // names from D are injected into C
        // 2) Why does cppreference say A is injected into `global` and
        //    not `C` namespace?
                           // names from A are injected into global namespace
        int k = 7; // OK to declare name identical to one introduced by a using
        // 3) What makes this ambiguous and not "one hides the other"?
        // int l = k;  // ambiguous: C::k or D::k
        int m = i;  // ok: B::i hides A::i
        int n = j;  // ok: D::j hides B::j
        int c = b;
    }
}

int main() 
{
    cout << "A::b " << A::b << endl; // prints "A::b 0"
    cout << "A::i " << A::i << endl; // prints "A::i 1"

    cout << endl;

    cout << "B::b " << B::b << endl; // prints "B::b 2"
    cout << "B::i " << B::i << endl; // prints "B::i 3"
    cout << "B::j " << B::j << endl; // prints "B::j 4"

    cout << endl;

    cout << "B::C::a " << B::C::a << endl; // prints "B::C::a 3"
    cout << "B::C::b " << B::C::b << endl; // prints "B::C::b 0"
    cout << "B::C::c " << B::C::c << endl; // prints "B::C::c 2"
    cout << "B::C::i " << B::C::i << endl; // prints "B::C::i 1"
    cout << "B::C::j " << B::C::j << endl; // prints "B::C::j 5"
    cout << "B::C::k " << B::C::k << endl; // prints "B::C::k 7"
    cout << "B::C::m " << B::C::m << endl; // prints "B::C::m 3"
    cout << "B::C::n " << B::C::n << endl; // prints "B::C::n 5"

    cout << endl;

    cout << "B::C::D::a " << B::C::D::a << endl; // prints "B::C::D::a 3"
    cout << "B::C::D::b " << B::C::D::b << endl; // prints "B::C::D::b 0"
    cout << "B::C::D::i " << B::C::D::i << endl; // prints "B::C::D::i 1"
    cout << "B::C::D::j " << B::C::D::j << endl; // prints "B::C::D::j 5"
    cout << "B::C::D::k " << B::C::D::k << endl; // prints "B::C::D::k 6"

    cout << endl;
    return 0;
}

完整输出:

我把编号的问题作为对我不理解的问题的评论。

我建议你并排打开上面的代码,这样你就可以看到我在引用什么。我保持行 < 80 个字符。
A::b 0
A::i 1

B::b 2
B::i 3
B::j 4

B::C::a 3 // 4) cppreference says A::i == 1 is hidden by B::i == 3
          //    so this is == 3 and not 1.
          //    Why doesn't A::i hide B::i?
          //    Doesn't the `using namespace A` make A::i closer in scope
          //    than B::i?
          //    Why does this go up the parent blocks C->B->B::i == 3 and
          //    not up the namespaces C->D->A->A::i == 1?

B::C::b 0 // 5) This is == A::b == 0. This goes through the
          //    `using namespace D` which contains `using namespace A`.
          //    Why does this go up the namespaces C->D->A->A::b == 0 and
          //    not the parent blocks to C->B->B::b == 2 like in question 4?
B::C::c 2 // 6) This is == B::b == 2 (go up blocks C->B->B::b == 2).
          //    Why is it not == B::C:b == 0
          //    (go up namespaces C->D->A->A::b == 0 like in question 5)
          //    from the assignment `int c = b`?
          //    I'm guessing because name lookup for b
          //    inside the namespace body is different than the B::C::b lookup
          //    outside of the namespace body.
B::C::i 1 // 7) Compared to question 9 below, i is assigned to m but 1 != 3.
          //    I think this is similar to question 6 where name lookup
          //    outside of the namespace body is different than inside.
          //    I'm not sure why this goes up namespaces C->D->A->A::i == 1
          //    and not blocks C->B->B::i == 3.
B::C::j 5 // 8) Why does it go up namespaces C->D->D::j and not blocks
          //    C->B->B::j == 4?
B::C::k
B::C::m 3 // 9) cppreference says B::i hides A::i so this is == B::i == 3
          //    Why does this go up blocks C->B->B::i == 3 and not namespaces
          //    C->D->A->A::i == 1?
          //    Actually, I guess questions 9 and 7 is the same situation as
          //    questions 6 and 5, respectively. Where m and i corresponds
          //    with c and b, respectively.
B::C::n 5 // 10) cppreference says D::j hides B::j so this is == D::j == 5
          //     Why does this go up namespaces C->D->D::j == 5 and not
          //     blocks C->B->B::j == 4? The only difference I see between
          //     question 9 and 10 is that for question 9, i isn't declared
          //     within D like j is.

B::C::D::a 3 // 11) cppreference says A::i is hidden by B::i so
             //     this == B::i == 3. Why does this go up the blocks
             //     D->C->B->B::i == 3 instead of the
             //     namespaces D->A->A::i == 1?
             //     This goes up the blocks like question 9 but not
             //     up the namespaces like question 10.
B::C::D::b 0 // 12) This probably goes up the namespaces D->A->A::b == 0 and not
             //     blocks D->C->B->B::b == 2 because b is accessed 
             //     outside the namespace body similar to questions 5, 7, and 8.
             //     Access inside the namespace body would be question 11 since
             //     the reference to i was captured inside a.
B::C::D::i 1 // 13) I think this is similar (~) to question 12 ~ 5, 7, and 8
             //     where it goes up namespaces D->A->A::i == 1 instead
             //     of blocks D->C->B->B::i == 3 because i is accessed outside
             //     of the namespace body.
B::C::D::j 5
B::C::D::k 6

上面出现的问题列表:
  • 为什么 cppreference 说 A 被注入(inject)到 global 而不是 D 命名空间?
  • 为什么 cppreference 说 A 被注入(inject)到 global 而不是 C 命名空间?
  • 是什么让这个模棱两可而不是“一个隐藏另一个”?
  • cppreference 说 A::i == 1 被 B::i == 3 隐藏,所以这是 == 3 而不是 0。为什么 A::i 不隐藏 B::i? using namespace A 不是使 A::i 的范围比 B::i 更近吗?为什么这会上升到父块 C->B->B::i == 1 而不是命名空间 C->D->A->A::i == 3?
  • 这是 == A::b == 0。这通过包含 using namespace Dusing namespace A 。为什么这会像问题 4 那样从命名空间 C->D->A->A::b == 0 而不是 C->B->B::b == 2 的父块上升?
  • 这是 == B::b == 2。为什么不是 == B::C:b == 0 来自赋值 int c = b ?我猜是因为 namespace 主体内 b 的名称查找与 namespace 主体外的 B::C::b 查找不同。
  • 与下面的问题 9 相比,i 被分配给 m 但 1 != 3。我认为这类似于问题 6,其中 namespace 主体外部的名称查找与内部不同。我不知道为什么这会上升命名空间 C->D->A->A::i == 1 而不是阻塞 C->B->B::i == 3。
  • 为什么它上升到命名空间 C->D->D::j 而不是阻塞 C->B->B::j == 4?
  • cppreference 说 B::i 隐藏 A::i 所以这是 == B::i == 3 为什么这会上升块 C->B->B::i == 3 而不是命名空间 C->D ->A->A::i == 1?其实我猜第9题和第7题分别和第6题和第5题是一样的情况。其中 m 和 i 分别对应于 c 和 b。
  • cppreference 说 D::j 隐藏 B::j 所以这是 == D::j == 5 为什么这会上升命名空间 C->D->D::j == 5 而不是阻塞 C->B -> B::j == 4?我在问题 9 和问题 10 之间看到的唯一区别是,对于问题 9,我不像 j 那样在 D 中声明。
  • cppreference 说 A::i 被 B::i 隐藏所以这 == B::i == 3. 为什么这会上升到块 D->C->B->B::i == 3命名空间 D->A->A::i == 1?这会像问题 9 这样的块上升,但不会像问题 10 那样上升到命名空间。
  • 这可能会上升到命名空间 D->A->A::b == 0 而不是阻塞 D->C->B->B::b == 2 因为 b 是在命名空间主体之外访问的,类似于问题5、7 和 8。在命名空间主体内部的访问将是问题 11,因为对 i 的引用是在 a 中捕获的。
  • 我认为这类似于 (~) 问题 12 ~ 5、7 和 8,它上升命名空间 D->A->A::i == 1 而不是块 D->C->B->B::i == 3 因为 i 在命名空间主体之外被访问。
  • 最佳答案

    // 1) Why does cppreference say A is injected into `global`
    //    and not `D` namespace?
    using namespace A; // all names from A injected into global namespace
    


    因为 global 是最近的包含 AD 的封闭命名空间。 using namespace 的效果在同一个页面上进行了解释,就在示例上方

    using namespace D; // names from D are injected into C
    // 2) Why does cppreference say A is injected into `global` and
    //    not `C` namespace?
                      // names from A are injected into global namespace
    


    因为 global 是最近的包含 AC 的封闭命名空间

    // 3) What makes this ambiguous and not "one hides the other"?
    // int l = k;  // ambiguous: C::k or D::k
    


    因为 D::kC 拉入了 using namespace D; 中,其效果也在示例上方进行了说明。

    Why doesn't A::i hide B::i? Doesn't the using namespace A make A::i closer in scope than B::i?



    如上所述,using namespace A; 将 A::i 拉入全局命名空间(从该块中查看时)。 B::i 比全局命名空间“范围更近”。

    通常,语言引用页面上的 cppreference 示例适用于直接前面的文本块,但您的主要绊脚石似乎拒绝相信出现在无关 namespace using namespace A; 中的 D 将 A 的声明注入(inject)全局 namespace 。这确实是它的作用。这就是它的用途。

    关于C++ 嵌套 `namespace` `using` Name Lookup Order of Preference,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48971405/

    相关文章:

    c++ - 从二叉搜索树 C++ 返回引用

    objective-c - Objective-C 中的变量作用域

    python-2.7 - 访问派生类中的基类属性 - 在 "class scope"

    javascript - 将函数添加到命名空间

    C++ 如何在不使用 winapi 的情况下 move 文件并将它们从一个磁盘复制到不同的磁盘?

    具有不同参数的 C++ boost 信号和插槽?

    c++ - 如何检查(通过预处理器)C 源文件是否被编译为 C++ 代码

    PHP:将未声明的类属性的默认可见性更改为 protected /私有(private)

    python - 覆盖父命名空间变量

    c# - 在 Unity UWP 应用程序中找不到命名空间 'Windows'