2010-09-19 63 views
0

我使用Code :: Blocks構建我的項目,其中包含三個文件:main.cpp,TimeSeries.cpp,TimeSeries.hTimeSeries.h提供了TimeSeries類聲明如下:對ClassName :: ClassName的未定義引用

template<class XType, class YType> class TimeSeries { 
public: 
    TimeSeries(void); 
    ~TimeSeries(void); 
}; 

然後TimeSeries.cpp包含: 的#include 「TimeSeries.h」

template<class XType, class YType> 
TimeSeries<XType, YType>::TimeSeries(void) { 
} 

template<class XType, class YType> 
TimeSeries<XType, YType>::~TimeSeries(void) { 
} 

最後,main.cpp包含

#include "TimeSeries.h" 
typedef TimeSeries<float, float> FTimeSeries; 

int main(int argc, char** argv) { 
    FTimeSeries input_data; 
    return 0; 
} 

建設當與C :: B,我得到以下錯誤:

undefined reference to `TimeSeries<float, float>::TimeSeries()' 

我該怎麼辦?

謝謝,
CFP。

回答

2

將代碼拆分爲頭文件和源文件的原因是聲明和實現是分開的。編譯器可以將源文件(編譯單元)翻譯成目標文件,其他希望使用類和函數的編譯單元只包含頭文件,並鏈接目標文件。這樣,代碼只能被編譯一次,並且可以通過鏈接來重用。

模板的問題在於,只要沒有爲它們提供參數,編譯器就無法編譯它們。使用不同參數實例化的相同模板會導致不同的類型。從編譯器的角度來看,std::vector<int>std::vector<float>沒有任何關聯。因此,模板類通常必須完全駐留在頭文件中,因爲在使用模板時,編譯器需要完整定義才能根據參數生成類。

正如@Gabriel Schreiber在his answer中指出的那樣,您可以告訴編譯器他應該使用一組特定的參數編譯模板,僅通過鏈接就可以將其提供給其他編譯單元。但是,這不會使該模板可用於其他參數集。

+0

感謝您的全面回答! – 2010-09-21 16:59:32

3

基本上所有的模板化代碼都應該在頭文件中定義,否則它將不會被編譯,因爲沒有在編譯單元中使用它。

每個cpp文件都被編譯爲一個單獨的單元,因此不會編譯構造函數和析構函數。當編譯TimeSeries.cpp時,編譯器無法知道您將在main.cpp中使用哪種類型的模板參數。

+1

所以我會把所有的代碼放在頭文件中?這很奇怪,不是嗎? – 2010-09-19 07:50:09

+0

@CFP:聽起來很奇怪,但對於模板而言,這是(不幸的)要走的路。 – 2010-09-19 11:10:35

1

您需要在您的.cpp文件添加此(定義如下):

template class TimeSeries<float, float>; 

當編譯器編譯TimeSeries.cpp它不知道這對於哪些類型的模板是需要,因爲它在另一個源文件中使用。你需要明確告訴編譯器。

閱讀您的Stroustrup副本或Internet上的顯式模板實例。

+0

我明白了,謝謝=)但是這會殺死模板的大部分力量,不是嗎? – 2010-09-21 17:04:23

相關問題