C ++嵌套`namespace``使用`名称查找偏好顺序

时间:2018-02-25 07:51:44

标签: 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;
}

完整输出:

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

我建议你并排打开上面的代码,这样你就可以看到我正在引用的内容。我保留了线条&lt; 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

上面出现的问题列表:

  1. 为什么cppreference说A被注入global而不是D命名空间?
  2. 为什么cppreference说A被注入global而不是C命名空间?
  3. 是什么让这种模棱两可而不是“一个人隐藏另一个人”?
  4. 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?
  5. 这是== A :: b == 0.这将通过包含using namespace D的{​​{1}}。为什么这会命名空间C-> D-> A-> A :: b == 0而不是父块到C-> B-> B :: b == 2就像问题一样4?
  6. 这是== B :: b == 2.为什么不是来自作业using namespace A的== B :: C:b == 0?我猜是因为命名空间体内的b的名称查找与命名空间体外的B :: C :: b查找不同。
  7. 与下面的问题9相比,i被分配给m但是1!= 3.我认为这类似于问题6,其中命名空间体外的名称查找与内部不同。我不确定为什么这会增加命名空间C-> D-> A-> A :: i == 1而不是块C-> B-> B :: i == 3。
  8. 为什么命名空间C-> D-> D :: j而不是C-> B-> B :: j == 4?
  9. cppreference说B :: i隐藏A :: i所以这是== B :: i == 3为什么这会上升到块C-&gt; B-&gt; B :: i == 3而不是命名空间C-> D-> A-> A :: i == 1?实际上,我猜问题9和7分别与问题6和5的情况相同。其中m和i分别对应c和b。
  10. cppreference说D :: j隐藏了B :: j所以这是== D :: j == 5为什么这个命名空间C-> D-&gt; D :: j == 5而不是块C-> B-> B :: j == 4?我在问题9和10之间看到的唯一区别是,对于问题9,我没有像J那样在D中声明。
  11. cppreference说A :: i被B :: i隐藏所以这= = B :: i == 3.为什么这会上升到块D-> C-> B-> B :: i == 3而不是命名空间D-> A-> A :: i == 1?这会像问题9一样上升,但不会像问题10那样上升名称空间。
  12. 这可能上升到命名空间D-> A-> A :: b == 0而不是块D-> C-> B-> B :: b == 2因为b被访问在命名空间体外部类似于问题5,7和8.在命名空间体内的访问将是问题11,因为对i的引用是在a内捕获的。
  13. 我认为这与问题12~5,7和8类似(〜),其中它上升名称空间D-> A-> A :: i == 1而不是块D-> C- &gt; B-&gt; B :: i == 3因为我在命名空间体外访问。

2 个答案:

答案 0 :(得分:2)

// 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;,因此其效果也在示例上方解释。

  

为什么A :: i隐藏B :: i?不使用命名空间A使A :: i在范围上比B :: i更近吗?

如上所述,using namespace A;将A :: i拉入全局命名空间(从该块中查看时)。 B::i更接近范围&#34;而不是全局命名空间。

通常,语言参考页面上的cppreference示例适用于前面的文本块,但看起来您的主要障碍是拒绝相信出现在不相关的命名空间using namespace A;中的D注入A进入全局命名空间的声明。这真的是它的作用。这就是它的用途。

答案 1 :(得分:1)

C ++ 17标准(here草稿)[basic.lookup.unqual]读取:

  

using-directive 命名的命名空间中的声明在包含 using-directive [[]]的命名空间中可见,并且被认为是该命名空间的成员。 / p>

后来在C ++ 17标准中,[namespace.udir]读取:

  

using-directive 指定可以在 using-directive后面出现 using-directive 的范围内使用命名空间中的名称。 。在不限定名称的查找过程中,这些名称看起来像是在最近的包含命名空间的封闭名称空间中声明的一样。 注意:在本文中,“包含”是指“直接或间接包含”。 — 尾注

这些至少可以部分回答您的问题。

您的示例代码是详尽的。如果还可以使用不够全面但简短的示例代码进行说明,请尝试以下操作:

{{ form.as_two_col_layout }}

由GCC 6.3编译后的输出:#include <iostream> namespace Your { int f(const int n) {return 10*n;} } namespace My { int f(const int n) {return 100*n;} namespace Our { using namespace Your; int g() {return f(42);} // lookup from here } } int main() { std::cout << My::Our::g() << "\n"; return 0; }