我最近看到这个代码在C ++项目的源文件中使用:
using namespace std;
#include <iostream>
忽略所有关于是否有using namespace std
一个好主意的问题,上述代码是否合法?在这两行之前,文件中没有代码。
我原以为这不会编译,因为在namespace std
指令将其包含到文件中之前,#include <iostream>
尚未在范围中声明,但是使用项目的构建系统编译得很好。如果某人有指向规范相关部分的链接,那将非常感激。
答案 0 :(得分:5)
一个可能有趣的数据点。当我编译以下内容时:
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
此时std
和no_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.
答案 1 :(得分:3)
我不认为这是合法的,但标准并非100%明确。 基本上,名称查找(如§3.4中所定义)找不到先前的名称 声明命名空间,因为没有一个。一切 取决于是否:
using namespace std;
是否是命名空间的声明。而且我没有看到任何文字 §7.3.4表示使用指令声明了指定的 命名空间。 G ++允许你的代码,但恕我直言,这是一个错误。
答案 2 :(得分:2)
来自SO / IEC 14882:2003
[7.3.3.9]使用声明声明的实体应在使用声明时根据其定义使用它。 在使用名称时不考虑使用声明后添加到命名空间的定义。
[3.4.3.2.2]给定X :: m(其中X是用户声明的命名空间)或给定:: m(其中X是全局命名空间),让S为m的所有声明的集合在X中以及在X及其使用的名称空间中由using指令指定的所有名称空间的传递闭包中,除了在任何名称空间(包括X)中忽略using-directive,直接包含一个或多个m的声明。在查找名称时不会多次搜索名称空间。如果S是空集,则程序格式错误。否则,如果S只有一个成员,或者引用的上下文是using-declaration(7.3.3),则S是m的必需声明集。否则,如果m的使用不允许从S中选择一个唯一的声明,则该程序是不正确的
因此,如果它恰好起作用,那就是侥幸而且不便携。
答案 3 :(得分:1)
此代码是未定义的行为[lib.using.headers]:
翻译单位应仅在任何外部声明或定义之外包含标题,并且在首次引用其在该翻译单元中声明或首先定义的任何实体之前,应在词汇上包括标题。
您引用std
,然后包含声明它的标头。即使这仍然是未定义的行为:
#include <string>
using namespace std;
#include <iostream>
答案 4 :(得分:1)
我认为在这种情况下标准(包括C ++ 0x)存在缺陷。
我们在第3.3.6节([basic.scope.namespace]
):
命名空间定义的声明性区域是其namespace-body。原始名称空间名称表示的潜在范围是由同一声明性区域中的每个名称空间定义与原始名称空间名称建立的声明性区域的串联。在namespace-body中声明的实体被称为命名空间的成员,并且这些声明引入命名空间的声明性区域的名称被称为命名空间的成员名称。名称空间成员名称具有名称空间范围它的潜在范围包括从名称的声明(3.3.2)开始的命名空间;对于指定成员名称空间的每个using-directive(7.3.4),成员的潜在范围包括在成员声明点之后的using-directive的潜在范围部分。
和
翻译单元的最外层声明区域也是名称空间,称为全局名称空间。在全局命名空间中声明的名称具有全局命名空间范围(也称为全局范围)。这种名称的潜在范围从其声明点(3.3.2)开始,并在作为其声明区域的翻译单元结束时结束。具有全局命名空间范围的名称被称为全局名称。
所以namespace std
是全局命名空间的成员,名称的范围从声明开始。
3.3.2([basic.scope.pdecl]
)告诉我们:
名称的声明点紧接在其完整的声明者(第8条)之后和初始化者之前(如果有的话),除非如下所述。
并且没有例外适用于名称空间。
因此,在声明符之前不能使用命名空间名称,但命名空间名称不是声明符。糟糕。
答案 5 :(得分:0)
最近,我遇到了同样的问题,并得到了我的技术负责人的建议;使用命名空间不保证方法的可见性,直到使用.h文件将具有相关方法的命名空间包含在文件中。 包括头文件解决了问题。