2017-04-07 45 views
1

我的問題是,下面的代碼是否有效:static_assert在未初始化模板類有效的專業化

template<int i> class Class 
{ 
    static_assert(sizeof(i) == 0, "Class instantiated with i != 1"); 
}; 

template<> class Class<1> {}; 

這個片段與g++編譯。但clang++被困在static_assert

error: static_assert failed "Class instantiated with non-int type" 

使用一種類型,而不是像int

template<typename T> class Class 
{ 
    static_assert(sizeof(T) == 0, "Class instantiated with non-int type"); 
}; 

template<> class Class<int> {}; 

,模板由兩種編譯器所接受。完全相同的模式適用於功能模板。

我發現open-std.org::Non-dependent static_assert-declarations,但這似乎並不適用,因爲我的static_assert依賴於模板參數。

您可以檢查godbolt.org

編輯描述的行爲:正如約翰·倫德伯格的評論指出我的問題是錯誤的。確實sizeof(i)不依賴於模板參數。 R.Sahu也完全正確:斷言i != 1會更有意義。爲此,兩個編譯器都接受代碼。

但是,上面的例子仍然編譯爲g++。由於open-std.org::Non-dependent static_assert-declarations適用於這種情況(我在這方面的錯誤問題再次道歉):g++在編譯代碼時沒有錯誤實際上是錯誤的?

+5

我不認爲你是正確「因爲我的static_assert是依賴於模板參數。」 sizeof(i)不依賴於i的*值*。 –

+0

爲什麼在第一個例子中使用sizeof?我的類型爲int,sizeof(i)與sizeof(int)相同。也許在斷言中你想直接使用我。 – Fabio

+2

你的意思是使用'static_assert(i!= 1,「使用i!= 1實例化的類)」;'有沒有機會? –

回答

1

鐺++是右拒絕你的代碼,但是g ++沒有錯誤地捕捉錯誤;這是「不需要診斷」的情況。

該標準嚴格定義模板中的表達式爲「依賴於類型」和/或「依賴於值」。鑑於template<int i>,i是取決於值,但不是類型依賴。

[14.6.2.2/4]: Expressions of the following forms are never type-dependent (because the type of the expression cannot be dependent):

  • ...
  • sizeofunary-expression
  • ...

[14.6.2.3/2]: Expressions of the following form are value-dependent if the unary-expression or expression is type-dependent or the type-id is dependent:

  • sizeofunary-expression
  • ...

所以sizeof(i)是不依賴的。

最後,14.6/8說:

If a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter, the program is ill-formed; no diagnostic is required.

0

首先,如果要斷言模板已被實例化了錯誤類型,則必須在static_assert是明確的:

#include <type_traits> 

template<typename T> class Class 
{ 
    static_assert(std::is_same<T, int>::value, "Class instantiated with non-int type"); 


}; 

其次,下面的行可能不會做你認爲:

template<> class Class<int> {}; 

你實際上是在這裏做什麼是創建一個全新的專業化,這並沒有任何關係做的默認模板專業化Class<T>

刪除爲int專業化和instanciating非int類的默認專業化的在兩個編譯器產生錯誤,因爲它應該:

int main() 
{ 
    Class<int> ci; 
    Class<float> cf; 
} 

例如錯誤:

<source>: In instantiation of 'class Class<float>': 
<source>:14:18: required from here 
<source>:5:5: error: static assertion failed: Class instantiated with non-int type 
    static_assert(std::is_same<T, int>::value, "Class instantiated with non-int type"); 
    ^~~~~~~~~~~~~ 
+0

感謝您的回答。但我認爲你的想法與我的有所不同。我想到了一個沒有(有用)默認實現的類,但是提供了幾個(不僅僅是一個)特化。通過這個,我可以在編譯期間選擇合適的實現。static_assert只提供可讀的錯誤信息。 – marlam

+0

@marlam right ...但請記住,您定義的每個專業化代表一個全新的類,它沒有'static_assert'。你正在定義'Class ',而不是實例化它。 –

+0

正確,那就是我的意思。如果'static_assert'屬於每個專業化,它會抵消這個想法。但是,我們現在仍然在質疑爲什麼'g ++'接受第一個片段(請參閱問題中的編輯)。 – marlam