轉(zhuǎn)自http://hi.baidu.com/shitiansunny/blog/item/8de3368761204f2a67096e1c.html
最近在用 template 編寫singleton模式代碼的時候,遇到了一個問題,template要求實現(xiàn)要在同一個文件中,所以,我只能在h文件中定義并實現(xiàn) singleton 模式類。類中必然要有靜態(tài)成員變量,靜態(tài)成員變量的定義成了問題,如果我放在cpp文件中,模板是不支持的,放在h文件中,如果h文件被多次包含,會出現(xiàn)重定義的情況。
回來,請教高手,得知,可以在初始化靜態(tài)成員變量前面加上__declspec(selectany) ,這樣編譯器會自動剔除對該靜態(tài)成員的重復(fù)定義。
最近半年也一直用WTL,ATL,COM等。其實在WTL,ATL中已經(jīng)大量使用了__declspec(selectany)方法。我猜想這是為解決template單文件編程和靜態(tài)成員變量在頭文件中定義會出現(xiàn)重復(fù)定義矛盾而提出的。
總的來說:
__declspec(selelctany) 使在頭文件中定義靜態(tài)成員變量可行。
===================================================================================
其他資料:
selectany使用在c/c++工程的連接期間,一般用得很少,所以很陌生。
這個屬性告訴編譯器聲明的全局變量是一個"任一揀選"(pick-any)COMDAT.在連接時間,如果多個COMDAT定義能看到,連接器選擇一個并且丟棄所有的剩余的。如果連接器選項/OPT:REF被選擇,COMDAT中所有的沒有引用的數(shù)據(jù)項被刪除。
一個全局?jǐn)?shù)據(jù)在EXE或者DLL中只能被初始化一次。當(dāng)同一個頭文件被多個源文件引用時,在頭中定義全局?jǐn)?shù)據(jù)始始化時,這個屬性被使用。這個屬性在c和c++的編譯器中都是可用的。
COMDAT record
一個常用對象文件格式(COFF)記錄,它包含的已被初始化的常用塊數(shù)據(jù)和打包的函數(shù)對連接器是可以見的。
packaged function
當(dāng)函數(shù)級的連接功能選擇開關(guān)被打開時,一個函數(shù)能被編譯器創(chuàng)建。在編譯器產(chǎn)生的對象文件中COMDAT記錄的打包的函數(shù)對于連接器是可見的。沒有打包的函數(shù)只在對象級(the object level)上連接。
下面是MSDN上一些例子:
//Correct - x1 is initialized and externally visible
__declspec(selectany) int x1=1;
//Incorrect - const is by default static in C++, so
//x2 is not visible externally (This is OK in C, since
//const is not by default static in C)
const __declspec(selectany) int x2 =2;
//Correct - x3 is extern const, so externally visible
extern const __declspec(selectany) int x3=3;
//Correct - x4 is extern const, so it is externally visible
extern const int x4;
const __declspec(selectany) int x4=4;
//Incorrect - __declspec(selectany) is applied to the uninitialized
//declaration of x5
extern __declspec(selectany) int x5;