2015-12-21 24 views
15

第一個代碼段編譯沒有任何警告(live example):爲什麼這些代碼片段的處理方式與GCC不同?

constexpr operator int() { return i; } 

GCC警告b是VLA:

#include <iostream> 

struct A { 
    constexpr A(): i(5){} 
    constexpr operator int() { return 5; } 
    int i; 
}; 

int main() { 
    A a; 
    int b[a]{ 0, 1, 2, 3, 4 }; 
    std::cout << b[4] << '\n'; 
} 

通過在轉換運算符(live example)返回i現在改變上面的片段。

對我而言,這兩個變體似乎都符合C++ 14中的§5.19[expr.const]/3。

回答

17

你在i執行升轉換,但對於[expr.const] /(2.7)這裏不作侵犯,(2.7.3)必須適用:

enter image description here

(2.7.1)涉及完整對象,(2.7.2)涉及字符串文字,而(2.7.4)涉及在表達式評估期限內開始生命週期的對象 - 由於a的聲明在b之前,因此不適用。

Define a as constexpr and the code is compliant。


小編的澄清的標準說:括號內的表達式必須是std::size_t類型的轉換的常量表達式([dcl.array]/1),這是在[expr.const]/4定義爲

轉換常量表達式T是一個表達式,隱式轉換爲T類型,其中轉換後的 表達式是一個常量表達式並且[...滿足要求...]

因此,真正的標準是有意與否

constexpr std::size_t s = a; 

將是有效的。由於上述原因,它不是,試圖使用先前定義的非對象的子對象。

+0

爲什麼'a'在這種情況下必須進行左值到右值的轉換?我這樣問,因爲§5.19/ 3(N4140)中的轉換常量表達式的定義似乎並不需要在聲明int b [a] {0,1 ,2,3,4};'。 – Ayrosa

+0

@Ayrosa好吧,'a'永遠不必經過一次,但它的轉換操作符必須被調用才能將其轉換爲'std :: size_t'。 ('a'是括號內'std :: size_t'類型的轉換常量表達式) – Columbo

+1

我花了一段時間才真正掌握了你所說的內容,並在答案中突出顯示。當然,要完全理解標準對於人來說不是一件容易的事。很好的回答(+1)。 – Ayrosa

4

數組大小必須是編譯時間常數,但在第二個例子中A::i初始化不會發生,直到運行時

+0

'A :: A()'是'constexpr'雖然... – YSC

+0

@YSC是的,但'main'函數中的變量'a'不是。 –

+1

而* this *是真正的警告源,不是嗎? – YSC

相關問題