class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
Chỉnh sửa : Muốn biết động lực đằng sau nó.
class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
Chỉnh sửa : Muốn biết động lực đằng sau nó.
class/struct
. Nó chỉ đơn giản là không được phép. Nhưng câu trả lời được chấp nhận không thảo luận về một lý do rất hợp lý để không cho phép nó. tức là xem xét Hello::World
ở đâu và xem xét ở đâu World
. Hy vọng rằng xóa bỏ nghi ngờ.
Câu trả lời:
Tôi không biết chính xác, nhưng suy đoán của tôi là việc cho phép điều này ở phạm vi lớp có thể gây ra nhầm lẫn:
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?
}
Vì không có cách rõ ràng để làm điều này, tiêu chuẩn chỉ nói rằng bạn không thể.
Bây giờ, lý do điều này ít khó hiểu hơn khi chúng ta đang nói về phạm vi không gian tên:
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;
bên trong namespace
cũng khác (và khai báo extern
hàm bên trong nó).
Hello::World Blah::DoSomething()
hoặc Blah::World Blah::DoSomething()
(nếu nó được cho phép), kiểu trả về của định nghĩa hàm thành viên không được coi là thuộc phạm vi của lớp trong ngôn ngữ, vì vậy nó phải đủ điều kiện. Hãy xem xét ví dụ hợp lệ về việc thay thế using
bằng typedef Hello::World World;
phạm vi lớp. Vì vậy, không nên có bất ngờ ở đó.
Bởi vì tiêu chuẩn C ++ cấm nó một cách rõ ràng. Từ C ++ 03 §7.3.4 [namespace.udir]:
using-chỉ thị : sử dụng không gian tên :: opt lồng nhau-tên-chỉ định opt không gian tên-tên ;
Một chỉ thị sử dụng sẽ không xuất hiện trong phạm vi lớp, nhưng có thể xuất hiện trong phạm vi không gian tên hoặc trong phạm vi khối. [Lưu ý: khi tra cứu tên không gian tên trong chỉ thị sử dụng, chỉ những tên không gian tên được xem xét, xem 3.4.6. ]
Tại sao tiêu chuẩn C ++ lại cấm nó? Tôi không biết, hãy hỏi một thành viên của ủy ban ISO đã phê duyệt tiêu chuẩn ngôn ngữ.
Tôi tin rằng lý do chính đáng là nó có thể gây nhầm lẫn. Hiện tại, trong khi xử lý mã định danh cấp lớp, tra cứu trước tiên sẽ tìm kiếm trong phạm vi lớp và sau đó trong không gian tên bao quanh. Việc cho phép using namespace
ở cấp độ lớp học sẽ có một số tác dụng phụ về cách thức tra cứu hiện được thực hiện. Đặc biệt, nó sẽ phải được thực hiện đôi khi giữa việc kiểm tra phạm vi lớp cụ thể đó và kiểm tra không gian tên bao quanh. Đó là: 1) hợp nhất cấp lớp và tra cứu cấp không gian tên đã sử dụng, 2) tra cứu không gian tên đã sử dụng sau phạm vi lớp nhưng trước bất kỳ phạm vi lớp nào khác, 3) tra cứu không gian tên đã sử dụng ngay trước không gian tên bao quanh. 4) tra cứu được hợp nhất với không gian tên bao quanh.
.
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
khai báo ở cấp không gian tên. Nó sẽ không thêm bất kỳ giá trị mới nào vào đó, nhưng mặt khác sẽ làm phức tạp thêm việc tra cứu các trình triển khai trình biên dịch. Tra cứu định danh không gian tên giờ đây độc lập với nơi kích hoạt tìm kiếm trong mã. Khi bên trong một lớp, nếu tra cứu không tìm thấy mã định danh ở phạm vi lớp, nó sẽ quay trở lại tra cứu không gian tên, nhưng đó chính xác là tra cứu không gian tên được sử dụng trong định nghĩa hàm, không cần duy trì trạng thái mới. Khi using
khai báo được tìm thấy ở cấp không gian tên, nội dung của không gian tên được sử dụng là đưa vào không gian tên đó cho tất cả các tra cứu liên quan đến không gian tên. Nếuusing namespace
được cho phép ở cấp lớp, sẽ có các kết quả khác nhau đối với việc tra cứu không gian tên của cùng một không gian tên chính xác tùy thuộc vào nơi kích hoạt tra cứu và điều đó sẽ làm cho việc triển khai tra cứu phức tạp hơn nhiều mà không có giá trị bổ sung.Dù sao, khuyến nghị của tôi là không sử dụng using namespace
khai báo gì cả. Nó làm cho mã đơn giản hơn để lập luận mà không cần phải ghi nhớ tất cả nội dung của không gian tên.
using
tồn tại. Bằng cách cố ý khai báo mọi thứ trong không gian tên dài lồng nhau. Ví dụ: glm
làm điều đó và sử dụng nhiều thủ thuật để kích hoạt / trình bày các tính năng khi khách hàng sử dụng using
.
using namespace std::placeholders
. cf en.cppreference.com/w/cpp/utility/filities/bind
namespace ph = std::placeholders;
Điều này có lẽ không được phép vì tính mở và tính đóng.
Việc nhập không gian tên vào các lớp sẽ dẫn đến những trường hợp buồn cười như sau:
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.
}
Tôi nghĩ đó là một khiếm khuyết của ngôn ngữ. Bạn có thể sử dụng cách giải quyết bên dưới. Hãy ghi nhớ cách giải quyết này, có thể dễ dàng đề xuất các quy tắc giải quyết xung đột tên cho trường hợp khi ngôn ngữ sẽ được thay đổi.
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 # cho phép một cái gì đó tương tự, nhưng chỉ ở phạm vi tệp. C ++using namespace
cho phép bạn kết hợp một không gian tên này vào một không gian tên khác.