C++11 constexpr

The C++11 constexpr stands for constant expression, it is one of the features added in C++11. The constexpr is used as a variable qualifier making the variable to remain invariant throughout it’s lifetime. It is somewhat similar to the const qualifier. Like the const qualifier, the constexpr is versatile and can have a global or local scope.

constexpr int ceI=89 ; //a global constexpr

int main( )
{
const int ci=34 ;
constexpr int ceI=89 ;

cout<< ::ceI << endl   //accessing the global constexpr ceI value
 << ceI ;   //local constexpr variable

ci=90 ;   //error! trying to change the value
ceI=78; //error! trying to change the value
::ceI=23 //error! trying to change the value

return 0 ;
}

Using the scope-resolution operator(::) we can access the global variable having the same name as the local variable.


Unique property of constexpr

constexpr qualify a variable to constant type, but it will be plain wrong if I were to say it simply qualify any variables to constant type like the const qualifier. constexpr is strict about the constantness of its variable .And it is also strict -infact more strict- about the constantness of the initializer. The initializer can initialize the constexpr variable only when it is of constant type and also if the initializer is a variable, then the variable must be initialized with a constant value. Look at the code below.

int i=90 ; //non-const variable

const ci=i , //work fine
   ci1=100 ; //work fine

constexpr int ce1=i ,  //error! 'i' is not constant
   ce2=ci ,  //error! ci is not initialized with constant variable
   ce3=ci1 ;  //work fine,ci1 is initialized with constant literal

Initializing ce1 with ‘i’ will gives an error message, this can be expected because ‘i’ is a non-const variable.

For ce2=ci, the error message is not expected because ‘ci’ is a const variable. But still we got an error since ci is initialized with ‘i’ which is a non-constant variable; you can see how much constexpr is strict about its initializer being a const type.

In the third initialization ce3=ci1, the compiler does not complain since ci1 is initialized with a literal which is a constant.

The strictness of constant initializer is even imposed upon an expression such as function returning a value and the retruned value being initialized to constexpr variable. The compiler demands that such function should be constexpr function(discussed in another post) and not any other function.

Link :C++11 constexpr function

constexpr int ce=78+func( ) ; //work fine if func() is constexpr function else error


Constexpr and pointers

The behaviour of constexpr pointer is not in league with the const pointer. If a pointer is defined as constexpr, the pointer is constant not the type which it points to. But in the case of const qualifier, the value pointed by the pointer is constant and not the pointer. Look at the code below.

constexpr int *ceipt=nullptr ; //ceipt is a constant pointer
const int *cipt=nullptr ; //cipt is a pointer to const int

++ceipt ;  //error! trying to change the pointer’s address
++cipt ;  //work fine, changing the address of the pointer

constexpr pointer pointing to const variable or non-const variable

A constexpr pointer can point to const or non-const variable. However, there is a variation on the conditions required for the constexpr pointer to point to non-constant or constant variable. We will discuss the cases separately.

First we will see the condition require for constexpr pointer to point to non-constant variable.

Constexpr pointer and non-const variable

For the constexpr pointer to point to non-const variable the variable must be a global variable. If the variable is not a global variable but a local variable then the variable must be static type. If any of these two conditions are not fulfill the constexpr pointer cannot point to the non-constant variable.

int i=67 ; //global variable

int main( )
{
int ii=45 ;

static int si=3000 ;

constexpr int *cept=&::i ; //work fine, pointing to global variable

*cept1=&ii , //error! ii is not global

*cept2=&si ; //work fine, si is local but static type

return 0;
}

The global or static variables have fixed addresses since they have a lifetime until the program terminates, hence constexpr pointer can point to such variables.

The local variable on the other hand are not stored at fixed address, meaning their lifetime can end when their scope end so they simply cannot be treated as constexpr variable. Hence, constexpr pointer cannot point to them.


Constexpr pointer and const variable

There are two conditions that must be fulfilled to allow constexpr pointer to point to const variable.

First:: The const variable must be global type or if it is a local variable it must be static type.This condition is required for the reason explained above; constexpr pointer pointing to non-const variable.

Second:: The constexpr pointer must also point to const variable. This means the constexpr pointer must be a constant pointer to const variable.This is achieved by adding ‘const’ keyword after the constexpr.

const int ci=4500;

constexpr int ce=9000 ;

int main( )
{
const int cil=78 ;
constexpr int cel=cil ;

static const int sci=6500 ;

constexpr const int *ceptG=&::ci , //work fine

*cept1G=&::ce , //work fine

*ceptL=&cil , //error!

*cept1L=&cel , //error!!

*ceptS=&sci ; //work fine

return 0 ;
}

Why is the second condition required? When constexpr pointer point to const variable the constantness of the variable being pointed to must also retain. The extra ‘const’ added after ‘constexpr’ enforces the constantness of the variable.

Some of the differences between const and constexpr is explicitly pointed out here differences between const and constexpr