Reputation: 3359
In cppref it gives the syntax of constant initialization:
static T & ref = constexpr;
static T object = constexpr;
Here's my two questions:
How could a lvalue reference T &
without const
be bound to a constexptr
,which is constant and unmodifiable ?
I try to provide some example but failed:
static int& ref = 6; //error, need a `const`
constexpr int a = 6; static int& ref = a; //error, need a `const`
Is it a necessity for the object of constant initialization to be const
/static
?In the standard it says:
Constant initialization is performed if a variable or temporary object with static or thread storage duration is initialized by a constant initializer for the entity.
Here the standard does not specify the obj to be const-qualified
/static-qualified
.
Upvotes: 9
Views: 1749
Reputation: 18041
The confusion is due to the naming: the term constant in constant initialization [basic.start.static]/2 and constant expression [expr.const] means evaluable at compile time without heroic efforts(1) of the compiler. This differs from the concept of a constant object which means that the value of the object will not changed once defined.
To illustrate the limit of evaluation at compile time let's look at the assembly of this code:
//case 0
int i0 = 5;
int j0 = i0;//no compil-time initialized
//case 1
const int i1=5;
int j1=i1; //compil-time initialized
//case 2
extern const int i2=5;
int j2=i2; //compile-time initialized
//case 3
extern const int i3;
int j3=i3; //no compil-time initialization
//case 4
extern const int i4;
int j4=i4; //no compil-time initialization
const int i4=5;
Generated assembly by gcc 7.3:
_GLOBAL__sub_I_example.cpp: # @_GLOBAL__sub_I_example.cpp
mov eax, dword ptr [rip + i0]
mov dword ptr [rip + j0], eax
mov eax, dword ptr [rip + i3]
mov dword ptr [rip + j3], eax
mov dword ptr [rip + j4], 5
ret
What is happening for:
(1) the principle is that the language shall not be too complex to compile. I just recycled the wording of the standard for template argument deduction where the term heroic effort appears litteraly. The same principle is applied to define what is a constant expression.
Upvotes: 7
Reputation: 141554
"constant initialization" means the initializer is a constant expression. Neither the expression nor the variable need to be const-qualified.
int x = 6;
at file scope is constant initialization.
Reference: C++17 [basic.start.static]/2:
Constant initialization is performed if a variable or temporary object with static or thread storage duration is initialized by a constant initializer for the entity.
Upvotes: 3
Reputation:
What that is trying to say is that
static int a;
static int & ref = a;
static_assert(&a == &ref, "");
is okay. The initialisation is a form of constant initialisation because a
is a constant expression when evaluated as an lvalue (but only as an lvalue!), and as a result of that, &a == &ref
is a constant expression which evaluates to true
.
Compare this to
void f() {
int a;
static int & ref = a;
static_assert(&a == &ref, "");
}
This is invalid. Although the initialisation of ref
is technically valid, it becomes a dangling reference as soon as the function returns. The next time the function is entered, a new int a
object is created. Because of that, &a == &ref
is not guaranteed to evaluate to true
. It is not a constant expression, and would have undefined behaviour if evaluated.
Upvotes: 6
Reputation: 66200
In the page you reference you can read
Sets the initial values of the static constants
I point your attention over constants
So T
must be a constant type.
So int const
is OK; constexpr int
is OK because constexpr
imply const
; int
without const
(or without constexpr
that imply const
) is wrong.
Upvotes: 1