constexpr explained with simple example

In C++11(Introduction to C++11), constexpr is added which improves the run-time performance of the code as it allows the compiler to compute the associated code at compile time if possible. constexpr specifier can be used with both variables and functions where only constant expressions are used which can be evaluated at compile time.

Few important points:

  1. A constexpr function return type and argument type must be literal types.
  2. A constexpr function cannot be virtual but it can be recursive.
  3. A constexpr function cannot have uninitialized variables. Till C++11 it can have only one return statement while from C++14 it can have more than one return statement.
  4. Any variable can be declared as constexpr, if it is initialized. In case of constructor initialization, the constructor also must be declared as constexpr.
  5. constexpr can also be used with references if the referenced object is initialized.
  6. Any constexpr function can only call other constexpr functions.
  7. constexpr function can also be used with non-const variables. No need to define two different functions for same.

Now, let’s take an example about constexpr functions.

#include <iostream>
#include <string.h>
#include <time.h>
#include <chrono>

using namespace std;
using namespace std::chrono;

constexpr int fibonacci(const int x)
{
    return((x <= 1) ? x : fibonacci(x - 1) + fibonacci(x - 2));
}

int main()
{
    cout << "Inside Main" << endl;
    high_resolution_clock::time_point t1 = high_resolution_clock::now();
    const int x = fibonacci(20);
    high_resolution_clock::time_point t2 = high_resolution_clock::now();
    auto duration1 = duration_cast<microseconds>(t2 - t1).count();
    cout << "Calculated at compile time: " << x <<" In duration: "<<duration1<< endl;

    int i = 0;
    cout << "Enter sequence number" << endl; cin >> i;
    high_resolution_clock::time_point t3 = high_resolution_clock::now();
    i = fibonacci(i);
    high_resolution_clock::time_point t4 = high_resolution_clock::now();
    auto duration2 = duration_cast<microseconds>(t4 - t3).count();
    cout << "Calculated at run time: " << i <<" In duration: "<< duration2<< endl;
}

Output of above example code:

Inside Main
Calculated at compile time: 6765 In duration: 0
Enter sequence number
20
Calculated at run time: 6765 In duration: 190

As seen in the output above, compile time calculation is being carried out for first call of “fibonacci” function, hence time taken is “0” microseconds (almost) as nothing to calculate there. but when we pass the same value via non const argument it takes “190” microseconds to calculate the same.

How to check whether constexpr evaluation actually happened at compile time:

Run the above program in debug mode and add a break point in “fibonacci” function. This break point will not hit for the first time when we are calling with const value “20” which means compile time evaluation is being done.
Please note that compile time evaluation will be done by the compiler if optimization options (-ox) is being used while compiling. It is also dependent on compiler implementation whether to carry out this optimization or not. “constexpr” is a way to tell compiler to do the optimization if it can. It’s totally dependent on compiler whether to do it or not.
However we can force compiler to calculate this value at compile time by defining variable as “const”. There are other ways also to force the compiler.

Inteview questiones related to constexpr

Leave a Reply

Your email address will not be published. Required fields are marked *