大家在使用C++代碼時或多或少都會使用到模板,使用模板時應該都是把定義放在了頭文件中,因為放在源文件中定義會編譯失敗。
那問題來了,模板中的函數定義一定要寫在頭文件中嗎?
先說結論:不一定要放在頭文件中,定義也可以放在源文件中,但操作起來還是有點麻煩的。
繼續往下看看
先看一段正常的模板代碼:
// template.h
#include
template <typename T>
struct TemplateTest {
T value;
void func();
};
template <typename T>
void TemplateTest::func() {
std::cout << typeid(T).name() << std::endl;
}
// test_template.cc
#include "template.h"
int main() {
TemplateTest<int> test;
test.func();
return 0;
}
這段代碼沒啥毛病,因為實現放在了頭文件中,也會正常輸出。
如果我把函數定義放在源文件中呢,會怎么樣?
// template.h
#include
template <typename T>
struct TemplateTest {
T value;
void func();
};
// template.cc
template <typename T>
void TemplateTest::func() {
std::cout << typeid(T).name() << std::endl;
}
// test_template.cc
#include "template.h"
int main() {
TemplateTest<int> test;
test.func();
return 0;
}
嗯,不出意外,編譯報錯了,報了個沒有某個函數實現的error:
/tmp/ccPghOjU.o: In function `main':
test_template.cc:(.text+0x1f): undefined reference to `TemplateTest::func()'
collect2: error: ld returned 1 exit status
為什么沒有此函數定義?
先補充個基礎知識,模板的本質。本質其實就是類型泛化,可以用一個T代替多種類型,對于上面的模板,假如有此種使用:
TemplateTest<int> test;
那模板最終可能變成這樣:
struct TemplateTest_int {
int value;
void func() {
std::cout << typeid(int).name() << std::endl;
}
};
如果有這兩種使用:
TemplateTest test;
TemplateTest<float> test;
那模板最終可能會變成這樣:
struct TemplateTest_int {
int value;
void func() {
std::cout << typeid(int).name() << std::endl;
}
};
struct TemplateTest_float {
float value;
void func() {
std::cout << typeid(float).name() << std::endl;
}
};
模板最終會展開成什么樣,取決于用戶是怎么使用它的。
那回到上面的問題,為什么把定義放在源文件中,編譯就失敗了呢,因為每個源文件的編譯都是獨立的,盡管在test_template.cc進行了TemplateTesttest的使用,但是在template.cc中卻感知不到,所以也就沒法定義相關的實現。
思路來了,只需要讓template.cc中感知到T有int類型的情況,那編譯應該就沒問題。這里有個語法,叫模板實例化,像這樣:
template struct TemplateTest<int>;
把這行代碼放在template.cc中:
// template.cc
#include "template.h"
template <typename T>
void TemplateTest::func() {
std::cout << typeid(T).name() << std::endl;
}
template struct TemplateTest<int>;
整個代碼的編譯就沒得問題了,通過這種方式即可以實現模板函數聲明與實現的分離。
這也印證了上面的結論。
這里我再拋出 幾個問題 ,大家可以討論討論:
- 模板的使用是否會導致代碼段體積增大?怎么解決?
- 模板的函數定義放在了頭文件中,好多個源文件都include此頭文件,是否會導致函數的multi definition類型的鏈接報錯?實際使用中貌似沒有報錯,為什么?大家有想過嗎?
-
C++
+關注
關注
22文章
2114瀏覽量
73856 -
頭文件
+關注
關注
0文章
25瀏覽量
9901 -
源文件
+關注
關注
0文章
30瀏覽量
4612
發布評論請先 登錄
相關推薦
評論