2009-07-10 44 views
3

在同一個編譯單元中,C++標準指出靜態初始化順序已被很好地定義 - 它是靜態對象聲明的順序。但是使用Sun Studio 12編譯器時遇到了直覺行爲。我已經定義了一個模板類helper<T>,其中包含T類型的靜態成員_data以及使用_data(調用foo)的靜態成員函數。在我的.cpp文件我有這個上面的main():模板的typedefs是否保存靜態初始化順序?

struct A { /* some definition */ }; 

typedef helper<int> s0; 
typedef helper<A> s1; 

注意,對於helper<int> typedef的自帶之前helper<A> typedef的。因此根據標準,我預計helper<int>::_data將在helper<A>::_data之前構建(記住_data是一個靜態成員)。在GCC上就是這樣,在Sun上它不是。

這是有問題的,因爲A的構造函數使用helper<int>::_data。我只有一個編譯單元,沒有更早的helper<A>潛在實例,所以我認爲應該定義好順序。這是Sun編譯器的bug,還是typedef在技術上不構成定義/實例?我的意思是,標準允許Sun編譯器的行爲?

我主要有如下():

int main() 
{ 
    //Swapping the order of these has no effect on Sun 
    s0::foo(); 
    s1::foo(); 
} 

有的S0或S1沒有其​​他用途。

回答

6

在同一個編譯單元中,C++標準指出靜態初始化順序已被很好地定義 - 它是靜態對象聲明的順序。

在您顯示的代碼中,您沒有聲明靜態數據成員。你有一個typedef-name的聲明。這些與此無關,也不影響任何訂單。 你可能想沿着這樣

如果我作出這樣的typedef聲明,它將實例helper<int>,因而第一實例的靜態數據成員聲明。

問題是,該行不會導致helper<int>的實例化。爲此,您需要一個顯式實例化或設法使其實例化(例如,創建一個helper<int>的對象,或者將它用作嵌套名稱說明符,如helper<int>::...,並顯式引用靜態成員 - 否則,創建它被省略)。

但有一個更深的問題。該命令是而不是靜態數據成員的聲明。訂單是其定義。考慮以下

struct C { C() { printf("hey\n"); } }; 
struct A { 
    static C a; 
    static C b; 
}; 

C A::b; 
C A::a; 

在這段代碼,B是之前創建的,即使A是B之前聲明。

下面的代碼打印2 1

struct C { C(int n) { printf("%d\n", n); } }; 

template<int N> 
struct A { 
    static C c; 
}; 

template<int N> 
C A<N>::c(N); 

// explicit instantiation of declaration and definition 
template struct A<2>; 
template struct A<1>; 

int main() { 

} 

但下面的代碼打印什麼,除非你在該行中main發表評論。

struct C { C(int n) { printf("%d\n", n); } }; 

template<int N> 
struct A { 
    static C c; 
}; 

template<int N> 
C A<N>::c(N); 

// implicit instantiation of declarations 
A<2> a2; 
A<1> a1; 

int main() { 
    // A<1>::c; A<2>::c; 
} 

我真的不確定第二個片段的正確輸出是什麼。閱讀標準,我無法確定訂單。它說,在14.6.4.1「實例化點」:

對於函數模板專業化,成員函數模板專業化,或者一個成員函數或類模板的靜態數據成員專業化,如果專業化隱式實例因爲它是從另一個模板專業化[...]引用的。否則,這種專門化的實例化點緊跟在引用特化的名稱空間範圍聲明或定義之後。

其定義的實例化點兩個main定義後立即出現。在其他定義似乎未指定之前實例化哪個定義。如果有人知道答案和khow其他編譯器的行爲(海灣合作委員會打印1 2,但表達式的順序main交換,打印2 1),請讓我知道在評論中。

有關詳細信息,請參見this answer about static object's lifetime

0

你實際上並沒有在該代碼中聲明任何對象。

你需要額外的代碼:

s0 one; 
s1 two; 

在這種情況下,這兩個對象現在實際上宣告,並應能正常工作。

您是否明確聲明瞭s0?

嘗試跟一個s0虛擬類型定義;並查看問題是否得到解決。

+0

從我的理解代碼*不*聲明對象。幫手有一個靜態數據成員。所以每當模板被實例化時,都會創建一個靜態數據成員(一個對象)。 typedef實例化模板....對吧? – 2009-07-10 16:03:37

+0

typedef沒有實例化模板。 – 2009-07-10 16:05:09