Quindi, per riassumere i punti principali, using namespace v99
e inline namespace
non erano gli stessi, il primo era una soluzione alternativa alle librerie di versioni prima che una parola chiave dedicata (inline) fosse introdotta in C ++ 11 che risolvesse i problemi di utilizzo using
, fornendo allo stesso tempo la stessa funzionalità di controllo delle versioni. L'uso using namespace
utilizzato per causare problemi con ADL (sebbene ADL ora sembri seguire le using
direttive) e la specializzazione fuori linea di una classe / funzione di libreria ecc. Da parte dell'utente non funzionerebbe se eseguita al di fuori del vero spazio dei nomi (il cui nome è il l'utente non dovrebbe e non dovrebbe saperlo, ovvero l'utente dovrebbe usare B :: abi_v2 :: piuttosto che solo B :: per la specializzazione da risolvere).
//library code
namespace B { //library name the user knows
namespace A { //ABI version the user doesn't know about
template<class T> class myclass{int a;};
}
using namespace A; //pre inline-namespace versioning trick
}
// user code
namespace B { //user thinks the library uses this namespace
template<> class myclass<int> {};
}
Questo mostrerà un avviso di analisi statica first declaration of class template specialization of 'myclass' outside namespace 'A' is a C++11 extension [-Wc++11-extensions]
. Ma se rendi lo spazio dei nomi A in linea, il compilatore risolve correttamente la specializzazione. Sebbene, con le estensioni C ++ 11, il problema scompaia.
Le definizioni fuori linea non si risolvono durante l'utilizzo using
; devono essere dichiarati in un blocco dello spazio dei nomi di estensione nidificato / non nidificato (il che significa che l'utente deve conoscere nuovamente la versione ABI, se per qualsiasi motivo gli è stato permesso di fornire la propria implementazione di una funzione).
#include <iostream>
namespace A {
namespace B{
int a;
int func(int a);
template<class T> class myclass{int a;};
class C;
extern int d;
}
using namespace B;
}
int A::d = 3; //No member named 'd' in namespace A
class A::C {int a;}; //no class named 'C' in namespace 'A'
template<> class A::myclass<int> {}; // works; specialisation is not an out-of-line definition of a declaration
int A::func(int a){return a;}; //out-of-line definition of 'func' does not match any declaration in namespace 'A'
namespace A { int func(int a){return a;};} //works
int main() {
A::a =1; // works; not an out-of-line definition
}
Il problema scompare quando si fa B in linea.
Gli altri inline
spazi dei nomi delle funzionalità consentono al writer della libreria di fornire un aggiornamento trasparente alla libreria 1) senza forzare l'utente a refactificare il codice con il nuovo nome dello spazio dei nomi e 2) prevenire la mancanza di verbosità e 3) fornire l'astrazione di dettagli irrilevanti per le API, mentre 4) fornire la stessa diagnostica e comportamento utili del linker che fornirebbe uno spazio dei nomi non in linea. Supponiamo che tu stia utilizzando una libreria:
namespace library {
inline namespace abi_v1 {
class foo {
}
}
}
Consente all'utente di chiamare library::foo
senza la necessità di conoscere o includere la versione ABI nella documentazione, che sembra più pulita. L'uso library::abiverison129389123::foo
sembrerebbe sporco.
Quando viene effettuato un aggiornamento foo
, vale a dire l'aggiunta di un nuovo membro alla classe, non influirà sui programmi esistenti a livello di API perché non utilizzeranno già il membro E la modifica del nome dello spazio dei nomi in linea non cambierà nulla a livello di API perché library::foo
funzionerà ancora.
namespace library {
inline namespace abi_v2 {
class foo {
//new member
}
}
}
Tuttavia, per i programmi che si collegano ad esso, poiché il nome dello spazio dei nomi in linea viene modificato in nomi di simboli come uno spazio dei nomi normale, la modifica non sarà trasparente al linker. Pertanto, se l'applicazione non viene ricompilata ma è collegata a una nuova versione della libreria, presenterà un simbolo che abi_v1
non è stato trovato errore, piuttosto che collegarsi effettivamente e quindi causare un misterioso errore logico in fase di esecuzione a causa dell'incompatibilità ABI. L'aggiunta di un nuovo membro provocherà la compatibilità ABI a causa della modifica della definizione del tipo, anche se non influisce sul programma al momento della compilazione (livello API).
In questo scenario:
namespace library {
namespace abi_v1 {
class foo {
}
}
inline namespace abi_v2 {
class foo {
//new member
}
}
}
Come l'utilizzo di 2 spazi dei nomi non in linea, consente di collegare una nuova versione della libreria senza dover ricompilare l'applicazione, poiché abi_v1
verrà modificata in uno dei simboli globali e utilizzerà la definizione del tipo (vecchio) corretta. La ricompilazione dell'applicazione causerebbe tuttavia la risoluzione dei riferimenti library::abi_v2
.
L'uso using namespace
è meno funzionale dell'uso inline
(in quanto le definizioni fuori linea non si risolvono) ma offre gli stessi 4 vantaggi di cui sopra. Ma la vera domanda è: perché continuare a usare una soluzione alternativa quando ora c'è una parola chiave dedicata per farlo. È una pratica migliore, meno dettagliata (è necessario cambiare 1 riga di codice anziché 2) e chiarire l'intenzione.
using namespace V99;
non funziona nell'esempio di Stroustrup.