使用命名空间 std 的排序;并包括?

Ordering of using namespace std; and includes?

提问人:templatetypedef 提问时间:7/27/2011 最后编辑:GEOCHETtemplatetypedef 更新时间:9/25/2021 访问量:8341

问:

我最近看到在C++项目的源文件中使用了以下代码:

using namespace std;
#include <iostream>

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

我本来以为这不会编译,因为在指令将其包含在文件中之前尚未在范围内声明,但是使用项目的构建系统可以编译得很好。如果有人有指向规范相关部分的链接,我们将不胜感激。namespace std#include <iostream>

C++ 语言律师 使用指令

评论

1赞 Björn Pollex 7/27/2011
此代码是用源文件还是头文件编写的?也许它被另一个声明命名空间的文件所包含。std
0赞 templatetypedef 7/27/2011
这是在源文件中,而不是头文件中。这是一个很好的澄清点!
0赞 Prasoon Saurav 3/7/2012
clang++ 给出一个警告:using 指令引用隐式定义的命名空间 'std';

答:

2赞 spraff 7/27/2011 #1

符合 SO/IEC 14882:2003

[7.3.3.9] 使用声明所声明的实体应根据其在使用声明时的定义在上下文中已知。使用名称时,不考虑在 using 声明之后添加到命名空间的定义。

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

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

评论

0赞 Björn Pollex 7/27/2011
突出显示的部分说该声明应该没有效果,但没有解释它是否合法。
1赞 templatetypedef 7/27/2011
查看规范的这一部分,这似乎指的是 或 形式的声明,而不是类似 的东西。usingusing std::coutusing std::stringusing namespace std
1赞 Yakov Galka 7/27/2011 #2

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

翻译单位应仅在任何外部声明或定义之外包括标题,并应在首次提及其在该翻译单元中声明或首先定义的任何实体之前按词法包括标题。

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

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

评论

0赞 MSalters 8/1/2011
对不起,不明白这是如何适用的。具体违反了哪一部分? 不是随附的外部声明或定义。它也不是对标头中声明或定义的实体的引用。using namespace std;
1赞 Yakov Galka 8/1/2011
@MSalters:它是对标头中声明的实体(命名空间 std)的引用。来自 [basic]:“实体是值、对象、引用、函数、枚举器、类型、类成员、模板、模板专用化、命名空间、参数包或此。
0赞 Yakov Galka 8/1/2011
@MSalters:这很好,因为我不太清楚。虽然我的引用似乎禁止 OP 大小写,但这也意味着您不能安全地将标准库标头包含在最外层的 *.cpp 中。请注意,C++11 FCD 删除了“该翻译单元中的第一个定义”部分,这更加可疑。
0赞 spraff 8/2/2011
“未定义的行为”是一个术语,用于编译和运行但具有未指定结果的代码(尽管这与不可预测不同)。如果你做错了事情,那么你就生活在罪恶中,但代码可能恰好没问题。#include
0赞 Yakov Galka 8/2/2011
@spraff:对不起,你错了。作为反例,C++03 说:“如果非空的源文件不以换行符结尾,或者以紧跟反斜杠字符的换行符结尾,则行为未定义。这种特殊情况在C++0x中被删除,但还有许多其他例子。
4赞 James Kanze 7/27/2011 #3

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

using namespace std;

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

7赞 Keith Thompson 8/7/2011 #4

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

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

需要明确的是,这两行是我编译的整个源文件。

在这一点上,既没有也没有被定义为命名空间,但 g++ 只抱怨第二个。我不认为在没有声明的情况下标识符有什么特别之处。我认为 @James Kanze 是对的,这是 g++ 中的一个错误。stdno_such_namespacestd

编辑:据报道 (5年前!

更新:现在已经 8 年多了,仍然没有分配给任何人,更不用说修复了。G++ 4.9.2 展示了这个问题。Clang++ 3.5 没有,但它会发出警告和致命错误:stdno_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++ 应该对此发出警告。

评论

0赞 Keith Thompson 9/16/2019
另一个更新:g++ 9.2.0 仍然有错误(尚未分配),尽管它不再报告语法错误。
0赞 alfC 9/25/2021
有趣的数据点。也许C++正在默默地包含某些内容,例如包括反过来包含哪些内容?#include<new>std
0赞 templatetypedef 9/25/2021
感谢您更新这个十年前的答案,让我们继续更新这个传奇!
1赞 Ben Voigt 8/7/2011 #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 条)之后和其初始值设定者(如果有)之前。

而且,这些例外都不适用于命名空间。

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

0赞 rajeshk 4/10/2013 #6

最近我遇到了同样的问题,我的技术主管建议我这样做;在使用 .h 文件的文件中包含具有相关方法的命名空间之前,使用命名空间并不能保证方法的可见性。 包括头文件解决了该问题。