Reputation: 5693
Am I right, that:
constexpr
is a pure function, andconstexpr
if it's not very expensive for compiler.And if so, why arent <cmath>
's functions defined with constexpr
?
Upvotes: 22
Views: 3554
Reputation: 25283
Every constexpr
function is pure, but not every pure function can or should be constexpr
.
[Examples involving constexpr
function templates are misleading, since function templates are not functions, they're patterns by which the compiler can generate functions. The outcome of function templates, their specialisations, are functions and they will be constexpr
iff possible.]
A pure function is one that only depends on its arguments, or other constant state. That's pretty much what a constexpr
function is. In addition, constexpr
functions must be defined (not only declared) prior to their first use (recursion seems to be allowed, though), and must consist of only the return statement. That's enough to make the allowed subset Turing-complete, but the result is not necessarily the most efficient form at runtime.
Which brings us to the mathematical functions. You can probably implement constexpr
sqrt()
or sin()
, but they would have to use a recursive implementation that the compiler can evaluate at compile-time, whereas at runtime, these would be better implemented in one assembler operation. Since constexpr
uses of sqrt()
and sin()
are few and far apart, its better to maximise runtime performance instead, which requires a form that isn't constexpr
able.
You may wonder why you can't write one constexpr
version of a function and one that's used at runtime, and I'd agree that would be nice to have, but the standard says you can't overload on constexpr
ness. Maybe in C++17...
Upvotes: -1
Reputation: 299730
constexpr
functions are not pure
because the constexpr
is a hint to the compiler that the function may be computed during the compilation if its arguments are constants and the operation mentionned in the body of the function, for these arguments, are themselves constexpr
.
The latter, using template code, allows us to demonstrate an impure constexpr
function:
template <typename T>
constexpr T add(T lhs, T rhs) { return lhs + rhs; }
instantiated with this type
DebugInteger operator+(DebugInteger lhs, DebugInteger rhs) {
printf("operator+ %i %i", lhs._value, rhs._value);
return DebugInteger(lhs._value + rhs._value);
}
Here, the operator+
is not constexpr, and may thus read/write global state.
We could say that a constexpr
function is pure
when evaluated at compilation time... but then it's simply replaced by a constant as far as the runtime is concerned.
Upvotes: 9
Reputation: 153889
In addition to the previous answers: constexpr on a function restricts its implementation greatly: its body must be visible to the compiler (inline), and must consist only of a single return statement. I'd be surprised if you could implement sqrt() or sin() correctly and still meet that last condition.
Upvotes: 10
Reputation: 354969
To add to what others have said, consider the following constexpr
function template:
template <typename T>
constexpr T add(T x, T y) { return x + y; }
This constexpr
function template is usable in a constant expression in some cases (e.g., where T
is int
) but not in others (e.g., where T
is a class type with an operator+
overload that is not declared constexpr
).
constexpr
does not mean that the function is always usable in a constant expression, it means that the function may be usable in a constant expression.
(There are similar examples involving nontemplate functions.)
Upvotes: 18