简体   繁体   English

C ++嵌套`namespace``使用`Name Lookup Preference Order

[英]C++ Nested `namespace` `using` Name Lookup Order of Preference

I was reading about using -directives on cppreference.com and they had some code I couldn't figure out the order preference for name lookup. 我正在读关于using上cppreference.com -directives和他们有一些代码,我无法弄清楚的名称查找顺序优先。

I have read about the the transitive property of using -directives on paragraph 3 , unqualified_lookup#namespace scope , and scope#namespace_scope . 我已经阅读了关于在第3段using -directives的传递属性unqualified_lookup#namespace scopescope#namespace_scope I also tried searching around on some other sites. 我也试过在其他一些网站上搜索。

If there is some more documentation you think I should read, please suggest them. 如果您认为我应该阅读更多文档,请提出建议。

Their code is the following: 他们的代码如下:

Don't spend too much time reading this code because I will be talking about my adapted version below. 不要花太多时间阅读这段代码,因为我将在下面讨论我的改编版本。

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
    }
}

I have adapted their code to print things out: 我已经调整了他们的代码来打印出来:

I put numbered questions as comments on ones I don't understand. 我把编号问题作为我不理解的问题的评论。 You do not have to answer all questions if you can explain the order or name lookup and you think I could answer the rest of the questions myself. 如果您可以解释订单或名称查找,并且您认为我可以自己回答其余问题,则无需回答所有问题。

If my questions are too confusing, can you instead try to explain each of the variable name lookups in cppreference's code above? 如果我的问题太混乱了,您可以尝试在上面的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;
}

Full Output: 全输出:

I put numbered questions as comments on ones I don't understand. 我把编号问题作为我不理解的问题的评论。

I suggest you open the above code side by side so you can see what I'm referencing. 我建议你并排打开上面的代码,这样你就可以看到我所引用的内容。 I kept lines < 80 chars. 我保持<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

List of questions that appeared above: 上面出现的问题列表:

  1. Why does cppreference say A is injected into global and not D namespace? 为什么cppreference说A被注入global而不是D命名空间?
  2. Why does cppreference say A is injected into global and not C namespace? 为什么cppreference说A被注入global而不是C命名空间?
  3. What makes this ambiguous and not "one hides the other"? 是什么让这种模棱两可而不是“一个隐藏另一个”?
  4. cppreference says A::i == 1 is hidden by B::i == 3 so this is == 3 and not 0. Why doesn't A::i hide B::i? cppreference说A :: i == 1被B :: i == 3隐藏所以这是== 3而不是0.为什么A :: i不隐藏B :: i? Doesn't the using namespace A make A::i closer in scope than B::i? using namespace A是否使A :: i在范围上比B :: i更接近? Why does this go up the parent blocks C->B->B::i == 1 and not up the namespaces C->D->A->A::i == 3? 为什么这会上升到父块C-> B-> B :: i == 1而不是命名空间C-> D-> A-> A :: i == 3?
  5. This is == A::b == 0. This goes through the using namespace D which contains using namespace A . 这是== A :: b == 0.这将通过using namespace D ,其中包含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? 为什么这会在命名空间C-> D-> A-> A :: b == 0上而不是像C-> B-> B :: b == 2的父块一样问题4?
  6. This is == B::b == 2. Why is it not == B::C:b == 0 from the assignment int c = b ? 这是== B :: b == 2.为什么它不是== B :: C:b == 0来自赋值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的名称查找与命名空间体外的B :: C :: b查找不同。
  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. 与下面的问题9相比,i被分配给m但是1!= 3.我认为这类似于问题6,其中名称空间体外的名称查找与内部不同。 I'm not sure why this goes up namespaces C->D->A->A::i == 1 and not blocks C->B->B::i == 3. 我不确定为什么这会增加命名空间C-> D-> A-> A :: i == 1而不是块C-> B-> B :: i == 3。
  8. Why does it go up namespaces C->D->D::j and not blocks C->B->B::j == 4? 为什么它上升名称空间C-> D-> D :: j而不是块C-> B-> B :: j == 4?
  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? cppreference说B :: i隐藏A :: i所以这是== B :: i == 3为什么这会上升到块C-> B-> B :: i == 3而不是命名空间C-> D- > A-> A :: i == 1? Actually, I guess questions 9 and 7 is the same situation as questions 6 and 5, respectively. 实际上,我猜问题9和7分别与问题6和5的情况相同。 Where m and i corresponds with c and b, respectively. 其中m和i分别对应于c和b。
  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? cppreference说D :: j隐藏了B :: j所以这是== D :: j == 5为什么这个命名空间C-> D-> D :: j == 5而不是块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. 我在问题9和10之间看到的唯一区别是,对于问题9,我没有像J那样在D中声明。
  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? cppreference说A :: i被B :: i隐藏所以这= = B :: i == 3.为什么这会上升到块D-> C-> B-> B :: i == 3而不是命名空间D-> A-> A :: i == 1? This goes up the blocks like question 9 but not up the namespaces like question 10. 这会像问题9一样上升,但不会像问题10那样上升名称空间。
  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. 这可能上升到命名空间D-> A-> A :: b == 0而不是块D-> C-> B-> B :: b == 2因为b在命名空间体外访问类似于问题5由于对i的引用是在a中捕获的,因此命名空间体内的访问将是问题11。
  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. 我认为这与问题12~5,7和8类似(〜),其中命名空间D-> A-> A :: i == 1而不是块D-> C-> B-> B: :i == 3因为我是在命名空间体外访问的。
 // 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 

Because global is the nearest enclosing namespace that contains both A and D . 因为global是包含AD的最近的封闭命名空间。 The effects of using namespace are explained on that same page, just above the example 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 

Because global is the nearest enclosing namespace that contains both A and C 因为global是包含AC的最近的封闭命名空间

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

Because D::k was pulled into C by using namespace D; 因为D::k通过using namespace D;被拉入C using namespace D; , and the effects of that are also explained just above the example. ,以及其效果也在示例上方进行了解释。

Why doesn't A::i hide B::i? 为什么A :: i不隐藏B :: i? Doesn't the using namespace A make A::i closer in scope than B::i? 使用命名空间A是否使A :: i在范围上比B :: i更接近?

As noted above, using namespace A; 如上所述, using namespace A; pulled A::i into global namespace (when viewed from within that block). 将A :: i拉入全局命名空间(从该块中查看)。 B::i is "closer in scope" than the global namespace. B::i比全局命名空间“更接近范围”。

In general, cppreference examples on language reference pages apply to the direcly preceding blocks of text, but it appears your main stumbling block is refusing to believe that using namespace A; 一般来说,语言参考页面上的cppreference示例适用于前面的文本块,但看起来你的主要障碍是拒绝相信using namespace A; that appears within the unrelated namespace D injects A's declarations into the global namespace. 出现在不相关的命名空间内的D将A的声明注入全局命名空间。 That's really what it does. 这就是它的功能。 That's what it's for. 这就是它的用途。

The C++17 standard (draft here ), [basic.lookup.unqual], reads: C ++ 17标准( 这里草案),[basic.lookup.unqual],读作:

The declarations from the namespace nominated by a using-directive become visible in a namespace enclosing the using-directive [and] are considered members of that enclosing namespace. 来自using-directive提名的命名空间的声明在包含using-directive [和]的命名空间中变得可见,被认为是该封闭命名空间的成员。

Later in the C++17 standard, [namespace.udir] reads: 后来在C ++ 17标准中,[namespace.udir]读取:

A using-directive specifies that the names in the nominated namespace can be used in the scope in which the using-directive appears after the using-directive . using-directive指定指定命名空间中的名称可以在using-directive出现在using-directive之后的范围内使用 During unqualified name lookup, the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace. 在非限定名称查找期间,名称看起来好像是在最近的封闭命名空间中声明的,该命名空间同时包含using-directive和指定的命名空间。 Note: In this context, "contains" means "contains directly or indirectly". 注意:在此上下文中,“包含”表示“直接或间接包含”。 end note - 结束说明

These might at least partly answer your question. 这些可能至少部分回答了你的问题。

Your sample code is thorough. 您的示例代码是彻底的。 If a less thorough but briefer sample code would also serve to illustrate, then try this: 如果一个不那么透彻但更简洁的示例代码也可以用来说明,那么试试这个:

#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;
}

Output after compilation by GCC 6.3: 4200 . GCC 6.3: 4200编译后的输出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM