variable usar son qué programacion métodos metodos metodo los estáticos estaticos estatico entre diferencia cuando clase atributos atributo c++ dll visual-studio-2005 static templates

c++ - usar - Variable miembro estático en plantilla, con múltiples dlls



static programacion (7)

Antes de que se aceptaran instancias de extern template 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 de advertencia para más detalles. Esta advertencia también aparece en contra de 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.

Mi código está construido en múltiples archivos .dll, y tengo una clase de plantilla que tiene una variable de miembro estática.

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

Cuando no uso plantillas, no hay 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 soluciones propuestas que usan "extern", pero creo que no puedo usarlas porque se supone que mi código 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.


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


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.



Hay dos soluciones para este problema que puedo ver.

Primero, ¿usa otra clase, una que no sea una plantilla, para mantener este valor estático, o para que sea global? - y exportarlo fuera del dll.

El otro es un poco más complicado en el sentido de que crea una instancia de la plantilla en el código y exporta los valores de plantilla instanciados. Entonces, para dar un ejemplo, digamos que tengo un tipo especial de clase intercalada de lista enlazada 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. Yo instanciaría las clases como tal:

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

Entonces podrías exportar las variables estáticas contenidas dentro.

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

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

Aunque la verdadera pregunta es por qué querría hacer esto, ya que técnicamente una DLL se puede usar en todos los procesos con solo una 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?


Existe la siguiente solución, también:

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

La descripción detallada de cómo puedes hacer esto:

Creación de instancia explícita de la plantilla del blog de Anteru


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)