using 命名空间 std 的顺序;并包括?

发布于 2024-11-26 10:34:59 字数 351 浏览 3 评论 0原文

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

using namespace std;
#include <iostream>

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

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

I recently saw this code being used in a source file in a C++ project:

using namespace std;
#include <iostream>

Ignoring all issues of whether it's a good idea to have using namespace std at all, is the above code even legal? There is no code in the file before these two lines.

I would have thought that this wouldn't compile, since namespace std hasn't been declared in scope until the #include <iostream> directive includes it into the file, but using the build system for the project this was compiling just fine. If someone has a link to a relevant part of the spec, that would be most appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

梦归所梦 2024-12-03 10:34:59

也许是一个有趣的数据点。 编译以下内容时

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++ 中的一个错误。

编辑:已经报道过。(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 年 7 月 24 日发布的评论建议 g++ 应对此发出警告。

A perhaps interesting data point. When I compile the following:

using namespace std;
using namespace no_such_namespace;

with g++ 4.5.2, I get:

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

To be clear, those two lines are the entire source file I compiled.

Neither std nor no_such_namespace has been defined as a namespace at that point, but g++ complains only about the second. I don't think there's anything special about the identifier std in the absence of a declaration of it. I think @James Kanze is right that this is a bug in g++.

EDIT: And it's been reported. (5 years ago!)

UPDATE: Now it's more than 8 years, and still hasn't been assigned to anyone, much less fixed. g++ 4.9.2 exhibits the problem. clang++ 3.5 doesn't, but it issues a warning for std and a fatal error for 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.

UPDATE: As of 2021-09-24, the bug report is still open and the bug exists in g++ 11.2.0. A comment posted 2021-07-24 suggests that g++ should warn about this.

不爱素颜 2024-12-03 10:34:59

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

using namespace std;

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

I don't think it's legal, but the standard isn't 100% clear about it.
Basically, name lookup (as defined in §3.4) can't find a previous
declaration of the namespace, because there isn't one. Everything
hinges on whether:

using namespace std;

is a declaration of the namespace or not. And I don't see any text in
§7.3.4 which says that a using-directive declares the nominated
namespace. G++ allows your code, but IMHO, this is a bug.

无妨# 2024-12-03 10:34:59

来自 SO/IEC 14882:2003

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

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

。因此,如果它碰巧起作用,那么它只是侥幸并且不可移植。

From SO/IEC 14882:2003

[7.3.3.9] The entity declared by a using-declaration shall be known in the context using it according to its definition at the point of the using-declaration. Definitions added to the namespace after the using-declaration are not considered when a use of the name is made.

[3.4.3.2.2] Given X::m (where X is a user-declared namespace), or given ::m (where X is the global namespace), let S be the set of all declarations of m in X and in the transitive closure of all namespaces nominated by using-directives in X and its used namespaces, except that using-directives are ignored in any namespace, including X, directly containing one or more declarations of m. No namespace is searched more than once in the lookup of a name. If S is the empty set, the program is ill-formed. Otherwise, if S has exactly one member, or if the context of the reference is a using-declaration (7.3.3), S is the required set of declarations of m. Otherwise if the use of m is not one that allows a unique declaration to be chosen from S, the program is ill-formed

So if it happens to work, it's a fluke and not portable.

年华零落成诗 2024-12-03 10:34:59

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

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

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

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

This code is undefined behavior [lib.using.headers]:

A translation unit shall include a header only outside of any external declaration or definition, and shall include the header lexically before the first reference to any of the entities it declares or first defines in that translation unit.

You reference std and then include a header that declares it. Even this is still undefined behavior:

#include <string>
using namespace std;
#include <iostream>
初见终念 2024-12-03 10:34:59

我认为标准(包括 C++0x)在这种情况下存在缺陷。

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

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

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

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

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

名称的声明点紧接在其完整声明符(第 8 条)之后和其初始值设定项(如果有)之前,除非下面另有说明。

并且所有例外都不适用于名称空间。

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

I think there's a flaw in the standard (including C++0x) with respect to this case.

We have in section 3.3.6 ([basic.scope.namespace]):

The declarative region of a namespace-definition is its namespace-body. The potential scope denoted by an original-namespace-name is the concatenation of the declarative regions established by each of the namespace-definitions in the same declarative region with that original-namespace-name. Entities declared in a namespace-body are said to be members of the namespace, and names introduced by these declarations into the declarative region of the namespace are said to be member names of the namespace. A namespace member name has namespace scope. Its potential scope includes its namespace from the name’s point of declaration (3.3.2) onwards; and for each using-directive (7.3.4) that nominates the member’s namespace, the member’s potential scope includes that portion of the potential scope of the using-directive that follows the member’s point of declaration.

and

The outermost declarative region of a translation unit is also a namespace, called the global namespace. A name declared in the global namespace has global namespace scope (also called global scope). The potential scope of such a name begins at its point of declaration (3.3.2) and ends at the end of the translation unit that is its declarative region. Names with global namespace scope are said to be global name.

So namespace std is a member of the global namespace, and the scope of the name starts at the point of declaration.

And 3.3.2 ([basic.scope.pdecl]) tells us:

The point of declaration for a name is immediately after its complete declarator (Clause 8) and before its initializer (if any), except as noted below.

And none of the exceptions apply to namespaces.

So a namespace name cannot be used before its declarator, but a namespace name isn't a declarator. Oops.

挥剑断情 2024-12-03 10:34:59

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

Recently i faced the same issue and been advised by my tech lead that; using namespace does not guarantee the visibility of the methods until the namespace with related methods are included in the file using .h file.
including the header file resolved the issue.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文