class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
編集:その背後にある動機を知りたい。
class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
編集:その背後にある動機を知りたい。
class/struct
。それは単に許可されていません。しかし、受け入れられた答えは、それを禁止する非常に論理的な論理的根拠を議論しています。つまり、どこを検討しHello::World
、どこを検討するかWorld
。それが疑問を解消することを願っています。
回答:
正確にはわかりませんが、クラススコープでこれを許可すると混乱が生じる可能性があると思います。
namespace Hello
{
typedef int World;
}
class Blah
{
using namespace Hello;
public:
World DoSomething();
}
//Should this be just World or Hello::World ?
World Blah::DoSomething()
{
//Is the using namespace valid in here?
}
これを行う明確な方法がないので、標準はあなたができないと言っているだけです。
さて、名前空間スコープについて話しているときにこれがそれほど混乱しない理由は次のとおりです。
namespace Hello
{
typedef int World;
}
namespace Other
{
using namespace Hello;
World DoSomething();
}
//We are outside of any namespace, so we have to fully qualify everything. Therefore either of these are correct:
//Hello was imported into Other, so everything that was in Hello is also in Other. Therefore this is okay:
Other::World Other::DoSomething()
{
//We're outside of a namespace; obviously the using namespace doesn't apply here.
//EDIT: Apparently I was wrong about that... see comments.
}
//The original type was Hello::World, so this is okay too.
Hello::World Other::DoSomething()
{
//Ditto
}
namespace Other
{
//namespace Hello has been imported into Other, and we are inside Other, so therefore we never need to qualify anything from Hello.
//Therefore this is unambiguiously right
World DoSomething()
{
//We're inside the namespace, obviously the using namespace does apply here.
}
}
using namespace Hello;
他の内部にnamespace
も当てはまります(そしてextern
その内部で関数を宣言します)。
Hello::World Blah::DoSomething()
またはBlah::World Blah::DoSomething()
(許可されている場合)、メンバー関数定義の戻り値の型は、言語のクラスのスコープ内にあるとは見なされないため、修飾する必要があります。交換の有効な例を考えusing
てtypedef Hello::World World;
、クラススコープでは。したがって、そこに驚きはないはずです。
C ++標準では明示的に禁止されているためです。C ++03§7.3.4[namespace.udir]から:
using-ディレクティブ: 名前空間の使用:: opt ネストされた名前指定子opt 名前空間名;
使用したディレクティブは、クラススコープに表示されてはならないが、名前空間スコープまたはブロックスコープに表示される場合があります。[注:usingディレクティブで名前空間名を検索する場合、名前空間名のみが考慮されます。3.4.6を参照してください。]
C ++標準で禁止されているのはなぜですか?わかりません。言語標準を承認したISO委員会のメンバーに聞いてください。
その理由は、おそらく混乱を招くだろうということだと思います。現在、クラスレベルの識別子を処理している間、ルックアップは最初にクラススコープを検索し、次にそれを囲む名前空間を検索します。using namespace
クラスレベルで許可すると、ルックアップの実行方法にかなりの副作用があります。特に、その特定のクラススコープをチェックしてから、それを囲む名前空間をチェックするまでの間に実行する必要があります。つまり、1)クラスレベルと使用済み名前空間レベルのルックアップをマージします。2)クラススコープの後、他のクラススコープの前に使用済み名前空間をルックアップします。3)囲んでいる名前空間の直前に使用済み名前空間をルックアップします。4)ルックアップはそれを囲む名前空間とマージされました。
。
namespace A {
void foo() {}
struct B {
struct foo {};
void f() {
foo(); // value initialize a A::B::foo object (current behavior)
}
};
}
struct C {
using namespace A;
struct foo {};
void f() {
foo(); // call A::foo
}
};
。
namespace A {
void foo() {}
}
void bar() {}
struct base {
void foo();
void bar();
};
struct test : base {
using namespace A;
void f() {
foo(); // A::foo()
bar(); // base::bar()
}
};
。
namespace A {
void foo( int ) { std::cout << "int"; }
}
void foo( double ) { std::cout << "double"; }
struct test {
using namespace A;
void f() {
foo( 5.0 ); // would print "int" if A is checked *before* the
// enclosing namespace
}
};
using
、名前空間レベルで宣言を適用するのとまったく同じ効果があります。それに新しい値を追加することはありませんが、一方でコンパイラ実装者の検索を複雑にします。名前空間識別子のルックアップは、コード内のルックアップがトリガーされる場所から独立しています。クラス内で、ルックアップがクラススコープで識別子を見つけられない場合、名前空間ルックアップにフォールバックしますが、それは関数定義で使用される名前空間ルックアップとまったく同じであり、新しい状態を維持する必要はありません。ときにusing
宣言が名前空間レベルで発見され、内容に使用される名前空間がされもたらしたため、その名前空間の中に、すべての名前空間を含む検索。場合using namespace
クラスレベルで許可された場合、ルックアップがトリガーされた場所に応じて、まったく同じ名前空間の名前空間ルックアップの結果が異なり、追加の値がないため、ルックアップの実装がはるかに複雑になります。とにかく、私の推奨は、宣言をまったく採用しないことusing namespace
です。これにより、すべての名前空間の内容を念頭に置く必要がなく、コードの推論が簡単になります。
using
存在する事実に基づいて設計される場合があります。深くネストされた長い名前空間で意図的に宣言することによって。たとえばglm
、それを行い、クライアントがを使用するときに機能をアクティブ化/提示するために複数のトリックを使用しますusing
。
using namespace std::placeholders
。cf en.cppreference.com/w/cpp/utility/functional/bind
namespace ph = std::placeholders;
これは、開放性と閉鎖性のためにおそらく許可されていません。
名前空間をクラスにインポートすると、次のような面白いケースが発生します。
namespace Foo {}
struct Bar { using namespace Foo; };
namespace Foo {
using Baz = int; // I've just extended `Bar` with a type alias!
void baz(); // I've just extended `Bar` with what looks like a static function!
// etc.
}
それは言語の欠陥だと思います。以下の回避策を使用できます。この回避策を念頭に置いて、言語が変更される場合の名前の競合の解決を提案するのは簡単です。
namespace Hello
{
typedef int World;
}
// surround the class (where we want to use namespace Hello)
// by auxiliary namespace (but don't use anonymous namespaces in h-files)
namespace Blah_namesp {
using namespace Hello;
class Blah
{
public:
World DoSomething1();
World DoSomething2();
World DoSomething3();
};
World Blah::DoSomething1()
{
}
} // namespace Blah_namesp
// "extract" class from auxiliary namespace
using Blah_namesp::Blah;
Hello::World Blah::DoSomething2()
{
}
auto Blah::DoSomething3() -> World
{
}
using namespace
。のようなものはありません。C#でも同様のことが可能ですが、ファイルスコープでのみ可能です。C ++をusing namespace
使用すると、ある名前空間を別の名前空間に組み込むことができます。