C++嵌套的"命名空间""使用"名称查找首选项顺序



我正在阅读有关 cppreference.comusing指令的信息,它们有一些代码,我无法弄清楚名称查找的顺序首选项。

我已经阅读了有关第 3 段、unqualified_lookup#命名空间作用域和作用域 #namespace_scope 的using-指令的传递属性。我还尝试在其他一些网站上搜索。

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

他们的代码如下:

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

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

上面出现的问题列表:

  1. 为什么 cppreference 说 A 被注入到global而不是D命名空间中?
  2. 为什么 cpp首选项说 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 Ausing namespace D。 为什么这会像问题 4 中那样将命名空间 C->D->A->A::b == 0 上升到 C->B->B::b == 2?
  6. 这是 == B::b == 2。为什么不是 == B::C:b == 0 从赋值int c = b?我猜是因为命名空间正文内 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. cpp首选项说 B::i 隐藏了 A::i 所以这是 == B::i == 3 为什么这会上升块 C->B->B::i ==
  10. 3 而不是命名空间 C->D->A->A::i == 1? 实际上,我想问题 9 和 7 分别与问题 6 和 5 的情况相同。其中 m 和 i 分别对应于 c 和 b。
  11. cpp首选项说 D::j 隐藏了 B::j,所以这是 == D::j == 5 为什么这会上升命名空间 C->D->D::j ==
  12. 5 而不是块 C->B->B::j == 4?我在问题 9 和 10 之间看到的唯一区别是,对于问题 9,i 不像 j 那样在 D 中声明。
  13. cpp首选项说 A::i 被 B::i 隐藏,所以这个 == B::i == 3。为什么这会上升块 D->C->B->B::i == 3 而不是命名空间 D->A->A::i == 1? 这会像问题 9 那样上升块,但不会像问题 10 那样上升命名空间。
  14. 这可能会上升命名空间 D->A->A::b == 0 而不是块 D->C->B->B::b == 2,因为 b 在命名空间主体外部访问类似于问题 5、7 和 8。 命名空间主体内的访问将是问题 11,因为对 i 的引用是在 a 中捕获的。
  15. 我认为这与问题 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

因为全局是包含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

因为全局是最近的封闭命名空间,它同时包含AC

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

因为D::kusing namespace D;拉入C,其影响也在示例上方进行了解释。

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

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

通常,语言参考页面上的 cpp首选项示例适用于前面的严重文本块,但似乎您的主要绊脚石是拒绝相信出现在不相关命名空间中的using namespace A;D将 A 的声明注入全局命名空间。这就是它真正的作用。这就是它的用途。

C++17标准(此处为草案)[basic.lookup.unqual]如下:

由 using-指令指定的命名空间中的声明在包含using-指令的命名空间中可见 [并且] 被视为该封闭命名空间的成员。

在 C++17 标准的后面,[namespace.udir] 写道:

using-指令

指定指定命名空间中的名称可以在 using-指令出现在using-指令之后的作用域中使用。在非限定名称查找期间,这些名称看起来就像是在最近的封闭命名空间中声明的,该命名空间同时包含 using-指令和指定的命名空间。注意:在这种情况下,"包含"是指"直接或间接包含"。—尾注

这些可能至少部分回答你的问题。

您的示例代码非常彻底。如果一个不太全面但更简短的示例代码也可以说明,那么请尝试以下操作:

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

GCC 6.3编译后的输出:4200

最新更新