2015-04-27 78 views
0

考慮下面的代碼:模板類的靜態變量的初始化,C++

//header.h 
template<class T> 
class A 
{ 
    static int x; 
}; 

template<class T> 
int A<T>::x = 0; 

//source1.cpp 
#include "header.h" 
void f(){} // dummy function 


//main.cpp 
#include "header.h" 
int main(){} 

在這種情況下,代碼完全編譯沒有錯誤,但如果我從類

class A 
{ 
    static int x; 
}; 

int A::x = 0; 
  1. 除去模板預選賽這種情況下,編譯器錯誤地定義了x的多個定義。任何人都可以解釋這種行爲嗎?
  2. 當模板類的靜態變量被初始化/實例化?
+0

1)類模板成員只在需要的時候被實例化。 2)這是一個棘手的問題。 –

+0

[模板靜態變量](http://stackoverflow.com/questions/1553854/template-static-variable) – Quentin

+0

可能的重複總之,**永遠**實例化頭文件中的靜態,這幾乎每次都會造成麻煩。每次包含頭文件時,靜態都會被實例化。 – bkausbk

回答

2

編譯器將自己刪除重複的模板實例。如果您將模板類轉換爲常規模板類,那麼您的責任是確保只存在靜態變量的一個定義(否則會出現鏈接器錯誤)。還要記住,靜態數據成員不會在不同類型的模板實例之間共享。使用C++ 11,您可以使用extern模板自行控制instatiations:using extern template (C++11)

至於instatiation的靜態成員的點:

14.6.4.1實例化點[temp.point] 1對於函數模板專業化,成員函數模板特,或用於一個專業化 成員函數或類模板的靜態數據成員,如果專業化被隱式實例化,因爲它是從另一個模板專業化中引用的,並且引用它的上下文取決於模板參數,實例化專業化n是封閉專業化的實例化的點。否則,這種專門化的實例化點 緊跟在引用特化的命名空間範圍聲明或定義之後。

所以instatiation的點應該是ie。如果在main()中第一次使用類型,則在main()之後。

+0

所以當C++標準堅持所有的靜態數據都應該在main不打擾之前初始化這個case的時候,我是否正確? –

+0

模板類的靜態成員的構造函數肯定會在main執行之前執行。當代碼構造以需要其定義的方式參照模板專業化時,將創建POI(實例化點)。 – marcinj

0

作爲名稱提示的模板是將用於不同參數多次的代碼片段。對於模板,編譯器將確保它們的方法和靜態字體定義是否僅鏈接在一起。因此,如果您使用其默認值創建靜態字段,則編譯器有義務提供單個內存單元(對於相同的模板參數集),即使模板類標題包含多次。不幸的是,非模板類你需要自己管理。

至於第二個問題,我相信標準並沒有說明什麼時候需要初始化靜態字段,每個編譯器都可以以它自己的方式實現它。

0
  1. 有必要實例化/初始化不在標題中的cpp文件中的靜態成員。靜態成員是類的屬性而不是對象的屬性,因此如果將頭文件包含在更多的cpp文件中,則看起來您正在初始化更多次。

  2. 對這個問題的回答比較複雜。模板不是一個類。它按需實例化。這意味着每個不同的模板使用都是一個獨立的「模板實例」。例如,如果您使用A<int>A<float>比您將有2個不同的類,因此您將需要初始化A<int>::xA<float>::x

欲瞭解更多信息請參考這個答案:https://stackoverflow.com/a/607335/1280316

+0

這不僅是好的做法,它還是一項要求或ODR。除非您的頭文件不包含在幾個TU中。 – Quentin

0

類(可能是模板或沒有)可以(也應該)在任何編譯單元被宣佈referes它。

靜態字段初始化確實定義了一個變量,因此它應該只存在於一個編譯單元中 - >這就是當類A不是模板時出現錯誤的原因。

但是,當你聲明一個模板,沒有真正創建,直到你實例化它。由於你永遠不會實例化模板,靜態字段永遠不會被定義,並且你不會有錯誤。

如果您在source1.cpp有兩個不同的實例(比如A<B>)和main.cpp(比如說A<C>)都仍然會罰款:你會得到A<B>::x的來源1,自A<B>主=>兩個不同的變量A<C>::xA<C>屬於不同類別。

在不同的編譯單元中實例化相同的類的情況比較棘手。它應該會產生一個錯誤,但如果這樣做了,你很難在模板中聲明特殊的字段。所以它被編譯器處理爲一個特殊情況,因爲它在這個other answer中解釋爲不產生錯誤。