3.1.9 Relaxed constexpr

What was the problem

The introduction of constexpr in C++11 [2.1.4] greatly simplified some compile-time complex computations, even though they were some limitations. The most frustrating of which was certainly the constraint that constexpr functions should contain a single statement (a return statement). In practice this means no variable, no branch or control flow other than the ternary ?: operator and using recursion for any loop-based algorithm. See for example this implementation of popcount() we wrote in section [2.1.4]:

#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; 
}
How the Problem is Solved

In C++14, these restrictions are lifted and we can implement this function in a less convoluted way3:

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

A subtle change in the transition from C++11 to C++14 is that constexpr used on a member function does not implies const anymore. For example, this code would not compile in C++11 but does in C++14:

struct s 
{ 
  int value; 
 
  constexpr int increment(int v) 
  { 
    // Can’t do that in C++11 as the function signature is actually 
    // 
    //   constexpr int increment(int) const. 
    // 
    // Okay in C++14, where the function signature is as declared. 
    return value += v; 
  } 
};

This can come as a surprise when switching to a newer standard since calling a constexpr-only member function on a const instance will suddenly trigger errors like “passing ‘const x’ as ‘this’ argument discards qualifiers”.

3Not that recursion is inherently convoluted. Some algorithms work very well when implemented in a recursive way, both regarding the readability and the performance, but even though any programmer worth is money must be know the practice I would argue that most code, i.e. the code we are familiar with, is non-recursive.