DLL中導出STL模板類的問題

接上一篇。shell

上一篇的dll在編譯過程當中一直有一個警告warning C4251: ‘CLASS_TEST::m_structs’ : class ‘std::vector<_Ty>’ needs to have dll-interface to be used by clients of class ,百函數

度之才發現是由於DLL中導出了STL中的類,二STL中的類默認是沒有導出的,所以報告這個警告。spa

程序中消除warning有兩種方法:.net

消極一點不去理他,反正不是error;日誌

積極一點,則想辦法去掉。去掉又用兩種方法:一種使用#pragma warning(disable: xxxx),眼不見,心不煩;另外就是找出解決問題的辦法了。在頭文件中,定義宏code

#ifdef DLL_EXPORT
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif

搜索之,獲得解決辦法,修改後代碼以下:blog

class DLL_API dllBase
{
public:
    dllBase ( void );
    ~dllBase ( void );
    int get();
private:
    static int base;
    template class DLL_API allocator< string >;
    template class DLL_API vector<string, allocator< string > >;
    vector<string> m_list;
};

但是這樣編譯又出問題了,error C2252: an explicit instantiation of a template can only occur at namespace scope。繼續搜索之,說是應該吧上面的兩句話放到類的外面接口

再次試之,成功了,代碼以下ci

template class DLL_API allocator< string >;
template class DLL_API vector<string, allocator< string > >;
class DLL_API dllBase
{
public:
    dllBase ( void );
    ~dllBase ( void );
    int get();
private:
    static int base;
    vector<string> m_list;
};

注:由於STL中只有vector能夠直接導出,因此該方法成功了,如果將vector換成List,則依然會繼續報告C4251錯誤,暫時還不知道怎麼解決。get

雖然能夠使用了,可是每次都在類前面寫入那麼一大堆東西,看着就有點煩,因而乎發現了一篇很是強大的日誌,在其中發現了一個比較好的辦法來解決這個問題,具體就不寫了。

可是使用它定義的帶參數的宏能夠比較方便的修改。

代碼以下:

#define DLL_STL_LIST( STL_API, STL_TYPE ) \
    template class STL_API std::allocator< STL_TYPE >; \
    template class STL_API std::vector<STL_TYPE, std::allocator< STL_TYPE > >;

DLL_STL_LIST ( DLL_API, string );

class DLL_API dllBase
{
public:
    dllBase ( void );
    ~dllBase ( void );
    int get();
private:
    static int base;
    vector<string> m_list;
};

 

參考的另外一篇博客:

1:狀況一
若是類的定義裏面僅含有 編譯器內置的類型變量, int, float 等等. 或者成員函數僅使用了這些變量做爲參數, 那麼很簡單.
直接
class __declspec(dllexport) YourClass

{
}
就好了.

2:狀況二
若是類內部使用了別的類, 那麼別的類最好也導出, 否則, 首先編譯的時候會出現編譯警告:
warning C4251: needs to have dll-interface 
意思是,你使用另外的一些類型/接口, 可是這些類型或接口沒有導出. 當你的client使用這些類型/接口的時候, 會出錯!
class __declspec(dllexport) YourClass

{
   YourAnatherClass m_data; // 這裏會 出現 warning 4251. 若是YourAnatherClass 沒有導出的話.
}
解決辦法就是: 在YourAnatherClass定義的地方加上
class __declspec(dllexport) YourAnatherClass 
{
}
如上, 當你的YourAnatherClass沒有導出的時候, dll的使用方會出現連接錯誤

3:狀況三
當類的內部使用了STL模板的時候, 也會出現C4251警告, 狀況會有所不一樣
class __declspec(dllexport) YourClass

{
   vector m_data; // 這裏會 出現 warning 4251. 由於vector類型沒有被導出
}
上面的使用模板(不管是stl模板,仍是自定義模板)的代碼,編譯dll時會出現C4251警告, 可是dll的使用方, 卻不會出現連接錯誤!!!
這個由於, dll的使用方那裏也有一套模板的定義, 當他們使用那個vector的時候, 雖沒有導出, 可是用戶本身也有一套STL模板(或者是自定義的模板),用戶會利用本身的模板實例化這個dll中沒有導出的東西!

因此, 對於由於使用STL(或模板)出現的c4251警告, 關閉之便可
#pragma warning(push)
#pragma warning(disable:4251)
//your declarations that cause 4251
#pragma warning(pop)

若想不使用經過關閉警告的方式關閉警告, 那麼就這樣

1)對於用戶自定義的模板
   template class DLLImportExportMacro SomeTemplate;
   SomeTemplate y;
2)對於STL的模板
template class DLL_API allocator< string >;

template class DLL_API vector<string, allocator< string > >;

vector<string> m_data;

相關文章
相關標籤/搜索