class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
Edit : Ingin tahu motivasi di baliknya.
c++
namespaces
using
language-lawyer
iammilind
sumber
sumber
using namespace
. C # memungkinkan sesuatu yang serupa, tetapi hanya pada lingkup file. C ++using namespace
memungkinkan Anda untuk menggabungkan satu namespace ke yang lain.class/struct
. Itu tidak diperbolehkan. Tetapi jawaban yang diterima memang membahas alasan yang sangat logis untuk melarangnya. yaitu di mana harus mempertimbangkanHello::World
dan di mana harus mempertimbangkanWorld
. Harapan yang menghilangkan keraguan.Jawaban:
Saya tidak tahu persis, tetapi dugaan saya adalah mengizinkan ini di ruang lingkup kelas dapat menyebabkan kebingungan:
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? }
Karena tidak ada cara yang jelas untuk melakukan ini, standar hanya mengatakan Anda tidak bisa.
Sekarang, alasan mengapa ini tidak terlalu membingungkan ketika kita berbicara tentang cakupan namespace:
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. } }
sumber
using namespace Hello;
di dalam yang lainnamespace
juga (dan menyatakanextern
fungsi di dalamnya).Hello::World Blah::DoSomething()
atauBlah::World Blah::DoSomething()
(jika diizinkan), tipe kembalian dari definisi fungsi anggota tidak dianggap berada dalam cakupan kelas dalam bahasa tersebut, jadi harus memenuhi syarat. Pertimbangkan contoh yang valid untuk menggantiusing
dengan atypedef Hello::World World;
at class scope. Jadi seharusnya tidak ada kejutan di sana.Karena standar C ++ secara eksplisit melarangnya. Dari C ++ 03 §7.3.4 [namespace.udir]:
Mengapa standar C ++ melarangnya? Saya tidak tahu, tanyakan kepada anggota komite ISO yang menyetujui standar bahasa.
sumber
Saya percaya bahwa alasannya adalah mungkin akan membingungkan. Saat ini, saat memproses pengenal tingkat kelas, pencarian pertama akan mencari di ruang lingkup kelas dan kemudian di ruang nama yang melingkupi. Mengizinkan
using namespace
di tingkat kelas akan memiliki beberapa efek samping pada bagaimana pencarian sekarang dilakukan. Secara khusus, itu harus dilakukan kadang-kadang antara memeriksa ruang lingkup kelas tertentu dan memeriksa ruang nama yang melingkupinya. Yaitu: 1) menggabungkan tingkat kelas dan pencarian tingkat ruang nama yang digunakan, 2) mencari ruang nama yang digunakan setelah cakupan kelas tetapi sebelum ruang lingkup kelas lainnya, 3) mencari ruang nama yang digunakan tepat sebelum ruang nama yang melingkupi. 4) pencarian digabungkan dengan namespace yang melingkupi..
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
deklarasi di tingkat namespace. Ini tidak akan menambahkan nilai baru apa pun untuk itu, tetapi di sisi lain akan mempersulit pencarian untuk pelaksana compiler. Pencarian pengenal ruang nama sekarang tidak bergantung pada tempat pencarian kode dipicu. Saat berada di dalam kelas, jika pencarian tidak menemukan pengenal pada ruang lingkup kelas, ia akan kembali ke pencarian namespace, tetapi itu adalah pencarian namespace yang persis sama yang digunakan dalam definisi fungsi, tidak perlu mempertahankan status baru. Ketikausing
deklarasi ditemukan di tingkat namespace, konten namespace yang digunakan dibawa ke namespace itu untuk semua pencarian yang melibatkan namespace. Jikausing namespace
diizinkan di tingkat kelas, akan ada hasil yang berbeda untuk pencarian namespace dari namespace yang sama persis tergantung dari mana pencarian dipicu, dan itu akan membuat implementasi pencarian jauh lebih kompleks tanpa nilai tambahan.Bagaimanapun, rekomendasi saya adalah tidak menggunakan
using namespace
deklarasi sama sekali. Itu membuat kode lebih sederhana untuk alasan tanpa harus mengingat semua konten ruang nama.sumber
using
ada. Dengan sengaja mendeklarasikan hal-hal dalam namespace panjang bersarang yang dalam. Misalnyaglm
melakukan itu, dan menggunakan beberapa trik untuk mengaktifkan / menampilkan fitur saat klien menggunakannyausing
.using namespace std::placeholders
. cf en.cppreference.com/w/cpp/utility/functional/bindnamespace ph = std::placeholders;
Ini mungkin tidak diizinkan karena keterbukaan vs ketertutupan.
Mengimpor namespace ke dalam kelas akan menyebabkan kasus lucu seperti ini:
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. }
sumber
namespace Foo
urutan pencarian untuk semua kode di dalam definisi tipestruct Bar
, seperti meletakkan baris itu di setiap badan fungsi anggota sebaris, kecuali bahwa itu juga akan aktif untuk penginisialisasi brace-or-equal, dll. Tapi itu akan tetap kedaluwarsa pada penjepit penutup, sama sepertiusing namespace
di dalam badan fungsi anggota. Sayangnya, sekarang tampaknya tidak ada cara untuk menggunakan pencarian Koenig-dengan-fallback dalam penginisialisasi brace-or-equal tanpa mencemari namespace yang melingkupinya.Saya pikir itu adalah cacat bahasa. Anda dapat menggunakan solusi di bawah ini. Mengingat solusi ini, mudah untuk menyarankan aturan resolusi konflik nama untuk kasus ketika bahasa akan diubah.
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 { }
sumber