在C++98/03語言標准中,對於源代碼中出現的每一處模板實例化,編譯器都需要去做實例化的工作;而在鏈接時,鏈接器還需要移除重復的實例化代碼。顯然,讓編譯器每次都去進行重復的實例化工作顯然是不必要的,並且連接器也因此受累。
在現實編碼世界里,一個軟件的實現可能會在很多代碼塊中使用同一種類型去實例化同一個模板。此時,如果能夠讓編譯器避免此類重復的實例化工作,那么可以大大提供編譯器的工作效率。因此,人們迫切需要一種手段(一種聲明方式)來告訴編譯器“該處出現的模板實例化工作已在其它編譯單元中完成,不再需要進行實例化”。
於是,一個新的語言特性————外部模板(Extern Template)————被納入到C++0x標准中。
在C++98/03中,已經有一個叫做顯示實例化(Explicit Instantiation)的語言特性,其目的是指示編譯器立即進行模板實例化操作(即強制實例化)。而外部模板語法就是在顯示實例化指令的語法基礎上進行修改得到的:通過在顯示實例化指令前添加前綴extern,從而得到外部模板的語法。
顯示實例化語法:template class vector<MyClass>;
外部模板語法:extern template class vector<MyClass>;
一旦在一個編譯單元中使用了外部模板聲明(如extern template class vector<MyClass>;),那么編譯器在編譯該編譯單元時,會跳過與該外部模板聲明匹配的模板實例化(如vector<MyClass>)。
因此,在C++0x中,“模板的顯示實例化指令、外部模板指令和使用”可以類比為“全局變量的定義、聲明和使用”。區別僅在於,模板代表代碼,而變量代表一段連續內存空間。
關於外部模板語法的一些約束:
1. 如果外部模板指令出現於一個編譯單元中,那么與之對應的顯示實例化必須出現於另一個編譯單元中或者同一個編譯單元的后續代碼中。
2. 外部模板指令不能用於一個靜態函數(即文件域函數),但可以用於類靜態函數。(注:這一點是顯而易見的,因為靜態函數沒有外部連接屬性,不可能在本編譯單元之外出現)。
3. 外部模板指令應用於類的成員,而不是類本身。(注:既然已經作用於類的所有成員了,也就相當於作用於類了)
4. 外部模板對於內聯函數是否有用,沒有明確規定,但鼓勵編譯器實現。
編譯器支持
Visual Studio好像是從VS2008(VC9)開始支持外部模板的。GCC似乎很早就支持外部模板了,但不清楚具體是在哪一個版本中加入的,至少4.3及其以后的版本是支持的。
Ref
1. Adding "extern template" (version 2)
2. C++0x,Extern Template @ Wiki
