C++模板坑,一起来issue
C++开发中通常将类定义放在C ++头文件(.h)中,并将实现放在C ++源文件(.cpp)中。然后,将源文件作为项目的一部分,这意味着将其单独编译。但是,当我们对模板类实施此过程时,将出现一些编译和链接问题。
本文阐述了三种可能的解决方案,帮助大家可以在实现该模板的源文件中创建一个模板类的对象,解决上述问题。
问题复现
头文件声明:
// temp.h
#ifndef _TEMP_H_
#define _TEMP_H_
#include
#include
template <typename T>
using Vec = std::vector;#define PRINTFMT(x) std::cout <" ";template <typename T>void TestTemp(const Vec &v, T target);#endif
头文件实现:
#include "temp.h"
template <typename T>
void TestTemp(const Vec &v, T target){
[=]() {
for (auto elem : v)
if (elem == target)
PRINTFMT(elem);
}();
}
报错:
undefined reference to....
问题描述:当在.h中声明了模板,.cpp中定义了模板,当main函数去进行模板实例化的时候,在声明处找不到对应的T类型,自然就出问题了。
1.第一种:同一文件
声明及定义都在.h文件中。
// temp.h
#ifndef _TEMP_H_
#define _TEMP_H_
#include
#include
template <typename T>
using Vec = std::vector;#define PRINTFMT(x) std::cout <" ";template <typename T>void TestTemp(const Vec &v, T target){
[=]() {for (auto elem : v)if (elem == target)
PRINTFMT(elem);
}();
}#endif
2.第二种:分离开+引入头文件
采用头文件声明,cpp定义,要想起作用,得在使用处引入两者并且定义处得用特化版本。
例如:
头文件实现:
// Temp.cpp
#include "temp.h"
void TestTemp(const Vec<int> &v, int target){
[=]() {
for (auto elem : v)
if (elem == target)
PRINTFMT(elem);
}();
}
template <typename T>
void TestTemp(const Vec &v, T target){
[=]() {
for (auto elem : v)
if (elem == target)
PRINTFMT(elem);
}();
}
实现:
#include "temp.h"
#include "temp.cpp"
int main() {
std::vector<int> v{1,2,3};
int target = 2;
TestTemp<int>(v,target);
return 0;
}
3.在末尾引入cpp
只需要在.h头文件末尾引入cpp即可。
头文件只需要声明:
// temp.h
#ifndef _TEMP_H_
#define _TEMP_H_
#include
#include
template <typename T>
using Vec = std::vector;#define PRINTFMT(x) std::cout <" ";template <typename T>void TestTemp(const Vec &v, T target);#include "temp.cpp"#endif
头文件定义即可:
// Temp.cpp
#include "temp.h"
template <typename T>
void TestTemp(const Vec &v, T target){
[=]() {
for (auto elem : v)
if (elem == target)
PRINTFMT(elem);
}();
}
调用处正常调用:
#include "temp.h"
int main() {
std::vector<int> v{1,2,3};
int target = 2;
TestTemp<int>(v,target);
return 0;
}
在一些开源项目中,这种方式比较常见,只不过这里的.cpp得改为.hpp。其余不变!
4.总结
本节针对日常代码中的难点进行了梳理,提出了几种解决方案。可以简单的把模板理解为一种特殊的宏,模板类不要当作类,在被实例化的时候一定得找到定义,不然只看到声明,就GG了。