2014-09-30 200 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