2013-10-14 255 views
4

當你有一個(非模板化)類,它包含一個靜態成員,如:靜態成員變量

class Foo 
{ 
    public: 

    static int x; 
}; 

然後Foo::x必須在一個被定義的,僅一個轉換單元,或者編譯器會抱怨多種定義。因此,在somefile.cpp你必須定義它:

int Foo::x = 10; 

這樣,訪問Foo::x被訪問相同的內存地址的轉換單元。

但如果Foo是類模板?現在

template <class T> 
class Foo 
{ 
    public: 

    static int x; 
}; 

Foo<T>::x可以在頭文件中定義,說:

template <class T> 
int Foo<T>::x = 10; 

所以,如果類模板Foofoo.hpptranslation_unit1.cpptranslation_unit2.cpp既包括foo.hpp定義,會記憶爲模板類Foo的一些實例的Foo<T>::x地址,(如Foo<int>::x例如)對於每個轉換單元不同?

+3

只有一次'Foo :: x'的實例,鏈接器會照顧它。 –

+0

[this](http://stackoverflow.com/questions/19341360/is-static-member-variable-initialized-in-a-template-class-if-the-static-menber-i/19341402#19341402)is不是愚蠢的,但它有一些關於如何靜態成員和模板一起工作的標準報價 – aaronman

回答

3

這是完全正常的,在這種情況下,在頭編譯器將確保定義它的存在只有一個實例,如果我們看到的草案C++標準節3.2一個定義規則款說( 重點礦山):

可以有多於一個類型中的一種定義(第9節),枚舉類型(7.2),與外部連接(7.1.2內聯函數),類模板(第14條),非靜態函數模板(14.5.6),類模板的靜態數據成員(14.5.1。3),成員函數

然後我們可以去部分的類模板段落 14.5.1.3靜態數據成員表示:

可以提供一種用於將靜態數據成員定義一個包含靜態成員的類模板定義的命名空間範圍。

並提供了以下示例:

template<class T> class X { 
    static T s; 
}; 
template<class T> T X<T>::s = 0; 
+0

「在這種情況下,在頭文件中定義它,編譯器將確保只有一個實例」我認爲,正如Daniel Frey所說,它應該是*鏈接器*(如果兩者有區別);同樣,每個TU只允許一個定義。 (好吧,如果在同一個TU中有多個,編譯器通過發佈診斷消息來確保只有一個定義;) – dyp

1

[basic.def.odr]/6明確允許在某些情況下「一類的模板的靜態數據成員」(與其他例外)的多個定義。

它再持續這樣的實體D

如果D的定義滿足所有這些要求,則程序應表現爲,如果有的D一個統一的定義。如果D定義不滿足 這些要求,則行爲是不確定的。

因此,在一個TU中實例化的模板的靜態數據成員的地址與在另一個TU中實例化的相同靜態數據成員的地址相等。上面提到強調


完整的報價,通道由我:

可以有一個類類型的多個定義,枚舉類型,具有外部鏈接,類模板內聯函數,非類模板的靜態數據成員 ,類模板的成員函數或模板專用 某些模板參數未在程序中指定,前提是每個定義 出現在不同的transl並且提供的定義滿足以下要求。鑑於這樣的實體命名D在多於一個翻譯單元,然後

  • D每個定義應包括令牌的相同序列的定義;
  • D的每個定義中,根據3.4查找到的對應名稱應指的是在D的定義中定義的實體,或者應該指在重載分辨率和部分模板專業化匹配後的同一實體,不同之處在於一個名稱可以指與內部或無鍵的const對象,如果該對象具有在D所有定義相同的文本類型,並且該目的是利用一個常量表達式初始化,和的值(但不是地址)對象被使用,並且該對象在D的所有定義中具有相同的值;和
  • D每個定義
  • ,相應的實體應具有相同的語言聯動;和
  • D的每個定義中,所涉及的重載操作符,對轉換函數,構造函數,操作符新函數和操作符刪除函數的隱式調用應指代相同的函數,或涉及D定義中定義的函數;和
  • D每個定義
  • ,由(隱式或顯式的)函數調用使用的默認參數被視爲如果令牌序列存在於的D定義;即,默認參數是受上述三個要求(和,如果默認參數具有默認參數的子表達式,這一要求遞歸地應用)。
  • 如果D是一個具有隱式聲明的構造函數的類,就好像構造函數是在每個使用odr的翻譯單元中隱式定義的,並且每個翻譯單元中的隱式定義都應該調用相同的構造函數基類或D的類成員。

如果D是一個模板,在多於一個翻譯單元被定義,則上述要求應當向從模板的封閉範圍在模板定義中所用的名稱在點應用,並且還依賴名實例。 如果D的定義滿足所有這些要求,則程序應表現爲,如果有的D一個統一的定義。如果D定義不滿足 這些要求,則行爲是不確定的。

1

你的問題是完全由在C++ 11標準14.4回答:

模板名稱具有連桿(3.5)。非成員函數模板可以具有內部鏈接;任何其他模板名稱應具有外部鏈接...

因此,類模板總會有外部鏈接等都是它的靜態數據成員(常量或沒有)。因此,Foo<int>::x將始終引用內存中的同一個實體,而不管該表達式出現在哪個翻譯單元中。鏈接程序可以實現此目的。