Czy istnieje lepszy sposób wyrażania zagnieżdżonych przestrzeni nazw w C ++ w nagłówku

99

Przerzuciłem się z C ++ na Javę i C # i uważam, że użycie przestrzeni nazw / pakietów jest tam znacznie lepsze (dobrze zorganizowane). Potem wróciłem do C ++ i próbowałem użyć przestrzeni nazw w ten sam sposób, ale wymagana składnia jest okropna w pliku nagłówkowym.

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

Poniższe również wydaje mi się dziwne (aby uniknąć głębokiego wcięcia):

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

Czy istnieje krótszy sposób wyrażenia powyższej rzeczy? Brakuje mi czegoś takiego

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

Aktualizacja

Ok, niektórzy twierdzą, że koncepcja użycia w Javie / C # i C ++ jest inna. Naprawdę? Myślę, że (dynamiczne) ładowanie klas nie jest jedynym celem przestrzeni nazw (jest to bardzo techniczna perspektywa). Dlaczego nie miałbym go używać ze względu na czytelność i strukturę, np. Pomyśl o „IntelliSense”.

Obecnie nie ma logiki / spoiwa między przestrzenią nazw a tym, co można tam znaleźć. Java i C # robią to znacznie lepiej ... Po co dołączać <iostream>i mieć przestrzeń nazw std? Ok, jeśli powiesz, że logika powinna opierać się na nagłówku, dlaczego #include nie używa przyjaznej składni „IntelliSense”, takiej jak #include <std::io::stream>lub <std/io/stream>? Myślę, że brakująca strukturalizacja w domyślnych bibliotekach jest jedną ze słabości C ++ w porównaniu z Javą / C #.

Jeśli wyjątkowość dla zajadłych konfliktów jest jednym punktem (który jest także punktem C # i Java), dobrym pomysłem jest użycie nazwy projektu lub nazwy firmy jako przestrzeni nazw, nie sądzisz?

Z jednej strony mówi się, że C ++ jest najbardziej elastyczny ... ale wszyscy mówili „nie rób tego”? Wydaje mi się, że C ++ może robić wiele rzeczy, ale ma okropną składnię, nawet w przypadku najłatwiejszych rzeczy w wielu przypadkach w porównaniu z C #.

Zaktualizuj 2

Większość użytkowników twierdzi, że tworzenie zagnieżdżenia głębszego niż dwa poziomy jest nonsensem. Ok, a co z przestrzeniami nazw Windows :: UI :: Xaml i Windows :: UI :: Xaml :: Controls :: Primitives w programowaniu pod Win8? Myślę, że użycie przestrzeni nazw przez Microsoft ma sens i jest rzeczywiście głębsze niż tylko 2 poziomy. Myślę, że większe biblioteki / projekty wymagają głębszego zagnieżdżenia (nienawidzę nazw klas, takich jak ExtraLongClassNameBecauseEveryThingIsInTheSameNameSpace ... wtedy też możesz umieścić wszystko w globalnej przestrzeni nazw).

Aktualizacja 3 - Zakończenie

Większość mówi „nie rób tego”, ale ... nawet wzmocnienie ma głębsze zagnieżdżenie niż jeden lub dwa poziomy. Tak, jest to biblioteka, ale: Jeśli chcesz kod wielokrotnego użytku - traktuj swój własny kod jak bibliotekę, którą dałbyś komuś innemu. Używam też głębszego zagnieżdżenia do celów wykrywania przy użyciu przestrzeni nazw.

Beachwalker
źródło
3
Czy to nadużycie namespacesłowa kluczowego?
Nawaz
4
przestrzenie nazw i systemy modułów c # / java nie służą temu samemu celowi, dlatego nie należy próbować ich używać w ten sam sposób. i nie, nie ma prostszej składni, po prostu dlatego, że nie ma sensu dostarczać składni ułatwiającej wykonywanie czynności, które nie są przeznaczone do wykonywania.
PlasmaHH,
@PlasmaHH ... więc słabością jest brak strukturyzacji standardowej biblioteki C ++? (zobacz mój prosty przykład w aktualizacji)
Beachwalker,
@Stegi: Jeśli potrafisz przedstawić rozsądne argumenty, dlaczego go brakuje i jakie solidne korzyści uzyskalibyśmy z takiej strukturyzacji, moglibyśmy porozmawiać o potencjalnych słabościach. Do tego czasu nazwałbym javas niekończące się zagnieżdżanie pakietów w najlepszym razie mylące.
PlasmaHH,
3
@PlasmaHH Intellisense i inne pomocniki do / po włączeniu nagłówka (pakietu). Duże projekty w jednej firmie mogą wymagać więcej niż jednego zagnieżdżenia (np. Vw :: golflib :: io), aby jasno określić, co zawiera przestrzeń nazw w jakim „zakresie”. Cóż, możesz po prostu użyć vw ::, ale jeśli przestrzeń nazw ma być używana do unikania kolizji, dlaczego deklarowanie jest tak okropne? To kończy się tak, że nikt go nie używa lub po prostu używa przestrzeni nazw o głębokości jeden (jak często sugeruje).
Beachwalker

Odpowiedzi:

135

C ++ 17 może uprościć zagnieżdżoną definicję przestrzeni nazw:

namespace A::B::C {
}

jest równa

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

Zobacz (8) na stronie przestrzeni nazw w cppreference:
http://en.cppreference.com/w/cpp/language/namespace

W1M0R
źródło
5
... włączone przez przełącznik kompilatora/std:c++latest
słoneczny księżyc
4
Zwróć uwagę, że jeśli będziesz używać /std:c++latestw programie Visual Studio 2015, a także korzystać z funkcji Boost, możesz napotkać bardzo mistyczne błędy kompilatora po dołączeniu niektórych nagłówków Boost. Napotkałem ten problem, jak opisano w tym pytaniu StackOverflow
Vivit,
1
Działa tak jak jest, przestrzeń nazw A :: B :: C. Testowałem z g ++ - 6,0
ervinbosenbacher
31

Aby uniknąć naprawdę głębokich wcięć, zwykle robię to w ten sposób:

namespace A { namespace B { namespace C
{
    class X
    {
        // ...
    };
}}}
Kurt Hutchinson
źródło
3
JFYI clang-formatnie może tego sformatować, ponieważ pokazujesz clang.llvm.org/docs/ClangFormatStyleOptions.html (NamespaceIndentation)
KindDragon
17

W pełni popieram odpowiedź Peterchena, ale chcę dodać coś, co dotyczy innej części twojego pytania.

Deklarowanie przestrzeni nazw jest jednym z bardzo rzadkich przypadków w C ++, w których lubię używać #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

Eliminuje to również potrzebę umieszczania komentarzy w pobliżu zamykającego nawiasu klamrowego przestrzeni nazw (czy kiedykolwiek przewinąłeś w dół do samego końca dużego pliku źródłowego i próbowałeś dodać / usunąć / zrównoważyć nawiasy klamrowe, w których brakowało komentarzy na temat tego, który nawias zamyka który zakres? .).

MY_COMPANY_BEGIN
MY_LIBRARY_BEGIN

class X { };

class Y { };

MY_LIBRARY_END
MY_COMPANY_END

Jeśli chcesz umieścić wszystkie deklaracje przestrzeni nazw w jednej linii, możesz to również zrobić z odrobiną (dość brzydkiej) magii preprocesora:

// 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__)

Teraz możesz to zrobić:

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;

W przypadku zagnieżdżenia głębszego niż trzy poziomy należy dodać makra pomocnicze do żądanej liczby.

Max Truxa
źródło
#defineChociaż nie lubię tego, jestem pod wrażeniem tej magii preprocesora ... tylko jeśli nie będę musiał dodawać dodatkowych makr pomocniczych do głębszego zagnieżdżania ... ,
galdin
13

Przestrzenie nazw C ++ służą do grupowania interfejsów, a nie do dzielenia komponentów lub wyrażania podziałów politycznych.

Standard robi wszystko, co w jego mocy, aby zabraniać używania przestrzeni nazw w stylu Java. Na przykład aliasy przestrzeni nazw umożliwiają łatwe używanie głęboko zagnieżdżonych lub długich nazw przestrzeni nazw.

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

namespace nsc = a::b::c;

Ale namespace nsc {}wtedy byłby to błąd, ponieważ przestrzeń nazw może być zdefiniowana tylko przy użyciu jej oryginalnej nazwy przestrzeni nazw . Zasadniczo standard ułatwia życie użytkownikowi takiej biblioteki, ale utrudnia wdrażanie . To zniechęca ludzi do pisania takich rzeczy, ale łagodzi skutki, jeśli to zrobią.

Powinieneś mieć jedną przestrzeń nazw na interfejs zdefiniowaną przez zestaw powiązanych klas i funkcji. Wewnętrzne lub opcjonalne interfejsy podrzędne mogą trafiać do zagnieżdżonych przestrzeni nazw. Ale głębokość więcej niż dwa poziomy powinna być bardzo poważną czerwoną flagą.

Rozważ użycie znaków podkreślenia i przedrostków identyfikatorów, jeśli ::operator nie jest potrzebny.

Potatoswatter
źródło
17
Ok, a co z przestrzeniami nazw Windows :: UI :: Xaml i Windows :: UI :: Xaml :: Controls :: Primitives w programowaniu pod Win8? Myślę, że użycie przestrzeni nazw przez Microsoft ma sens i jest rzeczywiście głębsze niż tylko 2 poziomy.
Beachwalker
2
Używanie mniej niż 2 poziomów jest czerwoną flagą, a użycie 3 lub 4 jest całkowicie w porządku. Próba osiągnięcia płaskiej hierarchii przestrzeni nazw, gdy nie ma to sensu, przeczy samemu celowi przestrzeni nazw - unikaniu kolizji nazw. Zgadzam się, że powinieneś mieć jeden poziom dla interfejsu, a drugi dla podinterfejsów i elementów wewnętrznych. Ale wokół tego potrzebujesz co najmniej jeszcze jednego poziomu dla przestrzeni nazw firmy (dla małych i średnich firm) lub dwóch dla firmy i działu (dla dużych firm). W przeciwnym razie przestrzenie nazw interfejsów będą kolidować z przestrzeniami z innych interfejsów o tej samej nazwie opracowanych w innym miejscu
Kaiserludi
@Kaiserludi Jaka jest techniczna przewaga company::divisionnad company_division?
Potatoswatter
@Potatoswatter Inside company :: anotherDivsion możesz po prostu użyć krótszego „podziału”. aby odnieść się do company :: Division nawet w nagłówkach, gdzie należy zdecydowanie unikać zanieczyszczania przestrzeni nazw wyższego poziomu przez użycie „using namespace”. Poza przestrzenią nazw firmy nadal można wykonać operację „using namespace company”; kiedy nazwy działów nie kolidują z żadnymi innymi przestrzeniami nazw w twoim zakresie, ale gdy nazwy interfejsów w niektórych obszarach nazw działów kolidują, więc nie możesz zrobić 'using namespace company_division;'.
Kaiserludi
3
@Potatoswatter Chodzi o to, że dostajesz to praktycznie za darmo (firma :: Division nie jest dłuższe niż company_division) i nie musisz najpierw definiować dodatkowego aliasu przestrzeni nazw, aby z niego korzystać.
Kaiserludi
7

Nie, i proszę, nie rób tego.

Celem przestrzeni nazw jest przede wszystkim rozwiązywanie konfliktów w globalnej przestrzeni nazw.

Dodatkowym celem jest lokalny skrót symboli; np. w złożonej UpdateUImetodzie można using namespace WndUIużyć krótszych symboli.

Pracuję nad projektem 1.3 MLoc i jedyne przestrzenie nazw, które mamy, to:

  • zaimportowane zewnętrzne biblioteki COM (głównie w celu izolowania konfliktów nagłówków między #importi #include windows.h)
  • Jeden poziom przestrzeni nazw „publicznego interfejsu API” dla niektórych aspektów (interfejs użytkownika, dostęp do bazy danych itp.)
  • Przestrzenie nazw „Szczegóły implementacji”, które nie są częścią publicznego interfejsu API (anonimowe przestrzenie nazw w plikach .cpp lub ModuleDetailHereBeTygersprzestrzenie nazw w bibliotekach tylko z nagłówkiem)
  • wyliczenia są największym problemem z mojego doświadczenia. Zanieczyszczają jak szalone.
  • Nadal uważam, że to zbyt wiele przestrzeni nazw

W tym projekcie nazwy klas itp. Używają dwu- lub trzyliterowego kodu regionu (np. CDBNodeZamiast DB::CNode). Jeśli wolisz to drugie, jest miejsce na drugi poziom „publicznych” przestrzeni nazw, ale nic więcej.

Wyliczenia specyficzne dla klasy itp. Mogą być członkami tych klas (chociaż zgadzam się, że nie zawsze jest to dobre i czasami trudno jest powiedzieć, czy powinieneś)

Rzadko też jest potrzebna przestrzeń nazw „firmowa”, chyba że masz duże problemy z bibliotekami innych firm, które są rozprowadzane jako binarne, nie dostarczają własnej przestrzeni nazw i nie można ich łatwo umieścić w jednej (np. W pliku binarnym dystrybucja). Jednak z mojego doświadczenia wynika , że zmuszanie ich do przestrzeni nazw jest znacznie łatwiejsze do wykonania.


[edytuj] Zgodnie z pytaniem uzupełniającym Stegi:

Ok, a co z przestrzeniami nazw Windows :: UI :: Xaml i Windows :: UI :: Xaml :: Controls :: Primitives w programowaniu pod Win8? Myślę, że użycie przestrzeni nazw przez Microsoft ma sens i jest rzeczywiście głębsze niż tylko 2 poziomy

Przepraszam, jeśli nie byłam wystarczająco jasna: dwa poziomy nie są sztywnym limitem, a więcej nie jest wewnętrznie złe. Chciałem tylko zaznaczyć, że rzadko potrzebujesz więcej niż dwóch, z mojego doświadczenia, nawet w przypadku dużej bazy kodu. Zagnieżdżanie głębsze lub płytsze to kompromis.

Teraz sprawa Microsoftu jest prawdopodobnie inna. Przypuszczalnie dużo większy zespół, a cały kod to biblioteka.

Zakładam, że Microsoft naśladuje tutaj sukces biblioteki .NET, w której przestrzenie nazw przyczyniają się do wykrywalności obszernej biblioteki. (.NET ma około 18000 typów).

Zakładałbym ponadto, że w przestrzeni nazw istnieje optymalny (rząd wielkości) symboli. powiedzmy, 1 nie ma sensu, 100 dźwięków dobrze, 10000 to zdecydowanie za dużo.


TL; DR: To kompromis i nie mamy twardych liczb. Graj ostrożnie, nie przesadzaj w żadnym kierunku. „Nie rób tego” pochodzi po prostu z „Masz z tym problemy, miałbym z tym problemy i nie widzę powodu, dla którego byś tego potrzebował”.

peterchen
źródło
8
Ok, a co z przestrzeniami nazw Windows :: UI :: Xaml i Windows :: UI :: Xaml :: Controls :: Primitives w programowaniu pod Win8? Myślę, że użycie przestrzeni nazw przez Microsoft ma sens i jest rzeczywiście głębsze niż tylko 2 poziomy.
Beachwalker
2
Jeśli potrzebuję stałych globalnego dostępu, lubię je umieszczać w przestrzeni nazw o takiej nazwie Constants, a następnie tworzyć zagnieżdżone przestrzenie nazw z odpowiednimi nazwami, aby kategoryzować stałe; w razie potrzeby używam dalszych przestrzeni nazw, aby zapobiec kolizji nazw. Ta Constantsprzestrzeń nazw jest sama w sobie zawarta w przestrzeni nazw typu catch-all dla kodu systemowego programu, o nazwie takiej jak SysData. To tworzy pełną nazwę zawierającą trzy lub cztery przestrzenie nazw (takich jak SysData::Constants::ErrorMessages, SysData::Constants::Ailments::Bitflagslub SysData::Defaults::Engine::TextSystem).
Justin Time - Przywróć Monikę
1
Gdy stałe są wymagane w rzeczywistym kodzie, każda funkcja, która ich potrzebuje, używa usingdyrektywy w celu wprowadzenia odpowiednich nazw, minimalizując możliwość wystąpienia konfliktów nazw. Uważam, że poprawia czytelność i pomaga dokumentować zależności dowolnego bloku kodu. Oprócz stałych staram się, jeśli to możliwe, trzymać go w dwóch przestrzeniach nazw (takich jak SysData::Exceptionsi SysData::Classes).
Justin Time - Przywróć Monikę
2
Ogólnie rzecz biorąc, powiedziałbym, że w ogólnych przypadkach najlepiej jest używać minimalnej liczby zagnieżdżonych przestrzeni nazw, ale jeśli z jakiegoś powodu potrzebujesz obiektów globalnych (stałych lub zmiennych, najlepiej tych pierwszych), należy użyć wielu zagnieżdżonych przestrzeni nazw aby podzielić je na odpowiednie kategorie, zarówno w celu udokumentowania ich użycia, jak i zminimalizowania potencjalnych kolizji nazw.
Justin Time - Przywróć Monikę
2
-1 dla „proszę nie rób tego” bez obiektywnych powodów (pomimo późniejszych wyjaśnień). Język obsługuje zagnieżdżone przestrzenie nazw, a projekt może mieć dobre powody, by ich używać. Dyskusja na temat możliwych takich przyczyn i wszelkich konkretnych, obiektywnych wad takiego postępowania odwróciłaby mój głos negatywny.
TypeIA
5

Oto cytat z dokumentacji Lzz (Lazy C ++):

Lzz rozpoznaje następujące konstrukcje C ++:

definicja przestrzeni nazw

Nienazwana przestrzeń nazw i wszystkie załączone deklaracje są wyprowadzane do pliku źródłowego. Ta reguła ma pierwszeństwo przed wszystkimi innymi.

Nazwa nazwanej przestrzeni nazw może być kwalifikowana.

   namespace A::B { typedef int I; }

jest równa:

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

Oczywiście jakość źródeł zależnych od takich narzędzi jest dyskusyjna ... Powiedziałbym, że to raczej ciekawostka, pokazująca, że ​​choroba składni wywołana przez C ++ może przybierać różne formy (ja też mam swoją ...)

CapelliC
źródło
2

Oba standardy (C ++ 2003 i C ++ 11) jasno mówią, że nazwa przestrzeni nazw jest identyfikatorem. Oznacza to, że wymagane są jawne zagnieżdżone nagłówki.

Mam wrażenie, że nie jest to wielka sprawa, aby umożliwić umieszczenie kwalifikowanego identyfikatora oprócz prostej nazwy przestrzeni nazw, ale z jakiegoś powodu jest to niedozwolone.

Kirill Kobelev
źródło
2

Ten artykuł dość dobrze porusza temat: Namespace Paper

Co w zasadzie sprowadza się do tego. Im dłuższe przestrzenie nazw, tym większa szansa, że ​​ludzie będą używać using namespacedyrektywy.

Patrząc na poniższy kod, możesz zobaczyć przykład, w którym to cię zrani:

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{};
}

Ten kod skompiluje się dobrze, jednak jeśli odkomentujesz wiersz, //using namespace def;wówczas przestrzeń nazw „testing” stanie się niejednoznaczna i wystąpią kolizje nazw. Oznacza to, że baza kodu może zmienić się ze stabilnej na niestabilną, włączając bibliotekę innej firmy.

W C #, nawet jeśli miałbyś używać using abc;i using def;kompilator jest w stanie to rozpoznaćtesting::myClass lub po prostu myClassznajduje się tylko w abc::testingprzestrzeni nazw, ale C ++ nie rozpozna tego i zostanie wykryty jako kolizja.

Wątpliwy
źródło
0

Tak, będziesz musiał to zrobić jak

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

Jednak próbujesz używać przestrzeni nazw w sposób, w jaki nie powinny być używane. Sprawdź to pytanie, może uznasz to za przydatne.

SingerOfTheFall
źródło
0

Możesz użyć tej składni:

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 {
    ...
};

Zwróć uwagę, że ta składnia jest poprawna nawet w C ++ 98 i jest prawie podobna do tego, co jest teraz dostępne w C ++ 17 z zagnieżdżonymi definicjami przestrzeni nazw .

Miłego unnesting!

Źródła:

smac89
źródło
To jest sytax wspomniany w pytaniu, w którym zamiast tego szuka się lepszego rozwiązania. Teraz, w przypadku C ++ 17, jest dostępna ważna alternatywa, jak stwierdzono w zaakceptowanej odpowiedzi. Przepraszamy, głosuj przeciw nie czytaniu pytania i odpowiedzi.
Beachwalker,
@Beachwalker nie dajmy się wciągnąć w składnię. Powyższa deklaracja przestrzeni nazw może równie dobrze być taka sama, jak w zaakceptowanej odpowiedzi. Główną kwestią, którą chciałem podkreślić w tej odpowiedzi, jest to, co powiedział OP, że przegapił, i to, co zrobiłem poniżej tego bałaganu w przestrzeni nazw. O ile widzę, wszyscy wydają się być skupieni na zadeklarowaniu wszystkiego w przestrzeni nazw, podczas gdy moja odpowiedź wyprowadza cię z zagnieżdżonego bałaganu i jestem pewien, że OP doceniłby tę składnię, gdyby ktoś wspomniał o niej 4 lata temu, kiedy to pytanie został zapytany jako pierwszy.
smac89
-1

[EDYCJA:]
Ponieważ zagnieżdżone przestrzenie nazw c ++ 17 są obsługiwane jako standardowa funkcja języka ( https://en.wikipedia.org/wiki/C%2B%2B17 ). Obecnie ta funkcja nie jest obsługiwana w g ++ 8, ale można ją znaleźć w kompilatorze w clang ++ 6.0.


[WNIOSEK:]
Użyj clang++6.0 -std=c++17jako domyślnego polecenia kompilacji. Wtedy wszystko powinno działać dobrze - i będziesz mógł skompilować się namespace OuterNS::InnerNS1::InnerNS2 { ... }w swoich plikach.


[ORYGINALNA ODPOWIEDŹ:]
Ponieważ to pytanie jest trochę stare, zakładam, że poszedłeś dalej. Ale dla innych, którzy wciąż szukają odpowiedzi, wpadłem na następujący pomysł:

Bufory Emacsa pokazujące plik główny, pliki przestrzeni nazw, polecenie / wynik kompilacji i wykonanie z wiersza poleceń.

(Czy mogę zrobić reklamę dla Emacsa tutaj :)?) Umieszczanie obrazu jest o wiele łatwiejsze i bardziej czytelne niż po prostu kod pocztowy. Nie mam zamiaru przedstawiać wyczerpującej odpowiedzi na wszystkie narożne sprawy, po prostu chciałem dać trochę inspiracji. (Całkowicie popieram C # i uważam, że w wielu przypadkach C ++ powinien przyjąć pewne funkcje OOP, ponieważ C # jest popularny głównie ze względu na porównywalną łatwość użycia).

ワ イ き ん ぐ
źródło
Aktualizacja: ponieważ C ++ 17 ma zagnieżdżone przestrzenie nazw ( nuonsoft.com/blog/2017/08/01/c17-nested-namespaces ), wydaje się, że moja odpowiedź nie jest już aktualna , chyba że używasz starszych wersji C ++ .
ワ イ き ん ぐ
1
Mimo że uwielbiam Emacsa, publikowanie obrazu nie jest idealne. Unika wyszukiwania / indeksowania tekstu, a także utrudnia dostęp do odpowiedzi osobom niedowidzącym.
Heinrich wspiera Monikę