How to Initialize a Constexpr Reference

how to initialize a constexpr reference

  1. Are constexpr references ever useful? (i.e., "better" than const references)

They are guaranteed to be initiailized before the program starts, whereas a reference to const can be initialized during dynamic initialization, after the program starts running.


  1. If yes, how can I effectively define them?

A constexpr reference has to bind to a global, not a local variable (or more formally, it has to bind to something with static storage duration).

A reference is conceptually equivalent to taking the address of the variable, and the address of a local variable is not a constant (even in main which can only be called once and so its local variables are only initialized once).

how to initialize a constexpr reference

  1. Are constexpr references ever useful? (i.e., "better" than const references)

They are guaranteed to be initiailized before the program starts, whereas a reference to const can be initialized during dynamic initialization, after the program starts running.


  1. If yes, how can I effectively define them?

A constexpr reference has to bind to a global, not a local variable (or more formally, it has to bind to something with static storage duration).

A reference is conceptually equivalent to taking the address of the variable, and the address of a local variable is not a constant (even in main which can only be called once and so its local variables are only initialized once).

Why can I not use a constexpr global variable to initialize a constexpr reference type?

Compile adding const after int.

constexpr int const & k = r ;
// ...........^^^^^

The problem is that constepxr implies const, so when you define r

constexpr int r =100;

you define constexpr as an int const value (also take into account that const is applied to the type on the left; on the right only if there isn't a type on the left; so const int and int const are the same thing).

But your k

constexpr int & k = r ;

isn't a const (implied by constexpr) reference to an int const but only a const reference to an int.

And you can't initialize a reference to an int variable with an int const value.

You can solve the error by making k a const reference to an int const.

Is the initializer of a constexpr variable at class scope allowed to reference the variable?

You aren't missing anything. This is GCC bug 99059, reported in GCC 11.

Your case applies too, since just like static inline, a constexpr variable must be initialized at the point of declaration. The same lookup related bug would affect C++14 code as well.

Using constinit variable to initialize a constexpr variable

Yes, the diagnostic is correct. constexpr variables must be initialized with a constant expression, and a is not a constant expression (it's a mutable variable).

The purpose of constinit (P1143) is to force a variable declaration to be ill-formed if it's initialization is not constant. It doesn't change anything about the variable itself, like it's type or anything (in the way that constexpr is implicitly const). Silly example:

struct T {
int i;
constexpr T(int i) : i(i) { }
T(char c) : i(c) { }
};

constinit T c(42); // ok
constinit T d('X'); // ill-formed

That is all constinit is for, and the only real rule is [dcl.constinit]/2:

If a variable declared with the constinit specifier has dynamic initialization ([basic.start.dynamic]), the program is ill-formed.
[ Note: The constinit specifier ensures that the variable is initialized during static initialization ([basic.start.static]).
end note
]

The const in constinit refers only to the initialization, not the variable, not any types. Note that it also doesn't change the kind of initialization performed, it merely diagnoses if the wrong kind is performed.

In:

constinit int a = 0;
constexpr int b = a;

0 is a constant expression, so the initialization of a is well-formed. Once we get past that, the specifier doesn't do anything. It's equivalent to:

int a = 0; // same behavior, a undergoes constant initialization
constexpr int b = a;

Which is straightforwardly ill-formed.



but at constant-initialization, its value is known, so it could be used to initialize b.

Sure, at this moment. What about:

constinit int a = 0;
cin >> a;
constexpr int b = a;

That's obviously not going to fly. Allowing this would require extending what a constant expression is (already the most complex rule in the standard, in my opinion) to allow for non-constant variables but only immediately after initialization? The complexity doesn't seem worth it, since you can always write:

constexpr int initializer = 0;
constinit int a = initializer;
constexpr int b = initializer;

Can I initialize a `constexpr static` member outside the class?

constexpr goes on the initializing declaration of a variable, so just put it outside the class:

struct Header
{
int msgType = -1, len;

static const std::size_t MAX_SIZE;

Header() { len = sizeof(*this); }
};

// ... declaration of subclasses ...

inline constexpr std::size_t Header::MAX_SIZE = std::max({ sizeof(A), sizeof(B), sizeof(C) });

Note that the implicit const must be spelled out in the declaration. The definition should go in the same header to avoid any translation unit seeing the declaration but not the inline, which is not allowed.



Related Topics



Leave a reply



Submit