C++11 constexpr :: it’s differences with const.


constexpr stands for constant expression ,it is one of the features added in C++11.The constexpr is used as a variable qualifier allowing the variable value to remain invariant throughout it’s lifetime.It’s properties is somewhat similar to the const keyword which qualify a variable to constant type and also preserve it’s constantness until it goes out of scope.Like the const qualifier the constexpr is versatile and can have a global or local scope.

Link: variables scope:local variables and global variables

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 when used,but it will be plain wrong if I were to say it simply qualify any variables to constant type like the const keyword.constexpr is strict about the constantness of it’s variable,but it is also strict-infact more strict- about the constantness of the initializer.The initializer can initialize the constexpr variable only when it is constant 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 value or variable
   ce3=ci1 ;  ///work fine,ci1 is initialized with constant literal

Initializing ce1 with i will given you an error message,this can be expected because ‘i’ is non-const variable.For ce2=ci,however getting an 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 non-constant variable;you can see how much constexpr is strict about it’s initializer being a const.In the third initialization ce3=ci1,the compiler does not complain since ci1 is initialized with a literal which is a constant.

This strictness of constant initializer is even imposed upon an expression such as function returning a value and initialized to constexpr variable.The compiler demands that such function should be constexpr function(discussed later) and not any other function type.

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





Constexpr and pointers

The behavior of constexpr pointer is not in league with a const pointer.If a pointer is defined as constexpr,the pointer is constant not the type which it points to.But in 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 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 condition require for the constexpr pointer to point to non-constant or constant variable type.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 that means if it is a local variable then the variable must be static type.If any of these two conditions is 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 ends,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 or if it has a local scope it must be static type.This condition is required for the reason explained above:in 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 constaness of the variable being pointed to must also retained.And the extra const added after constexpr enforces the constantness of the variable being pointed to.


 


Constexpr function

A constexpr function is defined like any other function however it must meet certain criteria for the function to be valid or to call it as constexpr function.They are:

i)It must return constexpr type.

ii)It’s body must not have a statement that allocate memory or generate run-time activity.For instance it cannot have a variable declaration inside it or have a conditional or loop statements.(Note this restriction is lifted in C++14).

Let us now try to define a function keeping in mind the above two criteria.

constexpr int constexprFunc( ) { return 9; } ///ok

///Doesn’t meet the criteria so error
constexpr int constexprFunc1( )
{
constexpr int ce=78 ; ///allocate memory

return ce ;
}

int i=8 ; ///global variable

///Doesn’t meet the criteria so error,but work fine with C++14
constexpr int constexprFunc2( )
{
if( i==true ) //generate run-time activity
{
//// your code
}

return i;
}

///valid constexpr function
constexpr int constexprFunc3( )
{
typedef int I ;

return 1 ;
}

Among the functions defined above only constexprFunc( ) and constexprFunc3( ) are valid constexpr functions.The other two functions will generate run-time activity,so they are invalid constexpr function.The two valid functions can be called to initialize a constexpr variable.Consider the expression given below.

constexpr int ce=78 + constexprFunc( ) , ///valid
  ce1=constexprFunc3( ) ; ///ditto as above

constexprFunc() and constexprFunc3( ) return type is constexp type so the value returned can be initialized to constexpr variable.

Passing argument to constexpr function

constexpr function doesn’t necessarily only have to return a value,it can also accept an argument.The argument of course cannot be constexpr type but it can be either a const or non-const type.Depending on whether the argument passed is const or non-const the returned value is treated as constexpr value or not.

i)If the argument passed is const or literal or constexpr value then the returned value is constexpr type.This permit the returned value to be treated as valid initializer for constexpr variable.

constexpr int ret_constexpr( int arg )
{
return arg*arg ;
}

int main( )
{
int i=90 ;
const int ci=89 , ci1=i ;
constexpr int ce=56 ;

constexpr int value=ret_constexpr( ci ) , ///work fine

value1=ret_constexpr(ci1) , ///error

value2=ret_constexpr(ce) , ///ok

value2=ret_constexpr(67) ; ///ok

return 0 ;
}

Well I am sure the reason behind why the call value1=ret_constexpr(ci1) , is an error by now.

ii)If you pass a non-const value the returned value type is treated as non-constant type so you cannot assigned such value to constexpr variable.But you can assigned it to non-constant variable.

constexpr int ret_constexpr( int arg )
{
return arg*arg ;
}

int main( )
{
int i=9 ;
constexpr int ce=89 ;

int val=ret_constexpr(i) , ///ok
  val1=ret_constexpr(ce) ; ///ok

return 0 ;
}

For the second call constexpr type is passed as argument and so the return type is also constexpr type but the value can still be assigned to val1.Assigning constexpr to non-constant variable is allowed because non-constant type is not specific about it’s initializer type, const or non-const.





Constexpr function and class

We cannot declare constexpr function as a member function like the other normal member function.If you want to declare constexpr function as a member function then you must declare it as static function,why? When you declare it as static the function is not bound to any object.If constexpr function is allowed to declare as non-static member function it is bound to any object of the class through ‘this’ pointer.Now this violates the rule that constexpr type can be associated only with const type and so it becomes not-so-constant function which is a total absurdity.

class Data
{
public:
Data( ) { }

static constexpr constexprFunc(int i) //work fine
{ return i*i; }

constexpr constexprFunc( int i ) { return i*i; } ///error non-static

~Data( ) { }
} ;

int main( )
{
Data dat ;

int i=9 ,
i1=dat.constexprFunc(i) ; ///work fine

return 0 ;
}

 


constexpr function as template function

constexpr function can be a template function.In this the normal template rules apply and also of course the rule of the constexpr function still applies.

template<class T*>constexpr int templ_func(T t)
{ return t*t; }

int main( )
{
constexpr double f=templ_func(56.67) ;

constexpr int ce=89 ;
constexpr int f=templ_func(ce) ;

return 0 ;
}

 


 


Stop wasting time,earn money($$$) from your website-Join Now!

Difference between const and constexpr

The two keywords ‘const’ and ‘constexpr’ qualify a variable or a function as constant.They adhere to the strict law that something constant must remain constant throughout it’s lifetime and any compromise on the part of the variable or function is not allowed.However,there are some variations on how these two function and no doubt we can find their differences even in some of our programs.Here I want to explicitly point out some of their differences.

First:: const can be used as qualifier in function parameter but constexpr cannot.

int func(const int ii) { return ii; }

int func(constexpr int ii) { return ii; } ///error

Second::If a function is made const it allows declaring of variable inside it or we can execute control statement inside it.constexpr on the other does not allow it due to not allowance of promotion of any activity during run-time(C++14 has certain relaxation on these rules).

class test
{
public:
int func(const int ii) const { if(i==0) {return ii;} else {return ++ii; } }

};

constexpr int constexprFunc( ) { int i=0; return i; } ///error


Conclusion

Well there is all to it about constexpr.Anymore discussions and you might have a brain damage 😀 (just kidding).If you have any doubts or confusion comment below or mail me.

*Note C++14 has imposed certain relaxations on constexpr function.Read about it here C++14 constexpr relaxation.


Related Link

->C++11 using auto keyword.
 
->C++11 using decltype() keyword.
 
->C++11 Smart pointer : Shared pointer ; why is it call shared pointers?