【发布时间】:2021-03-29 14:49:41
【问题描述】:
所有学生都对 C++using-directives 的行为感到惊讶。考虑一下这个 sn-p (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 的foo(Zoo::Lion);但实际上它最终会调用N1 的foo(Zoo::Cat)。
原因是using namespace NA 实际上并没有将NA 中的名称带入当前 范围;它将它们带入NA 和N2 的最小共同祖先 范围内,即::。并且using namespace N1 不会将N1 中的名称带入 current 范围;它将它们带入N1 和N2 的最小共同祖先范围,即NC。在这里,我画了一个漂亮的图表:
然后正常的非限定查找“查找”树,顺序为test–N2–NC–NB–::,一旦在@中找到名称foo就停止987654346@。查找树上较高的 NB 和 :: 中的 foo,因为它们已被 NC 中的 foo 隐藏。
我认为我对这种机制的理解足以解释它是如何工作的。我不明白的是为什么。在设计 C++ 命名空间时,为什么他们选择这种完全奇怪的机制,而不是像“名称被引入当前范围,就像使用 using-declaration”或“名称被带入全局范围”或“名称保留在原处,在每个“使用”命名空间中进行单独查找,然后合并在一起”?
在为 C++ 选择这种特定机制时有哪些考虑?
我正在寻找有关 C++ 设计的参考资料——书籍、博客文章、WG21 论文、D&E、ARM、反射器讨论、任何那种性质。我特别不在寻找“基于意见”的答案;我正在寻找设计该功能时指定的真正理由。
(我已阅读 The Design and Evolution of C++ (1994),第 17.4 节“命名空间”,但它甚至没有提到这种古怪的机制。D&E说:“using-directive 不会将名称引入本地范围;它只是使命名空间中的名称可访问。”这是 true,但缺乏理由。我希望 StackOverflow 可以做得更好。)
【问题讨论】:
-
如果 Stroustrup 不解释他的推理,那推理只能推断。我不确定你是否能得到一个完美的答案,但我非常愿意让这个问题保持开放状态,看看人们会想出什么。
标签: c++ c++98 name-lookup using-directives rationale