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:
- The function cannot be virtual; no surprise there.
- It must return something and that something must be a literal ("standard") type.
- Any parameters to the function must also be a literal type.
- 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. - ... 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
as its argument.
4: it only has one line, which is indeed a return statement.
5: 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.
Last updated 2014-07-19T15:44:11+00:00.
Links to the standard
constexpr
is covered in section 7.1.5
Benefits
Risks