C++20: The Big Four


This post presents you the big four: concepts, ranges, coroutines, and modules.



C++20 has a lot to offer. Before I give you a first impression to the big four, here is an overview of C++20. Besides the big four, many features affect the core language, the library, and the concurrency capabilities of C++20.

Compiler Support for C++20

The easiest way to get used to the new features is to play with them. Okay. This approach arises immediately the question: Which C++20 features are supported by which compiler? As so often, cppreference.com/compiler_support gives you the answer to the core language and the library.

To make it simple, the brand new GCC, Clang, and EDG compiler give the best support to the core language. Additionally, the MSVC and Apple Clang compiler support also many C++20 features.



The story is similar for the library. GCC has the best support for the library, followed by the Clang and the MSVC compiler.


The screenshots show only the beginning of the tables, but they also give you an answer which is not so satisfying. Even if you use all brand new compilers, there are many features which are not supported by any compiler.

Often, you find workarounds to play with the new features. Here are two examples:

  • Concepts: GCC support a previous version of concepts.
  • std::jthread: There is a draft implementation on Github maintained by Nicolai Josuttis.

To make my story short. The situation is not so bad. With a little tinkering, many new features can be tried out. I will mention this little tinkering, if necessary.

But now, let me give you a bird-eyes view of the new features. Of course, we should start with the big four.

The Big Four


The key idea of generic programming with templates is it to define functions and classes which can be used with various types. Often it happens that you instantiate a template with the wrong type. The result is typically a few pages of cryptic error messages. This sad story ends with concepts. Concepts empower you to write requirements for your templates which can be checked by the compiler. Concepts revolutionise the way, we think about and write generic code. Here is why:

  • Requirements for templates are part of the interface.
  • The overloading of functions or specialisation of class templates can be based on concepts.
  • We get improved error message because the compiler compares the requirements of the template parameter with the actual template arguments.

However, this is not the end of the story.

  • You can use predefined concepts or define your own.
  • The usage of auto and concepts is unified. Instead of auto, you can use a concept.
  • If a function declaration uses a concept, it automatically becomes a function template. Writing function templates is, therefore, as easy as writing a function.

The following code snippet shows you the definition and the usage of the straightforward concept Integral:

template<typename T>
concept bool Integral(){
    return std::is_integral<T>::value;

Integral auto gcd(Integral auto a,     
                  Integral auto b){
    if( b == 0 ) return a; 
    else return gcd(b, a % b);


Integral is the concept which requires from it type-parameter T that std::is_integral<T>::value holds. std::is_integral<T>::value is a function from the type-traits library which checks at compile-time if T is integral. If std::is_integral<T>::value evaluates to true, all is fine. If not, you get a compile-time error. For the curious ones - and you should be curious- here are my posts to the type-traits library.

The gcd algorithm determines the greatest common divisor, based on the Euclidean algorithm.  I used the so-called abbreviated function template syntax to define gcd. gcd requires from its arguments and return type, that they support the concept Integralgcd is a kind of function templates which puts requirements on its arguments and return value. When I remove the syntactic sugar, maybe you can see the real nature of gcd.

Here is the semantically equivalent gcd algorithm.

template<typename T>
requires Integral<T>()
T gcd(T a, T b){
    if( b == 0 ) return a; 
    else return gcd(b, a % b);


If you don't see the real nature of gcd, you have to wait for my posts to concepts which will come in a few weeks.

Ranges Library

The ranges library is the first customer of concepts. It supports algorithms which

  • can operate directly on the container; you don't need iterators to specify a range
  • can be evaluated lazily
  • can be composed

To make it short: The ranges library support functional patterns. 

Okay, code may help more than words. The following functions show function composition with the pipe symbol.


#include <vector>
#include <ranges>
#include <iostream>
int main(){
  std::vector<int> ints{0, 1, 2, 3, 4, 5};
  auto even = [](int i){ return 0 == i % 2; };
  auto square = [](int i) { return i * i; };
  for (int i : ints | std::view::filter(even) | 
                      std::view::transform(square)) {
    std::cout << i << ' ';             // 0 4 16


even is a lambda function which returns if a i is even and the lambda function square maps i to its square. The rest ist function composition which you have to read from left to right: for (int i : ints | std::view::filter(even) | std::view::transform(square)). Apply on each element of ints the filter even and map each remaining element to its square. If you are familiar with functional programming, this reads like prose.


Coroutines are generalised functions that can be suspended and resumed while keeping their state. Coroutines are the usual way to write event-driven applications. An event-driven application can be simulations, games, servers, user interfaces, or even algorithms. Coroutines are also typically used for cooperative multitasking.

We don't get with C++20 concrete coroutines; we will get a framework for writing our coroutines. The framework for writing coroutines consists of more than 20 functions which you partially have to implement and partially could overwrite. Therefore, you can tailor the coroutine to your needs.

Let me show you the usage of a special coroutine. The following program uses a generator for an infinite data-stream.

Generator<int> getNext(int start = 0, int step = 1){
    auto value = start;
    for (int i = 0;; ++i){
        co_yield value;            // 1
        value += step;

int main() {
    std::cout << std::endl;
    std::cout << "getNext():";
    auto gen = getNext();
    for (int i = 0; i <= 10; ++i) {
        gen.next();               // 2
        std::cout << " " << gen.getValue();                  
    std::cout << "\n\n";
    std::cout << "getNext(100, -10):";
    auto gen2 = getNext(100, -10);
    for (int i = 0; i <= 20; ++i) {
        gen2.next();             // 3
        std::cout << " " << gen2.getValue();
    std::cout << std::endl;


Okay, I have to add a few words. Thi piece is only a code-snippet. The function getNext is a coroutine because it uses the keyword co_yield. getNext has an infinite loop which returns the value after co_yield. A call to next() (line 2 and 3) resumes the coroutine and the following getValue call gets the value. After the getNext call, the coroutine pauses once more. It pauses until the next next() call. There is one big unknown in my example. This unknown is the return value Generator<int> of the getNext function. Here the complicated stuff starts, which will be part of detailed posts to coroutines.

Thanks to Wandbox online compiler, I can show you the output of the program.



 For modules, I make it quite short because the post is already too long.

 Modules promise:

  • Faster compile times
  • Isolation of macros
  • Express the logical structure of the code
  • Make header files superfluous
  • Get rid of an ugly macro workarounds

What's next?

After the high-level overview of the big four, I will continue in my next post with the core language features as shown in my image.


Thanks a lot to my Patreon Supporters: Paul Baxter,  Meeting C++, Matt Braun, Roman Postanciuc, Venkata Ramesh Gudpati, Tobias Zindl, Marko, G Prvulovic, Reiner Eiteljörge, Benjamin Huth, Reinhold Dröge, Abernitzke, Richard Ohnemus, Frank Grimm, Sakib, Broeserl, António Pina, and Markus Falkner.


Thanks in particular to:   crp4



Get your e-book at Leanpub:

The C++ Standard Library


Concurrency With Modern C++


Get Both as one Bundle

cover   ConcurrencyCoverFrame   bundle
With C++11, C++14, and C++17 we got a lot of new C++ libraries. In addition, the existing ones are greatly improved. The key idea of my book is to give you the necessary information to the current C++ libraries in about 200 pages. I also included more than 120 source files.  

C++11 is the first C++ standard that deals with concurrency. The story goes on with C++17 and will continue with C++20.

I'll give you a detailed insight in the current and the upcoming concurrency in C++. This insight includes the theory and a lot of practice with more than 140 source files.


Get my books "The C++ Standard Library" (including C++17) and "Concurrency with Modern C++" in a bundle.

In sum, you get more than 700 pages full of modern C++ and more than 260 source files presenting concurrency in practice.


Get your interactive course


Modern C++ Concurrency in Practice

C++ Standard Library including C++14 & C++17

educative CLibrary

Based on my book "Concurrency with Modern C++" educative.io created an interactive course.

What's Inside?

  • 140 lessons
  • 110 code playgrounds => Runs in the browser
  • 78 code snippets
  • 55 illustrations

Based on my book "The C++ Standard Library" educative.io created an interactive course.

What's Inside?

  • 149 lessons
  • 111 code playgrounds => Runs in the browser
  • 164 code snippets
  • 25 illustrations


0 #1 Pranabesh Das 2020-05-12 04:40
How to compile the Coroutines code in VC++ 2019 or even in Wandbox?

After adding the following headers


and -fcoroutines compiler switch it says

prog.cc:8:1: error: 'Generator' does not name a type
8 | Generator getNext(int start = 0, int step = 1){
| ^~~~~~~~~
prog.cc: In function 'int main()':
prog.cc:20:16: error: 'getNext' was not declared in this scope; did you mean 'getpt'?
20 | auto gen = getNext();
| ^~~~~~~
| getpt


My Newest E-Books

Course: Modern C++ Concurrency in Practice

Course: C++ Standard Library including C++14 & C++17

Course: Embedded Programming with Modern C++

Course: Generic Programming (Templates)

Course: C++ Fundamentals for Professionals

Subscribe to the newsletter (+ pdf bundle)

Blog archive

Source Code


Today 9577

Yesterday 13046

Week 30479

Month 170240

All 4620332

Currently are 180 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments