มีวิธีที่ดีกว่าในการแสดงเนมสเปซที่ซ้อนกันใน C ++ ภายในส่วนหัวหรือไม่


102

ฉันเปลี่ยนจาก C ++ เป็น Java และ C # และคิดว่าการใช้เนมสเปซ / แพ็คเกจนั้นดีกว่ามากที่นั่น (มีโครงสร้างที่ดี) จากนั้นฉันก็กลับมาที่ C ++ และพยายามใช้เนมสเปซในลักษณะเดียวกัน แต่ไวยากรณ์ที่ต้องการนั้นแย่มากในไฟล์ส่วนหัว

namespace MyCompany
{
    namespace MyModule
    {
        namespace MyModulePart //e.g. Input
        {
            namespace MySubModulePart
            {
                namespace ...
                {
                    public class MyClass    

สิ่งต่อไปนี้ดูแปลกสำหรับฉันเช่นกัน (เพื่อหลีกเลี่ยงการเยื้องลึก):

namespace MyCompany
{
namespace MyModule
{
namespace MyModulePart //e.g. Input
{
namespace MySubModulePart
{
namespace ...
{
     public class MyClass
     {

มีวิธีที่สั้นกว่าในการแสดงสิ่งข้างต้นหรือไม่? ฉันขาดอะไรบางอย่างเช่น

namespace MyCompany::MyModule::MyModulePart::...
{
   public class MyClass

อัปเดต

โอเคบางคนบอกว่าแนวคิดการใช้งานใน Java / C # และ C ++ นั้นแตกต่างกัน จริงๆ? ฉันคิดว่าการโหลดคลาส (ไดนามิก) ไม่ใช่จุดประสงค์เดียวสำหรับเนมสเปซ (นี่เป็นมุมมองที่มีเหตุผลทางเทคนิคมาก) เหตุใดฉันจึงไม่ควรใช้เพื่อให้อ่านง่ายและจัดโครงสร้างได้เช่นนึกถึง "IntelliSense"

ขณะนี้ไม่มีตรรกะ / กาวระหว่างเนมสเปซและสิ่งที่คุณสามารถหาได้ที่นั่น Java และ C # ทำได้ดีกว่ามาก ... ทำไมต้องรวม<iostream>และมีเนมสเปซstd? ตกลงถ้าคุณบอกว่าตรรกะควรพึ่งพาส่วนหัวที่จะรวมถึงทำไม #include ไม่ได้ใช้ "IntelliSense" ไวยากรณ์เป็นกันเองเหมือน#include <std::io::stream>หรือ<std/io/stream>? ฉันคิดว่าโครงสร้างที่ขาดหายไปใน libs เริ่มต้นเป็นจุดอ่อนอย่างหนึ่งของ C ++ เมื่อเทียบกับ Java / C #

หากความเป็นเอกลักษณ์ของความขัดแย้งมักเป็นจุดเดียว (ซึ่งเป็นจุดหนึ่งของ C # และ Java ด้วย) ความคิดที่ดีคือการใช้ชื่อโครงการหรือชื่อ บริษัท เป็นเนมสเปซคุณไม่คิดอย่างนั้นเหรอ?

ในแง่หนึ่งกล่าวว่า C ++ มีความยืดหยุ่นมากที่สุด ... แต่ใคร ๆ ก็บอกว่า "อย่าทำ"? สำหรับฉันแล้วดูเหมือนว่า C ++ สามารถทำอะไรได้หลายอย่าง แต่มีไวยากรณ์ที่น่ากลัวแม้จะเป็นสิ่งที่ง่ายที่สุดในหลาย ๆ กรณีเมื่อเทียบกับ C #

อัปเดต 2

ผู้ใช้ส่วนใหญ่บอกว่าเป็นเรื่องไร้สาระที่จะสร้างรังที่ลึกกว่าสองระดับ ตกลงแล้ว Windows :: UI :: Xaml และ Windows :: UI :: Xaml :: Controls :: Primitives namespaces ในการพัฒนา Win8 ล่ะ ฉันคิดว่าการใช้เนมสเปซของ Microsoft นั้นสมเหตุสมผลและลึกกว่าแค่ 2 ระดับ ฉันคิดว่าไลบรารี / โปรเจ็กต์ที่ใหญ่กว่านั้นต้องการการซ้อนที่ลึกกว่า (ฉันเกลียดชื่อคลาสเช่น ExtraLongClassNameBecauseEveryThingIsInTheSameNameSpace ... จากนั้นคุณสามารถใส่ทุกอย่างลงในเนมสเปซส่วนกลางได้เช่นกัน)

อัปเดต 3 - สรุป

ส่วนใหญ่บอกว่า "ไม่ต้องทำ" แต่ ... แม้บูสต์จะมีการสร้างรังที่ลึกขึ้นแล้วหนึ่งหรือสองระดับ ใช่มันคือไลบรารี แต่: หากคุณต้องการโค้ดที่ใช้ซ้ำได้ - ให้ถือว่ารหัสของคุณเองเหมือนกับไลบรารีที่คุณจะให้คนอื่น ฉันยังใช้การซ้อนที่ลึกขึ้นเพื่อจุดประสงค์ในการค้นหาโดยใช้เนมสเปซ


3
เป็นการใช้namespaceคีย์เวิร์ดในทางที่ผิดหรือไม่?
Nawaz

4
เนมสเปซและระบบโมดูล c # / java ไม่ได้ตอบสนองวัตถุประสงค์เดียวกันดังนั้นคุณไม่ควรพยายามใช้มันในลักษณะเดียวกัน และไม่ไม่มีไวยากรณ์ที่ง่ายกว่านี้เพียงแค่ใช้เพียงเล็กน้อยก็ไม่มีเหตุผลที่จะจัดหาไวยากรณ์เพื่อทำให้สิ่งต่างๆง่ายขึ้นซึ่งไม่ได้มีไว้เพื่อทำ
PlasmaHH

@PlasmaHH ... ดังนั้นจุดอ่อนคือโครงสร้างที่ขาดหายไปของ std lib ของ C ++? (ดูตัวอย่างง่ายๆของฉันในการอัปเดต)
Beachwalker

@Stegi: หากคุณสามารถให้ข้อโต้แย้งที่ชัดเจนว่าเหตุใดจึงหายไปและประโยชน์ที่เป็นรูปธรรมที่เราจะได้รับจากโครงสร้างดังกล่าวเราสามารถพูดถึงจุดอ่อนที่อาจเกิดขึ้นได้ จนถึงตอนนั้นฉันจะเรียกว่า javas ไม่มีที่สิ้นสุดของแพ็กเกจที่สร้างความสับสนให้ดีที่สุด
PlasmaHH

3
@PlasmaHH Intellisense และตัวช่วยอื่น ๆ สำหรับ / หลังส่วนหัว (แพ็คเกจ) รวม โปรเจ็กต์ขนาดใหญ่ภายใน บริษัท เดียวอาจต้องการการซ้อนกันมากกว่าหนึ่งรายการ (เช่น vw :: golflib :: io) เพื่อให้ได้คำชี้แจงที่ชัดเจนว่าเนมสเปซมี "ขอบเขต" อะไรบ้าง คุณสามารถใช้ vw :: แต่ถ้าต้องการใช้เนมสเปซเพื่อหลีกเลี่ยงการปะทะกันทำไมถึงประกาศที่น่ากลัว? สิ่งนี้จะจบลงด้วยจุดที่ไม่มีใครใช้มันหรือเพียงแค่ใช้เนมสเปซที่มีความลึก (เช่นเดียวกับที่แนะนำ)
Beachwalker

คำตอบ:


138

C ++ 17 อาจทำให้นิยามเนมสเปซที่ซ้อนกันง่ายขึ้น:

namespace A::B::C {
}

เทียบเท่ากับ

namespace A { namespace B { namespace C {
} } }

ดู (8) บนหน้าเนมสเปซบน cppreference:
http://en.cppreference.com/w/cpp/language/namespace


5
... เปิดใช้งานโดยสวิตช์คอมไพเลอร์/std:c++latest
sunny moon

4
โปรดทราบว่าหากคุณจะใช้/std:c++latestใน Visual Studio 2015 และใช้ Boost คุณอาจพบข้อผิดพลาดของคอมไพเลอร์ที่ลึกลับมากเมื่อคุณรวมส่วนหัว Boost ไว้ ฉันประสบปัญหานี้ตามที่อธิบายไว้ในคำถาม StackOverflow
Vivit

1
ใช้งานได้เหมือนเดิมเนมสเปซ A :: B :: C ฉันได้ทดสอบกับ g ++ - 6.0
ervinbosenbacher


17

ฉันสนับสนุนคำตอบของ peterchenอย่างเต็มที่แต่ต้องการเพิ่มบางอย่างที่ตอบคำถามส่วนอื่นของคุณ

การประกาศเนมสเปซเป็นหนึ่งในกรณีที่หายากมากใน C ++ ที่ฉันชอบใช้#defines

#define MY_COMPANY_BEGIN  namespace MyCompany { // begin of the MyCompany namespace
#define MY_COMPANY_END    }                     // end of the MyCompany namespace
#define MY_LIBRARY_BEGIN  namespace MyLibrary { // begin of the MyLibrary namespace
#define MY_LIBRARY_END    }                     // end of the MyLibrary namespace

นอกจากนี้ยังช่วยขจัดความจำเป็นในการแสดงความคิดเห็นที่อยู่ใกล้วงเล็บปีกกาปิดของเนมสเปซ (คุณเคยเลื่อนลงไปที่ด้านล่างของไฟล์ต้นฉบับขนาดใหญ่และพยายามเพิ่ม / ลบ / ปรับสมดุลวงเล็บที่ไม่มีความคิดเห็นเกี่ยวกับวงเล็บปีกกาที่ปิดขอบเขตใดไม่สนุก .).

MY_COMPANY_BEGIN
MY_LIBRARY_BEGIN

class X { };

class Y { };

MY_LIBRARY_END
MY_COMPANY_END

หากคุณต้องการใส่การประกาศเนมสเปซทั้งหมดในบรรทัดเดียวคุณสามารถทำได้เช่นกันด้วยเวทมนตร์ก่อนตัวประมวลผล (ค่อนข้างน่าเกลียด):

// helper macros for variadic macro overloading
#define VA_HELPER_EXPAND(_X)                    _X  // workaround for Visual Studio
#define VA_COUNT_HELPER(_1, _2, _3, _4, _5, _6, _Count, ...) _Count
#define VA_COUNT(...)                           VA_HELPER_EXPAND(VA_COUNT_HELPER(__VA_ARGS__, 6, 5, 4, 3, 2, 1))
#define VA_SELECT_CAT(_Name, _Count, ...)       VA_HELPER_EXPAND(_Name##_Count(__VA_ARGS__))
#define VA_SELECT_HELPER(_Name, _Count, ...)    VA_SELECT_CAT(_Name, _Count, __VA_ARGS__)
#define VA_SELECT(_Name, ...)                   VA_SELECT_HELPER(_Name, VA_COUNT(__VA_ARGS__), __VA_ARGS__)

// overloads for NAMESPACE_BEGIN
#define NAMESPACE_BEGIN_HELPER1(_Ns1)             namespace _Ns1 {
#define NAMESPACE_BEGIN_HELPER2(_Ns1, _Ns2)       namespace _Ns1 { NAMESPACE_BEGIN_HELPER1(_Ns2)
#define NAMESPACE_BEGIN_HELPER3(_Ns1, _Ns2, _Ns3) namespace _Ns1 { NAMESPACE_BEGIN_HELPER2(_Ns2, _Ns3)

// overloads for NAMESPACE_END
#define NAMESPACE_END_HELPER1(_Ns1)               }
#define NAMESPACE_END_HELPER2(_Ns1, _Ns2)         } NAMESPACE_END_HELPER1(_Ns2)
#define NAMESPACE_END_HELPER3(_Ns1, _Ns2, _Ns3)   } NAMESPACE_END_HELPER2(_Ns2, _Ns3)

// final macros
#define NAMESPACE_BEGIN(_Namespace, ...)    VA_SELECT(NAMESPACE_BEGIN_HELPER, _Namespace, __VA_ARGS__)
#define NAMESPACE_END(_Namespace, ...)      VA_SELECT(NAMESPACE_END_HELPER,   _Namespace, __VA_ARGS__)

ตอนนี้คุณสามารถทำได้:

NAMESPACE_BEGIN(Foo, Bar, Baz)

class X { };

NAMESPACE_END(Baz, Bar, Foo) // order doesn't matter, NAMESPACE_END(a, b, c) would work equally well

Foo::Bar::Baz::X x;

สำหรับการซ้อนที่ลึกกว่าสามระดับคุณจะต้องเพิ่มมาโครตัวช่วยจนถึงจำนวนที่ต้องการ


เท่าที่ฉันไม่ชอบ#defineฉันค่อนข้างประทับใจกับเวทย์มนตร์ก่อนตัวประมวลผลนั้น ... เฉพาะในกรณีที่ฉันไม่ต้องเพิ่มมาโครตัวช่วยเพิ่มเติมเพื่อการทำรังที่ลึกขึ้น ... ดีฉันจะไม่ใช้มันต่อไป .. .
galdin

13

เนมสเปซ C ++ ใช้เพื่อจัดกลุ่มอินเทอร์เฟซไม่ใช่เพื่อแบ่งส่วนประกอบหรือแสดงการแบ่งทางการเมือง

มาตรฐานดังกล่าวไม่ได้รับอนุญาตให้ใช้เนมสเปซเหมือน Java ตัวอย่างเช่นนามแฝงเนมสเปซเป็นวิธีการใช้ชื่อเนมสเปซแบบฝังลึกหรือแบบยาวได้อย่างง่ายดาย

namespace a {
namespace b {
namespace c {}
}
}

namespace nsc = a::b::c;

แต่namespace nsc {}จะเป็นข้อผิดพลาดเนื่องจากสามารถกำหนดเนมสเปซได้โดยใช้เนมสเปซ - ชื่อเดิมเท่านั้น โดยเฉพาะอย่างยิ่งสิ่งที่ทำให้มาตรฐานง่ายสำหรับผู้ใช้ของห้องสมุดดังกล่าว แต่ยากสำหรับimplementer สิ่งนี้กีดกันผู้คนจากการเขียนสิ่งเหล่านี้ แต่จะช่วยลดผลกระทบหากพวกเขาทำ

คุณควรมีหนึ่งเนมสเปซต่ออินเทอร์เฟซที่กำหนดโดยชุดของคลาสและฟังก์ชันที่เกี่ยวข้อง อินเทอร์เฟซย่อยภายในหรือทางเลือกอาจเข้าสู่เนมสเปซที่ซ้อนกัน แต่ความลึกมากกว่าสองระดับควรเป็นธงสีแดงที่ร้ายแรงมาก

พิจารณาใช้อักขระขีดล่างและคำนำหน้าตัวระบุในกรณีที่::ไม่จำเป็นต้องใช้ตัวดำเนินการ


17
ตกลงแล้ว Windows :: UI :: Xaml และ Windows :: UI :: Xaml :: Controls :: Primitives namespaces ในการพัฒนา Win8 ล่ะ ฉันคิดว่าการใช้เนมสเปซของ Microsoft นั้นสมเหตุสมผลและลึกกว่าแค่ 2 ระดับ
Beachwalker

2
การใช้น้อยกว่า 2 ระดับเป็นธงสีแดงและการใช้ 3 หรือ 4 ก็ทำได้ดี การพยายามบรรลุลำดับชั้นของเนมสเปซแบบแบนเมื่อไม่สมเหตุสมผลจะเอาชนะจุดประสงค์ของเนมสเปซ - หลีกเลี่ยงการปะทะกันของชื่อ ฉันยอมรับว่าคุณควรมีหนึ่งระดับสำหรับอินเทอร์เฟซและอีกระดับหนึ่งสำหรับอินเทอร์เฟซย่อยและอินเทอร์เฟซ แต่รอบ ๆ นั้นคุณต้องมีอย่างน้อยอีกหนึ่งระดับสำหรับเนมสเปซของ บริษัท (สำหรับ บริษัท ขนาดเล็กถึงขนาดกลาง) หรือสองระดับสำหรับ บริษัท และแผนก (สำหรับ บริษัท ใหญ่ ๆ ) มิฉะนั้นเนมสเปซของอินเทอร์เฟซของคุณจะปะทะกับอินเทอร์เฟซอื่นที่มีชื่อเดียวกันซึ่งพัฒนาขึ้นที่อื่น
Kaiserludi

@ Kaiserludi ข้อดีทางเทคนิคของcompany::divisionover company_divisionคืออะไร?
Potatoswatter

@Potatoswatter Inside company :: anotherDivsion คุณสามารถใช้ 'division' ที่สั้นกว่าได้ เพื่ออ้างถึง บริษัท :: แผนกแม้จะอยู่ในส่วนหัวซึ่งคุณควรหลีกเลี่ยงการสร้างเนมสเปซระดับสูงที่เป็นมลพิษโดยการใช้ 'การใช้เนมสเปซ' นอกเนมสเปซของ บริษัท คุณยังสามารถทำ "ใช้ บริษัท เนมสเปซ" ได้ เมื่อชื่อการแบ่งไม่ชนกับเนมสเปซอื่น ๆ ในขอบเขตของคุณ แต่เมื่อชื่ออินเทอร์เฟซภายในเนมสเปซบางส่วนเกิดการชนกันคุณจึงไม่สามารถ "ใช้เนมสเปซ company_division;" ได้
Kaiserludi

3
@ Potatoswatter ประเด็นก็คือคุณสามารถใช้งานได้ฟรี (company :: division ไม่ยาวไปกว่า company_division) และไม่จำเป็นต้องกำหนดนามแฝงเนมสเปซเพิ่มเติมก่อนเพื่อใช้งาน
Kaiserludi

7

ไม่และโปรดอย่าทำเช่นนั้น

จุดประสงค์ของเนมสเปซคือการแก้ปัญหาความขัดแย้งในเนมสเปซส่วนกลางเป็นหลัก

จุดประสงค์รองคือการย่อสัญลักษณ์ในท้องถิ่น เช่นUpdateUIวิธีการที่ซับซ้อนอาจใช้using namespace WndUIสัญลักษณ์ที่สั้นกว่า

ฉันอยู่ในโปรเจ็กต์ 1.3MLoc และเนมสเปซเดียวที่เรามีคือ:

  • ไลบรารี COM ภายนอกที่นำเข้า (ส่วนใหญ่เพื่อแยกความขัดแย้งส่วนหัวระหว่าง #importและ#include windows.h)
  • เนมสเปซ "API สาธารณะ" ระดับหนึ่งสำหรับบางแง่มุม (UI, การเข้าถึง DB เป็นต้น)
  • "Implementation Detail" เนมสเปซที่ไม่ได้เป็นส่วนหนึ่งของ API สาธารณะ (เนมสเปซที่ไม่ระบุชื่อใน. cpp ของหรือModuleDetailHereBeTygersเนมสเปซใน libs ส่วนหัวเท่านั้น)
  • enums เป็นปัญหาใหญ่ที่สุดในประสบการณ์ของฉัน พวกเขาก่อมลพิษอย่างบ้าคลั่ง
  • ฉันยังรู้สึกว่าเนมสเปซเยอะเกินไป

ในโครงการนี้ชื่อคลาส ฯลฯ ใช้รหัส "ภูมิภาค" สองหรือสามตัวอักษร (เช่นCDBNodeแทนDB::CNode) หากคุณต้องการอย่างหลังก็มีที่ว่างสำหรับเนมสเปซ "สาธารณะ" ระดับที่สอง แต่ไม่มีอีกแล้ว

enums เฉพาะคลาส ฯลฯ สามารถเป็นสมาชิกของคลาสเหล่านั้นได้ (แม้ว่าฉันจะเห็นด้วยว่าสิ่งนี้ไม่ดีเสมอไปและบางครั้งก็ยากที่จะบอกว่าคุณควร)

แทบไม่จำเป็นต้องมีเนมสเปซ "บริษัท " เช่นกันยกเว้นว่าคุณกำลังมีปัญหาใหญ่กับไลบรารีของบุคคลที่สามที่แจกจ่ายเป็นไบนารีอย่าให้เนมสเปซของตัวเองและไม่สามารถใส่ลงในเนมสเปซเดียวได้โดยง่าย (เช่นในไบนารี การกระจาย). อย่างไรก็ตามจากประสบการณ์ของฉันการบังคับให้พวกเขาเข้าสู่เนมสเปซนั้นทำได้ง่ายกว่ามาก


[แก้ไข]ตามคำถามติดตามผลของ Stegi:

ตกลงแล้ว Windows :: UI :: Xaml และ Windows :: UI :: Xaml :: Controls :: Primitives namespaces ในการพัฒนา Win8 ล่ะ ฉันคิดว่าการใช้เนมสเปซของ Microsoft นั้นสมเหตุสมผลและลึกกว่าแค่ 2 ระดับ

ขออภัยถ้าฉันไม่ชัดเจนพอ: สองระดับไม่ใช่ขีด จำกัด ยากและอื่น ๆ ก็ไม่ได้เลวร้ายอย่างแท้จริง ฉันแค่อยากจะชี้ให้เห็นว่าคุณแทบจะไม่ต้องการมากกว่าสองจากประสบการณ์ของฉันแม้แต่ในฐานรหัสขนาดใหญ่ การทำรังให้ลึกขึ้นหรือตื้นขึ้นเป็นการแลกเปลี่ยน

ตอนนี้กรณีของ Microsoft มีเนื้อหาที่แตกต่างออกไป น่าจะเป็นทีมที่ใหญ่กว่ามากและรหัสทั้งหมดคือไลบรารี

ฉันคิดว่า Microsoft กำลังเลียนแบบความสำเร็จของ. NET Library ซึ่งเนมสเปซมีส่วนช่วยในการค้นพบไลบรารีที่กว้างขวาง (.NET มีประมาณ 18000ประเภท)

ฉันคิดต่อไปว่ามีสัญลักษณ์ (ลำดับขนาดของ) ที่เหมาะสมที่สุดในเนมสเปซ พูด 1 ไม่สมเหตุสมผล 100 เสียงถูกต้อง 10,000 ชัดเจนมาก


TL; DR:มันเป็นการแลกเปลี่ยนและเราไม่มีตัวเลขที่ยาก เล่นให้ปลอดภัยอย่าหักโหมในทิศทางใด ๆ "อย่าทำอย่างนั้น" มาจากข้อความ "คุณมีปัญหาเกี่ยวกับเรื่องนั้นฉันมีปัญหากับสิ่งนั้นและฉันไม่เห็นเหตุผลว่าทำไมคุณถึงต้องการ"


8
ตกลงแล้ว Windows :: UI :: Xaml และ Windows :: UI :: Xaml :: Controls :: Primitives namespaces ในการพัฒนา Win8 ล่ะ ฉันคิดว่าการใช้เนมสเปซของ Microsoft นั้นสมเหตุสมผลและลึกกว่าแค่ 2 ระดับ
Beachwalker

2
หากฉันต้องการค่าคงที่การเข้าถึงทั่วโลกฉันต้องการใส่ค่าเหล่านี้ในเนมสเปซที่มีชื่อเหมือนConstantsจากนั้นสร้างเนมสเปซที่ซ้อนกันด้วยชื่อที่เหมาะสมเพื่อจัดหมวดหมู่ค่าคงที่ ถ้าจำเป็นฉันจะใช้เนมสเปซเพิ่มเติมเพื่อป้องกันการชนกันของชื่อ นี้Constantsnamespace เป็นตัวเองที่มีอยู่ในการจับทั้งหมด namespace SysDataรหัสระบบของโปรแกรมที่มีชื่อเช่น นี้จะสร้างชื่อที่มีคุณสมบัติครบถ้วนที่มีสามหรือสี่ namespaces (เช่นSysData::Constants::ErrorMessages, SysData::Constants::Ailments::BitflagsหรือSysData::Defaults::Engine::TextSystem)
Justin Time - คืนสถานะ Monica

1
เมื่อต้องการค่าคงที่ในโค้ดจริงฟังก์ชันใด ๆ ที่ต้องการจะใช้usingคำสั่งเพื่อสร้างชื่อที่เหมาะสมเพื่อลดความเป็นไปได้ของชื่อที่ขัดแย้งกัน ฉันพบว่ามันช่วยเพิ่มความสามารถในการอ่านและช่วยจัดทำเอกสารอ้างอิงของบล็อกโค้ดที่ระบุ นอกเหนือจากค่าคงที่ฉันมักจะพยายามเก็บไว้เป็นสองเนมสเปซถ้าเป็นไปได้ (เช่นSysData::ExceptionsและSysData::Classes)
Justin Time - คืนสถานะ Monica ใน

2
โดยรวมแล้วฉันจะบอกว่าในกรณีทั่วไปควรใช้เนมสเปซที่ซ้อนกันให้น้อยที่สุด แต่ถ้าคุณต้องการโกลบอลอ็อบเจกต์ด้วยเหตุผลบางประการ (ไม่ว่าจะคงที่หรือเปลี่ยนแปลงได้ควรใช้เนมสเปซที่ซ้อนกันหลายตัว เพื่อแยกเป็นหมวดหมู่ที่เหมาะสมทั้งเพื่อบันทึกการใช้งานและลดการชนกันของชื่อที่อาจเกิดขึ้น
Justin Time - คืนสถานะ Monica

2
-1 สำหรับ "โปรดอย่าทำเช่นนี้" โดยมีวัตถุประสงค์เหตุผล (แม้จะมีการชี้แจงในภายหลัง) ภาษารองรับเนมสเปซที่ซ้อนกันและโปรเจ็กต์อาจมีเหตุผลที่ดีในการใช้ การอภิปรายถึงเหตุผลที่เป็นไปได้และข้อเสียที่เป็นรูปธรรมและวัตถุประสงค์ในการทำเช่นนั้นจะทำให้การลงคะแนนของฉันกลับกัน
TypeIA

5

นี่คือคำพูดจากเอกสาร Lzz (Lazy C ++):

Lzz รู้จักโครงสร้าง C ++ ต่อไปนี้:

นิยามเนมสเปซ

เนมสเปซที่ไม่มีชื่อและการประกาศที่ปิดล้อมทั้งหมดจะถูกส่งออกไปยังไฟล์ต้นฉบับ กฎนี้จะแทนที่กฎอื่น ๆ ทั้งหมด

ชื่อของเนมสเปซที่ระบุชื่ออาจมีคุณสมบัติ

   namespace A::B { typedef int I; }

เทียบเท่ากับ:

   namespace A { namespace B { typedef int I; } }

แน่นอนว่าคุณภาพของแหล่งที่มาที่ขึ้นอยู่กับเครื่องมือดังกล่าวเป็นที่ถกเถียงกัน ... ฉันจะบอกว่ามันเป็นความอยากรู้อยากเห็นมากกว่าแสดงให้เห็นว่าโรคทางไวยากรณ์ที่เกิดจาก C ++ สามารถมีได้หลายรูปแบบ (ฉันก็มีของฉันเหมือนกัน ... )


2

ทั้งสองมาตรฐาน (C ++ 2003 และ C ++ 11) มีความชัดเจนมากว่าชื่อของเนมสเปซเป็นตัวระบุ ซึ่งหมายความว่าจำเป็นต้องมีส่วนหัวที่ซ้อนกันอย่างชัดเจน

ความประทับใจของฉันที่ว่านี่ไม่ใช่เรื่องใหญ่ที่จะอนุญาตให้วางตัวระบุที่มีคุณสมบัติเหมาะสมนอกจากชื่อธรรมดาของเนมสเปซ แต่ด้วยเหตุผลบางประการจึงไม่อนุญาต


2

กระดาษนี้ครอบคลุมหัวเรื่องค่อนข้างดี: Namespace Paper

ซึ่งโดยทั่วไปจะทำให้สิ่งนี้เดือด ยิ่งเนมสเปซของคุณยาวเท่าไหร่โอกาสที่ผู้คนจะใช้ไฟล์using namespaceคำสั่งนั้นก็มีมากขึ้นเท่านั้น

ดังนั้นเมื่อดูรหัสต่อไปนี้คุณจะเห็นตัวอย่างที่จะทำร้ายคุณ:

namespace abc { namespace testing {
    class myClass {};
}}

namespace def { namespace testing {
    class defClass { };
}}

using namespace abc;
//using namespace def;

int main(int, char**) {
    testing::myClass classInit{};
}

รหัสนี้จะคอมไพล์ได้ดีอย่างไรก็ตามหากคุณไม่ใส่ข้อคิดเห็นในบรรทัด //using namespace def;เนมสเปซ "การทดสอบ" จะคลุมเครือและคุณจะมีการชนกันของการตั้งชื่อ ซึ่งหมายความว่าฐานรหัสของคุณสามารถเปลี่ยนจากเสถียรไปเป็นไม่เสถียรได้โดยรวมไลบรารีของบุคคลที่สาม

ใน C # แม้ว่าคุณจะใช้งานusing abc;และusing def;คอมไพเลอร์สามารถรับรู้ได้ว่าtesting::myClassหรือแม้กระทั่งmyClassอยู่ในabc::testingเนมสเปซเท่านั้น แต่ C ++ จะไม่รู้จักสิ่งนี้และตรวจพบว่าเป็นการชนกัน


0

ใช่คุณจะต้องทำเช่น

namespace A{ 
namespace B{
namespace C{} 
} 
}

อย่างไรก็ตามคุณกำลังพยายามใช้เนมสเปซในลักษณะที่ไม่ควรใช้ ตรวจสอบคำถามนี้บางทีคุณอาจพบว่ามีประโยชน์


0

คุณสามารถใช้ไวยากรณ์นี้:

namespace MyCompany {
  namespace MyModule {
    namespace MyModulePart //e.g. Input {
      namespace MySubModulePart {
        namespace ... {
          class MyClass;
        }
      }
    }
  }
}

// Here is where the magic happens
class MyCompany::MyModule::MyModulePart::MySubModulePart::MyYouGetTheIdeaModule::MyClass {
    ...
};

หมายเหตุ: รูปแบบนี้ถูกต้องแม้จะอยู่ใน c ++ 98 และมันเกือบจะคล้ายกับสิ่งที่มีอยู่ใน C ++ 17 กับคำจำกัดความ namespace ซ้อนกัน

มีความสุขอย่างไม่ต้องสงสัย!

แหล่งที่มา:


นั่นคือ sytax ที่กล่าวถึงในคำถามที่มีการค้นหาโซลูชันที่ดีกว่าแทน ตอนนี้ด้วย C ++ 17 เป็นทางเลือกที่ใช้ได้ตามที่ระบุไว้ในคำตอบที่ยอมรับ ขออภัยไม่ได้อ่านคำถามและคำตอบ
Beachwalker

@Beachwalker อย่าจมอยู่กับไวยากรณ์ การประกาศเนมสเปซข้างต้นอาจเป็นเช่นเดียวกับในคำตอบที่ยอมรับ ประเด็นหลักที่ฉันต้องการเน้นด้วยคำตอบนี้คือสิ่งที่ OP บอกว่าเขาพลาดและสิ่งที่ฉันทำด้านล่างเนมสเปซนั้นยุ่งเหยิง เท่าที่ฉันเห็นทุกคนดูเหมือนจะมุ่งเน้นไปที่การประกาศทุกอย่างภายในเนมสเปซในขณะที่คำตอบของฉันจะพาคุณออกจากความยุ่งเหยิงที่ซ้อนกันและฉันแน่ใจว่า OP จะชื่นชมไวยากรณ์นี้หากมีใครพูดถึงเมื่อ 4 ปีก่อนเมื่อคำถามนี้ ถูกถามก่อน
smac89

-1

[แก้ไข:]
เนื่องจาก c ++ 17 เนมสเปซที่ซ้อนกันได้รับการสนับสนุนเป็นคุณลักษณะภาษามาตรฐาน ( https://en.wikipedia.org/wiki/C%2B%2B17 ) ณ ตอนนี้ฟีเจอร์นี้ยังไม่รองรับใน g ++ 8 แต่สามารถพบได้ในคอมไพเลอร์ clang ++ 6.0


[สรุป:]
ใช้clang++6.0 -std=c++17เป็นคำสั่งคอมไพล์เริ่มต้นของคุณ จากนั้นทุกอย่างจะทำงานได้ดี - และคุณจะสามารถรวบรวมnamespace OuterNS::InnerNS1::InnerNS2 { ... }ไฟล์ของคุณได้


[คำตอบเดิม:]
เนื่องจากคำถามนี้เก่าไปหน่อยฉันจะถือว่าคุณได้ดำเนินการต่อไป แต่สำหรับคนอื่น ๆ ที่ยังคงมองหาคำตอบฉันได้แนวคิดต่อไปนี้:

บัฟเฟอร์ Emacs แสดงไฟล์หลักไฟล์เนมสเปซคำสั่งคอมไพล์ / ผลลัพธ์และการดำเนินการบรรทัดคำสั่ง

(ฉันจะสร้างโฆษณาให้ Emac ที่นี่ได้ไหม :)?) การโพสต์รูปภาพนั้นง่ายกว่าและอ่านง่ายกว่าการโพสต์โค้ด ฉันไม่ได้ตั้งใจที่จะจัดหาเรือทอดสมอแบบเต็มรูปแบบในทุกกรณี แต่ฉันตั้งใจจะให้แรงบันดาลใจ (ฉันสนับสนุน C # โดยสิ้นเชิงและรู้สึกว่าในหลาย ๆ กรณี C ++ ควรใช้คุณสมบัติ OOP บางอย่างเนื่องจาก C # ได้รับความนิยมเนื่องจากความสะดวกในการใช้งานเมื่อเทียบกัน)


อัปเดต: เนื่องจาก C ++ 17 มีการซ้อนเนมสเปซ ( nuonsoft.com/blog/2017/08/01/c17-nested-namespaces ) ดูเหมือนว่าคำตอบของฉันจะไม่เกี่ยวข้องอีกต่อไปเว้นแต่คุณจะใช้ C ++ เวอร์ชันเก่ากว่า .
ワイきんぐ

1
เท่าที่ฉันรัก Emacs การโพสต์ภาพไม่เหมาะอย่างยิ่ง ซึ่งจะหลีกเลี่ยงการค้นหาข้อความ / การจัดทำดัชนีและยังทำให้คำตอบของคุณเข้าถึงได้ยากสำหรับผู้เยี่ยมชมที่มีความบกพร่องทางสายตา
Heinrich สนับสนุน Monica
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.