C++模板坑,一起来issue

开发 后端
C++开发中通常将类定义放在C ++头文件(.h)中,并将实现放在C ++源文件(.cpp)中。然后,将源文件作为项目的一部分,这意味着将其单独编译。但是,当我们对模板类实施此过程时,将出现一些编译和链接问题。本文阐述了三种可能的解决方案,帮助大家可以在实现该模板的源文件中创建一个模板类的对象,解决上述问题。

[[329857]]

C++开发中通常将类定义放在C ++头文件(.h)中,并将实现放在C ++源文件(.cpp)中。然后,将源文件作为项目的一部分,这意味着将其单独编译。但是,当我们对模板类实施此过程时,将出现一些编译和链接问题。

本文阐述了三种可能的解决方案,帮助大家可以在实现该模板的源文件中创建一个模板类的对象,解决上述问题。

问题复现

头文件声明:

 

  1. // temp.h 
  2. #ifndef _TEMP_H_ 
  3. #define _TEMP_H_ 
  4. #include <iostream> 
  5. #include <vector> 
  6. template <typename T> 
  7. using Vec = std::vector<T>; 
  8. #define PRINTFMT(x) std::cout << x << " "
  9.  
  10. template <typename T> 
  11. void TestTemp(const Vec<T> &v, T target); 
  12. #endif 

头文件实现:

 

  1. #include "temp.h" 
  2.  
  3.  
  4. template <typename T> 
  5. void TestTemp(const Vec<T> &v, T target) 
  6.     [=]() { 
  7.         for (auto elem : v) 
  8.             if (elem == target) 
  9.                 PRINTFMT(elem); 
  10.     }(); 

报错:

 

  1. undefined reference to.... 

问题描述:当在.h中声明了模板,.cpp中定义了模板,当main函数去进行模板实例化的时候,在声明处找不到对应的T类型,自然就出问题了。

1.第一种:同一文件

声明及定义都在.h文件中。

 

  1. // temp.h 
  2. #ifndef _TEMP_H_ 
  3. #define _TEMP_H_ 
  4. #include <iostream> 
  5. #include <vector> 
  6. template <typename T> 
  7. using Vec = std::vector<T>; 
  8. #define PRINTFMT(x) std::cout << x << " "
  9.  
  10. template <typename T> 
  11. void TestTemp(const Vec<T> &v, T target) 
  12.     [=]() { 
  13.         for (auto elem : v) 
  14.             if (elem == target) 
  15.                 PRINTFMT(elem); 
  16.     }(); 
  17. #endif 

2.第二种:分离开+引入头文件

采用头文件声明,cpp定义,要想起作用,得在使用处引入两者并且定义处得用特化版本。

例如:

头文件实现:

 

  1. // Temp.cpp 
  2. #include "temp.h" 
  3.  
  4. void TestTemp(const Vec<int> &v, int target) 
  5.     [=]() { 
  6.         for (auto elem : v) 
  7.             if (elem == target) 
  8.                 PRINTFMT(elem); 
  9.     }(); 
  10.  
  11. template <typename T> 
  12. void TestTemp(const Vec<T> &v, T target) 
  13.     [=]() { 
  14.         for (auto elem : v) 
  15.             if (elem == target) 
  16.                 PRINTFMT(elem); 
  17.     }(); 

实现:

 

  1. #include "temp.h" 
  2. #include "temp.cpp" 
  3.  
  4. int main() { 
  5.     std::vector<int> v{1,2,3}; 
  6.     int target = 2; 
  7.     TestTemp<int>(v,target); 
  8.  
  9.     return 0; 

3.在末尾引入cpp

只需要在.h头文件末尾引入cpp即可。

头文件只需要声明:

 

  1. // temp.h 
  2. #ifndef _TEMP_H_ 
  3. #define _TEMP_H_ 
  4. #include <iostream> 
  5. #include <vector> 
  6. template <typename T> 
  7. using Vec = std::vector<T>; 
  8. #define PRINTFMT(x) std::cout << x << " "
  9.  
  10. template <typename T> 
  11. void TestTemp(const Vec<T> &v, T target); 
  12. #include "temp.cpp" 
  13. #endif 

头文件定义即可:

 

  1. // Temp.cpp 
  2. #include "temp.h" 
  3.  
  4. template <typename T> 
  5. void TestTemp(const Vec<T> &v, T target) 
  6.     [=]() { 
  7.         for (auto elem : v) 
  8.             if (elem == target) 
  9.                 PRINTFMT(elem); 
  10.     }(); 

调用处正常调用:

 

  1. #include "temp.h" 
  2.  
  3. int main() { 
  4.     std::vector<int> v{1,2,3}; 
  5.     int target = 2; 
  6.     TestTemp<int>(v,target); 
  7.  
  8.     return 0; 

在一些开源项目中,这种方式比较常见,只不过这里的.cpp得改为.hpp。其余不变!

4.总结

本节针对日常代码中的难点进行了梳理,提出了几种解决方案。可以简单的把模板理解为一种特殊的宏,模板类不要当作类,在被实例化的时候一定得找到定义,不然只看到声明,就GG了。

责任编辑:庞桂玉 来源: C语言与C++编程
相关推荐

2012-04-14 20:47:45

Android

2012-06-25 09:37:24

Web

2012-11-08 17:33:53

智慧云

2021-06-09 08:15:50

volatileJava开发

2010-05-21 17:32:07

IIS服务器

2009-10-29 16:32:34

Oracle表空间

2012-09-10 13:42:55

PHP项目管理

2021-06-02 15:30:12

Synchronize并发多线程

2021-04-26 11:18:15

FedoraLinuxBug

2022-05-20 12:14:50

ZuulSpringClou

2011-09-07 22:59:07

联想一体机

2010-05-10 15:31:35

Unix文件

2009-07-14 16:35:57

Swing组件大全

2012-07-10 09:14:51

Web

2009-09-09 09:23:37

服务器稳定性

2017-11-02 14:39:54

2021-07-28 14:15:51

漏洞悬赏平台漏洞谷歌

2017-11-02 15:28:52

2021-01-20 15:31:00

区块链比特币数字货币
点赞
收藏

51CTO技术栈公众号