2.1.4 constexpr

What was the problem

Let’s say we have some complex computation, like for example counting the number of bits set to one in an integer:

int popcount(unsigned n) 
{ 
  return (n == 0) ? 0 : ((n & 1) + popcount(n >> 1)); 
}

What happens when we want to be able to call this function both with run-time values and compile-time constant as arguments? In the code below we would want the size of the array to be a constant, but as it is written its size will be computed at run-time, which makes it a non constant-sized array, which is not standard compliant.

int main(int argc, char**) 
{ 
  int array[popcount(45)]; 
  printf("%d\n", popcount(argc)); 
 
  return 0; 
}

A typical solution for this problem is to implement the computation via template classes and meta-programming:

#include<cstdio> 
 
template<unsigned N> 
struct popcount_t; 
 
template<> 
struct popcount_t<0> 
{ 
  enum { value = 0 }; 
}; 
 
template<unsigned N> 
struct popcount_t 
{ 
  enum 
    { 
      value = (N & 1) + popcount_t<(N >> 1)>::value 
    }; 
}; 
 
int popcount(unsigned n) 
{ 
  return (n == 0) ? 0 : ((n & 1) + popcount(n >> 1)); 
} 
 
int main(int argc, char**) 
{
  int array[popcount_t<45>::value];
  printf("%d\n", popcount(argc)); 
 
  return 0; 
}

This implementation works but has two major problems: first it is incredibly verbose, second it forces us to implement the same algorithm twice, respectively for run time and compile time computations, doubling the risk of bugs and errors.

How the Problem is Solved

The constexpr keyword introduced in C++11 allows us to use the same implementation for both compile-time and run-time computations.

#include<cstdio> 
 
constexpr int popcount(unsigned n) 
{ 
  return (n == 0) ? 0 : ((n & 1) + popcount(n >> 1)); 
} 
 
int main(int argc, char**) 
{
  int array[popcount(45)];
  printf("%d\n", popcount(argc)); 
 
  return 0; 
}

This keyword can be applied to a variable or a function to explicitly tell the compiler that it can and should be computed at compile-time when it appears in constant expressions. It is for example totally possible to call the constexpr popcount() function as a template argument, like in popcount<popcount<42>>().