2009-12-28 14 views
8

tengo una clase llamada "SimObject":no puede exportar función de plantilla

namespace simBase 
{ 
    class __declspec(dllexport) SimObject: public SimSomething 
    { 
     public: 

      template <class T> 
      void updateParamValue(const std::string& name, T val); 
    } 
} 

tengo otra clase llamada "ITerrainDrawable":

namespace simTerrain 
{ 
    class __declspec(dllexport) ITerrainDrawable : public simBase::SimObject 
    { 
    } 
} 

Estas clases están en diferentes bibliotecas. SimObject está en simBase, ITerrainDrawable está en las bibliotecas de simTerrain. Incluso si ITerrainDrawable se deriva de SimObject y que incluye la biblioteca de simBase, me sale un error de enlace:

unresolved external symbol

1>ITerrainDrawable.obj : error LNK2019: unresolved external symbol "public: void __thiscall simBase::SimObject::updateParamValue<float>(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,float)" ([email protected]@[email protected]@@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]) referenced in function "public: void __thiscall simTerrain::ITerrainDrawable::setTerrainSize(float)" ([email protected]@[email protected]@[email protected]) 
1>ITerrainDrawable.obj : error LNK2019: unresolved external symbol "public: void __thiscall simBase::SimObject::updateParamValue<class osg::Vec4f>(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class osg::Vec4f)" ([email protected]@[email protected]@@[email protected]@@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@@Z) referenced in function "public: void __thiscall simTerrain::ITerrainDrawable::setSatelliteTextureBorders(class osg::Vec2f,class osg::Vec2f)" ([email protected]@[email protected]@[email protected]@@[email protected]) 

¿Por qué obtengo este error?

Todo funciona bien si no uso la función de plantilla pero la necesito.

Si muevo esta función a la biblioteca simTerrain funciona bien, pero no quiero usar la función duplicada porque hay muchas bibliotecas como simTerrain.

Respuesta

10

C++ realmente no es compatible con la compilación separada del código de la plantilla; debe colocar la definición de la plantilla en un archivo de encabezado.

+0

gracias Neil :) funcionó cuando muevo la definición de la función al encabezado – ufukgun

5

La implementación completa de una clase de plantilla debe estar en el encabezado de esa clase de plantilla. Los estándares ANSI/ISO para C++ permiten una forma de poner la implementación en una unidad de compilación separada utilizando la palabra clave de exportación , pero actualmente hay compiladores que realmente lo soportan.

Para obtener más información, lea this y this.

+0

uso VisualStudio2008 y la respuesta a la exportación es: advertencia C4237: la palabra clave 'export' aún no está soportada, pero está reservada para uso futuro – ufukgun

6

hay dos modelo de compilación de plantillas:

  1. modelo de compilación de inclusión (como incluir el archivo de cabecera)
  2. modelo de compilación independiente (separación de la interfaz de la aplicación)

Puede usar palabra clave de exportación en el momento de la definición de la plantilla para la segunda opción.

export template <class T> 
void updateParamValue(const std::string& name, T val) {} 

Pero no estoy seguro de que todo el compilador lo admita.

+0

uso VisualStudio2008 y la respuesta a la exportación es: advertencia C4237: la palabra clave 'export' aún no se admite, pero está reservada para uso futuro – ufukgun

+0

vC++ 7.0 no lo admite, puede ser que la próxima versión pueda ser compatible. Pero lo ejecuto en el compilador linux GNU C++ 8.2 que lo admite. – Ashish

+0

me gustaría que su respuesta sea cierta pero estúpida vs no la admite todavía:/ no me gusta escribir definiciones de funciones en el encabezado. – ufukgun

4

Aquí está el ejemplo de trabajo:

template<class T> TEST_API void foo(T) 
{ 
    std::cout << "test"; 
} 

template TEST_API void foo(int); 
template TEST_API void foo(char); 

volcado de test.dll archivo

Tipo de archivo: DLL

sección contiene los siguientes exportaciones de test.dll

00000000 characteristics 
4FDEF629 time date stamp Mon Jun 18 12:34:33 2012 
    0.00 version 
     1 ordinal base 
     3 number of functions 
     3 number of names 

ordinal hint RVA  name 

     1 0 00001032 [email protected]@@[email protected] = @ILT+45([email protected]@@[email protected]) 
     2 1 00001014 [email protected]@@[email protected] = @ILT+15([email protected]@@[email protected]) 
1

Debe especificar que la especialidad de la plantilla (archivo cpp está bien).Esto significa que necesita para exportar toda combinación de argumentos de plantilla, que se va a utilizar:

template __declspec(dllexport) void updateParamValue<int>(const std::string& name, T val); 
template __declspec(dllexport) void updateParamValue<short>(const std::string& name, T val); 
...... 

yo uso esto en Visual Studio 2013 y funciona.

Cuestiones relacionadas