2017-07-27 36 views
1
int d = 1; 
constexpr void add() 
{ 
    d++; 
} 

int main() 
{ 

} 

GCC 7.1將在下面報告錯誤。錯誤信息非常清楚。問題是我在constexpr中沒有看到任何明確的解釋來描述它是非法的。爲什麼在constexpr非成員函數中訪問全局非常量變量是不合法的

有人可以解釋規範中定義的規則這種情況下違反嗎?

 

main.cpp: In function 'constexpr void add()': 

main.cpp:8:1: error: the value of 'd' is not usable in a constant expression 

} 

^ 

main.cpp:4:5: note: 'int d' is not const 

int d = 1; 

    ^
+5

「至少存在一組參數值使得函數的調用可能是核心常量表達式的一個被評估的子表達式「 –

+0

似乎違反規則#16(對象的修改,除非對象具有非易失性字面量類型並且其生命週期開始於表達式的評估內)。但是如果我改爲無效的add() d = 2; }然後它可以通過。 – Kane

+0

來自clang的錯誤消息看起來很清楚,常量表達式無法修改在該表達式之外可見的對象。但我仍然無法找到它在哪些規則中破解http://en.cppreference.com/w/cpp/language/constant_expression#Core_constant_expressions – Kane

回答

0

從引用你的標準角度來看,這些評論是很好的,但在這裏希望有一個更直觀的解釋。

A constexpr函數在編譯時必須可縮減爲常量表達式。由於您正在與該函數中的常規,非constint進行交互,因此編譯器無法確定d++在任何情況下都是如此。考慮以下情況:

int d; 
constexpr void add() { 
    d++; 
} 

void foo() { 
    int n; 
    std::cin >> n; 
    d = n; 
    add(); 
} 

在這種情況下,dfoo()值是在編譯時不確定的,因此,不能確定你希望add()離開你的常量表達式。我希望有所幫助。

+0

這是不正確的。 constexpr只是意味着如果所有的前提條件都滿足了,它將在編譯時進行評估。否則,它會動態運行。 – Kane

2

cppreference

核心常量表達式是不具有任何的子表達式的下列中的任一個的任何表達式(忽略不計算表達式如的sizeof操作數或內置& &的右操作數當左操作數評估爲false時)。

...

16)的對象的變形例中,除非該對象具有非易失性文字的類型和它的壽命開始的表達式的求值之內。

在你的榜樣,d的一生開始add評價前 - 所以裏面addd任何修改是非法的。引用上的示例專門用於遞增,但這適用於所有修改。

編輯:不是從標準報價,因爲據我所知,你得買它......

+0

我認爲這個人的一生可能是理性的,但GCC7.1在這種情況下不會抱怨,http://coliru.stacked-crooked.com/a/d4e544c05b187b03。如果d = 2更改爲d + = 2,則會發出抱怨。而且,相同的代碼在叮噹時總是失敗,http://coliru.stacked-crooked.com/a/5d83921f7f0e871b – Kane

相關問題