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

NoS*_*tAl 12 c++ constexpr c++11

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

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

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

顺便说一下,有相关的Q但是大多数A甚至都不提纯东西,或者当他们这样做时,他们没有指明为什么std允许这个的原因. constexpr与纯函数之间的关系

Pot*_*ter 9

在标准中,相关要求隐藏在主要constexpr功能要求列表下方.它在§7.1.5/ 5中:

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

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

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

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

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


Naw*_*waz 7

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

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

例,

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
Run Code Online (Sandbox Code Playgroud)

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


Joh*_*itb 6

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

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

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