2011-08-05 13 views
18

Estoy descubriendo que lo que he considerado una "mejor práctica" para el uso del espacio de nombres en C++ está perjudicando la legibilidad de mi código y haciendo que me pregunte cómo usarlos bien.C++ namespace best practice dilemma

Mi programa consiste en unos pocos módulos diferentes que están principalmente integrados en las bibliotecas que utiliza la aplicación "principal". Cada biblioteca utiliza su propio espacio de nombres, y sus espacios de nombres están todos "dentro" de un espacio de nombres de proyecto para ayudar a evitar conflictos de nombres con código de terceros. Así que termino con nombres de clase como "myproject :: logging :: Logger" y "myproject :: reporting :: ReportType" (como ejemplos compilados).

Hasta ahora todo bien. Y en mis archivos .cpp no ​​tengo ningún problema. Utilizo "using myproject :: logging" en la parte superior, por ejemplo, y puedo referirme limpiamente a mi clase Logging. En el improbable caso de un conflicto entre dos de mis espacios de nombres, puedo decir explícitamente cuál quiero. Esto funciona bien

Sin embargo, los archivos de encabezado son diferentes. Se considera una mala práctica colocar declaraciones en los archivos de encabezado, ya que afectarán el código no relacionado que puede no esperarlas. Así que siempre califico completamente todos los nombres en archivos .hpp. Eso fue algo feo pero manejable hasta ahora, así que lo aguanté. Pero ahora estoy aumentando el uso de código de plantilla en mis bibliotecas, lo que significa que hay mucho más código actual en mis archivos .hpp ahora. Y tener que calificar completamente cada nombre hace que el código sea prácticamente ilegible debido a la longitud de los nombres de tipo.

Estoy empezando a sentir que los beneficios de los espacios de nombres y las mejores prácticas para usarlos están empezando a ser superados por la imposibilidad de escritura del código que estoy escribiendo. Estoy empezando a preguntarme si sería mejor abandonar el uso de espacios de nombres para obtener el beneficio de un código más legible y solucionar cualquier conflicto de nombres si aparecen y cuando aparecen.

Una alternativa es usar espacios de nombres de una sola capa, así que en lugar de "myproject :: logging :: Logger" simplemente tendría "log :: Logger" que ayudaría mucho pero haría que la probabilidad de conflictos de espacio de nombres fuera mucho mayor , y también tienen espacios de nombres que transmiten información menos útil.

Como he dicho, esto sólo afecta realmente el código en archivos .hpp como estoy feliz usando "el uso de espacio de nombres" en mis archivos de implementación para facilitar su uso, pero es convierta en un problema cuando miro mi código de plantilla en archivos .hpp ahora y piensa "eww ...." que no puede ser bueno: P

¿Alguien tiene algún consejo práctico?

+2

'directivas using' están en el ámbito, por lo que quizás se podrían hacer algunas abreviaturas espacio de nombres que no se escapan fuera del archivo de cabecera? –

Respuesta

13

He estado en esta situación antes. A menudo ocurre que muchas funciones/clases de plantillas en sus encabezados son realmente "implementaciones", aunque por la naturaleza de las plantillas en C++ se ven obligados a ponerlas en un archivo de encabezado. Por lo tanto, simplemente pongo todo en algún espacio de nombres de "detalle" o "implementación", donde puedo usar cómodamente "usar el espacio de nombres". Al final, "dejo caer" lo que las personas deberían usar en el lugar correspondiente. De esta manera:

namespace myproject { namespace somemodule { 

namespace _implementation { 

using namespace myproject::othermodule; 
using namespace myproject::yetanothermodule; 

template <...> 
class some_internal_metafunction{ 
... 
}; 

template <...> 
class stuff_people_should_use_outside { 
... 
}; 

} // namespace implementation  

using stuff_people_should_use_outside ; 
}} // namespace myproject::somemodule 

Sin embargo, este enfoque puede ampliar un poco los nombres en los informes del compilador.

Como alternativa, puede renunciar a los espacios de nombres de los módulos. Pero puede que no sea una buena idea para un proyecto extremadamente grande.

+2

¿Tiene que ser 'using _implementation :: stuff_people_should_use_outside;'? – Hugues

+0

@dsign: ¡Debería considerar actualizar su respuesta! – abhiarora

5

¿De nada? Me desharía de la parte "mi proyecto". ¿Cuál es la probabilidad de que su biblioteca utilice exactamente el mismo nombre de espacio de nombres que otros y tienen un símbolo definido con el mismo nombre que otro?

Además, sugeriría nombres más cortos para los espacios de nombres que espera que se usen en los encabezados.

+6

"¿Cuál es la probabilidad de que su biblioteca use exactamente el mismo nombre de espacio de nombres que otro y tenga un símbolo definido con el mismo nombre que otro" para el ejemplo dado, 'logging :: Logger', yo diría que la posibilidad es bastante alto que hay dos de esos en el mundo. Cualquiera que intente usar ambas bibliotecas en un programa es menos probable, pero en las probabilidades ':: myproject :: Logger' es algo más seguro que' :: logging :: Logger' (suponiendo que "myproject" se reemplaza con el nombre real del proyecto , De c). –

0

Si su proyecto no es muy muy grande (es decir, muy grande), usar solo myproject debe ser suficiente. Si realmente desea dividir su proyecto en partes, puede usar espacios de nombres más generalizados. Por ejemplo, si estuviera construyendo un motor de juegos, buscaría espacios de nombres como MyEngine :: Core, MyEngine :: Renderer, MyEngine :: Input, MyEngine :: Sound etc.

+0

No es solo el * tamaño * del proyecto: es la volatilidad del código, la rigidez de los ciclos de publicación, la probabilidad de requisitos/entidades funcionales similares, etc., y el grado de coordinación que resulta práctico entre los desarrolladores. Por ejemplo, los desarrolladores en gran medida independientes (por ejemplo en diferentes países) con ciclos de publicación estrictos escribiendo mucho código nuevo para hacer cosas similares (por ejemplo, diferentes fórmulas de precios para valores) tendrían más probabilidades de espacios de nombres independientes que un solo desarrollador que predomina la implementación de los existentes funciones .... –

2

Mi experiencia ha sido que es mucho es más conveniente tener un espacio de nombre para todo su código por las razones que mencionó en su publicación original. Este espacio de nombres protege sus identificadores contra choques con identificadores de bibliotecas de terceros. Su espacio de nombres es su dominio y es fácil mantenerlo libre de conflictos de nombres.

+0

"Su espacio de nombre es su dominio" - si lo nombra con un GUID o algo así. Único, memorable y breve: elija dos ;-) –

+1

Memorable no es necesario, siempre puede buscarlo. Entonces, único y corto. –

+1

Así que terminas llamando a tu espacio de nombre de nivel superior 'hFPu9_'. En la práctica, no hay mucho problema aquí, pero en principio dos proyectos no relacionados podrían elegir el mismo espacio de nombre de nivel superior, y entonces usted tiene problemas. Es por eso que Java usa nombres de dominio inversos. Proporciona exclusividad a costa de la brevedad. –

18

Esto es lo que hago.

En <mylibrary.h>:

namespace myproject { 
    namespace mylibrary 
    { 
    namespace impl 
    { 
     using namespace otherlibrary; 
     using namespace boost; 
     using namespace std; 
     using namespace whatever::floats::your::boat; 

     class myclass; 
     class myotherclass; 
    }; 
    using impl::myclass; 
    using impl::myotherclass; 
    }; 
}; 

En la fuente:

#include <mylibrary.h> 
using namespace myproject::mylibrary; //clean! 
+0

Esto parece una buena solución. No entiendo el número de líneas comentario/broma de Maxim. –

+0

Ya veo. obtienes 2 veces las líneas para prototipos de función. Uno para el prototipo de una función, y el otro para "usar impl :: function" :(. Aunque es bueno para las clases –