Compartir a través de


Alteración de nombres de estilo anterior para instancias de plantillas exportadas

Actualización: noviembre 2007

Un aspecto del trabajo de conformidad de Visual C++ es permitir la sobrecarga de especializaciones de plantillas de función y plantillas normales.

Por ejemplo, el siguiente código se compila bien en Visual Studio .NET 2003, pero genera errores en Visual Studio .NET:

// bc_exported_templ_instan.cpp
template<typename T, typename U>
T ConvertTo(const U &u) {
   return static_cast<T>(u);
}

char ConvertTo(const int &i) {
   return static_cast<char>(i);
}

int main() {
   char c1 = ConvertTo(1);
   char c2 = ConvertTo<char, int>(2);
}

Para admitir la sobrecarga de especializaciones de plantillas de función y plantillas normales, el compilador ha cambiado la forma de crear nombres representativos para especializaciones de plantillas de función. Un nombre representativo actualizado incluye ahora la codificación de los argumentos de plantilla, así como la codificación del parámetro de función y de los tipos de valor devueltos. Para las funciones del ejemplo anterior, el compilador de C++ de Visual Studio .NET 2003 generará los siguientes nombres representativos:

?ConvertTo@@YADABH@Z      – char ConvertTo(const int &);
??$ConvertTo@DH@@YADABH@Z – char ConvertTo<char, int>(const int &);

Esto no debería implicar ningún cambio en la manera de desarrollar las aplicaciones. Una área donde este cambio sí afecta a los usuarios es si la exportación es una especialización de una plantilla de función de una DLL utilizada en una aplicación que no se ha vuelto a compilar con el nuevo compilador. Por ejemplo:

// bc_exported_templ_instan2.h
#include <iostream>
#ifdef _DLL_EXPORT
#define DLL_LINKAGE __declspec(dllexport)
#else
#define DLL_LINKAGE __declspec(dllimport)
#endif

template<typename T>
void f(const T &rT) {
   std::cout << "i = " << rT << std::endl;
}
template DLL_LINKAGE void f<int>(const int &);

Se compilará el código siguiente para crear la DLL:

// bc_exported_templ_instan2.cpp
// compile with: /D_DLL_EXPORT /EHsc /LD
#include "bc_exported_templ_instan2.h"

Si, a continuación, hace lo siguiente:

dumpbin /exports bc_exported_templ_instan2.dll

Verá que el nombre representativo de la especialización exportada de la plantilla de función es ??$f@H@@YAXABH@Z.

Si una aplicación existente tiene una dependencia sobre esta DLL, y esta aplicación se generó con el compilador de Visual C++ de Visual Studio .NET (o una versión anterior) y no se puede o no se desea volver a generar esta aplicación, entonces se obtendrá un error en tiempo de ejecución, ya que la aplicación estará esperando un punto de entrada con el nombre antiguo. Sin embargo, la nueva DLL sólo exportará una función con el nuevo nombre.

// bc_exported_templ_instan3.cpp
// compile with: /EHsc /link bc_exported_templ_instan2.lib
#include "bc_exported_templ_instan2.h"
int main() {
   f(1);
}

La corrección para este problema consiste en cambiar cómo se genera la DLL, de modo que exporte tanto el nombre antiguo como el nuevo para la especialización de la plantilla de función. Esto se consigue utilizando la opción /export en el vinculador. Por ejemplo:

cl /D_DLL_EXPORT /EHsc /LD a.cpp /link /export:?f@@YAXABH@Z=??$f@H@@YAXABH@Z 

Este comando indica al vinculador que cree una exportación para ambos nombres especificados, pero asignándoles al mismo símbolo.

Vea también

Referencia

Cambios importantes en el compilador de Visual C++