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]:
การใช้คำสั่ง : โดยใช้ namespace :: การเลือก ที่ซ้อนกันชื่อ-ระบุการเลือก namespace ชื่อ ;
ใช้-สั่งจะไม่ปรากฏในขอบเขตของคลาส แต่อาจปรากฏอยู่ในขอบเขต namespace หรืออยู่ในขอบเขตบล็อก [หมายเหตุ: เมื่อค้นหาชื่อเนมสเปซในคำสั่งการใช้จะพิจารณาเฉพาะชื่อเนมสเปซเท่านั้นดู 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
STL cf th.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 Foo
ลำดับการค้นหาสำหรับโค้ดทั้งหมดภายในนิยามประเภทของstruct Bar
เช่นเดียวกับการใส่บรรทัดนั้นในทุกฟังก์ชันของสมาชิกแบบอินไลน์ยกเว้นว่าจะใช้งานสำหรับตัวเริ่มต้นแบบรั้งหรือเท่ากับเป็นต้น แต่ก็ยังคง หมดอายุที่วงเล็บปีกกาปิดเช่นเดียวกับusing namespace
ภายในร่างกายฟังก์ชันของสมาชิก ตอนนี้ดูเหมือนจะไม่มีวิธีใดเลยในการใช้ Koenig-with-fallback lookup ในตัวเริ่มต้นแบบรั้งหรือเท่ากันโดยไม่ทำให้เนมสเปซที่ปิดล้อมอยู่
ฉันคิดว่ามันเป็นความบกพร่องของภาษา คุณอาจใช้วิธีแก้ปัญหาด้านล่าง โปรดทราบว่าวิธีแก้ปัญหานี้เป็นเรื่องง่ายที่จะแนะนำกฎของการแก้ปัญหาความขัดแย้งของชื่อสำหรับกรณีที่จะเปลี่ยนภาษา
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
ช่วยให้คุณสามารถรวมเนมสเปซหนึ่งเข้ากับอีกเนมสเปซได้