how to initialize a constexpr reference
- 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.
- 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
- 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.
- 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: Theconstinit
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
C++ Array Assignment of Multiple Values
Do Class/Struct Members Always Get Created in Memory in the Order They Were Declared
Variadic Function Template with Pack Expansion Not in Last Parameter
When and How to Use Exception Handling
Faster Bulk Inserts in SQLite3
Why Can't Static_Cast Be Used to Down-Cast When Virtual Inheritance Is Involved
A How to Create a Matrix in C++
Detect 32-Bit or 64-Bit of Windows
How to Make Generic Computations Over Heterogeneous Argument Packs of a Variadic Template Function
Std::Fstream Buffering VS Manual Buffering (Why 10X Gain with Manual Buffering)
Linking a Shared Library with Another Shared Lib in Linux
Which Headers in the C++ Standard Library Are Guaranteed to Include Another Header
How to Use Std::String in a Constexpr
Relative Performance of Std::Vector VS. Std::List VS. Std::Slist
How to Find the Size of an Int[]