11

最近、C++ プロジェクトのソース ファイルで次のコードが使用されているのを見ました。

using namespace std;
#include <iostream>

持っているのが良い考えかどうかという問題をすべて無視してusing namespace std、上記のコードは合法ですか? この 2 行より前のコードはファイルにありません。

ディレクティブがファイルに含めるnamespace stdまでスコープで宣言されていないため、これはコンパイルされないと思っていましたが、プロジェクトのビルドシステムを使用すると、これは問題なくコンパイルされました。#include <iostream>誰かが仕様の関連部分へのリンクを持っている場合は、それが最も高く評価されます.

4

6 に答える 6

7

おそらく興味深いデータ ポイントです。以下をコンパイルすると:

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

明確にするために、これらの 2 行は、私がコンパイルしたソース ファイル全体です。

その時点ではどちらstdも名前空間として定義されていませんが、g++ は 2 番目についてのみ文句を言います。宣言がない場合、識別子について特別なことは何もno_such_namespaceないと思います。stdこれはg ++のバグであるという@James Kanzeは正しいと思います。

編集:そしてそれは報告されています。(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++ がこれについて警告する必要があることを示唆しています。

于 2011-08-07T01:06:28.010 に答える
4

合法ではないと思いますが、基準はそれについて 100% 明確ではありません。基本的に、(§3.4 で定義されているように) 名前検索では、名前空間の以前の宣言を見つけることができません。すべては、次のいずれかにかかっています。

using namespace std;

名前空間の宣言かどうか。また、§7.3.4 には、using ディレクティブが指定された名前空間を宣言するというテキストはありません。G++ はコードを許可しますが、これはバグです。

于 2011-07-27T09:45:05.087 に答える
2

SO/IEC 14882:2003 より

[7.3.3.9] using 宣言によって宣言されたエンティティは、using 宣言の時点での定義に従って、それを使用するコンテキストで認識されるものとします。using 宣言の後に名前空間に追加された定義は、名前の使用時に考慮されません。

[3.4.3.2.2] X::m (X はユーザーが宣言した名前空間) または ::m (X はグローバル名前空間) が与えられた場合、S を X 内の m のすべての宣言の集合とし、 X およびその使用される名前空間の using ディレクティブによって指定されたすべての名前空間の推移閉包。名前の検索では、名前空間が複数回検索されることはありません。S が空集合の場合、プログラムの形式は正しくありません。それ以外の場合、S のメンバーが 1 つだけの場合、または参照のコンテキストが using-declaration (7.3.3)の場合、S は m の宣言の必須セットです。それ以外の場合、m の使用が S から一意の宣言を選択できるものでない場合、プログラムは不正な形式です。

したがって、たまたま機能する場合は、まぐれであり、移植性がありません。

于 2011-07-27T08:07:28.110 に答える
1

このコードは未定義の動作です [lib.using.headers]:

翻訳単位は、外部の宣言または定義の外側にのみヘッダーを含める必要があり、その翻訳単位で宣言または最初に定義するエンティティのいずれかへの最初の参照の前に、辞書的にヘッダーを含める必要があります。

参照stdしてから、それを宣言するヘッダーを含めます。これでも未定義の動作です:

#include <string>
using namespace std;
#include <iostream>
于 2011-07-27T08:35:24.300 に答える
1

このケースに関しては、標準 (C++0x を含む) に欠陥があると思います。

セクション 3.3.6 ( [basic.scope.namespace]) には次のものがあります。

名前空間定義の宣言領域は、その名前空間本体です。original-namespace-name によって示される潜在的なスコープは、その original-namespace-name を持つ同じ宣言領域内の名前空間定義のそれぞれによって確立された宣言領域の連結です。名前空間本体で宣言されたエンティティは、名前空間のメンバーと呼ばれ、これらの宣言によって名前空間の宣言領域に導入された名前は、名前空間のメンバー名と呼ばれます。名前空間のメンバー名には、名前空間のスコープがあります。その潜在的なスコープには、名前の宣言ポイント (3.3.2) 以降の名前空間が含まれます。そして、メンバーの名前空間を指定する各 using ディレクティブ (7.3.4) について、

翻訳単位の最も外側の宣言領域も、グローバル名前空間と呼ばれる名前空間です。グローバル名前空間で宣言された名前には、グローバル名前空間スコープ (グローバル スコープとも呼ばれます) があります。そのような名前の潜在的な範囲は、その宣言のポイント (3.3.2) で始まり、その宣言領域である翻訳単位の終わりで終わります。グローバル名前空間スコープを持つ名前は、グローバル名と呼ばれます。

これnamespace stdはグローバル名前空間のメンバーであり、名前のスコープは宣言の時点から始まります。

そして 3.3.2 ( [basic.scope.pdecl]) は次のことを教えてくれます。

名前の宣言のポイントは、完全な宣言子 (第 8 節) の直後で、初期化子 (存在する場合) の前です。ただし、以下に示す場合を除きます。

また、名前空間に適用される例外はありません。

そのため、宣言子の前に名前空間名を使用することはできませんが、名前空間名は宣言子ではありません。おっとっと。

于 2011-08-07T01:56:54.730 に答える
0

最近、私は同じ問題に直面し、技術リーダーから次のようにアドバイスされました。名前空間を使用しても、関連するメソッドを含む名前空間が .h ファイルを使用してファイルに含まれるまで、メソッドの可視性は保証されません。ヘッダーファイルを含めることで問題が解決しました。

于 2013-04-10T15:20:47.797 に答える