2017-04-20 122 views
3
#include <iostream> 

using namespace std; 

template<const int arr[]> 
struct S { 
    static constexpr int value = arr[0]; 
}; 

constexpr int arr[] = { 5 }; 

int main() { 
    cout << S<arr>::value << endl; 
} 

該程序編譯細並打印5用gcc 5.1和更高,但MSVC 19.10.25019給出如下錯誤:使用constexpr陣列作爲模板非類型參數(C++ 14)

錯誤C2975:「S」:爲「改編」無效模板參數,預計 編譯時間常數表達式錯誤C2131:表達沒有 計算爲一個常數

這是程序合法根據C++ 14 Standard還是gcc在這裏太寬大了?

+0

對於初始化記錄,Clang也接受這個代碼。 – jwimberley

+0

如果用'arr [1]'替換'arr []',MSVC會說什麼? – jwimberley

+0

@jwimberley它不會改變任何東西。 –

回答

2

該程序是完整的,據我所見。

根據[temp.param]/8,模板參數實際上具有類型const int*,而不是const int[]

一種非型模板參數類型的「陣列的T」或「函數返回T」被調整爲類型 「指針T」或「函數指針返回T」,分別。

根據[temp.arg.nontype]/1,我們可以使用具有靜態存儲持續時間和外部連接的一個完整的陣列對象的名稱作爲參數傳遞給這樣的模板參數:

對於非A型,非模板模板參數一個模板參數應是一個:

...

- 常量螞蟻表達式(5.19)指定具有靜態存儲持續時間和外部或內部鏈接的完整對象的地址,或者包含功能 模板和函數template-id,但不包括非靜態類成員,表達(忽略括號內)作爲&ID-表達,其中ID-表達是一個對象或函數的名稱,不同的是 &可以省略如果名稱是指功能或陣列和將被省略如果相應的 模板參數是一個參考...

arr是一個常量表達式,儘管MSVC認爲它不是。它是[expr.const]/2的核心常量表達式,因爲它不包含任何禁止的評估,並且它是一個常量表達式,因爲它指向具有靜態存儲持續時間([expr.const]/4)的對象。

因爲模板參數是指具有靜態存儲持續時間的數組,所以在模板實例化時數組邊界是已知的。因此它可以驗證對arr[0]的訪問是一個合法的核心常量表達式,因爲它具有定義明確的行爲,並且屬於[expr中允許的左值到右值轉換的類別。常數]/2:

...整型或枚舉類型的非易失性glvalue引用到非易失性const對象與前述 一個初始化,以恆定表達

+0

從技術上講,它違反了[temp.arg.nontype] /2.1:「對於指針類型的非類型模板參數,常量表達式的值不應該是......的地址子對象」。指針指向數組的第一個元素,它是一個子對象。但是,這是目前的措辭已知的問題;請參閱CWG 2043。 –