constexpr

We all know that on occassion const does not work as planned. In the latest edition of C++, we have a generalization of const-ness to try to solve some of the problems. As a part of raising the population of C++ keywords to 73 with 11 more text alternatives to the broken typewriter operators, we now have a solution.

The discussion in the standard opens with the words "The constexpr specifier shall be applied only to the definition of an object, the declaration of a function or function template, or the declaration of a static data member of a literal type." Certainly doesn't leave out much, does it? And it does correctly mean that you can be very cool and use the new keyword in some of the places where you previously used const:

const int i = 42;     // old 
constexpr int i = 42; // new

Under a lot of convenient conditions, a function can be qualified with constexpr, as well. From a commonsense perspective, the conditions necessary for a constexpr function are:

  1. The function cannot be virtual; no surprise there.
  2. It must return something and that something must be a literal ("standard") type.
  3. Any parameters to the function must also be a literal type.
  4. The only statement in the function is a single one that says return xyz;, where xyz is some kind of expression that can be completely evaluated at compile time.
  5. ... and finally, everything referred to (including data) in the function must be defined, and not just declared, before the definition of the constexpr function. Now this is a lemma that follows from #4 if you think about it, but it is a little clearer to think of this as a rule of its own.

For example, the following function from our own code is a candidate for constexpr conversion

117 uint32_t roundUpwards(uint32_t i)
118 {
119   return (i & 0xFFF) ? (((i >> 12) + 1) << 12) : i;
120 }
  1. it is not virtual.
  2. it returns a uint32_t.
  3. it takes a uint32_t
  4. as its argument.
  5. it only has one line, which is indeed a return statement.
  6. everything that appears in that line is either the argument, i, or it is a numeric literal.

The standard points out that any function declared as constexpr is implicitly inline, which is hardly surprising. Unlike the inline directive, constexpr must appear in both the declaration and the definition if they happen to be separated.

The remainder of the rules are more complicated, and we are sure to get our typing fingers slapped by the compiler's ruler. Some of them are straightforward if you give a little thought to the purpose of this new keyword.

constexpr objects have constructors, and those constructors (including copy constructors) must be writeable without use of any statements in the body of the constructor. In other words, it must be this sort of affair.

class T {
  constexpr T (U u, V v, W w) : mU(u), mV(v), mW(w) { }
  ...
};

Where U and V are simple types, and mU, etc., are members of the T class.

And so, all this seeming hocus pocus allows us to eliminate one of the more grindingly tedious points of order in C++: it has always been a little too difficult to create const objects dynamically.