问题
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