簡體   English   中英

模板類的靜態變量初始化,C ++

[英]Template class's static variable initialization, 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. 當模板類的靜態變量被初始化/實例化時?

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

至於靜態成員的身份點:

14.6.4.1實例化點[temp.point] 1對於功能模板特殊化,成員函數模板特殊化或類模板的成員函數或靜態數據成員的特殊化,如果該特殊化是因為引用而隱式實例化的在另一個模板特化內,引用它的上下文取決於模板參數,特化的實例化點是封閉特化的實例化點。 否則, 此類專門化的實例化點將立即跟隨引用該專門化的名稱空間范圍聲明或定義。

因此,要點是 如果您是第一次在main()內部使用類型,則在main()之后。

顧名思義,模板是代碼片段,將針對不同的參數多次使用。 對於模板,編譯器將確保它們的方法和靜態字段定義是否僅鏈接在一起。 因此,如果使用默認值創建靜態字段,則即使模板類頭被多次包含,編譯器也必須提供單個存儲單元(對於相同的模板參數集)。 不幸的是,您需要自己管理非模板類。

關於第二個問題,我認為該標准並未說明何時需要初始化靜態字段,每個編譯器都可以按照自己的方式實現。

  1. 有必要在cpp文件中而不在標頭中實例化/初始化靜態成員。 靜態成員是類的屬性,而不是對象的屬性,因此,如果在更多cpp文件中包含頭文件,則似乎要對其進行多次初始化。

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

有關更多信息,請參見以下答案: https : //stackoverflow.com/a/607335/1280316

可以(並且應該)在引用該類的任何編譯單元中聲明一個類(是否為模板)。

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

但是,當您聲明模板時,直到實例化該模板,才真正創建任何東西。 由於您永遠不會實例化模板,因此永遠不會定義靜態字段,並且不會出錯。

如果您在source1.cpp (例如A<B> )和main.cpp (例如A<C> )中有兩個不同的實例化, source1.cpp一切仍然可以:在source1和A<C>::x得到A<B>::x main =>中的A<C>::x是兩個不同的變量,因為A<B>A<C>是不同的類。

在不同的編譯單元中實例化同一類的情況比較棘手。 它應該會產生一個錯誤,但是如果發生了,則幾乎無法在模板中聲明特殊字段。 因此,由編譯器將其作為特殊情況進行處理,因為該其他答案對此進行了解釋,以不產生錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM