2014-09-30 108 views
3

好吧,這可能是一個愚蠢的問題,但我完全不明白章節12.1.6.2 - 在C++編程語言的constexpr函數下的條件評估。這是整個很短的文字。函數的條件評估

不評估不在constexpr 函數中採用的條件表達式的分支。這意味着沒有采取的分支可以運行時評估 。例如:

constexpr int check(int i) 
{ 
    return (low<=i && i<high) ? i : throw out_of_range(); 
} 

constexpr int low = 0; 
constexpr int high = 99; 

// ... 
constexpr int val = check(f(x,y,z)); 

你可能想象低,高到被 在編譯時已知的配置參數,而不是在設計時,和F(X,Y,Z) 計算一些依賴於實現值。

Source for context

我試圖運行上面的代碼,試圖更多的解釋理解,但我得到一個錯誤。有人可以提供更清晰的解釋嗎?

編輯:我創建了一個程序來測試這一點:

#include<iostream> 
#include<stdexcept> 

using namespace std; 

constexpr int low = 0; 
constexpr int high = 99; 

constexpr int check(int i) { 
    return (low<=i && i<high) ? i : throw out_of_range(); 
} 

constexpr int f(int x, int y, int z) { 
    return x*y*z; 
} 

int main() { 
    constexpr int val = check(f(2,2,2)); 
    cout << val << '\n'; 
} 

它將無法運行:

no matching function for call to 'std::out_of_range::out_of_range()' //I'm really surprised at this 
    return (low<=i && i<high) ? i : throw out_of_range(); 
error: body of constexpr function 'constexpr int check(int)' not a return-statement 
} 
error: 'constexpr int check(int)' called in a constant expression 
    constexpr int val = check(f(2,2,2)); 
+1

注意'f'也必須是'constexpr'函數。 – aschepler 2014-09-30 16:20:11

+0

您可能想查看是否可以使用'static_assert()'。 http://en.cppreference.com/w/cpp/language/static_assert – dgnuff 2014-09-30 16:43:19

+0

@dgnuff'static_assert' _requires_一個常量表達式,所以如果你將它添加到'check'中,你不能在運行時調用check恆定的論點。上面例子的要點是它是一個有效的運行時檢查,它也可以用來初始化constexpr變量。 – 2014-09-30 17:02:34

回答

7

這意味着在constexpr功能的條件分支被允許使用非常量表達式(即那些需要運行時評估的表達式,例如拋出異常),只要在常量表達式上下文中調用該函數時從不採用該分支。

因此,只要函數的參數是常量表達式,並且條件(low<=i && i<high)爲true,就可以調用check來初始化constexpr變量val

如果參數不是常量,函數調用不是常量表達式,因此不能初始化變量constexpr

如果條件爲false,則函數需要接受假分支,該分支需要拋出異常,這需要運行時評估,所以函數不是常量表達式,所以不能初始化變量constexpr

當參數是一個常量表達式時,編譯器知道在編譯時是否會採用分支,所以只要條件爲true它可以完全忽略false分支,並且不會抱怨拋出異常在編譯時是不可能的。

在運行時調用該函數時,它可以有任何參數,並且可以採用false分支,並且將針對正常(非constexpr)函數對throw進行評估。

+0

謝謝我現在明白了。但我想測試它,它不會運行?請檢查我的編輯。 – morbidCode 2014-09-30 16:46:18

+0

'std :: out_of_range'沒有默認構造函數,您需要傳遞一個字符串,例如'拋出std :: out_of_range(「我必須低於<=我<高」) – 2014-09-30 17:00:53