能否從編譯原理的角度詳細的描述一下模板編譯的過程?
以及 能夠順便從編譯原理的角度講解一下模板編譯時, 為什麼寫.cpp文件時linker會報錯?
這個問題很大,而我也其實到現在也沒有完整的,清晰的弄清楚模板在編譯器的實現。但是針對這個問題,我想我可以簡單的回答一下你提到的linker為什麼會報錯。我希望我可以盡量用簡單的語言來敘述,讓看的人都能理解。
首先,模板和class,function都不同,模板是一個模式,它可以讓編譯器利用這個模式來生成一些列的class和function,這是最本質最重要的一點。於是,要讓編譯器生成完整的代碼,編譯器需要看見模板的定義和所需要填充的類型,這樣編譯器才能生成"正常"的代碼。
然後回到你的問題,你所提到的寫在一個cpp裡面,那麼更延伸一點兒莫過於.h放置聲明,.cpp放置實現。
舉一個栗子
// x.h
#pragma once
template &
class X
{
public:
void foo(T t);
};
// x.cpp
#include "x.h"
template &
void X&
// main.cpp 於是乎,我們知道了T的類型為char,我們需要利用這一個定義好的模式來生成x的構造函數以及foo函數,其中要填充的類型是char。然而很遺憾的是,我們編譯器在編譯x.cpp的時候才看見模板的定義,而在編譯main.cpp的時候才看見X&
#include "x.h"
int main()
{
X&
x.foo("a");
}
接下來,或許就是你疑惑的地方了,為什麼編譯器不知道把main.cpp的char拿到x.cpp那裡去,為什麼linker會報錯。
我們的編譯器比較「愚蠢」,每次它編譯完一個cpp文件,當它編譯另一個cpp文件的時候它就忘記了其他cpp文件的信息了,所以即使x.cpp有模板定義,main.cpp有X&
那麼為什麼會在linker階段報錯呢?在main.cpp中,我們有X&
// x.cpp
#include "x.h"
template &
void X&
void bar()
{
X&
xx.foo("a");
}
這樣的話,我們的linker在x.o中就能找到相關的信息了。
那麼除了上文說的export關鍵字,還有沒有可以解決linker的錯誤呢?C++11引入了extern template,如這樣
// x.cpp
#include "x.h"
template &
void X&
template class X&
// main.cpp
#include "x.h"
// I know, someelse where must define X&
extern template class X&
int main()
{
X&
x.foo("a");
}
然而,extern template更重要的目的其實是降低冗餘的模板實例化代碼生成,可以參見C++提案Adding "extern template" (version 2) 和我同事在13年寫的一篇博客 The XL C/C++ V11.1 compiler supports extern templates (C/C++ Cafe)
模版就是函數+佔位符,假設佔位符有N種可能,那麼編譯的時候,就要生成N個函數。 具體調用哪個函數,由實際傳入的參數來決定。 模版不是動態編譯,所以有很多限制。
先把模版展開然後編譯,c++是個強類型靜態語言你把定義寫道cpp裡面linker肯定報錯,簡單來說就是頭文件展開後找不到定義了
可以買一本c++ templates 裡面比較詳細
推薦閱讀:
※編譯程序是否有操作系統的參與?
※編譯器、解釋器和虛擬機有什麼區別和聯繫?大體原理是什麼?
※編譯器處理轉義符?
※Android上ARM本地庫是如何運行在其他CPU架構上的?
※Linux/Unix中查看一個C/C++大工程中所有函數的調用順序,有哪些方法?