微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么 C++ 的“使用命名空间”的工作方式如此?

如何解决为什么 C++ 的“使用命名空间”的工作方式如此?

所有学生都对 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的{​​{1}};但实际上它最终调用foo(Zoo::Lion)N1

原因是 foo(Zoo::Cat) 实际上并未将 using namespace NA 中的名称带入 current 范围;它将它们带入NANA最不共同祖先范围,即N2。并且 :: 不会将 using namespace N1 中的名称带入 current 范围;它将它们带入 N1N1 的最不共同的祖先作用域,即 N2在这里,我画了一个漂亮的图表:

Diagram

然后正常的非限定查找“查找”树,顺序为NCtestN2NCNB,尽快停止因为它在 :: 中找到名称 foo。位于 NCNB 中的树更高的 foos 无法通过查找找到,因为它们已被 :: 中的 foo 隐藏。

我想我很了解这个机制,可以解释它是如何工作的。我不明白的是为什么。在设计 C++ 命名空间时,为什么他们选择这种完全奇怪的机制,而不是更直接的方式,例如“名称被带入当前范围,就像使用 using-declaration”或“名称被带入全局范围”或“名称留在原处,在每个‘使用’的命名空间中进行单独的查找,然后合并在一起”?

在为 C++ 选择这种特殊机制时有哪些考虑?

我正在专门寻找有关 C++ 设计的参考资料——书籍、博客文章、WG21 论文、D&EARM、反射器讨论,以及任何那种性质。我特别不是寻找“基于意见”的答案;我正在寻找设计该功能时指定的真正理由。

(我已经阅读了C++ 的设计和演化(1994 年),第 17.4 节“命名空间”,但它甚至没有提到这种古怪的机制。D&E说:“using-directive 不会将名称引入本地范围;它只是使名称空间中的名称可访问。”这是真实,但缺乏基本原理。我希望 StackOverflow 可以做得更好。)

解决方法

引用 C++ Primer (5th Edition) 节“18.2.2. 使用命名空间成员”的摘录

using 指令引入的名称范围更复杂 比使用声明中的名称范围。正如我们所见,一个使用 声明将名称放在与使用相同的范围内 声明本身。就好像 using 声明为 命名空间成员。

using 指令不声明本地别名。反而有效果 将命名空间成员提升到最近的包含 命名空间本身和 using 指令。

using 声明和 using 之间的作用域差异 指令直接源于这两个设施的工作方式。如果是 一个 using 声明,我们只是让 name 可以直接在 本地范围。相比之下, using 指令使 a 的全部内容 命名空间可用 一般来说,命名空间可能包括定义 不能出现在本地范围内。因此, using 指令 被视为出现在最近的封闭命名空间范围内。

因此,与 using-declarations 相比,using-directives 在作用域处理上的这种差异不会阻止声明相同的名称。发生此类名称冲突时,将允许使用,但任何不明确的用法都必须明确指定预期版本。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。