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

Glennan Carnie

Technical Consultant at Feabhas Ltd
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.
Glennan Carnie

Latest posts by Glennan Carnie (see all)

Dislike (0)

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