The constexpr is a keyword present in C++11. This keyword indicates a constant value or a constant expression during the compilation phase. The constexpr is used with both variables as well as with functions.
The use of constexpr causes compiler to evaluate an expression at compile time. This expression then becomes a constant value at run-time.
This means, if the program uses constexpr in a variable definition, then it becomes a constant variable. And, consequently, when the program uses constexpr with an expression or function then compiler executes it to create a final contant value. However, it should be noted that all the inputs of a constexpr function must be known at compilation.
Since, the use of constexpr causes compiler to replace expressions with a constant, therefore, use of constexpr leads to improvement in run-time performance.
Basic example – calling constexpr function to set a constexpr variable
In following example, the variable “iy” is constexpr. The value of “iy” is based on function “permuation”, which is also a contexpr function. And, since, the input of permutation is known at compile time (const int ix=6), therefore, compiler shall execute this function during compilation and generate a constant value.
#include <iostream> //main header
using namespace std; //namespace
constexpr int permutation(int N)
{
return (N?N*permutation(N-1):1);
}
int main()
{
const int ix=6;
constexpr int iy = permutation(x);
cout << iy << endl;
return 0;
}
Using Non-constexpr function with constexpr variable
C++ compiler evaluates only those functions in compilation which are declared as constexpr. In the following example, even though the input of function “permutation” is compile-time constant, but this will not compile to assign value to variable “iy”. The compile-time evaluation cannot happen in absence of constexpr keyword.
#include <iostream> //main header
using namespace std; //namespace
int permutation(int N) //No constexpr
{
return (N?N*permutation(N-1):1);
}
int main()
{
const int ix=6;
constexpr int iy = permutation(ix);
cout << iy << endl;
return 0;
}
The above program shall generate following error during compilation.
All Literal types can be constexpr
In C++11, all built-in types except “void” qualify to become contexpr. Same rule will apply for user-defined types, because constructors and other member functions may be constexpr
Passing non-constant input to constexpr function
A constexpr function only expects a contant input during compilation phase. In the following example, program uses a variable “ix” to provide an input. This is wrong because technically the value “ix” can change anytime.
#include <iostream> //main header
using namespace std; //namespace
constexpr int permutation(int N)
{
return (N?N*permutation(N-1):1);
}
int main()
{
int ix=3; //ix is not constant
constexpr int iy = permutation(ix);
cout << iy << endl;
return 0;
}
The compiler shall throw following error and cause compilation to stop.
Using constexpr function with (non-constexpr) variable
The program can use a contexpr function even for non-constexpr variables. In such cases, the compiler shall not evaluate any value at compile-time, but these will be used just like normal functions.
#include <iostream> //main header
using namespace std; //namespace
constexpr int permutation(int N) //constexpr
{
return (N?N*permutation(N-1):1);
}
int main()
{
int ix;
int iy = permutation(ix); //y is not const
cout << iy << endl;
return 0;
}
The above program shall compile but y will not be a compile time constant.
Only one return-line statement in C++11
In C++11, a constexpr function can have only one single return-line statement. The compiler shall throw an error if multiple lines are present. This limitation is not in C++14. The following program shall compile in C++14 but not in C++11.
#include <iostream> //main header
using namespace std; //namespace
constexpr int permutation(int N) //multiple lines
{
if(!N) return 1;
return N * permutation(N-1);
}
int main()
{
constexpr int ix = 6;
constexpr int iy = permutation(ix);
cout << iy << endl;
return 0;
}
C++11 compiler shall throw following error:
constexpr as constructor
A constructor can also be of type contexpr. This means, if the program creates an object, then constructor code shall run at compile-time.
In the following example, the constructor is accepting an integer parameter. Since, the constructor argument value is constant therefore, the compiler shall construct the object during compilation. Finally, the object which is created will be a constant object.
#include <iostream> //main header
using namespace std; //namespace
class MainFunda
{
int ival;
public:
constexpr MainFunda(int ip) : ival(ip) { }
void printAddress() const
{
cout << "The address at runtime is : "
<< &ival << endl;
}
};
int main()
{
constexpr MainFunda oa(4); //Constant object (in C++11)
oa.printAddress();
return 0;
}
Output is:
The address at runtime is : 0x7ffd000b577c
Please note that the constructor do not have any code in the definition. If constructor has some statement which can be executed only in run-time, then compiler shall throw an error.
constexpr MainFunda(int ip) : ival(ip)
{
cout << "This is constructor"; //This cannot execute
}
The compiler will generate following error
In C++11, constexpr object can’t modify the object
Please note that in above example, the function printAddress is declared as const. This is because the object “a” that was created will be a constant.
There are 2 restrictions in C++11.
Firstly, any constexpr member functions implicitly become constant functions. Therefore, a non-constant object cannot call such member functions.
Secondly, a member function with void return type cannot become constexpr. This is because void is not a literal type in C++11.
Both these restrictions are lifted in C++14,
#include <iostream> //main header
using namespace std; //namespace
class MainFunda
{
int ival;
public:
constexpr MainFunda(int ip) : ival(ip) { }
constexpr void setValue(int iv) //void return invalid
{
ival = iv; //Modify the object
}
};
int main()
{
MainFunda a2(4);
a2.setValue(5);
return 0;
}
The above program shall compile in C++14 but give out following error in C++11. This cause following 2 errors to be thrown.