所有学生都对 C++ using-directives的行为感到惊讶。考虑这个片段(Godbolt):
namespace NA {
int foo(Zoo::Lion);
}
namespace NB {
int foo(Zoo::Lion);
namespace NC {
namespace N1 {
int foo(Zoo::Cat);
}
namespace N2 {
int test() {
using namespace N1;
using namespace NA;
return foo(Zoo::Lion());
}
}
}
}
你可能会认为test
会调用NA
's foo(Zoo::Lion)
; 但实际上它最终调用了N1
's foo(Zoo::Cat)
。
原因是它using namespace NA
实际上并没有将名称从当前范围中NA
引入;它将它们带入 and 的最不常见的祖先范围,即. 并且不会将名称带入当前范围;它将它们带入 and 的最不常见的祖先范围,即. 在这里,我画了一个漂亮的图表:NA
N2
::
using namespace N1
N1
N1
N2
NC
然后正常的非限定查找“查找”树,顺序为test
–<code>N2–<code>NC–<code>NB–<code>::,一旦foo
在NC
. 树上较高的 foo , inNB
和::
,没有通过查找找到,因为它们已被foo
in隐藏NC
。
我认为我对这种机制的理解足以解释它是如何工作的。我不明白为什么。在设计 C++ 命名空间时,他们为什么选择这种完全怪异的机制,而不是像“使用声明一样将名称带入当前范围”或“将名称带入全局范围”之类的更直接的东西还是“名称留在原处,在每个'使用'的命名空间中进行单独的查找,然后合并在一起”?
为 C++ 选择这种特殊机制时有哪些考虑?
我正在寻找有关 C++ 设计的参考资料——书籍、博客文章、WG21 论文、D&E、ARM、反射器讨论,以及任何类似性质的东西。我并不是在寻找“基于意见”的答案;我正在寻找设计该功能时指定的真正理由。
(我读过The Design and Evolution of C++ (1994),第 17.4 节“命名空间”,但它甚至没有提到这种古怪的机制。D&E说:“使用指令不会将名称引入本地范围;它只是使命名空间中的名称可以访问。”这是真的,但缺乏理由。我希望 StackOverflow 可以做得更好。)