对类模板的成员函数的未定义引用

时间:2012-02-19 19:03:22

标签: c++ templates stl containers

我想在模板类方法中使用迭代器。 这是我的代码:(testclass.h)

template<typename T, typename container>
class TestClassX
{
public:
    void gen(typename container::iterator first );
};

和文件testclass.cpp:

template<typename T, typename container>
void TestClassX<T, container>::gen(typename container::iterator first)
{

}

当我尝试运行它时:

TestClassX<unsigned, std::vector<unsigned> > testx;
testx.gen(it);

我收到错误:

Error:undefined reference to `TestClassX<unsigned int, std::vector<unsigned int, std::allocator<unsigned int> > >::gen(__gnu_cxx::__normal_iterator<unsigned int*, std::vector<unsigned int, std::allocator<unsigned int> > >)'

我使用mingw32 4.4

我希望有一个类可以写入不同的容器,如std :: vector,std :: list,QVector或QList,它们都具有STL样式的迭代器。

3 个答案:

答案 0 :(得分:10)

模板类方法必须在头文件中定义。当您使用模板类时,编译器实际上为给定的模板参数编译该类的版本。因此,要求在包含头文件时每种方法的主体都可用。

删除源文件并将主体包含在testclass.h中:

template<typename T, typename container>
class TestClassX
{
public:
    void gen(typename container::iterator first ) {

    }
};

答案 1 :(得分:1)

模板类方法不需要在头文件中定义。但是如果你这样做,你需要定义一个单独的编译单元(例如templates.cpp),并且你需要包含模板类的源代码文件(例如#include&#34; container.cpp&#34; // .cpp而不是.hpp文件) 那么你需要定义你正在使用的模板的实例(例如模板类Container;)。 您还需要为模板类定义对象(例如Link)。在这种特殊情况下,由于我们使用指向此对象的指针(例如Link *,在Containter中),我们只需要向前声明&#39;那个对象。

这是完整的template.cpp文件。您将编译并链接其余代码。

class Link;
#include "Container.cpp"    // use the source code, not the header
template class Container<Link*>; 

我喜欢使用此方法,因为它会阻止编译器自动生成模板类实例,并让您知道何时无法找到它。

使用选项-fno-implicit-templates与gcc编译。

构建时,所有内容都将按正常方式编译,但收集器将重新编译templates.cpp文件以查找使用该模板的所有对象。

答案 2 :(得分:0)

如前所述,在实例化模板时,定义必须存在于同一个编译单元中。

我个人更喜欢将定义与声明分开 这样可以使头文件更清晰,并在视觉上将界面与实现区分开来。

因此,一种解决方案可以如下:

//TestClass.hpp

//Interface:
template<typename T>
class TestClassX
{
public:
    void gen(int a);
    //more declaraions...
}; 

//Implementations:
template<typename T>
void TestClassX<T>::gen(int a)
{
    //beautiful code
}

您可以将实现和界面放在单独的文件中 (即分别为TestClass.hppITestClass.hppTestClass.hpp最初将#include ITestClass.hpp,然后定义功能,如上例所示 然后,客户只需要#include TestClass.hpp