エクスポートされたテンプレートのインスタンス化における旧スタイルの名前変形
更新 : 2007 年 11 月
Visual C++ 準拠作業の 1 つは、関数テンプレートおよび標準テンプレートの特殊な形式をオーバーロードできるようにすることです。
たとえば、次のコード例は、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);
}
関数テンプレートおよび標準テンプレートの特殊な形式をオーバーロードできるようにするために、コンパイラは、関数テンプレートの特殊な形式の修飾名の作成方法を変更しました。新しくなった修飾名には、テンプレート引数のエンコーディング、関数パラメータと戻り値の型のエンコーディングが含まれます。前の例の関数では、Visual Studio .NET 2003 の C++ コンパイラは次の修飾名を生成します。
?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 Studio .NET (またはそれ以前) の Visual C++ コンパイラでビルドされていた場合は、このアプリケーションの再ビルドを行わなければ、ランタイム エラーが発生します。これは、このアプリケーションが、古い名前のエントリ ポイントを想定しているためです。しかし、新しい 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 のビルド方法を変更する方法が考えられます。これは、link プログラムへの /export を使用することによって行います。次に例を示します。
cl /D_DLL_EXPORT /EHsc /LD a.cpp /link /export:?f@@YAXABH@Z=??$f@H@@YAXABH@Z
これにより、link は、指定された名前の両方のエクスポートを作成しながら、これらの名前を同じシンボルにマップします。