Skip to main content

Compile time programming in C++20

· 4 min read
Bryan Flood

A look at compile time programming in C++20 and Beyond

One of the main stand out features of C++ is Compile time computing.

With C++20 comes a whole host of improvements for compile time computing.

I decided I would do a brief review of some of these changes and possible future improvements.

Just as an aside, a few of these features are yet to implemented by any of the main compilers.

Please see cppreference for the latest news on compiler support.

Since the introduction of constexpr as an alternative to template metaprogramming in C++11 each release has brought some sort of improvement and I believe C++20 provides the biggest improvement yet.

C++ 20 Additions#

  • Constexpr new and delete1
  • Constexpr std::string2 and std::vector3
  • Constexpr virtual functions4
  • Constexpr try catch5
  • Constexpr dynamic_cast and polymorphic typeid6
  • Constexpr container operations7
  • Constinit8
  • Unevaluated asm-declaration in constexpr functions9
  • Trivial default initialization in constexpr functions10
  • Consteval11

Most of these changes are self-explanatory but result in more code being implicitly constexpr.

The benefit of this isn't just limited to more of your work being done at compile time.

Making things constexpr allows the compiler to provide better error messages and makes your code more likely to be correct.

Interesting Additions#

New, Delete along with std::string and std::vector#

By far the biggest limitation of constexpr was the inability to do anything with dynamic memory.

This resulted in a lot of code rewriting.

Something like Hana Dusíková's compile time regular expressions library12 would have been far easier to implement had these features been in place.

Currently no compiler supports constexpr std::string2 or std:::vector3 but it will work very similar to how constexpr new and delete1 is currently implemented.

The limitation of these new features is that memory allocated from within a constexpr function must be also deallocated at compile time.

For example this means that you will not be able to create a std::string at compile time and access it from run time. Trivial Godbolt New and Delete Example

Constinit#

Constinit8 is a new keyword used to declare a variable as static requiring it to be initialised with a compile-time constant.

Consteval#

Consteval11 a new keyword that mean a function must be evaluated at compile time and produce a compile-time constant.

Future Additions#

std::embed#

std::embed13 is a really interesting proposal that could make it into C++23. It allows external resources to be accessed at compile time.

There are so many different applications for this kind of feature. One that springs to mind is compiling GLSL to SPIR-V within a Vulkan application at compile time.

At the moment there are various different implementations available based on the feedback given by the standards committee.

One way to try it out today with Clang and GCC is by visiting Matt GodBolt's Compiler Explorer.

Summary#

Although I focused on constexpr features there is a lot more that C++ 20 has to offer.

Even within the realm of compile time computing the addition of concepts will make template metaprogramming far more readable and easier to write.

I would recommend experimenting and learning how to use these features in your code.

You can try most of these features today whether it be through Compiler explorer or by pulling the latest GCC or Clang Docker.

Footnotes#

  1. Constexpr new and delete
  2. Constexpr std::string
  3. Constexpr std::vector
  4. Constexpr virtual functions
  5. Constexpr try catch
  6. Constexpr dynamic_cast and polymorphic typeid
  7. Constexpr container operations
  8. Constinit
  9. Unevaluated asm-declaration in constexpr functions
  10. Trivial default initialization in constexpr functions
  11. Consteval
  12. Hana Dusíková's compile time regular expressions library
  13. std::embed