Understanding Major Upcoming Updates in C++: The Big Four Features of C++20

Selected from modernescpp

Author: JP Tech et al.

Compiled by Machine Heart

Contributors: Panda, Du Wei

C++20 (the 2020 version of the C++ programming language standard) will be a significant update for the C++ language, introducing a plethora of new features. Recently, C++ developer Rainer Grimm has been introducing the new features of C++20 through a series of blog posts. So far, two articles in this series have been published, and this is the first one, mainly introducing the Big Four of C++20 (the four major new features: Concepts, Ranges, Coroutines, and Modules) as well as core language updates (including some new operators and indicators).

Understanding Major Upcoming Updates in C++: The Big Four Features of C++20

C++20 has many updates,the above image showcases an overview of the C++20 updates.Next, the author will first introduce the compiler support for C++20, then discuss The Big Four (the four major new features) and new features in the core language. Compiler Support for C++20 The simplest way to adapt to new features is to try them out.So, we face the question:Which compilers support which features of C++20?Generally speaking, cppreference.com/compiler_support_ can provide answers regarding core language and library support. In short, the brand new GCC, Clang, and EDG compilers provide the best support for the core language.Additionally, MSVC and Apple Clang compilers also support many C++20 features.

Understanding Major Upcoming Updates in C++: The Big Four Features of C++20

C++20 Core Language Features.The situation is similar for library support.GCC has the best support for libraries, followed by Clang and MSVC compilers.

Understanding Major Upcoming Updates in C++: The Big Four Features of C++20

C++20 Library Features.The screenshots above only show part of the corresponding tables, and it can be seen that the performance of these compilers is not very satisfactory.Even if you are using a brand new compiler, many new features are still unsupported. Generally, you can find ways to experiment with these new features.Here are two examples:

  • Concepts:

    GCC supports an earlier version of concepts;

  • std::jthread:

    There is a draft implementation on GitHub from Nicolai Josuttis:

    https://github.com/josuttis/jthread

In short, the situation is not as dire as it seems.With some adjustments, many new features can be experimented with.If necessary, I will mention how to make such modifications.The Big FourConcepts (concept) The key idea for generic programming using templates is to define functions and classes that can be used with various types.However, there often arise issues with incorrect types during template instantiation, resulting in pages of incomprehensible error messages.Now with Concepts, this problem can be put to rest.Concepts allow you to specify requirements for templates, and the compiler can check these requirements.Concepts revolutionize the way we think about and write generic code.The reasons are as follows:

  • Template requirements are part of the interface;

  • Function overloading or specialization in class templates can be based on concepts;

  • Because the compiler can compare the requirements of template parameters with the actual template parameters, better error messages can be obtained.

However, that is not all.

  • You can use predefined concepts or define your own concepts;

  • The usage of auto and concepts is unified.You can use concepts instead of auto;

  • If a function declaration uses a concept, it automatically becomes a function template.This makes writing function templates as simple as writing functions.

The following code snippet demonstrates a simple definition and usage of the 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);
}

The Integral concept requires the type parameter T from std::is_integral<T>::value.The std::is_integral<T>::value function comes from the type-traits library, which checks at compile time if T is an integer.If the value of std::is_integral<T>::value is true, there is no problem.If it is not true, you will receive a compile-time error.If you are curious (and you should be), my article introduces the type-traits library:https://www.modernescpp.com/index.php/tag/type-traits. The gcd algorithm is based on the Euclidean algorithm for determining the greatest common divisor (greatest common divisor).I used this abbreviated function template syntax to define gcd.The gcd function requires its parameters and return type to support the Integral concept.The gcd function is a type of function template that has requirements for both parameters and return values.When I remove this syntactic sugar, perhaps you can see the true nature of gcd. The following code is semantically equivalent to the 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 still haven’t seen the true nature of gcd, I will publish a dedicated article introducing concepts in a few weeks. Ranges Library The Ranges Library is the first client of concepts.It supports algorithms that meet the following conditions:

  • Can operate directly on containers;no iterators are needed to specify a range;

  • Can be lazily evaluated;

  • Can be composed.

In simple terms:The Ranges Library supports functional patterns. The code may be clearer than the language description.The following function demonstrates function composition using the pipe operator:

#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 that returns true when i is even;the lambda function square maps i to its square.The remaining functions must be read from left to right in the i-th function composition:for (int i : ints | std::view::filter(even) | std::view::transform(square)). This applies the filter even to each element of ints and then maps each remaining element to its square.If you are familiar with functional programming, this reads like a prose poem.Coroutines Coroutines are generalized functions that can pause or resume while maintaining state.Coroutines are typically used to write event-driven applications.Event-driven applications can be simulations, games, servers, user interfaces, or algorithms.Coroutines are also often used for cooperative multitasking. We will not introduce the specific coroutines of C++20 here, but will cover the framework for writing coroutines.The framework for writing coroutines consists of over 20 functions, some of which you need to implement and others may need to be rewritten.Thus, you can adjust coroutines according to your needs. The following demonstrates the usage of a specific coroutine.The following program uses a generator that produces 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;
}

A few words must be added.This code is just a snippet.The function getNext is a coroutine because it uses the keyword co_yield.getNext has an infinite loop that returns value after co_yield.Calling next() (comments on lines 2 and 3) will resume this coroutine, and the next getValue call will fetch this value.After calling getNext, this coroutine pauses again.This pause will continue until the next call to next().In my example, there is a significant unknown, which is the return value of the getNext function, Generator<int>.This part is complex, and I will elaborate on it in my article on coroutines later. Using the Wandbox online compiler, I can show you the output of this program:

Understanding Major Upcoming Updates in C++: The Big Four Features of C++20

Modules Modules can be briefly introduced.Modules promise to achieve:

  • Faster compilation times;

  • Isolation of macros;

  • Expressing the logical structure of code;

  • No need to use header files;

  • Getting rid of ugly macro methods.

Original link: https://www.modernescpp.com/index.php/thebigfourThis article is compiled by Machine Heart, please contact this public account for authorization to reprint.✄————————————————Join Machine Heart (Full-time reporter / Intern):[email protected]Submission or inquiry for coverage: content@jiqizhixin.comAdvertising & Business Cooperation:[email protected]

Leave a Comment