Vermeiden Sie die übermäßige Verwendung von Namespaces

7

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?

    
Maxpm 02.05.2011, 13:16
quelle

4 Antworten

11

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 :

umbenennen %Vor%

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.

    
jalf 02.05.2011, 13:59
quelle
7

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%     
Neil Butterworth 02.05.2011 13:26
quelle
3

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%     
Johann Gerell 02.05.2011 13:23
quelle
2

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:

%Vor%

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);

    
Mark B 02.05.2011 13:26
quelle