2010-06-12 21 views
7

Estoy usando una biblioteca de terceros C++ que coloca todas sus clases en un espacio de nombres versionado, llamémoslo tplib_v44. También definen un espacio de nombres genéricos de alias:Alias ​​de espacio de nombres C++ y declaración directa

namespace tplib = tplib_v44; 

Si una visión de declarar un miembro de la biblioteca en mi propio archivo .h utilizando el espacio de nombres genéricos ...

namespace tplib { class SomeClassInTpLib; } 

... consigo errores de compilación en la cabecera de la biblioteca de terceros (que está siendo incluido más tarde en mi archivo de aplicación .cpp):

error C2386: 'tplib' : a symbol with this name already exists in the current scope 

Si utilizo el espacio de nombres específica de la versión, entonces todo funciona bien, pero luego .. w ¿ese es el punto? ¿Cuál es la mejor manera de lidiar con esto?

[EDITAR] FYI para los lectores futuros, esta era la biblioteca de la ICU. Una solución (al menos en mi situación) está en los comentarios a la respuesta aceptada.

Respuesta

4

Parece que hay una solución fea para esto, pero no es una buena solución.

Para ACE (with a decent explanation) y , definen las macros que puede utilizar para hacer esto "genéricamente".

ACE_BEGIN_VERSIONED_NAMESPACE_DECL 
class ACE_Reactor; 
ACE_END_VERSIONED_NAMESPACE_DECL 

XERCES_CPP_NAMESPACE_BEGIN 
class DOMDocument; 
class DOMElement; 
XERCES_CPP_NAMESPACE_END 

Parece que un desafortunado C++ artefacto, trate de buscar en torno a su tplib para estas macros.

El estándar trata los espacios de nombres y los alias del espacio de nombres como cosas diferentes. Estás declarando tplib como un espacio de nombres, por lo que cuando el compilador intenta asignar un alias más tarde, no puede ser ambos, por lo que el compilador se queja.

+0

Esto estuvo muy cerca de lo que terminó funcionando para mí. Al final resultó que, mi biblioteca (la biblioteca de la ICU) tiene un encabezado pequeño (uversion.h) que, entre otras cosas, define el alias del espacio de nombres. Si incluyo este encabezado en mi encabezado, puedo usar una macro del espacio de nombres versionado que definen (U_ICU_NAMESPACE) en mi archivo de encabezado y me escapo con el espacio de nombres genérico en mis archivos cpp. Por lo tanto, estoy aislado de los cambios en el espacio de nombres versionado pero con dependencias mínimas en tiempo de compilación. –

0

Er ... Lo que dices aparece hacia atrás. Todo lo contrario, ¿de qué sirve intentar declarar tu clase como miembro del espacio de nombres tplib? (Olvidando por un segundo que ni siquiera es un espacio de nombres, sino un alias de espacio de nombres, por eso obtienes el error.)

Es obvio que tienes algún tipo de sistema de control de versiones basado en espacios de nombres y alias de namespace. Si su clase se presenta por primera vez en una "versión" específica del espacio de nombres (como 44), ese es el espacio de nombres en el que debe declararse. ¿Por qué intenta meter su declaración de clase "atrás en el tiempo", es decir, en todo versiones anteriores del espacio de nombres (como 43 y, por ejemplo, 30)? Tu clase no existía en las versiones anteriores, por lo que no debes forzarla allí.

+1

Supongo que mi pregunta original no estaba clara. El desarrollador del tercero proporciona el alias del espacio de nombres para que pueda referirme a sus clases como 'tplib :: SomeClass'. Están usando el espacio de nombres versionado internamente. Por lo tanto, en su próximo lanzamiento, el espacio de nombre interno podría ser 'tplib_v50'.Pero no tendré que pasar por todos mis archivos y cambiar 'tplib_v44 ::' por 'tplib_v50 ::' porque estoy usando el alias. No estoy declarando mi clase en el espacio de nombres; simplemente reenviando una clase de esa biblioteca en el archivo de encabezado de mis clases. Espero que tenga sentido. –

1

Creo que su problema se debe a tplib ser un alias en lugar de un espacio de nombres reales

Dado que el control de versiones está dentro de una biblioteca de terceros que pueda no ser capaz de usarlo, pero utilizando el espacio de nombres versionado dentro de un versionado el espacio de nombres (en lugar de crear alias) parece funcionar para g ++ 4.0.1 y 4.1.2. Sin embargo, tengo la sensación de que esto no debería funcionar ... y tal vez haya otros problemas que desconozco.

//This is the versioned namespace 
namespace tplib_v44 
{ 
    int foo(){ return 1; } 
} 

//An unversioned namespace using the versioned one 
namespace tplib 
{ 
    using namespace tplib_v44; 
} 


//Since unversioned is a real namespace, not an alias you can add to it normallly. 
namespace tplib 
{ 
    class Something {}; 
} 


int main() 
{ 
    //Just to make sure it all works as expected 
    tplib::foo(); 
} 
+0

Solo tenga en cuenta que esto no generará un error si 'Something' ya fue declarado en el espacio de nombres versionado. Aceptará silenciosamente y 'tplib :: Something' se referirá a la versionada, ignorando' tplib :: Something'. Además, ADL no funcionará para llamadas con 'Something' como argumento: el espacio de nombres versionado no se buscará para los candidatos. –

+0

@Johannes - Eso suena sensato. ¿Puedes dar un ejemplo de cómo ADL fracasará en el caso de uso y no en el caso del espacio de nombres directo? –

0

EDIT: He tenido señaló que he echado de menos el punto de la pregunta - por favor no hacer caso omiso!

Además de los problemas resaltados en las otras respuestas, también me preocupa un poco que intente agregar su propio código a un espacio de nombre definido por un tercero en primer lugar.

Existen espacios de nombres para evitar el conflicto de símbolos (clases, típicos, enumeraciones, etc.) conflictivos, colocándolos en su propio espacio de nombres, desarrollando así un símbolo exclusivo totalmente calificado de los potencialmente parcialmente calificados. Agregar su propio código al espacio de nombre de un tercero puede causar problemas si (por ejemplo) en una versión posterior deciden que también quieren usar el mismo símbolo (como agregar su propio SomeClassInTpLib): de repente, los espacios de nombres de los conflictos de nombre están destinados a previene que sus crines se vuelvan feas. Esta es la razón por la que generalmente es una mala práctica agregar al espacio de nombres std.

Una solución mucho más segura que evita el problema por completo es simplemente usar su propio espacio de nombres. Llámelo tplib_ex o algo similar y la asociación seguirá siendo clara, pero el conflicto no será un problema y su problema relacionado con alias también desaparecerá.

+0

No está agregando símbolos a la biblioteca, está intentando reenviar los objetos que ya existen dentro del espacio de nombres de terceros (alias). – Stephen

+0

Ah, de hecho. De alguna manera se perdió eso. Gracias por la corrección. – Mac

0

¿cuál es el punto?

que le impide la adición de material adicional en su espacio de nombres, tal vez porque piensan que añadir mucho más pronto nombres (y el hecho de que están usando un espacio de nombres versionado puede sugerir que). Sin embargo, estas son solo especulaciones. Esto tiene el efecto secundario de evitar declaraciones futuras en el espacio de nombres que crees que es más razonable, por lo que creo que es una mala práctica de programación de su parte.

¿Cuál es la mejor manera de lidiar con esto?

No hay mejor manera, pero trate de evitar el uso de macros, las macros son feas y no son agradables de ver (no me gustan todas esas cosas mayúsculas). Si su preocupación es sobre "¿qué sucede cuando cambian la versión?" (Sí, en teoría, debe cambiar "v44" por "v45" en todos los códigos)

y simplemente utilice 1 encabezado único para reenviar y declarar todo lo que necesita.

TpLibForwards.hpp

#ifdef XXXXXX_TPLIB 
    #error "XXXXXX_TPLIB is already taken, change to something else" 
#endif 
#define XXXXXX_TPLIB tplib_v44 
//... and that's why I don't like keeping macros around.. 

namespace XXXXXX_TPLIB 
{ 

    // FORWARD DECLARATIONS 
    class A1; 
    class A2; 
    //... 
} 
namespace tplib = XXXXXX_TPLIB; 
#undef XXXXXX_TPLIB 

Si cambian la biblioteca, entonces sólo tiene que solicitar el cambio y 1 en 1 archivo. Muchos programadores ya mantienen las declaraciones avanzadas en un punto porque eso es mucho más manejable y en caso de que tenga que reenviar declarar muchas cosas, mantenga otros encabezados más limpios y mucho más legibles.

#include <TpLibForwards.hpp> // my forwards declarations 
Cuestiones relacionadas