模板化成员函数的声明和实现
Declaration and implementation of templated member functions
我正在尝试创建一个快速的实用程序类,通过组合扩展std::vector
。为此,我想使其尽可能通用。
当在单个文件(即main.cpp)中声明和实现时,该类运行良好:
主.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;
};
...
.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);
}
主.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;
}
错误
函数 'FVector::forEach<(lambda at blah/main.cpp:95:21)>' 有 内部链接,但未定义
显然,我的语法中的某些内容非常错误,但是我找不到如何声明/实现这些函数。
谢谢!
C++模板是特殊的动物:模板的每个实例化都是一个不同的类。这意味着,如果您尝试将模板类定义放在其自己的 cpp 中,因为该翻译单元中不需要实例化,编译器将不生成任何实例。当您尝试使用另一个翻译单元中的一个时,链接器会抱怨,因为它找不到具体的定义。
该标准在草案 n4296 中声明(强调我的):
14 模板 [临时]
...
函数模板、类模板的成员函数、变量模板或 类模板应在隐式实例化的每个翻译单元中定义(14.7.1),除非 相应的专业化在某个翻译单元中显式实例化 (14.7.2);无诊断 必填。
这就是为什么常见的用途是在头文件中的模板上编写完整的定义,以确保定义将存在于每个翻译单元中。
现在,只有一个如何为 FVector 创建实例的配方,但没有创建任何实例。您需要实例化一个。源文件无法"知道"需要哪些实例,因为它不包含在使用模板中的类的某个地方,这就是问题所在(好吧,表述不正确,但我希望你明白这一点 - 基本上,当文件包含标头时,它可以使用标头中的所有内容从模板中创建类, 但不是它甚至不知道的某些来源中的内容)
这可以通过编写类似的东西来完成
template class FVector<double>;
在源文件的末尾,使其专用化一倍以上,然后对于应该存在的每个 forEach 专用化都相同。我通常有另一个文件,ClassNameSpecialization.h(在你的例子中是FVectorSpecialization.h),它只包含这样的行,并包含在源文件的末尾。可以轻松添加一些专业。
如果您希望 FVector 是动态的,能够使用任何可能与代码一起使用的模板参数,则需要在标头中实现它,尽管这当然很丑陋。
- 是什么原因导致它无法编译?它是声明签名还是在函数本身的实现中
- 如何制作 cmakelists.txt编译使用在其他地方声明和实现的函数和类的 CPP
- 在实现文件中使用模板参数声明方法
- 在 h 和 cpp 文件中单独声明和实现模板有时有效,有时会出现链接器错误
- 在声明或实现中延迟初始化C++单一实例
- 声明中的实现C
- 如何实现声明功能-C 11,编译时间
- enable_if在类声明之外实现的方法专用化
- 将模板化实现分配给先前声明的函数
- 头文件中的类声明和实现
- 实现文件只能识别其他类的远期声明
- 避免对实现接口的类使用多个几乎相同的声明
- 模板化成员函数的声明和实现
- 如何用默认模板参数分离模板类的声明和实现
- 当声明了虚拟析构函数但没有实现时会发生什么情况
- 如何使用 std::enable_if 时拆分声明和实现
- 如何在类声明之外实现显式覆盖
- 使用声明实现这个抽象类
- 如何在类(c++)中声明/实现特定类型的数组
- 应该在无指针类中声明/实现析构吗?