2011-02-17 51 views
3

考慮:沒有定義可用於靜態const成員與初始化?

template<class T> 
struct S { 
    static int const N = 1; 
}; 

extern template class S<int>; 

template<class T> 
int f(T n) { 
    return n + S<T>::N; // line 10 
} 

int main() { 
    return f(1);  // line 14 
} 

//template class S<int>; // intentionally commented out to trigger error 

我得到:

foo.cpp: In function ‘int f(T) [with T = int]’: 
foo.cpp:10: instantiated from ‘const int S<int>::N’ 
foo.cpp:10: instantiated from ‘int f(T) [with T = int]’ 
foo.cpp:14: instantiated from here 
foo.cpp:10: error: explicit instantiation of ‘S<int>::N’ but no definition available 

爲什麼我得到的錯誤?

  1. 做一個明確的模板實例聲明的一點是,這樣的定義可以別處,然而編譯(不鏈接)給出了一個錯誤。 (在實際應用中,當前註釋過的外部實例化聲明將在另一個翻譯單元中)。
  2. 在這種情況下,該值具有常量初始化程序因此編譯器理論上可以直接使用該值。
  3. 當我不做顯式模板實例化聲明時,我(奇怪)不必明確定義S<T>::N

這是在Mac OS X 10.6.6上的g ++ 4.2.1。

+0

那麼你可以使用`enum {N = 1};`而不是`static const`。 – kennytm 2011-02-17 18:02:33

+0

@KennyTM:不回答問題。很顯然,這個例子是我的真實代碼的簡化例子。真正的代碼需要一個無符號長設置爲〜0,AFAIK,枚舉不能是「無符號」。 – 2011-02-17 18:05:05

回答

2
extern template class S<int>; 

我覺得這條線會導致錯誤,因爲它告訴編譯器去尋找顯式實例的S<int>地方,但沒有明確的實例存在。因此錯誤。

一旦你評論這一行,我認爲代碼應該編譯好。


編輯:

好了,看到這樣:http://www.ideone.com/oQnOi

正如我所說的,它編譯罰款!


編輯:

我想$ 9.4.2/4(由標記B報價爲準)並不適用於類模板的靜態成員,$ 14.5.1.3 [溫度。靜態]不強制的靜態成員在命名空間範圍來定義:

一種用於 可以在命名空間範圍可以設置靜態數據成員定義 附上靜態 會員的班級模板的定義。

的例子如下爲,

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

注意,它不說「必須提供」,而「可以提供」。所以我認爲名稱空間作用域中類模板靜態成員的定義是可選的。

2

從9.4.2/2:

在其類定義的靜態數據 成員的聲明不 一個定義,並且可以比cvqualified 空隙以外的不完全 類型的。靜態數據成員的定義應出現在名稱空間 範圍內,該範圍包含成員的類 定義。在 名稱空間範圍的定義中,使用:: 運算符,靜態數據成員的名稱應按其類名合格 。

而從9.4.2/4:

如果靜態數據成員是常量 積分或const枚舉類型的,其 在類定義 聲明可以指定一個 constantinitializer內容應是一個 積分常量表達式(5.19)。 在這種情況下,該成員可以在 其範圍內出現在 積分常量表達式中。如果在程序中使用 並且名稱空間 範圍定義不應包含 初始值設定項,則成員仍應在名稱空間範圍中定義的 。

從這些參考文獻中,我們可以推斷(「......仍應定義......」在9.4.2/4中),如果沒有定義,那麼程序就沒有格式良好。