C ++嵌套的`namespace``using`名称查找优先顺序
C++ Nested `namespace` `using` Name Lookup Order of Preference
我正在阅读有关 using
-directives on cppreference.com 的文章,他们有一些代码我无法确定名称查找的顺序偏好。
我已经阅读了 the transitive property of using
-directives on paragraph 3, unqualified_lookup#namespace scope, and scope#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 被注入到
global
而不是 D
命名空间?
- 为什么 cppreference 说 A 被注入到
global
而不是 C
命名空间?
- 是什么让这个变得模棱两可而不是"one hides the other"?
- 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 A
的 using namespace D
。为什么这会上升到命名空间 C->D->A->A::b == 0 而不是 C->B->B::b == 2 的父块,就像问题 4 中那样?
- 这是 == B::b == 2。为什么它不是来自赋值
int c = b
的 == B::C:b == 0?我猜是因为在命名空间主体内查找 b 的名称与在命名空间主体外查找 B::C::b 不同。
- 与下面的问题 9 相比,i 被分配给 m 但 1 != 3。我认为这类似于问题 6,其中名称空间外部的名称查找与内部不同。我不确定为什么这会上升到命名空间 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,i 不像 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 是最近的包含 A
和 D
的封闭命名空间。 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 是最近的包含 A
和 C
的封闭命名空间
// 3) What makes this ambiguous and not "one hides the other"?
// int l = k; // ambiguous: C::k or D::k
因为 D::k
被 using namespace D;
拉进了 C
,其效果也在例子上面解释了。
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
比全局命名空间 "closer in scope"。
一般来说,语言参考页面上的 cppreference 示例适用于直接前面的文本块,但您的主要绊脚石似乎拒绝相信 using namespace A;
出现在不相关的命名空间 D
将 A 的声明注入全局命名空间。这就是它的作用。这就是它的用途。
C++17 标准(草案here),[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.
后来在 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. 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. Note: In this context, "contains" means "contains directly or indirectly". — end note
这些至少可以部分回答您的问题。
您的示例代码很详尽。如果一个不太彻底但更简短的示例代码也可以用来说明,那么试试这个:
#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
.
我正在阅读有关 using
-directives on cppreference.com 的文章,他们有一些代码我无法确定名称查找的顺序偏好。
我已经阅读了 the transitive property of using
-directives on paragraph 3, unqualified_lookup#namespace scope, and scope#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 被注入到
global
而不是D
命名空间? - 为什么 cppreference 说 A 被注入到
global
而不是C
命名空间? - 是什么让这个变得模棱两可而不是"one hides the other"?
- 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 A
的using namespace D
。为什么这会上升到命名空间 C->D->A->A::b == 0 而不是 C->B->B::b == 2 的父块,就像问题 4 中那样? - 这是 == B::b == 2。为什么它不是来自赋值
int c = b
的 == B::C:b == 0?我猜是因为在命名空间主体内查找 b 的名称与在命名空间主体外查找 B::C::b 不同。 - 与下面的问题 9 相比,i 被分配给 m 但 1 != 3。我认为这类似于问题 6,其中名称空间外部的名称查找与内部不同。我不确定为什么这会上升到命名空间 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,i 不像 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 是最近的包含 A
和 D
的封闭命名空间。 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 是最近的包含 A
和 C
// 3) What makes this ambiguous and not "one hides the other"? // int l = k; // ambiguous: C::k or D::k
因为 D::k
被 using namespace D;
拉进了 C
,其效果也在例子上面解释了。
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
比全局命名空间 "closer in scope"。
一般来说,语言参考页面上的 cppreference 示例适用于直接前面的文本块,但您的主要绊脚石似乎拒绝相信 using namespace A;
出现在不相关的命名空间 D
将 A 的声明注入全局命名空间。这就是它的作用。这就是它的用途。
C++17 标准(草案here),[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.
后来在 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. 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. Note: In this context, "contains" means "contains directly or indirectly". — end note
这些至少可以部分回答您的问题。
您的示例代码很详尽。如果一个不太彻底但更简短的示例代码也可以用来说明,那么试试这个:
#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
.