Quu*_*one 26 c++ using-directives rationale name-lookup c++98
所有学生都对 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());
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
你可能认为test会叫NA的foo(Zoo::Lion); 但实际上它最终会调用N1's foo(Zoo::Cat)。
原因是这using namespace NA实际上并没有将名称NA带入当前范围;它带来他们到最小共同祖先的范围NA和N2,这是::。并且using namespace N1不会将名称N1带入当前范围;它带来了他们进入的最低共同祖先的范围N1和N2,这是NC。在这里,我画了一个漂亮的图表:

然后正常的非限定查找“查找”树,顺序为test– N2– NC– NB– ::,一旦foo在NC. 树上的 foos in NBand::没有通过查找找到,因为它们已经被fooin隐藏了NC。
我想我对这种机制的理解足以解释它是如何工作的。我不明白的是为什么。在设计 C++ 命名空间时,为什么他们选择这种完全奇怪的机制,而不是更直接的方式,例如“名称被引入当前范围,就像使用声明一样”或“名称被引入全局范围”或“名称留在原处,在每个‘使用’的命名空间中进行单独的查找,然后合并在一起”?
为 C++ 选择这种特殊机制的考虑因素是什么?
我正在专门寻找 C++ 设计的参考资料——书籍、博客文章、WG21 论文、D&E、ARM、反射器讨论,以及任何此类性质的东西。我特别不是在寻找“基于意见”的答案;我正在寻找设计该功能时指定的真正理由。
(我读过The Design and Evolution of C++ (1994),第 17.4 节“命名空间”,但它甚至没有提到这种古怪的机制。D&E说:“ using 指令不会将名称引入本地范围;它只是使名称空间中的名称可访问。”这是真的,但缺乏基本原理。我希望 StackOverflow 可以做得更好。)
小智 2
引用《C++ Primer(第五版)》的摘录部分“18.2.2. 使用命名空间成员”的
\n\n\nusing 指令引入的名称范围比 using 声明中的名称范围更复杂\n。正如我们\xe2\x80\x99 所见,using 声明将名称置于与 using 声明本身相同的作用域中。这就好像 using 声明为命名空间成员声明了一个本地别名。
\nusing 指令不声明本地别名。相反,它的作用是将命名空间成员提升到最近的范围,其中包含命名空间本身和 using 指令。
\nusing 声明和 using 指令之间的范围差异直接源于这两个工具的工作方式。在使用 using 声明的情况下,我们只是让 name 在本地范围内可直接访问。相比之下,using 指令使命名空间的全部内容可用。通常,命名空间可能包含不能出现在本地作用域中的定义。因此,using 指令被视为出现在最近的封闭命名空间范围中。
\n
因此,与using 声明相比, using 指令的作用域处理差异不会阻止声明相同的名称。当发生此类名称冲突时,将允许使用,但任何不明确的用法都必须明确指定预期版本。
\n