我试图制作一个快速的实用工具类,通过构图扩展std::vector
。为此,我想让它尽可能通用。
当在单个文件(即main.cpp)中声明和实现时,该类运行良好:
的main.cpp
#include <iostream>
#include <algorithm>
#include <vector>
template<typename T>
class FVector {
public:
FVector(std::vector<T> vector): _vector(vector) {}
template <typename unaryOperation>
void forEach(unaryOperation op) {
std::for_each(_vector.begin(),_vector.end(),op);
};
private:
std::vector<T> _vector;
};
int main(int argc, const char * argv[]) {
auto printInt = [](int i){ std::cout << i << std::endl; };
std::vector<int> numbers{1, 2, 3, 4, 5};
FVector<int> fNumbers{numbers};
fNumbers.forEach(printInt);
return 0;
}
但是当我尝试将类放在自己的.h和.cpp文件中时,编译器找不到构造函数或函数。
FVector.h
...
#include <vector>
template<typename T>
class FVector {
public:
FVector( std::vector<T> );
template <typename unaryOperation>
void forEach(unaryOperation);
private:
std::vector<T> _vector;
};
...
FVector.cpp
#include "FVector.hpp"
#include <algorithm>
template <typename T>
FVector<T>::FVector( std::vector<T> vector ): _vector(vector) {}
template <typename T>
template <typename unaryOperation>
void FVector<T>::forEach(unaryOperation op) {
std::for_each(_vector.begin(),_vector.end(),op);
}
的main.cpp
#include <iostream>
#include "FVector.hpp"
int main(int argc, const char * argv[]) {
auto printInt = [](int i){ std::cout << i << std::endl; };
std::vector<int> numbers{1, 2, 3, 4, 5};
FVector<int> fNumbers{numbers};
fNumbers.forEach(printInt);
return 0;
}
错误
功能&#39; FVector :: forEach&lt;(lambda at blah / main.cpp:95:21)&gt;&#39;具有 内部联系但未定义
显然,我的语法中的某些内容非常错误,但我无法找到如何声明/实现这些函数。
谢谢!
答案 0 :(得分:1)
现在,只有一个配方如何为FVector创建实例,但没有创建。你需要实例化一个。源文件无法“知道”需要哪些实例,因为它不包含在使用模板中的类的地方,这就是问题(好的,错误的表述,但我希望你明白这一点 - 基本上,当一个文件包含一个标题,它可以使用标题中的所有内容来创建一个模板中的类,但不是某些来源甚至不知道的内容。
这可以通过编写类似
的内容来完成template class FVector<double>;
在源文件的末尾,将其专门化为double,然后对应存在的每个forEach-specialization都相同。我通常有另一个文件,ClassNameSpecialization.h(在你的情况下是FVectorSpecialization.h),它只包含这些行,并包含在源文件的末尾。可以轻松添加一些特化。
如果你希望FVector是动态的,能够处理任何可能与代码一起使用的模板参数,你需要在标题中实现它,尽管这当然很难看。
答案 1 :(得分:1)
C ++模板是特殊动物:模板的每个实例都是不同的类。这意味着如果您尝试将模板类定义放在其自己的cpp中,因为该转换单元中不需要任何实例化,编译器将不生成任何实例。当你试图使用另一个翻译单元中的一个时,链接器会抱怨,因为它找不到具体的定义。
标准在n4296草案中声明(强调我的):
14个模板[temp]
...
函数模板,类模板的成员函数,变量模板或静态数据成员 类模板应在每个隐式实例化的翻译单元中定义(14.7.1),除非 在一些翻译单元中明确地实例化了相应的专业化(14.7.2);没有诊断 必需的。
这就是为什么常用的是在头文件中的模板上编写完整定义,以确保定义将出现在每个翻译单元中。