DLL 無法直接導出模板類別,必須先**顯式實例化**再匯出。本文詳述導出 `std::vector` 等 STL 容器、包含 STL 成員的類別、自定型別作模板參數時的完整步驟與陷阱。
// VecDLL.h
#ifdef VECDLL_EXPORTS
#define VECDLL_API __declspec(dllexport)
#else
#define VECDLL_API __declspec(dllimport)
#endif
// 顯式實例化宣告 (DLL 端定義,EXE 端引用)
#define EXPIMP_TEMPLATE extern VECDLL_API
// 導出 std::vector
EXPIMP_TEMPLATE template class VECDLL_API std::vector;
// 導出函數
VECDLL_API int fnVecDll(std::vector& vec);
// VecDLL.cpp
#include "VecDLL.h"
// 顯式實例化定義 (僅 DLL 端編譯)
template class VECDLL_API std::vector;
int fnVecDll(std::vector& vec) {
vec.push_back(42);
return vec.size();
}
自定型別必須實作 `operator<` 與 `operator==`(STL 容器比較操作需求):
class CPerson {
public:
int m_nAge;
char m_strName[40];
bool operator<(const CPerson& c) const { return m_nAge < c.m_nAge; }
bool operator==(const CPerson& c) const { return m_nAge == c.m_nAge; }
};
// 導出 std::vector
EXPIMP_TEMPLATE template class VECDLL_API std::vector;
VECDLL_API int fnVecDllPerson(std::vector& vec);
原因:顯式實例化會強制實例化容器所有成員函數(含比較操作),故需提供比較運算子。若不關心語意,可單純 `return true`。
// 先導出成員容器實例
EXPIMP_TEMPLATE template class VECDLL_API std::vector;
class VECDLL_API CContainer {
public:
std::vector m_vecNum;
void Add(int n) { m_vecNum.push_back(n); }
int Size() const { return m_vecNum.size(); }
};
VecDLL.h:共用介面宣告(含 `EXPIMP_TEMPLATE` 巨集)VecDLL.cpp:DLL 實作與顯式實例化定義ClientEXE.cpp:引用 DLL,連結 `VecDLL.lib`| 錯誤現象 | 原因 | 解決 |
|---|---|---|
| 連結錯誤 LNK2001 未解析外部符號 | 缺少顯式實例化定義 | DLL 端 .cpp 加入 `template class VECDLL_API std::vector<...>;` |
| 執行期崩潰 / 堆損毀 | DLL/EXE CRT 版本不一致 | 專案屬性 → C/C++ → 代碼生成 → 執行階段程式庫 統一設定 |
| 類別大小不匹配 | STL 實作差異 (Debug/Release 混用) | 同樣 CRT 設定 |
| 導出 map/set 失敗 | 巢狀類別 (iterator, node) 無法導出 | 改用 vector + 排序/二分搜尋,或自行實作介面類別 |
完整 DLL/EXE 範例專案已附於配套資源。