In December 2020, C++20 was officially published as a revision of the language standard, and it is one of the most ambitious since C++11. For many experts it is not “just another version”, but the point where C++ truly adapts to modern programming: safer generics, modules, coroutines, new standard-library utilities and a significant cleanup of historical baggage.

Four years later, with the standard consolidated and stable support in major compilers, it is worth revisiting what C++20 actually brings to the table and why it is reshaping how high-performance applications are written.


A standard with more changes than C++14 and C++17 combined

C++20 replaced C++17 and later became the base for C++23. The standardisation committee (WG21) finalized it in February 2020, it was approved in September, and published in December of that year.

The list of new features is long: the standard adds large blocks of functionality (concepts, modules, coroutines, ranges), broadens the use of constexpr, introduces new keywords such as consteval and constinit, explicitly defines that signed integers use two’s complement representation, revises the memory model, and adds a substantial number of utilities to the standard library.

In practice, C++20 is becoming the new minimum version that many teams require for modern projects.


Concepts: more readable templates and clearer errors

Templates have always been one of C++’s greatest strengths—and headaches. Until now, compilation errors caused by misusing templates could span dozens of lines.

Concepts let developers express, inside the language itself, which requirements a type must meet to be used in a template: for example, that it provides a certain operator, type alias or function.

Instead of relying on comments or documentation, you can write:

template <Sortable T>
void sort_span(std::span<T> data);
Code language: HTML, XML (xml)

where Sortable is a concept describing what that type can do.

The result:

  • Clearer compiler errors
  • APIs that are more self-descriptive
  • The ability to overload based on real capabilities of types, not just inheritance hierarchies

Modules: finally moving beyond the header hell

Another major feature is modules. Up to C++20, the compilation model was anchored to header files (.h) and #include directives, with well-known issues: huge rebuilds after small changes, macro-related surprises, long build times…

Modules introduce a native way to declare what a translation unit exports and what it imports from others, without textual includes. This allows:

  • Significant improvements in compilation times
  • Fewer errors due to macros and redefinitions
  • Better encapsulation of a library’s internals

Adoption is gradual, because it requires full support from compilers and tooling, but modules point toward a far more manageable C++ in large codebases.


Coroutines: asynchronous code without wrestling with threads

Coroutines are another key addition in C++20. They allow developers to write asynchronous or cooperative code with a syntax almost identical to sequential code, using the new keywords co_await, co_return and co_yield.

In practice, they make it easier to implement:

  • Network servers handling thousands of connections
  • Data-processing pipelines
  • Lazy generators of sequences

without hand-crafted state machines or an uncontrolled proliferation of threads. Complexity moves into the libraries that define awaitable types, but application developers gain readability and expressiveness.


The “spaceship” operator and other core improvements

C++20 also brings more down-to-earth changes that help in everyday development:

  • The <=> operator (“spaceship”) allows defining ordering for a type in one shot, automatically deriving <, <=, >, >= and often equality as well.
  • consteval and immediate functions guarantee that certain functions are always evaluated at compile time, enforcing that checks and calculations happen before the program runs.
  • constinit ensures that a variable with static storage duration is constant-initialized at compile time, avoiding subtle issues with global initialization order.
  • More constexpr: virtual functions, try/catch, dynamic_cast, typeid and other constructs are now allowed in constant expressions, bringing C++ closer to a language capable of powerful compile-time metaprogramming.

On top of that, the standard finally specifies that signed integers use two’s complement representation, matching real-world hardware and simplifying certain optimisations and reasoning.


Standard library: ranges, span, format, chrono and more

The standard library (STL) receives a substantial upgrade:

  • Ranges (<ranges>) provide a unified way to work with sequences and algorithms through lazy views, functional composition and better interoperability with standard containers.
  • std::span is a lightweight view over contiguous memory (arrays, std::vector, etc.), similar to std::string_view but mutable and for any type.
  • std::format and the new std::chrono additions make it easier to format text and work with dates, calendars and time-zones in a modern way.
  • New concurrency and synchronisation utilities such as std::jthread, std::stop_token, std::atomic_ref, futex-like atomic wait/notify operations, semaphores, latches and barriers.
  • Bit-operations utilities (std::countl_zero, std::countr_one, std::bit_width, etc.).
  • std::source_location, std::bit_cast, constexpr-enabled containers like std::string and std::vector, and many other components that modernise the STL.

All this makes it possible to write safer, more expressive code using standard components, reducing the need for custom libraries for common tasks.


Language cleanup: less historical baggage

C++20 also trims older or unsafe parts of the language:

  • It removes several C-derived headers that served no real purpose in C++ (<ccomplex>, <cstdbool>, etc.).
  • It drops old features such as dynamic exception specifications (throw(...) clauses).
  • It deprecates most uses of volatile, clarifying that it is not the right tool for concurrency.
  • It encourages the use of attributes like [[likely]], [[unlikely]] and [[nodiscard]] to guide the compiler and better document intent.

This is not a break with the past, but it is a clear move towards a more coherent C++.


Compiler support and adoption

Although the standard was published in 2020, full support has arrived gradually. Recent versions of GCC, Clang and Microsoft Visual C++ provide broad C++20 support under the usual flags (-std=c++20 or /std:c++20), making it viable for production use on Windows, Linux, Android and iOS.

For many teams, the question is no longer “is it supported?” but rather when to migrate large projects and how to mix modern code with legacy codebases.


What C++20 means for developers

Taken together, C++20 confirms a clear trend:

  • More expressiveness (concepts, ranges, coroutines).
  • More compile-time safety (consteval, constinit, expanded constexpr).
  • Continued focus on performance and low-level control, staying true to the language’s roots.

The trade-off is greater conceptual complexity: learning “all of C++20” takes time, and mixing old and new styles can cause friction. But the standard now offers a solid toolbox for writing modern software without giving up the near-metal performance that has always defined C++.

For teams still on C++11 or C++14, C++20 is a compelling target: not just a newer standard, but a chance to revisit architecture, APIs and coding style with a decade of lessons learned baked into the language itself.


Frequently Asked Questions (FAQ)

1. What are the main differences between C++17 and C++20 for application developers?
The most visible changes are concepts, modules and coroutines, plus ranges and std::span in the standard library. C++20 also greatly expands constexpr and introduces the <=> operator. In practice, this means clearer templates, better support for concurrency and more expressive APIs.

2. Do I have to use modules and coroutines when adopting C++20?
No. C++20 is backward-compatible: you can keep working with traditional headers and concurrency models based on threads or futures. Modules and coroutines are optional, but particularly attractive for large projects (compilation times) and for networked or I/O-heavy services.

3. Which compilers offer stable C++20 support today?
Recent releases of GCC, Clang and Microsoft Visual C++ provide broad C++20 support via the standard flags (-std=c++20 or /std:c++20). It is always worth checking each compiler’s feature matrix, but for most server, desktop and mobile applications the support is mature enough.

4. Is it worth migrating a large project to C++20 if it runs fine on C++14 or C++17?
It depends on the project’s expected lifetime. If it will be maintained for many years, C++20 offers benefits in readability, maintainability, performance (thanks to new primitives and optimisations) and compile-time safety. Migration can be gradual: enable C++20 in the compiler and start using new features in specific modules or components, without rewriting everything at once.

Scroll to Top