### Introduction

In some scenarios, our program would call some functions `func`

with the exact same argument `N`

several times. Computing the return value of such functions during runtime might take a while if the cost of computing `func(N)`

is high. However, with the `constexpr`

specifier, we could compute the value of `func(N)`

during compile-time and save it to the program. During runtime, whenever the program sees `func(N)`

, it would treat it as a constant and get the value directly from the program without conducting the computation.

In this blog post, I am going to demonstrate the `constexpr`

specifier is capable of accelerating programs by computing the value of functions during runtime.

### Example

We prepared two sets of functions, `fib1`

and `fib2`

are used to compute Fibonacci number, `getSize1`

and `getSize2`

are just identity functions. The difference between `fib1`

and `fib2`

, `getSize1`

and `getSize2`

, is the `constexpr`

specifier.

The `constexpr`

specifier would try to compute the value of expressions to compile-time constants if it is possible. In this way, the program runs much faster.

```
// A C++ program to demonstrate use of constexpr
// To compile the program:
// g++ constexpr.cpp -o constexpr -Werror=vla
#include <iostream>
#include <chrono>
constexpr long long int fib1(int n)
{
return (n <= 1)? n : fib1(n-1) + fib1(n-2);
}
long long int fib2(int n)
{
return (n <= 1)? n : fib2(n-1) + fib2(n-2);
}
constexpr size_t getSize1(size_t n)
{
return n;
}
size_t getSize2(size_t n)
{
return n;
}
int main ()
{
// This is allowed because getSize1(10) is a constant during compile-time.
int array1[getSize1(10)];
// This is not allowed because getSize2(10) is a variable during compile-time.
// g++ would actually allow this "erroneous" grammar due to VLA.
// To disable VLA, add `-Werror=vla` to the command for compile.
// int array2[getSize2(10)];
std::chrono::steady_clock::time_point time_start;
std::chrono::steady_clock::time_point time_end;
// Value of res1 is computed at compile time.
time_start = std::chrono::steady_clock::now();
long long int res1 = fib1(30);
time_end = std::chrono::steady_clock::now();
std::cout << "Time Elapsed: " << std::chrono::duration_cast<std::chrono::nanoseconds>(time_end - time_start).count() << "[ns]" << std::endl;
std::cout << res1 << std::endl;
// Value of res2 needs to be computed during runtime.
time_start = std::chrono::steady_clock::now();
long long int res2 = fib2(30);
time_end = std::chrono::steady_clock::now();
std::cout << "Time Elapsed: " << std::chrono::duration_cast<std::chrono::nanoseconds>(time_end - time_start).count() << "[ns]" << std::endl;
std::cout << res2 << std::endl;
int n;
std::cout << "Please input a value for computing Fibonacci number: " << std::endl;
std::cin >> n;
time_start = std::chrono::steady_clock::now();
long long int res3 = fib1(n);
time_end = std::chrono::steady_clock::now();
std::cout << "Time Elapsed: " << std::chrono::duration_cast<std::chrono::nanoseconds>(time_end - time_start).count() << "[ns]" << std::endl;
std::cout << res3 << std::endl;
return 0;
}
```

To compile the program, run the following command in the terminal.

```
$ g++ constexpr.cpp -o constexpr -Werror=vla
```

Note that `-Werror=vla`

is to disable VLA for `g++`

for non-standard dynamic array creation.

```
$ ./constexpr
Time Elapsed: 360[ns]
832040
Time Elapsed: 5603501[ns]
832040
Please input a value for computing Fibonacci number:
30
Time Elapsed: 4179985[ns]
832040
```

We found that the `fib1(30)`

has been treated as a compile-time constant. Therefore, the “computation” of the first Fibonacci number took 360 ns. Because `fib2`

does not have the `constexpr`

specifier, the `fib2(30)`

needed to be computed during runtime. Therefore, it took 5603501 ns, much longer, to compute the exact same Fibonacci number. Although `fib1`

does have the `constexpr`

specifier, `fib1(n)`

, however, has to be computed during runtime, because `n`

is a runtime variable. Therefore, even though we asked the computer to compute the exact same Fibonacci number, it still took 4179985 ns to run.

### Difference to the inline Specifier

The `inline`

specifier could significantly reduce the time of function call overhead. Therefore, if the function is frequently called and fast to compute, we should always consider using the `inline`

specifier. However, the functions are always executed during runtime. `constexpr`

might be better used for functions that take long to compute because the values might be already computed during compile time.

### Conclusions

If you find your program is slow because of repeatedly computing the same constants during runtime. Try to add `constexpr`

to some key functions for those computations.