Coming in C++20

The main features in C++20 of interest to scientific computing are:

Modules

Modules are source files that are compiled independently of your program that can then be imported. They replace the role of headers in C++20. Note that compiler support is not that great at the moment.

See Overview of modules in C++

One of the advantages of modules is that they can greatly speed up compilation times.

Note

Compiler support for modules is not very good at the moment.

Here’s a simple example. First the module:

Listing 157 example.cpp
module;

// includes must be in the "global fragment" and preced the main
// purview that's why we add the `module;` above.

#include <cmath>

export module Example;

export double f(double x) {
    return std::sin(x);
}

Now the main program:

Listing 158 main.cpp
import Example;

#include <iostream>

int main() {

    double x{0.0};

    std::cout << f(x) << std::endl;

}

and finally, a GNUmakefile:

Listing 159 GNUmakefile
MODULEFILES := example.cpp
SOURCEFILES := main.cpp

MODULEOBJS := $(MODULEFILES:.cpp=.o)
SOURCEOBJS := $(SOURCEFILES:.cpp=.o)

%.o : %.cpp
	g++ -std=c++20 -fmodules-ts -c $<

main: ${MODULEOBJS} ${SOURCEOBJS}
	g++ -std=c++20 --modules-ts -o $@ ${MODULEOBJS} ${SOURCEOBJS}

clean:
	rm -rf *.o main gcm.cache

Note

This compiles with GCC 11.4, but curiously not with GCC 14…

Concepts

Views

C++ 20 introduces the ranges library. This allows us to more easily consider views into our containers.

Here’s an example of using a range-based for loop over a set of integers:

Listing 160 iota_loop.cpp
#include <iostream>
#include <ranges>

int main() {

    for (auto i : std::views::iota(2, 7)) {
        std::cout << i << std::endl;
    }

}

Range Adaptors

Range adaptors look like pipes that we saw when discussing Bash (see: https://learn.microsoft.com/en-us/cpp/standard-library/range-adaptors?view=msvc-170)

Here’s an example of using an adaptor to reverse the iteration through a vector using a range-based for loop:

Listing 161 reverse_adaptor.cpp
#include <iostream>
#include <vector>
#include <ranges>

int main() {

    std::vector<double> v{1, 2, 3, 4, 5};

    for (auto e : v | std::views::reverse) {
        std::cout << e << " ";
    }
    std::cout << std::endl;

}

3-way Comparison

Here’s a good discussion: https://stackoverflow.com/questions/67284403/why-should-i-use-the-three-way-comparison-operator-instead-of-the-two-way