class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
Düzenleme : Arkasındaki motivasyonu bilmek ister.
class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
Düzenleme : Arkasındaki motivasyonu bilmek ister.
class/struct
. Sadece buna izin verilmiyor. Ancak kabul edilen cevap, buna izin vermemek için çok mantıklı bir mantığı tartışıyor. yani nerede dikkate alınmalı Hello::World
ve nerede dikkate alınmalı World
. Umarım bu şüpheyi giderir.
Yanıtlar:
Tam olarak bilmiyorum, ancak benim tahminim sınıf kapsamında buna izin verilmesi kafa karışıklığına neden olabilir:
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?
}
Bunu yapmanın bariz bir yolu olmadığından, standart sadece yapamayacağınızı söylüyor.
Şimdi, ad alanı kapsamlarından bahsederken bunun daha az kafa karıştırıcı olmasının nedeni:
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;
diğerinin içinde namespace
de geçerli (ve extern
içindeki işlevi ilan etmek).
Hello::World Blah::DoSomething()
veya Blah::World Blah::DoSomething()
(izin verildiyse), bir üye işlev tanımının dönüş türü, dildeki sınıf kapsamında kabul edilmez, bu nedenle nitelenmesi gerekir. using
Bir typedef Hello::World World;
sınıf kapsamıyla değiştirmenin geçerli bir örneğini düşünün . Bu yüzden orada sürpriz olmamalı.
Çünkü C ++ standardı bunu açıkça yasaklamaktadır. C ++ 03 §7.3.4'ten [namespace.udir]:
kullanma yönergesi : isim - alanı :: opt iç içe-isim-belirleyici kullanma tercih isim-alanı-ismi ;
Kullanım yönergesi sınıf kapsamında görünmez, ancak ad alanı kapsamında veya blok kapsamında görünebilir. [Not: using-yönergesinde bir isim-alanı-ismi aranırken, sadece isim-alanı isimleri dikkate alınır, bkz. 3.4.6. ]
C ++ standardı bunu neden yasaklıyor? Bilmiyorum, dil standardını onaylayan ISO komitesi üyelerinden birine sorun.
Mantığın muhtemelen kafa karıştırıcı olacağına inanıyorum. Şu anda, bir sınıf düzeyi tanımlayıcı işlenirken, arama önce sınıf kapsamında ve ardından çevreleyen ad alanında arama yapacaktır. using namespace
Sınıf düzeyinde izin vermenin, aramanın şimdi nasıl gerçekleştirildiği üzerinde oldukça bazı yan etkileri olacaktır. Özellikle, söz konusu sınıf kapsamının kontrol edilmesi ile çevreleyen ad alanının kontrol edilmesi arasında bazen yapılması gerekir. Yani: 1) sınıf düzeyini ve kullanılan ad alanı düzeyi aramalarını birleştirin, 2) sınıf kapsamından sonra , ancak herhangi bir sınıf kapsamından önce kullanılan ad alanını arayın, 3) kullanılan ad alanını çevreleyen ad alanından hemen önce arayın. 4) arama, çevreleyen ad alanıyla birleştirildi.
.
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
bildirimi ad alanı düzeyinde uygulamakla tam olarak aynı etkiye sahip olacaktır . Buna herhangi bir yeni değer katmaz, ancak diğer yandan derleyici uygulayıcılarının aranmasını karmaşıklaştırır. Ad alanı tanımlayıcı araması, artık aramanın kodun neresinden tetiklendiğinden bağımsızdır. Bir sınıfın içindeyken, arama tanımlayıcıyı sınıf kapsamında bulamazsa, ad alanı aramasına geri döner, ancak bu, bir işlev tanımında kullanılan ad alanı aramasının aynısıdır, yeni durumu korumaya gerek yoktur. Ne zaman using
beyan ad düzeyinde bulunursa, içeriği kullanılan ad olan getirdi için o ad içine tüm ad içeren aramalarının. Eğerusing namespace
sınıf düzeyinde izin verildiğinde, aramanın nereden tetiklendiğine bağlı olarak tam olarak aynı ad alanının ad alanı araması için farklı sonuçlar olacaktır ve bu, aramanın uygulanmasını hiçbir ek değer olmaksızın çok daha karmaşık hale getirecektir.Neyse, benim öneri değil istihdam using namespace
hiç beyanname. Tüm ad alanlarının içeriğini akılda tutmak zorunda kalmadan kodu mantıklı hale getirir.
using
var olan gerçeği etrafında tasarlanabilir . Derin iç içe geçmiş uzun ad alanlarındaki şeyleri kasıtlı olarak bildirerek. Örneğin glm
, bunu yapar ve müşteri kullandığında özellikleri etkinleştirmek / sunmak için birden fazla numara kullanır using
.
using namespace std::placeholders
. cf en.cppreference.com/w/cpp/utility/functional/bind
namespace ph = std::placeholders;
Açıklık ve kapalılık nedeniyle buna büyük olasılıkla izin verilmiyor .
Ad alanlarını sınıflara aktarmak, bunun gibi komik durumlara yol açar:
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 Foo
, tür tanımındaki tüm kodlar için arama sırasına eklenmesine izin verin struct Bar
, ancak ayraç veya eşit başlatıcılar vb. İçin de etkin olacaktır. Ama yine de using namespace
Bir üye işlev gövdesinin içinde olduğu gibi, kapanış parantezinde sona erer . Şimdi maalesef, kapsayıcı ad alanını kirletmeden bir küme ayracı veya eşitleme başlatıcısında Koenig-with-fallback aramasını kullanmanın herhangi bir yolu yok gibi görünüyor.
Sanırım dilin bir kusuru. Aşağıdaki geçici çözümü kullanabilirsiniz. Bu geçici çözümü göz önünde bulundurarak, dilin değiştirileceği durum için ad uyuşmazlıkları çözümü önermek kolaydır.
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 # benzer bir şeye izin verir, ancak yalnızca dosya kapsamında. C ++ 'larusing namespace
bir ad alanını diğerine eklemenize izin verir.