Quando ricevo un certo grado di feedback, ritengo che non sia molto più prevedibile, quindi mi piacerebbe riassumere tutto quanto detto.
Una parte della critica ha indicato che il problema che sto cercando di risolvere non è chiaro.
Esiste l'effetto transitivo di using namespace/name
. Secondo me, può essere indesiderato in alcune situazioni, ma non esiste un modo standard per farlo scomparire. Questo è il problema che sto cercando di risolvere. Quindi, ho proposto un modello per questo scopo:
namespace your_namespace {
namespace __local__ {
//names not intended to be in your_namespace, including those introduced by "using" directive should be here
//they will be visible to the de facto body of your_namespace, while not being exposed
namespace __exported__ { //will be inlined into your_namespace
//everything you'd like to have in your_namespace
}
}
using namespace __local__::__exported__; //the inlining
}
L'attualità è discutibile.
Sebbene le pratiche classiche di gestione dei nomi funzionino, potrebbero implicare verbosità e forzare un certo design. Secondo me, il modello è ragionevolmente semplice, innocuo e garantisce la libertà nel senso che rende alcuni stili di codifica non errori.
È stato abbastanza notato che le applicazioni non sono chiare. Li interromperò nelle seguenti categorie:
-
Riduzione della piastra di calpestio. La fonte principale di verbosità sono i nomi complessi
- nodi dell'albero del nome con profondità > 1, dove 0 è il globale stesso. Possono venire dal tuo codice e vengono spesso da loro
codice esterno che si desidera riutilizzare. Nel primo caso, non è un problema
finché non hai un albero dei nomi molto complicato. In quest'ultimo,
non dipende da te e potrebbe potenzialmente essere abbastanza
significativo. Immagina una libreria che devi usare, che usa pesantemente
namespace (giustificato dalla complessità), come Boost. Potresti finire
con codice come:
//library.hpp
namespace library {
namespace foo {
struct A;
namespace bar {
struct B;
namespace baz {
struct C;
struct D;
//...
}
}
}
//... Hypothetically endlessly complicated name tree
}
//module1.hpp
//includes library.hpp
namespace myproject {
// can't use using directive, because it may cause name conflicts in other modules,
// and in the namespaces using "myproject" namespace
library::foo::A someFn(library::foo::bar::B, library::foo::bar::baz::C, library::foo::bar::baz::D);
library::foo::bar::baz::C someOtherFn(library::foo::bar::baz::C, library::foo::bar::baz::C, library::foo::bar::baz::D);
struct E {
library::foo::A a;
library::foo::bar::B b;
library::foo::bar::baz::C c;
library::foo::bar::baz::D d;
//...
};
//... Hypothetically endless number of inevitable endlessly complex and varying names usages
//... Hypothetically endlessly complicated name tree
}
//module2.hpp
//includes some other name-complex libraries
namespace myproject {
//... Hypothetically endless number of differently named members (not conflicting with existing actual members)
//... Hypothetically endless number of inevitable endlessly complex and varying names usages
}
È notevolmente semplificato con il modello:
//module1.hpp
//includes library.hpp
namespace myproject {
namespace module_1 {
using namespace library::foo; //these directives won't impact "myproject"
using namespace bar;
using namespace baz;
namespace __exported__ {
A someFn(B, C, D); //users of the function would have to explicitly deal with external names, which is right in my vision
C someOtherFn(C, C, D);
struct E {
A a;
B b;
C c;
D d;
};
}
}
using namespace module_1::__exported__;
}
Questo era un esempio di progetto one-namespace. È ancora più reale quando c'è un namespace per modulo e dipendono i moduli
l'uno sull'altro. Anche questo è stato un esempio di classico
header-con-dichiarazioni-sources-con-definizioni. Quando progetti
una libreria di sola intestazione, quindi c'è un ulteriore carico di gestione
nomi lunghi ad es. nei corpi delle funzioni.
Nonostante esistano soluzioni alternative, hanno dei difetti:
-
I typedef non sono applicabili a tutti i tipi di nomi e introducono un nome nello spazio dei nomi
-
L'alias dello spazio dei nomi non è ancora un nome breve ed è esso stesso un nome nel namespace.
-
L'utilizzo di direttive nell'ambito della funzione probabilmente si duplicherà, poiché diverse funzioni spesso funzionano con gli stessi nomi.
-
incapsulamento.
Questo approccio consente non solo di isolare le importazioni, ma anche di avere membri privati dello spazio dei nomi.
-
Razionalizzazione del design.
Nessuno metterà in discussione la virtù della modularità. Mentre ci sono meccanismi per implementare la modularità del codice, vale a dire, diversi file e inclusione, non penso sia sufficiente. I nomi sono nell'essenza di un modulo: la sua struttura logica. C ++ consente il nome fisico di un modulo (nome file) e il nome logico divergente, ma penso che dovrebbero essere coerenti. E i nomi nel modulo non dovrebbero essere mescolati con i nomi da cui dipende.
Mi pentirò di dirlo, ma in altri sistemi di moduli, ad es. ES6 o Java, i moduli hanno nomi complessi per una migliore identificazione, ad es. packageName.shortName, che sono coerenti con i loro nomi fisici; hanno nomi interiori, che esportano, e i nomi che consumano (importa), e questi ultimi non sono mai in conflitto con il primo; Personalmente, adotto queste viste e non vedo come questo concetto sia in conflitto con C ++.
L'utilizzo di macro è sconsigliato.
Ho creato macro come supplemento all'idea. Il modello può essere utilizzato senza di loro.
Creandoli ero distorto alla percezione individuale, dove era familiare, e considerato più dichiarativo e amp; codice pulito. Finché questa cosa non è standardizzata all'interno di un gruppo, dovrebbe essere, ovviamente, evitata dai membri del gruppo.
Incapsulamento insufficiente.
L'utilizzo diretto di your_namespace::__local__
avrebbe rovinato tutto. Ecco perché l'ho oscurato tramite il nome sottolineato. Questa tecnica di incapsulamento è puramente semantica, quindi non completamente affidabile: chiunque può ancora fare riferimento a quel nome. Sfortunatamente, è il massimo che ottieni qui. Ad ogni modo, penso che il buon senso suggerisca di non usare qualcosa chiamato come __do_not_touch_me__
.
L'utilizzo di nomi underscored è sconsigliato.
Sì, viola le raccomandazioni dello standard e dovrebbe essere cambiato.
Ringrazio tutti per aver partecipato!