Ich bin von C ++ zu Java und C # gewechselt und denke, dass die Verwendung von Namespaces / Paketen dort viel besser ist (gut strukturiert). Dann bin ich zu C ++ zurückgekehrt und habe versucht, Namespaces auf die gleiche Weise zu verwenden, aber die erforderliche Syntax in der Header-Datei ist schrecklich.
namespace MyCompany
{
namespace MyModule
{
namespace MyModulePart //e.g. Input
{
namespace MySubModulePart
{
namespace ...
{
public class MyClass
Folgendes erscheint mir ebenfalls seltsam (um den tiefen Einzug zu vermeiden):
namespace MyCompany
{
namespace MyModule
{
namespace MyModulePart //e.g. Input
{
namespace MySubModulePart
{
namespace ...
{
public class MyClass
{
Gibt es eine kürzere Möglichkeit, das oben Gesagte auszudrücken? Mir fehlt so etwas
namespace MyCompany::MyModule::MyModulePart::...
{
public class MyClass
Aktualisieren
Ok, einige sagen, dass das Konzept der Verwendung in Java / C # und C ++ unterschiedlich ist. "Ja wirklich?" Ich denke, dass das (dynamische) Laden von Klassen nicht der einzige Zweck für Namespaces ist (dies ist eine sehr technisch begründete Perspektive). Warum sollte ich es nicht für eine Lesbarkeit und Strukturierung verwenden, z. B. an "IntelliSense" denken?
Derzeit gibt es keine Logik / Kleber zwischen einem Namespace und dem, was Sie dort finden können. Java und C # machen das viel besser ... Warum <iostream>
Namespace einschließen und haben std
? Ok, wenn Sie sagen, die Logik sollte sich auf den einzuschließenden Header stützen, warum verwendet das #include keine "IntelliSense" -freundliche Syntax wie #include <std::io::stream>
oder <std/io/stream>
? Ich denke, die fehlende Strukturierung in den Standardbibliotheken ist eine Schwäche von C ++ im Vergleich zu Java / C #.
Wenn die Eindeutigkeit für eifrige Konflikte ein Punkt ist (was auch ein Punkt von C # und Java ist), ist es eine gute Idee, den Projekt- oder Firmennamen als Namespace zu verwenden, finden Sie das nicht?
Einerseits heißt es, C ++ sei am flexibelsten ... aber alle sagten "mach das nicht"? Es scheint mir, dass C ++ viele Dinge kann, aber eine schreckliche Syntax hat, selbst für die einfachsten Dinge in vielen Fällen im Vergleich zu C #.
Update 2
Die meisten Benutzer sagen, es sei Unsinn, eine tiefere Verschachtelung als zwei Ebenen zu erstellen. Ok, was ist mit Windows :: UI :: Xaml und Windows :: UI :: Xaml :: Controls :: Primitives-Namespaces in der Win8-Entwicklung? Ich denke, die Verwendung von Namespaces durch Microsoft ist sinnvoll und in der Tat tiefer als nur 2 Ebenen. Ich denke, größere Bibliotheken / Projekte benötigen eine tiefere Verschachtelung (ich hasse Klassennamen wie ExtraLongClassNameBecauseEveryThingIsInTheSameNameSpace ... dann könnten Sie auch alles in den globalen Namespace einfügen.)
Update 3 - Fazit
Die meisten sagen "Tu es nicht", aber ... selbst Boost hat eine tiefere Verschachtelung als ein oder zwei Level. Ja, es ist eine Bibliothek, aber: Wenn Sie wiederverwendbaren Code möchten, behandeln Sie Ihren eigenen Code wie eine Bibliothek, die Sie jemand anderem geben würden. Ich verwende auch eine tiefere Verschachtelung für Erkennungszwecke unter Verwendung von Namespaces.
quelle
namespace
Schlüsselwörtern?Antworten:
C ++ 17 könnte die Definition verschachtelter Namespaces vereinfachen:
ist äquivalent zu
Siehe (8) auf der Namespace-Seite unter cppreference:
http://en.cppreference.com/w/cpp/language/namespace
quelle
/std:c++latest
/std:c++latest
von Visual Studio 2015 und Boost möglicherweise sehr mystische Compilerfehler auftreten, wenn Sie einige Boost-Header einfügen. Ich war mit diesem Problem konfrontiert, wie in dieser StackOverflow-Frage beschriebenUm wirklich tiefe Einrückungen zu vermeiden, mache ich das normalerweise so:
quelle
clang-format
kann das nicht formatieren, wenn Sie clang.llvm.org/docs/ClangFormatStyleOptions.html (NamespaceIndentation)Ich unterstütze Peterchens Antwort voll und ganz , möchte aber etwas hinzufügen, das einen anderen Teil Ihrer Frage anspricht.
Das Deklarieren von Namespaces ist einer der sehr seltenen Fälle in C ++, in denen ich die Verwendung von
#define
s wirklich mag .Dadurch entfällt auch die Notwendigkeit von Kommentaren in der Nähe der schließenden Klammer des Namespace (Haben Sie jemals zum Ende einer großen Quelldatei gescrollt und versucht, Klammern hinzuzufügen / zu entfernen / auszugleichen, bei denen Kommentare darüber fehlten, welche Klammer welchen Bereich schließt? Kein Spaß .).
Wenn Sie alle Namespace-Deklarationen in eine einzelne Zeile setzen möchten, können Sie dies auch mit ein wenig (ziemlich hässlicher) Präprozessor-Magie tun:
Jetzt können Sie dies tun:
Um tiefer als drei Ebenen zu verschachteln, müssten Sie Hilfsmakros bis zur gewünschten Anzahl hinzufügen.
quelle
#define
s auch nicht mag, ich bin ziemlich beeindruckt von dieser Präprozessor-Magie ... nur wenn ich keine zusätzlichen Hilfsmakros für eine tiefere Verschachtelung hinzufügen muss ... nun, ich werde sie sowieso nicht verwenden. .C ++ - Namespaces werden verwendet, um Schnittstellen zu gruppieren, nicht um Komponenten zu teilen oder politische Spaltungen auszudrücken.
Der Standard tut alles, um die Java-ähnliche Verwendung von Namespaces zu verbieten. Namespace-Aliase bieten beispielsweise die Möglichkeit, tief verschachtelte oder lange Namespace-Namen einfach zu verwenden.
Wäre
namespace nsc {}
dann aber ein Fehler, da ein Namespace nur mit seinem ursprünglichen Namespace-Namen definiert werden darf . Im Wesentlichen erleichtert der Standard dem Benutzer einer solchen Bibliothek die Arbeit, dem Implementierer jedoch die Arbeit . Dies hält die Leute davon ab, solche Dinge zu schreiben, mildert jedoch die Auswirkungen, wenn sie dies tun.Sie sollten einen Namespace pro Schnittstelle haben, der durch eine Reihe verwandter Klassen und Funktionen definiert ist. Interne oder optionale Subschnittstellen können in verschachtelte Namespaces verschoben werden. Aber mehr als zwei Ebenen tief sollten eine sehr ernste rote Fahne sein.
Verwenden Sie Unterstriche und Bezeichnerpräfixe, wenn der
::
Operator nicht benötigt wird.quelle
company::division
übercompany_division
?Nein, und bitte tu das nicht.
Der Zweck von Namespaces besteht hauptsächlich darin, Konflikte im globalen Namespace zu lösen.
Ein sekundärer Zweck ist die lokale Abkürzung von Symbolen; Beispielsweise kann eine komplexe
UpdateUI
Methode ein verwendenusing namespace WndUI
, um kürzere Symbole zu verwenden.Ich bin in einem 1.3MLoc-Projekt und die einzigen Namespaces, die wir haben, sind:
#import
und zu isolieren#include windows.h
)ModuleDetailHereBeTygers
Namespaces in Nur-Header-Bibliotheken)In diesem Projekt verwenden Klassennamen usw. einen aus zwei oder drei Buchstaben bestehenden "Regions" -Code (z . B.
CDBNode
anstelle vonDB::CNode
). Wenn Sie Letzteres bevorzugen, gibt es Platz für eine zweite Ebene von "öffentlichen" Namespaces, aber nicht mehr.Klassenspezifische Aufzählungen usw. können Mitglieder dieser Klassen sein (obwohl ich der Meinung bin, dass dies nicht immer gut ist und es manchmal schwer zu sagen ist, ob Sie sollten)
Es wird auch selten ein "Firmen" -Namensraum benötigt, außer wenn Sie große Probleme mit Bibliotheken von Drittanbietern haben, die als Binärdateien verteilt werden, keinen eigenen Namespace bereitstellen und nicht einfach in einen eingefügt werden können (z. B. in einer Binärdatei) Verteilung). Nach meiner Erfahrung ist es jedoch viel einfacher , sie in einen Namespace zu zwingen .
[Bearbeiten] Gemäß Stegis Folgefrage:
Es tut mir leid, wenn ich nicht klar genug war: Zwei Levels sind keine harte Grenze, und mehr ist an sich nicht schlecht. Ich wollte nur darauf hinweisen, dass Sie meiner Erfahrung nach selbst auf einer großen Codebasis selten mehr als zwei benötigen . Tiefer oder flacher nisten ist ein Kompromiss.
Nun ist der Microsoft-Fall wohl anders. Vermutlich ein viel größeres Team, und der gesamte Code ist eine Bibliothek.
Ich würde davon ausgehen , Microsoft wird hier den Erfolg der .NET - Bibliothek zu imitieren, wo Namensräume zum Beitrag Auffindbarkeit der umfangreichen Bibliothek. (.NET hat ungefähr 18000 Typen.)
Ich würde weiter annehmen, dass es in einem Namespace ein optimales Symbol (Größenordnung von Symbolen) gibt. Sagen wir, 1 macht keinen Sinn, 100 klingt richtig, 10000 ist eindeutig zu viel.
TL; DR: Es ist ein Kompromiss, und wir haben keine harten Zahlen. Gehen Sie auf Nummer sicher und übertreiben Sie in keine Richtung. Das "Tu das nicht" kommt nur von "Du hast Probleme damit, ich hätte Probleme damit, und ich sehe keinen Grund, warum du es brauchen würdest.".
quelle
Constants
einfügen und dann verschachtelte Namespaces mit geeigneten Namen erstellen, um die Konstanten zu kategorisieren. Bei Bedarf verwende ich dann weitere Namespaces, um Namenskollisionen zu vermeiden. DieserConstants
Namespace ist selbst in einem Catch-All-Namespace für den Systemcode des Programms enthalten, mit einem Namen wieSysData
. Dies schafft einen vollständig qualifizierten Namen , die drei oder vier Namensräume (wieSysData::Constants::ErrorMessages
,SysData::Constants::Ailments::Bitflags
, oderSysData::Defaults::Engine::TextSystem
).using
Anweisung, um die entsprechenden Namen einzugeben, wodurch die Möglichkeit von Namenskonflikten minimiert wird. Ich finde, es verbessert die Lesbarkeit und hilft, die Abhängigkeiten eines bestimmten Codeblocks zu dokumentieren. Abgesehen von Konstanten neige ich dazu, es möglichst auf zwei Namespaces (wieSysData::Exceptions
undSysData::Classes
) zu beschränken.Hier ein Zitat aus Lzz (Lazy C ++) docs:
Natürlich ist die Qualität der Quellen, die von solchen Tools abhängt, umstritten ... Ich würde sagen, es ist eher eine Kuriosität, die zeigt, dass die durch C ++ induzierte Syntaxkrankheit viele Formen annehmen kann (ich habe auch meine ...)
quelle
Beide Standards (C ++ 2003 und C ++ 11) weisen sehr deutlich darauf hin, dass der Name des Namespace ein Bezeichner ist. Dies bedeutet, dass explizit verschachtelte Header erforderlich sind.
Mein Eindruck, dass dies keine große Sache ist, um neben einem einfachen Namen des Namespace einen qualifizierten Bezeichner zu platzieren, aber aus irgendeinem Grund ist dies nicht zulässig.
quelle
Sie können diese Syntax verwenden:
Beachten Sie, dass diese Syntax auch in C ++ 98 gültig ist und fast der in C ++ 17 mit verschachtelten Namespace-Definitionen verfügbaren ähnelt .
Glücklich unnesting!
Quellen:
quelle
Dieses Papier behandelt das Thema ziemlich gut: Namespace-Papier
Was im Grunde genommen darauf hinausläuft. Je länger Ihre Namespaces sind, desto wahrscheinlicher ist es, dass Benutzer die
using namespace
Richtlinie verwenden.Wenn Sie sich also den folgenden Code ansehen, sehen Sie ein Beispiel, bei dem dies Ihnen schaden wird:
Dieser Code wird jedoch gut kompiliert. Wenn Sie die Zeile
//using namespace def;
auskommentieren, wird der "Test" -Namensraum mehrdeutig und es treten Namenskollisionen auf. Dies bedeutet, dass Ihre Codebasis durch Einfügen einer Bibliothek eines Drittanbieters von stabil zu instabil wechseln kann.Selbst wenn Sie in C # verwenden
using abc;
undusing def;
der Compiler dies erkennen kanntesting::myClass
odermyClass
sich nur imabc::testing
Namespace befindet, erkennt C ++ dies nicht und es wird als Kollision erkannt.quelle
Ja, du musst es so machen
Sie versuchen jedoch, die Namespaces so zu verwenden, dass sie nicht verwendet werden sollen. Überprüfen Sie diese Frage, vielleicht finden Sie sie nützlich.
quelle
[BEARBEITEN:]
Da verschachtelte C ++ 17-Namespaces als Standardsprache unterstützt werden ( https://en.wikipedia.org/wiki/C%2B%2B17 ). Ab sofort wird diese Funktion in g ++ 8 nicht unterstützt, sie befindet sich jedoch im Compiler in clang ++ 6.0.
[SCHLUSSFOLGERUNG:]
Verwenden Sie
clang++6.0 -std=c++17
als Standardkompilierungsbefehl. Dann sollte alles gut funktionieren - und Sie können mitnamespace OuterNS::InnerNS1::InnerNS2 { ... }
in Ihren Dateien kompilieren .[URSPRÜNGLICHE ANTWORT:]
Da diese Frage etwas alt ist, gehe ich davon aus, dass Sie weitergezogen sind. Aber für andere, die immer noch nach einer Antwort suchen, kam mir die folgende Idee:
(Darf ich hier Werbung für Emacs machen :)?) Das Posten eines Bildes ist viel einfacher und lesbarer als das einfache Posten von Code. Ich habe nicht die Absicht, alle Eckfälle vollständig zu beantworten, sondern wollte mich nur inspirieren lassen. (Ich unterstütze C # voll und ganz und bin der Meinung, dass C ++ in vielen Fällen einige OOP-Funktionen übernehmen sollte, da C # hauptsächlich aufgrund seiner vergleichbaren Benutzerfreundlichkeit beliebt ist.)
quelle