0

我正在使用 Code::Blocks 来构建我的项目,其中包含三个文件:main.cpp, TimeSeries.cpp, TimeSeries.h. TimeSeries.hTimeSeries类提供如下声明:

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。

4

3 回答 3

3

基本上所有的模板化代码都应该在头文件中定义,否则它不会被构建,因为在编译单元中没有使用它。

每个 cpp 文件被编译为一个单独的单元,因此构造函数和析构函数没有被编译。当编译 TimeSeries.cpp 时,编译器无法知道您将在 main.cpp 中使用什么类型的模板参数。

于 2010-09-19T07:42:52.103 回答
2

将代码拆分为头文件和源文件的原因是声明和实现是分开的。编译器可以将源文件(编译单元)翻译成目标文件,而其他想要使用类和函数的编译单元只需包含头文件,并链接目标文件。这样,代码只需编译一次,并且可以通过链接重用。

模板的问题在于,只要没有为它们提供参数,编译器就无法编译它们。使用不同参数实例化的相同模板会产生不同的类型。std::vector<int>并且std::vector<float>从编译器的角度来看,没有任何关系。因此,模板类通常必须完全驻留在头文件中,因为在使用模板时,编译器需要完整的定义才能根据参数生成类。

正如@Gabriel Schreiber 在他的回答中指出的那样,您可以告诉编译器他应该使用一组特定的参数编译模板,只需通过链接就可以将其提供给其他编译单元。但是,这不会使模板可用于其他参数集。

于 2010-09-19T11:14:09.303 回答
1

您需要将其添加到您的 .cpp 文件中(在定义下方):

template class TimeSeries<float, float>;

当编译器编译 TimeSeries.cpp 时,它不知道哪些类型需要模板,因为它在另一个源文件中使用。您需要明确告诉编译器。

在您的 Stroustrup 副本或互联网上阅读有关显式模板实例化的信息。

于 2010-09-19T11:04:11.557 回答