Поделиться через


Старый стиль искажения имен для экспортированных экземпляров шаблонов

Обновлен: Ноябрь 2007

Одним из аспектов работы по согласованию Visual C++ является разрешение перегрузки специализаций шаблонов функций и обычных шаблонов.

Например, код из следующих примеров успешно компилируется в Visual Studio .NET 2003, но в 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);
}

Для поддержки перегрузки специализаций шаблонов функций и обычных шаблонов изменен способ создания компилятором декорированных имен для специализаций шаблонов функций. Обновленное декорированное имя теперь включает кодирование аргументов шаблона, а также кодирование параметров и возвращаемых значений функций. Например, для функций из предыдущего примера компилятор C++ в Visual Studio .NET 2003 будет создавать следующее декорирование имен:

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

Это не подразумевает каких-либо изменений в способе разработки приложений. Данное изменение затрагивает пользователей, например в случае, когда экспорт является специализацией шаблона функции из библиотеки DLL, использующейся в приложении, которое не было заново скомпилировано новым компилятором. Например:

// 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 &);

Для создания библиотеки DLL будет компилироваться следующий код:

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

Если затем будет выполнена команда:

dumpbin /exports bc_exported_templ_instan2.dll

то можно будет видеть, что экспортированная специализация шаблона функции получает декорированное имя ??$f@H@@YAXABH@Z.

Если существующее приложение с зависимостью в данной библиотеке DLL было построено компилятором Visual C++ в Visual Studio .NET (или в предыдущих версиях), и нет возможности или желания выполнить построение этого приложения заново, то будет получена ошибка во время выполнения, поскольку приложение будет ожидать точку входа со старым именем. Однако новая библиотека DLL будет экспортировать функцию с новым именем.

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

Решение этой проблемы состоит в том, чтобы изменить порядок построения библиотеки DLL так, чтобы она экспортировала как старое, так и новое имя специализации шаблона функции. Это можно сделать, включив /export в программу компоновки библиотеки. Например:

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

Этот код приводит к созданию экспорта для обоих указанных имен при сопоставлении их с одним и тем же символом.

См. также

Ссылки

Критические изменения в компиляторе Visual C++