Meine Bibliothek verwendet mehrere verschachtelte Namespaces, die wie folgt aussehen:
%Vor%Der Namespace "Utilities" enthält nützliche Erweiterungen für jede der Klassen, die nicht in der eigentlichen Klasse enthalten sein dürfen.
Der Namensraum "Bibliotheksname" ist notwendig, weil damit weitgefasste Konflikte mit anderen Bibliotheken vermieden werden. Der Namensraum "Utilities" ist notwendig, um die Art der Mehrdeutigkeit zu vermeiden, die sich aus Dinge wie diese , und die darin enthaltenen" Class name "-Namespaces vermeiden Namenskonflikte zwischen Dienstprogrammen, die für ähnliche Klassen geschrieben wurden.
Trotzdem ist es in der Praxis immer noch ein enormer Ärger. Nehmen Sie zum Beispiel Folgendes:
%Vor%Das lässt mich denken, dass ich etwas ernsthaft falsch mache. Gibt es einen einfacheren Weg, Dinge organisiert zu halten, intuitiv und eindeutig?
Sehen Sie sich an, wie die Standardbibliothek (oder der Boost) organisiert ist. Fast alles befindet sich innerhalb des einzelnen Namensraums std
. Es gibt nur wenig zu gewinnen, wenn man alles in seinen eigenen Namensraum legt.
Boost stellt meiste Dinge in boost
zur Verfügung, während große Bibliotheken einen einzelnen Unternamespace erhalten (zB boost::mpl
oder boost::filesystem
). Und Bibliotheken definieren häufig einen einzelnen aux
Subnamespace für interne Implementierungsdetails.
Sie sehen jedoch normalerweise keine tiefgründigen oder feinkörnigen Namespace-Hierarchien, da sie nur mühsam arbeiten und von diesen wenig bis gar nicht profitieren.
Hier sind ein paar gute Faustregeln:
Hilfsfunktionen, die sich auf eine bestimmte Klasse beziehen, sollten sich im selben Namespace befinden wie die Klasse, damit ADL funktionieren kann. Dann brauchen Sie den Namen der Hilfsfunktion beim Aufruf nicht zu qualifizieren. (So, wie Sie sort
anstelle von std::sort
für Iteratoren aufrufen können, die in std
definiert sind.)
Denken Sie bei allem anderen daran, dass der Zweck von Namespaces ist, Namenskonflikte zu vermeiden und nicht viel mehr. Daher sollte sich Ihre gesamte Bibliothek im a Namespace befinden, um Konflikte mit Benutzercode zu vermeiden. Innerhalb dieses Namespaces besteht jedoch kein technischer Bedarf für weitere Unternamespaces, es sei denn, Sie möchten kollidierende Namen einführen.
Vielleicht möchten Sie die Interna Ihrer Bibliothek in einen Sub-Namespace unterteilen, damit Benutzer sie nicht versehentlich aus dem Hauptnamensraum abholen, ähnlich wie Boost's aux
.
Aber im Allgemeinen würde ich so wenig verschachtelte Namespaces wie möglich vorschlagen.
Und schließlich tendiere ich dazu, kurze, leicht zu typisierende und leicht lesbare Namen für meine Namespaces zu verwenden (auch hier ist std
ein gutes Beispiel dafür. Kurz und bündig, und fast immer ohne weitere verschachtelte Namespaces, so dass Sie keinen Krampf bekommen, weil Sie es oft schreiben müssen, und deshalb Ihren Quellcode nicht zu sehr durcheinanderbringt.)
Nur die erste Regel über Hilfsfunktionen und ADL würde es erlauben, dass Ihr Beispiel stattdessen wie folgt umgeschrieben wird:
%Vor% Dann könnten wir MyLibrary
in, sagen wir, Lib
:
und Sie sind auf etwas ziemlich überschaubar.
Es sollte keine Konflikte zwischen ähnlichen Dienstprogrammfunktionen für verschiedene Klassen geben. C ++ ermöglicht es Ihnen, Funktionen zu überladen und Vorlagen zu spezialisieren, so dass Sie sowohl Insert(ContainerA)
als auch Insert(ContainerB)
im selben Namespace haben können.
Und natürlich sind Konflikte zwischen Namespaces und Klassen nur möglich, wenn Sie tatsächlich zusätzliche verschachtelte Namespaces haben
Denken Sie daran, dass in Ihrem Library
-Namespace allein Sie vorschreiben, welche Namen eingeführt werden. Und so können Sie Namenskonflikte vermeiden, indem Sie einfach keine kollidierenden Namen erstellen. Ein Namespace, um Benutzercode von Bibliothekscode zu trennen, ist wichtig, da die beiden sich möglicherweise nicht gegenseitig kennen, und so können Konflikte unbeabsichtigt auftreten.
Aber in deiner Bibliothek kannst du einfach alles geben, was nicht kollidiert.
Wenn etwas wehtut, hör auf damit. Es ist absolut nicht notwendig, tief verschachtelte Namespaces in C ++ zu verwenden - sie sind nicht als Architekturgeräte gedacht. Mein eigener Code verwendet immer eine einzige Ebene von Namespaces.
Wenn Sie darauf bestehen, verschachtelte Namespaces zu verwenden, können Sie immer kurze Aliase für sie erstellen:
%Vor%dann:
%Vor%Eine Deklaration in einer Headerdatei erfordert, dass der Namespace den globalen Namespace nicht verschmutzt:
%Vor%Aber in der Quelldatei können Sie usings verwenden:
%Vor% Der vollständig qualifizierte Name sieht für mich eigentlich nicht so schlecht aus, aber ich mag es, in Methoden- und Klassennamen explizit zu sein. Aber using
kann helfen:
Sie könnten wahrscheinlich mit einem using namespace MyLibrary
bei globalem Gültigkeitsbereich in Ihren Quelldateien davonkommen und es so machen:
Und dann können Sie die spezifischen Funktionen importieren, die Sie benötigen:
using MyLibrary::Utilities::MyContainer::Insert
und dann
MyContainer<int> Numbers = Insert(OtherContainer, 123, 456);
Tags und Links c++ namespaces organization ambiguity