Both const
and constexpr
can be applied to variables and functions. Even though they are similar to each other, in fact they are very different concepts.
Both const
and constexpr
mean that their values can't be changed after their initialization. So for example:
const int x1=10;
constexpr int x2=10;
x1=20; // ERROR. Variable 'x1' can't be changed.
x2=20; // ERROR. Variable 'x2' can't be changed.
The principal difference between const
and constexpr
is the time when their initialization values are known (evaluated). While the values of const
variables can be evaluated at both compile time and runtime, constexpr
are always evaluated at compile time. For example:
int temp=rand(); // temp is generated by the the random generator at runtime.
const int x1=10; // OK - known at compile time.
const int x2=temp; // OK - known only at runtime.
constexpr int x3=10; // OK - known at compile time.
constexpr int x4=temp; // ERROR. Compiler can't figure out the value of 'temp' variable at compile time so `constexpr` can't be applied here.
The key advantage to know if the value is known at compile time or runtime is the fact that compile time constants can be used whenever compile time constants are needed. For instance, C++ doesn't allow you to specify C-arrays with the variable lengths.
int temp=rand(); // temp is generated by the the random generator at runtime.
int array1[10]; // OK.
int array2[temp]; // ERROR.
So it means that:
const int size1=10; // OK - value known at compile time.
const int size2=temp; // OK - value known only at runtime.
constexpr int size3=10; // OK - value known at compile time.
int array3[size1]; // OK - size is known at compile time.
int array4[size2]; // ERROR - size is known only at runtime time.
int array5[size3]; // OK - size is known at compile time.
So const
variables can define both compile time constants like size1
that can be used to specify array sizes and runtime constants like size2
that are known only at runtime and can't be used to define array sizes. On the other hand constexpr
always define compile time constants that can specify array sizes.
Both const
and constexpr
can be applied to functions too. A const
function must be a member function (method, operator) where application of const
keyword means that the method can't change the values of their member (non-static) fields. For example.
class test
{
int x;
void function1()
{
x=100; // OK.
}
void function2() const
{
x=100; // ERROR. The const methods can't change the values of object fields.
}
};
A constexpr
is a different concept. It marks a function (member or non-member) as the function that can be evaluated at compile time if compile time constants are passed as their arguments. For example you can write this.
constexpr int func_constexpr(int X, int Y)
{
return(X*Y);
}
int func(int X, int Y)
{
return(X*Y);
}
int array1[func_constexpr(10,20)]; // OK - func_constexpr() can be evaluated at compile time.
int array2[func(10,20)]; // ERROR - func() is not a constexpr function.
int array3[func_constexpr(10,rand())]; // ERROR - even though func_constexpr() is the 'constexpr' function, the expression 'constexpr(10,rand())' can't be evaluated at compile time.
By the way the constexpr
functions are the regular C++ functions that can be called even if non-constant arguments are passed. But in that case you are getting the non-constexpr values.
int value1=func_constexpr(10,rand()); // OK. value1 is non-constexpr value that is evaluated in runtime.
constexpr int value2=func_constexpr(10,rand()); // ERROR. value2 is constexpr and the expression func_constexpr(10,rand()) can't be evaluated at compile time.
The constexpr
can be also applied to the member functions (methods), operators and even constructors. For instance.
class test2
{
static constexpr int function(int value)
{
return(value+1);
}
void f()
{
int x[function(10)];
}
};
A more 'crazy' sample.
class test3
{
public:
int value;
// constexpr const method - can't chanage the values of object fields and can be evaluated at compile time.
constexpr int getvalue() const
{
return(value);
}
constexpr test3(int Value)
: value(Value)
{
}
};
constexpr test3 x(100); // OK. Constructor is constexpr.
int array[x.getvalue()]; // OK. x.getvalue() is constexpr and can be evaluated at compile time.