Main
- Preface
- Chapter 01: Towards Modern C++
- Chapter 02: Language Usability Enhancements
- Chapter 03: Language Runtime Enhancements
- Chapter 04: Containers
- Chapter 05: Smart Pointers and Memory Management
- Chapter 06: Regular Expression
- Chapter 07: Parallelism and Concurrency
- Chapter 08: File System
- Chapter 09: Minor Features
- Chapter 10: C++20
- Chapter 11: C++23
- Chapter 12: C++26 (Outlook)
- Appendix 1: Further Study Materials
- Appendix 2: Modern C++ Best Practices
- Appendix 3: Modern C++ Feature Index
Chapter 10: C++20
C++20 seems to be an exciting update.
For example, as early as C++11, the Concept,
which was eager to call for high-altitude but ultimately lost, is now on the line.
The C++ Organizing Committee decided to vote to finalize C++20 with many proposals,
such as Concepts/Module/Coroutine/Ranges/ and so on.
In this chapter, we'll take a look at some of the important features that
C++20 will introduce.
Concept
The concept is a further enhancement to C++ template programming. In simple terms, the concept is a compile-time feature. It allows the compiler to evaluate template parameters at compile-time, greatly enhancing our experience with template programming in C++. When programming with templates, we often encounter a variety of heinous errors. This is because we have so far been unable to check and limit template parameters. For example, the following two lines of code can cause a lot of almost unreadable compilation errors:
#include <list> |
The root cause of this code error is that std::sort must provide
a random iterator for the sorting container, otherwise it will not be used,
and we know that std::list does not support random access.
In the conceptual language, the iterator in std::list does not satisfy
the constraint of the concept of random iterators in std::sort.
After introducing the concept, we can constrain the template parameters
like this:
template <typename T> |
abbreviate as:
template<Sortable T> // T is a Sortable typename |
Even use it directly as a type:
void sort(Sortable& c); // c is a Sortable type object |
Let's look at a practical example. The following uses a requires expression to define a concept Addable, requiring that a type support + with a result convertible back to the type, and uses it to constrain a function template:
#include <concepts> |
When an argument of an unsatisfying type is passed, the compiler tells us directly that the constraint is not satisfied, instead of emitting a long cascade of internal template-instantiation errors.
Modules
Modules aim to solve the many problems of the traditional header mechanism: repeated parsing, macro pollution, include-order sensitivity, and slow compilation. A module is declared with export module and explicitly exports the entities visible to the outside:
// math.cppm — module interface unit |
Consumers use import instead of #include:
// main.cpp |
Unlike the other examples in this book, compiling modules requires dedicated toolchain support and usually two steps (compile the module interface unit first, then the consumer); it cannot be built with a single
clang++ file.cppcommand. Consult your compiler's documentation for the exact build procedure.
Ranges
Ranges provide a higher-level, composable abstraction over the standard-library algorithms and iterators. With range adaptors and the pipe operator |, several lazy transformations can be chained in a declarative style:
#include <iostream> |
These views are lazily evaluated: the filtering and transformation are computed element by element only when result is iterated, with no intermediate container created.
Coroutines
A coroutine is a function that can be suspended and resumed. Any function whose body uses co_await, co_yield, or co_return is a coroutine. Note that C++20 provides only the language machinery plus the low-level support facilities in <coroutine>, leaving the "glue" such as the promise_type to the user or a library (a ready-made std::generator only arrived in C++23).
Here is a minimal lazy generator that yields values one at a time with co_yield:
#include <coroutine> |
A note on Contracts and Transactional Memory
A common misconception is worth clarifying: Contracts and Transactional Memory are not part of C++20.
- Contracts were once in the C++20 working draft but were removed before the standard was published; they are now an important feature targeting C++26 (see this repository's C++26 tracking issue #318).
- Transactional Memory exists only as a Technical Specification (TS) and was never merged into the C++20 standard.
This chapter therefore no longer presents them as C++20 features.
Conclusion
In general, I finally saw the exciting features of Concepts/Ranges/Modules in C++20. This is still full of charm for a programming language that is already in its thirties.
Further Readings
Changkun Ou © 2016-2026. The book is licensed under Creative Commons Attribution-NonCommercial-NoDerivatives 4.0, code is open sourced under the MIT License.
If you like the book, you could donate the author.