C++模板坑,一起來issue
C++開發(fā)中通常將類定義放在C ++頭文件(.h)中,并將實現(xiàn)放在C ++源文件(.cpp)中。然后,將源文件作為項目的一部分,這意味著將其單獨編譯。但是,當(dāng)我們對模板類實施此過程時,將出現(xiàn)一些編譯和鏈接問題。
本文闡述了三種可能的解決方案,幫助大家可以在實現(xiàn)該模板的源文件中創(chuàng)建一個模板類的對象,解決上述問題。
問題復(fù)現(xiàn)
頭文件聲明:
- // 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
頭文件實現(xiàn):
- #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....
問題描述:當(dāng)在.h中聲明了模板,.cpp中定義了模板,當(dāng)main函數(shù)去進行模板實例化的時候,在聲明處找不到對應(yīng)的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定義,要想起作用,得在使用處引入兩者并且定義處得用特化版本。
例如:
頭文件實現(xiàn):
- // 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);
- }();
- }
實現(xiàn):
- #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);
- }();
- }
調(diào)用處正常調(diào)用:
- #include "temp.h"
- int main() {
- std::vector<int> v{1,2,3};
- int target = 2;
- TestTemp<int>(v,target);
- return 0;
- }
在一些開源項目中,這種方式比較常見,只不過這里的.cpp得改為.hpp。其余不變!
4.總結(jié)
本節(jié)針對日常代碼中的難點進行了梳理,提出了幾種解決方案??梢院唵蔚陌涯0謇斫鉃橐环N特殊的宏,模板類不要當(dāng)作類,在被實例化的時候一定得找到定義,不然只看到聲明,就GG了。