Questa tecnica viene talvolta utilizzata per gestire le dipendenze transitive nelle librerie di sola intestazione. Generalmente non è una buona pratica.
Il problema: sto scrivendo una libreria C ++. Ho inserito tutte le mie dichiarazioni in namespace foo { ... }
. Quindi gli utenti della mia libreria possono evitare quel namespace. Ma cosa succede quando voglio usare un'altra libreria nella mia biblioteca? Chiamiamo la seconda libreria bar
. Se uso normalmente la libreria della barra, espongo gli spazi dei nomi foo
e bar
agli utenti. La mia dipendenza non è invisibile e potrebbe rompere il codice dei miei utenti.
Se la libreria bar
rende il suo spazio dei nomi configurabile, posso evitarlo spostandolo in uno spazio dei nomi foo::detail::bar
.
In un primo momento, potrebbe sembrare che potrei semplicemente includere un'intestazione all'interno di uno spazio dei nomi:
namespace foo { namespace detail {
#include <bar.h>
} }
Tuttavia, le intestazioni sono generalmente scritte per supporre che siano incluse al livello più alto. In particolare, si aspetti che ciò interrompa la libreria standard utilizzata attraverso quell'intestazione. Ciò fallirà anche se la barra non è una libreria di sola intestazione, perché il codice oggetto verrà compilato in un diverso spazio dei nomi.
L'uso delle macro è la soluzione preferibile. Una singola macro dello spazio dei nomi che accetta valori come foo::detail
non è sufficiente prima di C ++ 17, pertanto sono necessarie macro separate per la dichiarazione inizio / fine e lo spazio dei nomi effettivo. Per esempio. vedi questo esempio in Hydra .
Tuttavia, queste tecniche soffrono di vari problemi e restrizioni.
-
In genere i file di intestazione contengono ancora guardie, in modo che ciascuna unità di compilazione possa importare una libreria al massimo uno spazio dei nomi. In pratica, questa non è una grande restrizione.
-
Se una libreria viene importata in più spazi dei nomi, tutti gli oggetti dichiarati da quella libreria vengono duplicati. Questo può o non può essere desiderato.
-
Se la libreria con spazi dei nomi variabili non è una libreria di sola intestazione, anche il codice oggetto per quella libreria deve essere compilato nello spazio dei nomi corretto. Ciò richiede di definire i macro necessari nel tuo sistema di compilazione.
Il problema principale che queste macro stanno cercando di risolvere è che C ++ non ha un sistema di moduli adeguato. In che modo gli altri linguaggi si rivolgono a spazi dei nomi potenzialmente in conflitto?
-
Java ha una convenzione di denominazione dei pacchetti basata su nomi di dominio, quindi non dovrebbero verificarsi conflitti tra le organizzazioni. Per esempio. Se tieni premuto example.com
, dovresti mettere la libreria foo nello spazio dei nomi com.example.foo
.
-
Ruggine e Perl hanno un indice di libreria centrale (Casse e CPAN, rispettivamente). Basta non usare nessuno spazio dei nomi che potrebbe essere riservato lì. Inoltre, Rust non rende visibile lo spazio dei nomi di una cassa a meno che non lo importi, mentre la regola a definizione singola C ++ è globale.
-
Python ha importazioni relative. Un modulo ben scritto non ha bisogno di conoscere la sua posizione assoluta.
Speriamo che i moduli C ++ adotteranno una soluzione ragionevole quando alla fine arriveranno.
L'esempio di tupla a cui sei collegato è fondamentalmente diverso: lo scopo di tale libreria è quello di patchare la libreria standard se non fornisce una sua tupla. Qui, la configurabilità dello spazio dei nomi viene fornita solo per posizionare opzionalmente la tupla in un diverso spazio dei nomi.
Per riassumere: gli spazi dei nomi configurabili hanno usi legittimi durante la creazione di librerie per le librerie. La maggior parte del codice C ++ non dovrebbe preoccuparsi di questo, specialmente del codice dell'applicazione.