我想在模板类方法中使用迭代器。 这是我的代码:(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样式的迭代器。
答案 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.hpp
和ITestClass.hpp
)
TestClass.hpp
最初将#include ITestClass.hpp
,然后定义功能,如上例所示
然后,客户只需要#include TestClass.hpp
。