choxsword
choxsword

Reputation: 3359

Confusion about constant initialization

In cppref it gives the syntax of constant initialization:

static T & ref = constexpr; 
static T object = constexpr;    

Here's my two questions:

Q1

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`  

Q2

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

Answers (4)

Oliv
Oliv

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:

  • case 0, j0 is not initialized at compil-time because i0 is not a constant.[expr.constant]/2.7
  • case 1 and 2, are compil-time initialized because they fit to an exception of the previous rule [expr.constant]/2.7.3.
  • case 3 and case4, j3 and j4 are not initialized at compil-time because they do not fit to this last rule exception because they have not a preceding initialization, (at least it could be solved at link time, but this would be an heroic effort or dependent of the implementation quality)

(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

M.M
M.M

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

user743382
user743382

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

max66
max66

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

Related Questions