2008-12-29 17 views
15

Mi código está creado en varios archivos .dll, y tengo una clase de plantilla que tiene una variable de miembro estática.Variable de miembro estático en plantilla, con varios archivos DLL

Quiero que la misma instancia de esta variable de miembro estática esté disponible en todas las dlls, pero no funciona: Veo una instancia diferente (valor diferente) en cada una de ellas.

Cuando no uso plantillas, no hay ningún problema: inicialice el miembro estático en uno de los archivos de origen y use las directivas __declspec (dllexport) y __declspec (dllimport) en la clase. Pero no funciona con plantillas. ¿Hay alguna manera de hacer que funcione?

vi algunas propuestas de solución que utilizan "externo", pero yo creo que no puedo usarlo porque mi código se supone que funciona con Visual Studio 2002 y 2005.

Gracias.

Aclaración: Deseo tener una instancia diferente de variable estática por cada tipo diferente de instanciación de plantilla. Pero si instancia la plantilla con el mismo tipo en 2 dlls diferentes, quiero tener la misma variable en ambos.

Respuesta

2

Cree una especialización de plantilla y luego exporte los miembros estáticos de la especialización.

+0

Gracias, funciona. Pero de esta manera tengo que crear una especialización para cada tipo, y pierdo todo el punto de las plantillas. ¿Hay alguna solución sin eso? –

+0

vea el enlace en la solución que mencioné para mantener la flexibilidad de la plantilla –

1

Hay dos soluciones para este problema que puedo ver.

En primer lugar, ¿utiliza otra clase, una que no es una plantilla, para mantener este valor estático o convertirlo en global? - y exportarlo fuera de la dll.

La otra es un poco más complicada en cuanto a que crea una instancia de la plantilla en el código y exporta ese valor de plantilla instanciado. Así que, para dar un ejemplo, digamos que tengo un tipo especial de clase intercalada de lista vinculada y necesito tener un valor estático compartido en las DLL. Escribí el código para ser modelado, pero solo se usa realmente para algunos pocos tipos. Crearía una instancia de las clases como tal:

template <class T> class Foo; 
template<> class Foo<int> {}; 

Luego podría exportar las variables estáticas contenidas en.

__declspec(dllexport) int Foo<int>::StaticMember = 0; 

(O algo así, estoy un poco oxidado con la realización de DLL de exportación/importación.)

Aunque la verdadera pregunta es ¿por qué quieres hacer esto, ya que técnicamente es un archivo DLL puede ser utilizado en procesos con una sola copia almacenada en la memoria. ¿Realmente quiere que solo haya una versión de la estática para todos los procesos, o uno por proceso?

+0

puede instanciar explícitamente solo la estática: template int SpecialFooList :: staticMember; dentro de un archivo cpp, entonces no necesita especializar toda la plantilla. lo que haces actualmente no es C++ válido y no estoy seguro de lo que debería significar :) –

+0

si quieres crear una instancia explícita de una plantilla completa, lo haces con la clase de plantilla SpecialFooList ; –

+0

Bien, corrigió los errores de codificación (graves), gracias por el aviso. – Daemin

3

El problema es que cada instanciación de plantilla diferente es un tipo diferente con su propia variable estática que no se comparte con otras instancias que tienen diferentes parámetros de plantilla. Podría proporcionar una clase base no de plantilla que contenga la variable estática.

+0

ahh, ESO es lo que quiso decir! Estaba viendo su pregunta sin saber a qué se refería. Creo que lo has clavado. nice –

+1

No, quiero tener una instancia diferente de variable estática por cada tipo diferente de instanciación de plantilla. Pero si instancia la plantilla con el mismo tipo en 2 dlls diferentes, quiero tener la misma variable en ambos. –

0

Antes de extern template instanciaciones aceptadas en el borrador del estándar, parece que Microsoft implementó una extensión para el compilador de VC++.

El compilador de VC++ generará una advertencia si se utiliza la extensión no estándar; VS.NET (2003) y posteriores se refieren a esta descripción warning para más detalles. Esta advertencia también se enumera en VS 6.0.

Personalmente, nunca intenté usar esta extensión, por lo que no puedo responder a esta sugerencia. Obviamente, estoy restringiendo esta respuesta a Microsoft Visual Studio (vi un comentario tuyo sobre Unix) pero publico con la esperanza de que pueda ser útil.

4

Existe la siguiente solución, así:

  • en el biblioteca: una instancia explícita cierta especialización plantilla y compartirlos con dllexport
  • en el programa principal:
    • si la especialización está disponible, se usará desde la biblioteca
    • si la especialización ción no está disponible se compila en el programa principal

El desciption en detalle cómo se puede hacer esto:

Anteru's blog Explicit template instantiation

2

Parece que hay una manera de hacer esto con menos limitaciones para el código que usa la clase de plantilla.

Haga que el miembro estático sea un puntero. Cree un mapa global que tenga un tipo conocido fijo y se pueda exportar desde el DLL. El mapa usa el typeid() de la clase como clave y la dirección de la "variable global por clase" como valor. Inicialice el miembro estático a través de una función que comprueba si la clase ya existe en el mapa y, si es así, fuerza a la segunda versión de la clase (en la segunda DLL) a apuntar a la variable estática de la primera versión de la clase.

De esta forma, cada DLL tiene un objeto estático distinto, pero cada DLL también tiene un puntero y todos los punteros apuntan al mismo objeto estático.

Aquí hay un pseudocódigo, suponiendo que el tipo de estática es el mismo que el de la plantilla (pero debe adaptarse fácilmente para otros casos).

map<string,void*> dllexport the_map; // instantiate this once in a single DLL 

T *set_the_global(T *candidate) { 
    map<string,void*>::iterator r = the_map.find(string(typeid(the_class<T>).name())); 
    if(r == the_map.end()) { 
    the_map[string(typeid(the_class<T>).name())] = (void*)candidate; 
    return candidate; // new class: use it as global storage location 
    } else { 
    return (T*)(r->second); // class already has global storage location 
    } 
} 

template <class T> class the_class { 
    virtual void something(); // so RTTI exists 
    static T *the_global; // use this! always points to the same object 
    static T one_per_dll; // only used in initialisation 
}; 
template<class T> the_class<T>::one_per_dll; 
template<class T> the_class<T>::the_global = set_the_global(&the_class<T>::one_per_dll) 
Cuestiones relacionadas