2010-01-21 43 views
6

我正在研究跨越許多共享庫的相當大小的項目。我們也非常依賴STL,Boost和我們自己的模板類和函數。許多導出的類包含模板成員,導出的函數包含模板參數。在共享對象/ DLL中使用模板化的類和函數

這裏是我該怎麼辦庫中導出一個精簡的例子:

#if defined(_MSC_VER) && defined(_DLL) 
    // Microsoft 
    #define EXPORT __declspec(dllexport) 
    #define IMPORT __declspec(dllimport) 
#elif defined(_GCC) 
    // GCC 
    #define EXPORT __attribute__((visibility("default"))) 
    #define IMPORT 
#else 
    // do nothing and hope for the best at link time 
    #define EXPORT 
    #define IMPORT 
#endif 

#ifdef _CORE_COMPILATION 
#define PUBLIC_CORE EXPORT 
#define EXTERNAL_CORE 
#else 
#define PUBLIC_CORE IMPORT 
#define EXTERNAL_CORE extern 
#endif 

#include <deque> 

// force exporting of templates 
EXTERNAL_CORE template class PUBLIC_CORE std::allocator<int>; 
EXTERNAL_CORE template class PUBLIC_CORE std::deque<int, std::allocator<int> >; 

class PUBLIC_CORE MyObject 
{ 
private: 
    std::deque<int> m_deque; 
}; 

SO,我的問題是,當我在Visual Studio(2008和2010)編譯,我得到以下警告:

警告C4251: '的std :: _ Deque_val < _Ty,_Alloc> :: _ Almap' :類 '的std ::分配器< _Ty>' 需要 具有的dll間通過類 的 客戶的std :: _ Deque_val < _Ty,_Alloc>'

這似乎意味着,我沒有出口std::allocator<int>,這是我使用的臉。而且它不喜歡我的出口是不正確的,因爲不包括

EXTERNAL_CORE template class PUBLIC_CORE std::allocator<int>; 
EXTERNAL_CORE template class PUBLIC_CORE std::deque<int, std::allocator<int> >; 

產生了警告:

警告C4251: '爲MyObject :: m_deque': 類 '的std :: deque的< _Ty>'需要有 的dll接口由 類客戶端使用「爲MyObject」

我能想到的唯一的事情是,_Ty約個警告e std::allocator在說什麼是不是int,但我似乎無法找到任何跡象,否則,因爲std::deque<int>將在邏輯上分配一個std::allocator<int>

一個使用中的應用程序可以很好地使用這個類,但我有一種直覺,認爲這個警告不應該被忽略。在Linux中使用g ++進行編譯時,不會發生錯誤(儘管這並不意味着它正常工作)。 g ++是否自動執行MSVC無法執行的操作?我一直在Linux上使用GCC,在OSX上使用LLVM,在Windows上使用MSVC,但是我可能會轉而使用MinGW進行Windows開發,所以放棄MSVC並不是完全沒有問題的(如果這樣做太不方便) 。

+1

_very_很好,你嘗試解釋這些警告! – xtofl 2010-01-21 15:05:44

+0

這是一個(或類似的)http://stackoverflow.com/q/5661738/417197的重複? – 2013-11-05 09:29:39

回答

3

正如您所知,導出文件中的模板實際上是編譯器的'允許您填寫任何您認爲必要的'權限。

這意味着如果您使用編譯器A編譯頭文件,它可能會實例化一個完全不同於編譯器B的deque<int>。一些成員的順序可能會改變,一個成員變量甚至實際類型。

這就是編譯器警告你的原因。

編輯:就將此一些後果的解釋

那麼您的共享庫將很好地只有當通過相同編譯器編譯的共同努力。如果您希望他們一起工作,您可以確保所有客戶端代碼都「看到」相同的聲明(通過使用相同的stl實現),或者退出添加模板到您的API。

+1

+1:不僅是相同的編譯器,而是相同編譯器的相同版本。例如,VS 2008和VS 2008 SP1可能會有不同的STL類型實現。 – 2010-01-21 15:14:34

+0

我的印象是像'EXTERNAL_CORE模板類PUBLIC_CORE std :: deque >'這樣的語句是爲了強制編譯器編譯使用者使用原始編譯器的std :: deque實現,直到__dllimport。容器是我真正遇到問題的唯一的東西(因爲出口的東西不那麼複雜似乎工作正常)。 – 2010-01-21 15:18:59

+0

@Travis:例如,目標編譯器如何知道std :: deque的原始實現是什麼? – 2010-01-21 15:32:16