您遇到的问题是编译器不知道要实例化模板的哪个版本。当您将函数的实现移至 x.cpp 时,它位于与 main.cpp 不同的翻译单元中,并且 main.cpp 无法链接到特定实例化,因为它不存在于该上下文中。这是 C++ 模板的一个众所周知的问题。有以下几种解决方案:
1) 只需将定义直接放入 .h 文件中,就像之前所做的那样。这有优点和缺点,包括解决问题(优点),可能使代码可读性较差,在某些编译器上更难调试(缺点),并且可能增加代码膨胀(缺点)。
2)将实现放在x.cpp中,并且#include "x.cpp"
从内部x.h
。如果这看起来很时髦并且错误,请记住#include
只是读取指定的文件并编译它就好像该文件是x.cpp
换句话说,这与上面的解决方案#1 的作用完全相同,但它将它们保留在单独的物理文件中。在做这种事情时,重要的是不要尝试编译#include
d 文件是它自己的。出于这个原因,我通常会给这些类型的文件一个hpp
扩展名以区分它们h
文件和来自cpp
files.
文件:dumper2.h
#include <iostream>
#include <string>
#include <vector>
void test();
template <class T> void dumpVector( std::vector<T> v,std::string sep);
#include "dumper2.hpp"
文件:dumper2.hpp
template <class T> void dumpVector(std::vector<T> v, std::string sep) {
typename std::vector<T>::iterator vi;
vi = v.begin();
std::cout << *vi;
vi++;
for (;vi<v.end();vi++) {
std::cout << sep << *vi ;
}
std::cout << "\n";
return;
}
3)由于问题在于特定的实例化dumpVector
对于尝试使用它的翻译单元来说是未知的,您可以在定义模板的同一翻译单元中强制对其进行特定实例化。只需添加以下内容即可:template void dumpVector<int>(std::vector<int> v, std::string sep);
...到定义模板的文件。这样做,您不再需要#include
the hpp
文件中的h
file:
文件:dumper2.h
#include <iostream>
#include <string>
#include <vector>
void test();
template <class T> void dumpVector( std::vector<T> v,std::string sep);
文件:dumper2.cpp
template <class T> void dumpVector(std::vector<T> v, std::string sep) {
typename std::vector<T>::iterator vi;
vi = v.begin();
std::cout << *vi;
vi++;
for (;vi<v.end();vi++) {
std::cout << sep << *vi ;
}
std::cout << "\n";
return;
}
template void dumpVector<int>(std::vector<int> v, std::string sep);
顺便说一句,总的来说,您的模板函数正在使用vector
by-value。您可能不想这样做,并通过引用或指针传递它,或者更好的是,传递迭代器以避免制作临时和复制整个向量。