2013-07-08 75 views
3

我在win7中使用VS2008,在CentOS 18中使用g ++ 4.7。當我使用動態共享庫時,問題只出現在Windows上。當我將它轉換爲靜態庫時,程序鏈接正常。Visual Studio dll導出類和函數模板實例的問題

我知道共享庫模板函數/類應該在頭文件中定義,或者應該通過編譯單元提供模板類型(參數)的模板實例化。我選擇了後面的選項。我以前做過,我通過

Why can templates only be implemented in the header file?

C++ Shared Library with Templates: Undefined symbols error

去,但我不能,爲什麼在Windows儘快弄清楚,我轉換對DLL它未能解決的符號庫: 錯誤LNK2019:無法解析的外部符號「void __cdecl HelpingRegistration(double)」(?? $ HelpingRegistration @ N @@ YAXN @ Z)在函數_main中引用

在Windows中,它在靜態庫中工作正常。 在Linux中,動態庫和共享庫都可以工作。

//Static library 
//Library header 
#ifndef _TEMPLATED_STATIC_LIB_ 
#define _TEMPLATED_STATIC_LIB_ 

#include <iostream> 
#include <string> 
#include "Export.h" 

template<typename T> 
class EXPORT TemplatedStaticLib 
{ 
public: 
    TemplatedStaticLib(){}; 
    ~TemplatedStaticLib(){}; 

    void print(T t); 

}; 

template<typename T> 
EXPORT void HelpingRegistration(T); 

#endif 

//庫的.cpp

#include "TemplatedStaticLib.h" 
#include <typeinfo> 


template<typename T> 
void TemplatedStaticLib<T>::print(T t) 
{ 
    std::cout << "Templated Print: "<< t<< " type:: " << typeid(t).name() << std::endl; 
} 

//Class Template explicit instantiation 
template class TemplatedStaticLib<double>; 
template class TemplatedStaticLib<std::string>; 

template<typename T> 
void HelpingRegistration(T t) 
{ 
    std::cout << "Function Templated Print: " << t << " type: " << typeid(t).name() << std::endl; 
     //return t; 
} 

//function template explicit instantiation 
template void HelpingRegistration<>(double); 
template void HelpingRegistration<>(std::string); 

//視窗符號出口

//.h 

#ifndef STATIC_LIB_EXPORT 
#define STATIC_LIB_EXPORT 

#if !defined WIN32 
    #define EXPORT 
#elif defined LIB_EXPORTS 
    #define EXPORT __declspec(dllexport) 
#else 
    #define EXPORT __declspec(dllimport) 
#endif 

//STATIC_LIB_EXPORT 
#endif 

//庫用戶的.cpp

#include <TemplatedStaticLib/TemplatedStaticLib.h> 

#include<string> 

int main(int argc, char* argv[]) 
{ 
    double aDouble = 3.9; 
    TemplatedStaticLib<double> double_test; 
    double_test.print(aDouble); 

    std::string aString = "James"; 
    TemplatedStaticLib<std::string> string_test; 
    string_test.print(aString); 

    HelpingRegistration(aDouble); 
    HelpingRegistration(aString); 


    return 0; 
} 
+0

有這個文學成千上萬的重複。您不能像平常一樣將模板化的類分割爲頭文件和源文件,它們都必須位於頭文件中。 –

+0

[爲什麼模板只能在頭文件中實現?](http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) – juanchopanza

+0

@Joachim Pileborg它肯定可以按照問題http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file中提供的答案所示完成,我也是這樣做的,只有在Windows DLL它導致問題請認真閱讀完整的問題第一 – jazaman

回答

2

我的工作出了問題。在windows下,模板和函數模板的導出方式不同,網絡上有一個有趣的閱讀。

如果在翻譯單元(.cpp)上實例化類模板,VS編譯器會導出類模板符號。

但是,在函數模板的情況下,關鍵字'__declspec(dllexport)'需要明確存在,以使符號出現在動態庫上。

e.g

template EXPORT void HelpingRegistration<double>(double); 
//EXPORT is defined as __declspec(dllexport) 

這只是其中VS決定不同的事情另一種情況。這裏有一個有趣的讀物: http://www.codesynthesis.com/~boris/blog/2010/01/18/dll-export-cxx-templates/

3

我相信你需要導出專業化。

template class EXPORT TemplatedStaticLib<double>; 
template class EXPORT TemplatedStaticLib<std::string>; 

,並幾乎在你的頭一樣:你已經在你的.cpp文件試過這種

template class EXPORT TemplateStaticLib<double>; 
template class EXPORT TemplateStaticLib<std::string>; 

認爲將與您導出宏工作(假設.cpp文件見__declspec(dllexport),標題見__declspec(dllimport))。我承認我不是Windows'__declspec的專家。

我承認我畫我的回答從這個對方的回答對intarwebs:http://social.msdn.microsoft.com/Forums/vstudio/en-US/4fd49664-e28e-4f23-b1eb-b669d35ad264/function-template-instantation-export-from-dll(滾動一路底部的Franjo555的最終版本。)

+0

存在類模板符號。但免費函數模板符號丟失。我使用dumpbin/EXPORT來查看符號。我制定了我將要發佈的解決方案。 – jazaman

+0

雖然我需要導出函數模板實例化,但您的想法是正確的...感謝 – jazaman

+0

假設類本身已導出/導入,則不需要'__declspec(dllimport)'方法。 –

0

我相信這是因爲編譯器在模板類首次與特定參數一起使用時爲模板類創建專用代碼。由於編譯器在編譯編譯單元(.cpp文件)時僅使用包含的頭文件(.h),因此所有的tmplate代碼必須在.h文件中可用。您可以從dll導出專門的模板類,但不能從模板類本身導出。