【问题标题】:Ordering of using namespace std; and includes?using namespace std 的排序;包括?
【发布时间】:2011-10-14 01:02:51
【问题描述】:

我最近在一个 C++ 项目的源文件中看到了这段代码:

using namespace std;
#include <iostream>

完全忽略using namespace std 是否是个好主意的所有问题,上面的代码是否合法?这两行之前的文件中没有代码。

我原以为这不会编译,因为直到 #include &lt;iostream&gt; 指令将它包含到文件中之前,namespace std 尚未在范围内声明,但使用项目的构建系统编译就好了.如果有人有指向规范相关部分的链接,那将不胜感激。

【问题讨论】:

  • 这段代码是写在源文件还是头文件中?也许它被另一个声明命名空间std的文件包含。
  • 这是在源文件中,而不是在头文件中。这是一个很好的澄清点!
  • clang++ 给出警告:using 指令引用隐式定义的命名空间'std';

标签: c++ language-lawyer using-directives


【解决方案1】:

一个可能很有趣的数据点。当我编译以下内容时:

using namespace std;
using namespace no_such_namespace;

使用 g++ 4.5.2,我得到:

c.cpp:2:17: error: ‘no_such_namespace’ is not a namespace-name
c.cpp:2:34: error: expected namespace-name before ‘;’ token

要清楚,这两行是我编译的整个源文件。

此时stdno_such_namespace 都没有被定义为命名空间,但 g++ 只抱怨第二个。我不认为标识符std 在没有声明的情况下有什么特别之处。我认为@James Kanze 是正确的,这是 g++ 中的一个错误。

编辑:And it's been reported.(5 年前!)

更新:现在已经 8 年多了,仍然没有分配给任何人,更不用说修复了。 g++ 4.9.2 出现了这个问题。 clang++ 3.5 没有,但它对std 发出警告,对no_such_namespace 发出致命错误:

c.cpp:1:17: warning: using directive refers to implicitly-defined namespace 'std'
using namespace std;
                ^
c.cpp:2:17: error: expected namespace name
using namespace no_such_namespace;
                ^
1 warning and 1 error generated.

更新:截至 2021 年 9 月 24 日,错误报告仍处于打开状态,并且该错误存在于 g++ 11.2.0 中。 2021-07-24 发布的评论表明 g++ 应该对此发出警告。

【讨论】:

  • 另一个更新:g++ 9.2.0 仍然存在这个错误(尚未分配),但它不再报告语法错误。
  • 有趣的数据点。也许 C++ 正在默默地包含一些东西,例如包含 #include&lt;new&gt; 又包含 std
  • 感谢您更新这个有十年历史的答案,让我们继续了解传奇!
【解决方案2】:

我认为这不合法,但标准并不是 100% 明确。 基本上,名称查找(如 §3.4 中所定义)找不到以前的 命名空间的声明,因为没有。一切 取决于是否:

using namespace std;

是否是命名空间的声明。而且我没有看到任何文字 §7.3.4 说使用指令声明了指定的 命名空间。 G++ 允许您的代码,但恕我直言,这是一个错误。

【讨论】:

    【解决方案3】:

    来自 SO/IEC 14882:2003

    [7.3.3.9] 由 using-declaration 声明的实体应根据 using-declaration 处的定义在使用它的上下文中为人所知。 在使用名称时不考虑在 using 声明之后添加到命名空间的定义。

    [3.4.3.2.2] 给定 X::m(其中 X 是用户声明的命名空间)或给定 ::m(其中 X 是全局命名空间),令 S 是 m 的所有声明的集合在 X 中以及在 X 中由 using 指令指定的所有命名空间的传递闭包及其使用的命名空间中,除了在任何命名空间中忽略 using 指令,包括 X,直接包含一个或多个 m 声明。在名称查找中不会多次搜索命名空间。如果 S 是空集,则程序非良构。否则,如果 S 恰好有一个成员,或者如果 引用的上下文是 using-declaration (7.3.3),则 S 是 m 的必需声明集。否则,如果 m 的使用不允许从 S 中选择唯一声明,则程序是非良构的

    因此,如果它碰巧起作用,那只是侥幸而不是便携。

    【讨论】:

    • 高亮部分表示该声明应该没有效果,但并没有说明是否合法。
    • 查看这部分规范,这似乎是指using 形式为using std::coutusing std::string 的声明,而不是using namespace std 之类的声明。
    【解决方案4】:

    这段代码是未定义的行为[lib.using.headers]:

    翻译单元应仅在任何外部声明或定义之外包含标头,并且应在第一次引用它在该翻译单元中声明或首先定义的任何实体之前在词法上包含标头。

    您引用std,然后包含一个声明它的标头。即使这仍然是未定义的行为:

    #include <string>
    using namespace std;
    #include <iostream>
    

    【讨论】:

    • 抱歉,不知道这是如何应用的。具体违反了哪一部分? using namespace std; 不是封闭的外部声明或定义。它也不是对标头中声明或定义的实体的引用。
    • @MSalters:它是对标头中声明的实体(命名空间标准)的引用。来自 [basic]:“实体是值、对象、引用、函数、枚举器、类型、类成员、模板、模板特化、命名空间、参数包或 this。”
    • @MSalters:这很好,因为我不太清楚。尽管我的引用似乎禁止 OPs 的情况,但这也意味着除了最外层的 *.cpp 之外,您不能安全地在任何地方包含标准库头文件。请注意,C++11 FCD 删除了“翻译单元中的第一个定义”部分,这更加可疑。
    • “未定义的行为”是一个术语,表示将编译和运行但具有未指定结果的代码(尽管这与不可预测不同)。如果你没有正确地#include 事情,那么你就生活在罪恶中,但代码可能发生是好的。
    • @spraff:对不起,你错了。作为一个反例,C++03 说:“如果一个非空的源文件不以换行符结尾,或者以紧跟反斜杠字符的换行符结尾,则行为未定义。”这种特殊情况在 C++0x 中已被删除,但还有许多其他示例。
    【解决方案5】:

    我认为这个案例的标准(包括 C++0x)存在缺陷。

    我们在第 3.3.6 节中有 ([basic.scope.namespace]):

    命名空间定义的声明区域是它的命名空间主体。由 original-namespace-name 表示的潜在范围是由同一声明区域中的每个命名空间定义与该 original-namespace-name 建立的声明区域的串联。在命名空间主体中声明的实体被称为命名空间的成员,由这些声明引入命名空间的声明区域的名称被称为命名空间的成员名称。命名空间成员名称具有命名空间范围。它的潜在范围包括从名称的声明点(3.3.2)开始的名称空间;对于每个指定成员命名空间的 using 指令 ​​(7.3.4),成员的潜在范围包括在成员声明点之后的 using 指令的潜在范围部分。

    翻译单元的最外层声明区域也是一个命名空间,称为全局命名空间。在全局命名空间中声明的名称具有全局命名空间范围(也称为全局范围)。这种名称的潜在范围从其声明点 (3.3.2) 开始,并在作为其声明区域的翻译单元的末尾结束。具有全局命名空间范围的名称称为全局名称。

    所以namespace std 是全局命名空间的成员,名称的范围从声明点开始。

    3.3.2 ([basic.scope.pdecl]) 告诉我们:

    名称的声明点紧跟在其完整的声明符(第 8 条)之后和其初始化程序(如果有)之前,除非如下所述。

    并且没有任何例外适用于命名空间。

    所以命名空间名称不能在其声明符之前使用,但命名空间名称不是声明符。哎呀。

    【讨论】:

      【解决方案6】:

      最近我遇到了同样的问题,我的技术主管告诉我; using namespace 不保证方法的可见性,直到具有相关方法的命名空间包含在文件 using .h 文件中。 包括头文件解决了这个问题。

      【讨论】:

        猜你喜欢
        • 2011-09-26
        • 1970-01-01
        • 2011-09-22
        • 2017-04-20
        • 2016-02-27
        • 1970-01-01
        • 1970-01-01
        • 2013-09-15
        • 1970-01-01
        相关资源
        最近更新 更多