I am really confused about a constexpr
concept, as I have read constexpr
is evaluated at compile time, so it is useful for performance optimization versus normal const
.
constexpr int i = 0;
constexpr int& ri = i;
The above code returns an error "invalid initialization of reference of type 'int&' from expression of type 'const int'", why?
Also, the next code has an error:
constexpr int i = 0;
constexpr int* ri = &i;
If I replaced the constexpr
keyword with const
, all above worked correctly.
Re
” if I replaced the constexpr word with const all above worked correctly."
A const int*
essentially means (const int)*
, except that you can't use parentheses that way. A constexpr int*
means constepxr (int*)
(ditto note).
This is because constexpr
is not part of the type, you can't name the type constexpr int
, say, while const
is part of the type.
Instead of
constexpr int i = 0;
constexpr int& ri = i;
which attempts to declare a constexpr
reference to non-const
, just write
constexpr int i = 0;
constexpr int const& ri = i;
You can read that backwards as ri
is a reference to a const
int
which is constexpr
(evaluated at compile time).
Addendum:
It ¹appears that C++14 requires local non-static
constexpr
objects to have automatic storage duration, modulo the as-if rule for optimization.
To cater for this, i.e. to make the code portable across compilers, if the above declarations appear locally in a function, add static
to ensure static storage duration for the object that one refers to:
void oops()
{
static constexpr int i = 0; // Necessary with some compilers.
constexpr int const& ri = i;
}
Otherwise it may not compile with e.g. g++, and it's probably what the C++14 and C++11 standards require, by omission of suitable constraints on constexpr
.
Notes:
¹ See the discussion of R. Sahu's answer.
constexpr int i = 0;
constexpr int * ri = &i;
The second line is a problem because the pointer does not point to a const
object. The pointer itself is const
.
Using
constexpr int i = 0;
constexpr int const * ri = &i;
solves that problem. However, that will be still a problem if the variables are defined in a function scope.
constexpr int i = 0;
constexpr int const* ri = &i;
int main() {}
is a valid program.
void foo()
{
constexpr int i = 0;
constexpr int const* ri = &i;
}
int main() {}
is not a valid program.
Here's what the C++11 standard has to say about address constant expression:
5.19 Constant expressions
3 ..
An address constant expression is a prvalue core constant expression of pointer type that evaluates to the address of an object with static storage duration, to the address of a function, or to a null pointer value, or a prvalue core constant expression of type std::nullptr_t
.
As you said, constexpr
is evaluated at compile time. So the value must be evaluable when compiling.
For example:
constexpr int i = 0;
constexpr int& ri = i;
For first line, 0 is evaluable when compiling, its value is 0.
But for second line, compiler needs address of i
to do the assignment, which is determined at runtime. So this line will fail.
Here are my 2 cents:
The constexpr
feature defines computation that happens during the compile time. Reasonable question:
- Does it make sense to allow any computation?
Reasonable answer:
- No, because this would require a lot of machinery, resources, etc right inside the compiler while there is no direct need for that.
Because of that standard allows pretty limited set of features inside the constexpr
code. One may argue why exactly this set and not something more? Well, later on the standard may evolve and allow more.