提问人:templatetypedef 提问时间:7/27/2011 最后编辑:GEOCHETtemplatetypedef 更新时间:9/25/2021 访问量:8341
使用命名空间 std 的排序;并包括?
Ordering of using namespace std; and includes?
问:
我最近看到在C++项目的源文件中使用了以下代码:
using namespace std;
#include <iostream>
忽略它是否是一个好主意的所有问题,上述代码是否合法?在这两行之前,文件中没有代码。using namespace std
我本来以为这不会编译,因为在指令将其包含在文件中之前尚未在范围内声明,但是使用项目的构建系统可以编译得很好。如果有人有指向规范相关部分的链接,我们将不胜感激。namespace std
#include <iostream>
答:
符合 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 中选择唯一声明,则程序的格式不正确
因此,如果它碰巧起作用,那就是侥幸,不便携。
评论
using
using std::cout
using std::string
using namespace std
此代码是未定义的行为 [lib.using.headers]:
翻译单位应仅在任何外部声明或定义之外包括标题,并应在首次提及其在该翻译单元中声明或首先定义的任何实体之前按词法包括标题。
引用并包含声明它的标头。即使这仍然是未定义的行为:std
#include <string>
using namespace std;
#include <iostream>
评论
using namespace std;
#include
我不认为这是合法的,但标准并不是 100% 清楚的。 基本上,名称查找(如§3.4中所定义)找不到以前的 命名空间的声明,因为没有命名空间。万事 取决于是否:
using namespace std;
是否是命名空间的声明。而且我没有看到任何文字 §7.3.4 其中说 using 指令声明了被提名的 命名空间。G++ 允许你的代码,但恕我直言,这是一个错误。
一个可能有趣的数据点。当我编译以下内容时:
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++ 中的一个错误。std
no_such_namespace
std
编辑:据报道。 (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++ 应该对此发出警告。
评论
#include<new>
std
我认为在这种情况下,标准(包括 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 条)之后和其初始值设定者(如果有)之前。
而且,这些例外都不适用于命名空间。
因此,命名空间名称不能在其声明符之前使用,但命名空间名称不是声明符。哎呀。
最近我遇到了同样的问题,我的技术主管建议我这样做;在使用 .h 文件的文件中包含具有相关方法的命名空间之前,使用命名空间并不能保证方法的可见性。 包括头文件解决了该问题。
评论
std