Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ why can't classes with const reference member variables be created using constexpr?

Tags:

c++

constexpr

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:

  1. Why is s1 not a constant expression?
  2. What is the best practice way of handling this?

Many thanks!

like image 296
mike.s.23 Avatar asked May 26 '21 11:05

mike.s.23


People also ask

Are constexpr variables const?

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 .

Should I use constexpr or const?

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.

Why does constexpr need to be static?

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.

Is constexpr implicitly const?

In C++11, constexpr member functions are implicitly const.

What is the difference between constexpr and constexpr variables?

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.

When can a reference be declared as constexpr?

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.

What is not initialized in constexpr?

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.

When should I use const or reference member variables?

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.


Video Answer


1 Answers

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};
}
like image 136
mediocrevegetable1 Avatar answered Oct 13 '22 10:10

mediocrevegetable1