为什么constexpr适用于不纯的功能

时间:2012-11-08 18:08:30

标签: c++ c++11 constexpr

在浏览constexpr的一个旧问题时,我偶然发现了一个非常(恕我直言)的重要评论。 基本上它归结为: (这是合法的C ++ 11 :()

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

我的问题是标准允许这是什么原因。由于我是参考透明度的忠实粉丝,我希望他们有充分的理由:)我想知道。

BT有相关的Q但是大多数A甚至都不提纯东西,或者当他们这样做时,他们没有指明为什么std允许这个的原因。 Relation between constexpr and pure functions

3 个答案:

答案 0 :(得分:9)

在标准中,相关要求隐藏在constexpr函数的主要要求列表下方。它在§7.1.5/ 5中:

  

对于constexpr函数,如果不存在函数参数值,使得函数调用替换将产生常量表达式(5.19),则程序格式错误;无需诊断。

§5.19定义了常量表达式的要求,因此您无法调用rand()

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

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

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

答案 1 :(得分:7)

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

但是,它与 pure impure 无关,因为这些术语暗示输出仅取决于输入,无论您调用多少次具有相同输入参数值的函数,每次输出都是相同的,无论是在编译时还是在运行时计算。

实施例,

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是纯函数,无论它是在编译时还是在运行时计算。

答案 2 :(得分:6)

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

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

有用的副作用是在常量计算期间可能导致错误。即如果违反了简单分支中的前提条件,则可能导致对不纯表达式的求值,引发编译时错误(断言或异常在这里是一个好主意,因为当在一个函数中调用该函数时它继续抱怨运行时上下文)。