Bitesize Modern C++ : constexpr

A constant expression is an expression that can be evaluated at compile-time. The const qualifier gives a weak guarantee of a constant expression – a const-qualified type may not be changed after initialisation but that does not guarantee it will be initialised at compile-time. For example:

image

C++11 introduces a strong form of constant expression, constexpr, which also expands the capabilities of compile-time evaluation.

constexpr objects

A constexpr variable is essentially the same as qualifying the type as const with the additional requirement that its initialiser(s) must be known at compile-time. Any object type that could be made const can be made a constexpr object.  As expected, the object must be initialised on definition.  Note that literals are, by definition, constant expressions.

image

Since constexpr types have their value known at compile-time they can be placed in read-only memory; and, for built-in types (and provided you don’t take their address) the compiler doesn’t even have to store the object. We’ll look at user-defined (class)types in a moment.

constexpr functions

So far, so what?

The real power of constant expressions comes from the fact that not only objects but functions may be qualified as constexpr.

A constexpr function is one that may be evaluated at compile-time; and hence used in the definition of other constant expressions:

image

Of course, there are some limitations with constexpr functions:

  • They must have exactly one return statement
  • They cannot have local variables
  • They cannot have conditional expressions
  • They cannot throw exceptions
  • They cannot include a goto statement
  • All parameters must be (capable of being) constexpr objects

Put simply, in order to be a constexpr function everything the function needs to be computed must be known at compile-time. Making a function a constant expression implies it is inline.

(Note: C++14 relaxes some of these requirements with respect to local variables and conditionals).

Marking a function as a constexpr doesn’t limit it to only be usable at compile-time. They may still be used at run time:

image

ROM-able types

The use of constexpr for functions extends to member functions, too. Marking a member function as a constexpr implicitly makes it a const function, meaning it cannot change any of the attributes of the class.

This is also true of constructors. Making a class’s constructor a constexpr allows objects of that type to themselves be constexpr objects.

image

Since everything required to construct the Rommable object is known at compile-time it can be constructed in read-only memory.

In order to be truly ROM-able there are some additional requirements we must satisfy (over and above the requirements for a constexpr function):

  • The class cannot have any virtual functions (virtual functions cannot be constant expressions)
  • The class cannot have a virtual base class
  • All base classes and all const members must be initialised by the constructor

 

More information

Can’t wait? Download the full set of articles as a PDF, here.

To learn more about Feabhas’ Modern C++ training courses, click here.

Glennan Carnie
Dislike (0)
Website | + posts

Glennan is an embedded systems and software engineer with over 20 years experience, mostly in high-integrity systems for the defence and aerospace industry.

He specialises in C++, UML, software modelling, Systems Engineering and process development.

About Glennan Carnie

Glennan is an embedded systems and software engineer with over 20 years experience, mostly in high-integrity systems for the defence and aerospace industry. He specialises in C++, UML, software modelling, Systems Engineering and process development.
This entry was posted in C/C++ Programming and tagged , , , , , . Bookmark the permalink.

Leave a Reply