Why constexpr works for impure functions

元气小坏坏 提交于 2019-12-08 15:07:37

问题


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


回答1:


In the standard, the relevant requirement is buried below the main list of requirements for constexpr functions. It's in §7.1.5/5:

For a constexpr function, if no function argument values exist such that the function invocation substitution would produce a constant expression (5.19), the program is ill-formed; no diagnostic required.

§5.19 defines the requirements for constant expressions, such that you can't call rand().

The relaxed restriction allows you to have functions that are conditionally pure. Your example f(true) is a valid template argument, but f(false) is not.

The downside, of course, is that the compiler won't verify that a constexpr function can actually be used for its intended purpose. You need to write test cases.

Ah, litb's answer is also correct. (But this one is worded more simply.)




回答2:


The keyword constexpr in the function definition tells the compiler that this function may be executed at compile-time if the all the arguments and variables are known at the compile-time itself. There is no such guarantee, though, for example when some of the values can be known only at runtime in which case the function will be executed at runtime.

However, it has nothing to do with pure or impure, since these terms imply that the output depends on the inputs only, and no matter how many times you call the function with the same values of input parameters, the output will be same everytime, irrespective of whether it is computed at compile-time or runtime.

Example,

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

Note that here add is a pure function irrespective of whether it is computed at compile-time or runtime.




回答3:


Because for some domain of input parameters, the impure path will never be taken. For that domain, constexpr will work fine.

For instance, your function may have a simple branch and a more complicated branch. And you may specify that for your function to be usable in constant expressions, the function arguments must be such that this and that condition is met, yielding to the simple branch in your function that is always pure.

A useful sideeffect of this is that you can cause errors during constant computation. I.e if a precondition in the simple branch is violated, you could cause the evaluation of an impure expression, provoking a compile time error (an assertion or an exception is a good idea here, as it continues to complain when the function is invoked in a runtime context).



来源:https://stackoverflow.com/questions/13295089/why-constexpr-works-for-impure-functions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!