C++模板坑,一起來issue
C++開發中通常將類定義放在C ++頭文件(.h)中,并將實現放在C ++源文件(.cpp)中。然后,將源文件作為項目的一部分,這意味著將其單獨編譯。但是,當我們對模板類實施此過程時,將出現一些編譯和鏈接問題。
本文闡述了三種可能的解決方案,幫助大家可以在實現該模板的源文件中創建一個模板類的對象,解決上述問題。
問題復現
頭文件聲明:
- // temp.h
- #ifndef _TEMP_H_
- #define _TEMP_H_
- #include <iostream>
- #include <vector>
- template <typename T>
- using Vec = std::vector<T>;
- #define PRINTFMT(x) std::cout << x << " ";
- template <typename T>
- void TestTemp(const Vec<T> &v, T target);
- #endif
頭文件實現:
- #include "temp.h"
- template <typename T>
- void TestTemp(const Vec<T> &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 <iostream>
- #include <vector>
- template <typename T>
- using Vec = std::vector<T>;
- #define PRINTFMT(x) std::cout << x << " ";
- template <typename T>
- void TestTemp(const Vec<T> &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<T> &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 <iostream>
- #include <vector>
- template <typename T>
- using Vec = std::vector<T>;
- #define PRINTFMT(x) std::cout << x << " ";
- template <typename T>
- void TestTemp(const Vec<T> &v, T target);
- #include "temp.cpp"
- #endif
頭文件定義即可:
- // Temp.cpp
- #include "temp.h"
- template <typename T>
- void TestTemp(const Vec<T> &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了。