12

while browsing one of my old questions on constexpr I stumbled onto a very(IMHO) important comment. Basically it boils down to : (this is legal C++11 :( )

 constexpr double f(bool b)
 {
 return b? 42:42/(rand()+1); // how pure is rand ;)
 }

My question is what is the reason this is allowed by the standard. Since Im a big fan of referential transparency I hope they have a good reason :) and I would like to know it.

BTW there is related Q but most of the A even dont mention pure thing, or when they do they dont specify the reasoning why std allows this. Relation between constexpr and pure functions

4

3 回答 3

9

在标准中,相关要求隐藏在功能要求的主要列表之下constexpr。它在第 7.1.5/5 节中:

对于 constexpr 函数,如果不存在函数参数值使得函数调用替换会产生常量表达式 (5.19),则程序是非良构的;无需诊断。

§5.19 定义了常量表达式的要求,这样你就不能调用rand().

宽松的限制允许您拥有条件纯函数。您的示例f(true)是有效的模板参数,但f(false)不是。

当然,缺点是编译器不会验证constexpr函数是否可以实际用于其预期目的。您需要编写测试用例。

啊,litb的回答也是正确的。(但这个措辞更简单。)

于 2013-01-23T04:03:13.593 回答
7

函数定义中的关键字constexpr告诉编译器,如果所有参数和变量在编译时本身是已知的,则该函数可以在编译时执行。但是,没有这样的保证,例如,当某些值只能在运行时知道时,在这种情况下,函数将在运行时执行。

但是,它与pureimpure无关,因为这些术语意味着输出仅取决于输入,并且无论您使用相同的输入参数值调用函数多少次,每次输出都将相同,不管它是在编译时还是运行时计算的。

例子,

constexpr int add(int a, int b) { return a + b; } //pure!

const int a = 2, b = 3; //const
int c = 2, d = 3;       //non-const

//we may read update c and d here!

const int v1 = add(2,3);  //computed at compile-time
const int v2 = add(a,3);  //computed at compile-time
const int v3 = add(2,b);  //computed at compile-time
const int v4 = add(a,b);  //computed at compile-time

const int v3 = add(c,3);  //computed at runtime
const int v3 = add(c,b);  //computed at runtime
const int v3 = add(a,d);  //computed at runtime
const int v3 = add(c,d);  //computed at runtime

请注意,这里add是一个纯函数,无论它是在编译时还是运行时计算的。

于 2012-11-08T18:18:08.960 回答
6

因为对于输入参数的某些域,永远不会采用不纯的路径。对于该域, constexpr 可以正常工作。

例如,您的函数可能有一个简单的分支和一个更复杂的分支。并且您可以指定要使您的函数在常量表达式中可用,函数参数必须满足这个和那个条件,从而产生函数中始终为纯的简单分支。

这样做的一个有用的副作用是,您可能会在持续计算期间导致错误。即,如果违反了简单分支中的先决条件,您可能会导致对不纯表达式的评估,从而引发编译时错误(断言或异常在这里是一个好主意,因为在调用函数时它会继续抱怨运行时上下文)。

于 2012-11-08T19:42:21.187 回答