首先明確什么是“外部”(extern)涩笤。比如a.c文件中有個(gè)int i,而另一個(gè)文件b.c文件中想使用i這個(gè)變量狡相,則需要在b.c文件中做一個(gè)聲明:
extern int i;
這樣的好處是员寇,在分別編譯了a.c和b.c之后羽戒,其生成的目標(biāo)文件a.o和b.o中只有i這個(gè)符號(hào)的一份定義芋酌。a.o中的i是實(shí)在存在于a.o目標(biāo)文件的數(shù)據(jù)區(qū)中的數(shù)據(jù)极阅,而在b.o中剧腻,只是記錄了i符號(hào)會(huì)引用其他目標(biāo)文件中數(shù)據(jù)區(qū)中的名為i的數(shù)據(jù)。這樣一來(lái)涂屁,在鏈接器將a.o和b.o鏈接成單個(gè)可執(zhí)行文件(或者庫(kù)文件)c的時(shí)候书在,c文件的數(shù)據(jù)區(qū)也只會(huì)有一個(gè)i的數(shù)據(jù)。
而如果b.c中聲明int i的時(shí)候不加上extern拆又,那么i就會(huì)實(shí)在存在于a.o和b.o的數(shù)據(jù)區(qū)中儒旬,鏈接器在鏈接a.o和b.o的時(shí)候,就會(huì)報(bào)錯(cuò)帖族,因?yàn)闊o(wú)法決定相同的符號(hào)是否需要合并栈源。
而對(duì)于函數(shù)模板,比如在test.h的文件中聲明如下:
template<typename T> void fun(T){}
在test1.cpp中竖般,定義如下
#include "test.h"
void test1(){
fun(3);
}
在test2.cpp中甚垦,定義如下
#include "test.h"
void test2(){
fun(4);
}
由于兩個(gè)源代碼模板函數(shù)參數(shù)類型一致,所以實(shí)例化出了兩個(gè)一樣的函數(shù)fun<int>(int),代碼重復(fù),鏈接器會(huì)只保留一份艰亮。如果源代碼中有過(guò)多的模板闭翩,編譯器會(huì)做很多實(shí)例化工作,鏈接器又會(huì)做很多去重工作迄埃,會(huì)導(dǎo)致編譯時(shí)間和鏈接時(shí)間過(guò)長(zhǎng)疗韵。為了解決這個(gè)問題,引入了“外部”模板侄非。
在C++11中蕉汪,我們可以使用如下聲明,針對(duì)上面的代碼逞怨,我們可以者疤,在test1.cpp中做顯示的實(shí)例化:
#include "test.h"
template void fun<int>(int);//顯示的實(shí)例化
void test1(){
fun(3);
}
在test2.cpp中,做外部模板聲明:
#include "test.h"
extern template void fun<int>(int);//外部模板的聲明
void test2(){
fun(4);
}
需要注意叠赦,外部模板聲明不能用于一個(gè)靜態(tài)函數(shù)驹马,但可以用于類靜態(tài)成員函數(shù)。