樣板具現化的舊樣式名稱改變

更新:2007 年 11 月

Visual C++ 一致化作業的其中一方面,就是要允許函式樣板 (Function Template) 和一般樣板之特製化的多載化 (Overloading)。

例如,下列範例在 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);
}

為了支援函式樣板和一般樣板之特製化的多載化,編譯器會變更其建立函式樣板之特製化的裝飾名稱 (Decorated Name) 之方式。現在,裝飾名稱包含了樣板引數的編碼方式,以及函式參數和傳回型別的編碼方式。對於先前範例中的函式,Visual Studio .NET 2003 中的 C++ 編譯器會產生下列名稱裝飾 (Name Decoration):

?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++ 編譯器所建置,則如果程式開發人員不能或不想重新建置此應用程式,就會因為應用程式需要具有舊名稱的進入點 (Entry Point) 而出現執行階段錯誤。但是,這個新的 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++ 編譯器的重大變更