constexpr

constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time. The main idea is performance improvement of programs by doing computations at compile time rather than run time. It specifies that the value of an object or a function can be evaluated at compile time and the expression can be used in other constant expressions.

In below example, both PI1 and PI2 are constant. However only PI2 is a compile-time constant. It shall be initialised at compile time. PI1 may be initialised at compile time or run time.

const     double PI1 = 3.141592653589793;
constexpr double PI2 = 3.141592653589793;

int size = 10;

// Error! constexpr variable 'arraySize1' must be initialised by a constant expression
constexpr auto arraySize1 = size;
std::array<int, size> data1;

// No Error, value is compile time
constexpr auto arraySize2 = 10;    // fine, 10 is a compile-time constant
std::array<int, arraySize2> data2; // fine, arraySize2 is constexpr

Constant Expression Functions

A constant-expression function is a function declared constexpr. Its body must be non-virtual and consist of a single return statement only. Its arguments and return value must have literal types. It can be used in place of macros and hardcoded literals without sacrificing performance or type safety.

constexpr int max() { return INT_MAX; }

constexpr int square(int x)
{
  return x * x;
}

// Compile-time evaluation of square(5)
const int res = square(5); 

// Compilation Error
constexpr bool get_val()
{
    bool res = false;
    return res;
}

Constant Expression Objects

A constant-expression object is an object declared constexpr. It must be initialised with a constant expression or an rvalue constructed by a constant-expression constructor with constant-expression arguments. A constant-expression object behaves as if it was declared const, except that it requires initialisation before use and its initialiser must be a constant expression.

struct S
{
public:

  // constant-expression function
  constexpr int two() {return sz*2;}

private :
  // constant-expression object
  static constexpr int sz = 256;
};

constexpr S s;
int arr[s.two()];

constexpr vs const

Both keywords can be used in the declaration of objects as well as functions. Important difference are

  • constexpr is mainly for optimisation while const is for practically const objects like value of Pi.
  • Both of them can be applied to member methods. Member methods are made const to make sure that there are no accidental changes by the method. On the other hand, the idea of using constexpr is to compute expressions at compile time so that time can be saved when code is run.
  • const can only be used with non-static member function whereas constexpr can be used with member and non-member functions. const gives a guarantee that the member function does not modify any of the non-static data members. constexpr declares the function fit for use in constant expressions.