In the following code, I try to store a const reference to another class:
struct A {
};
struct B {
constexpr B(A const & _a) : a(_a) {}
A const & a;
};
int main() {
constexpr A s1;
constexpr B s2{s1};
}
however, the compiler (gcc 11.1) complains with:
cctest.cpp: In function ‘int main()’:
cctest.cpp:12:22: error: ‘B{s1}’ is not a constant expression
12 | constexpr B s2{s1};
|
and I can't work out why s1
is not considered a constant expression. s1
itself is a constexpr in the code. I know this probably has something to do with lifetimes of the references, but I can't work out the logic. In the code that this example came from, I don't want to store a copy of A, I really do just want a reference or (smart) pointer. So:
s1
not a constant expression?Many thanks!
constexpr variables A constexpr variable must be initialized at compile time. All constexpr variables are const . A variable can be declared with constexpr , when it has a literal type and is initialized. If the initialization is performed by a constructor, the constructor must be declared as constexpr .
const applies for variables, and prevents them from being modified in your code. constexpr tells the compiler that this expression results in a compile time constant value, so it can be used in places like array lengths, assigning to const variables, etc.
A static constexpr variable has to be set at compilation, because its lifetime is the the whole program. Without the static keyword, the compiler isn't bound to set the value at compilation, and could decide to set it later.
In C++11, constexpr member functions are implicitly const.
constexpr variables. The primary difference between const and constexpr variables is that the initialization of a const variable can be deferred until run time. A constexpr variable must be initialized at compile time. All constexpr variables are const. A variable can be declared with constexpr, if it has a literal type and is initialized.
A reference may be declared as constexpr when both these conditions are met: The referenced object is initialized by a constant expression, and any implicit conversions invoked during initialization are also constant expressions. All declarations of a constexpr variable or function must have the constexpr specifier.
Not initialized int j = 0; constexpr int k = j + 1; //Error! j not a constant expression A constexpr function is one whose return value is computable at compile time when consuming code requires it. Consuming code requires the return value at compile time to initialize a constexpr variable, or to provide a non-type template argument.
One of the primary examples is inheritance hierarchies. And in those cases, it is fine to use const or reference member variables. Another use case of const or reference members is in local function objects, where you don't care about assignment behavior.
Clang 12.0.0+ gives a descriptive note about the issue:
note: address of non-static constexpr variable 's1' may differ on each invocation of the enclosing function; add 'static' to give it a constant address
So you need to add a static
here:
struct A {
};
struct B {
constexpr B(A const & _a) : a(_a) {}
A const & a;
};
int main() {
constexpr static A s1;
constexpr B s2{s1};
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With