Programming with C 20 Concepts Coroutines Ranges and more Updated 2024 2nd Edition Andreas Fertig 2024 Scribd Download
Programming with C 20 Concepts Coroutines Ranges and more Updated 2024 2nd Edition Andreas Fertig 2024 Scribd Download
com
https://ebookname.com/product/programming-
with-c-20-concepts-coroutines-ranges-and-more-
updated-2024-2nd-edition-andreas-fertig/
OR CLICK BUTTON
DOWLOAD EBOOK
https://ebookname.com/product/navigating-communication-with-seriously-
ill-patients-2e-apr-25-2024-2nd-edition-elise-c-carey/
ebookname.com
https://ebookname.com/product/programming-with-c-3rd-edition-
ravichandran/
ebookname.com
https://ebookname.com/product/with-fabric-and-thread-more-
than-20-inspired-quilting-and-sewing-patterns-1st-edition-joanna-
figueroa/
ebookname.com
https://ebookname.com/product/encyclopedia-of-clothing-and-
fashion-1st-edition-valerie-steele/
ebookname.com
Robert Lax 1. ed. Edition Paul J. Spaeth
https://ebookname.com/product/robert-lax-1-ed-edition-paul-j-spaeth/
ebookname.com
https://ebookname.com/product/bridging-cultural-conflicts-a-new-
approach-for-a-changing-world-michelle-lebaron/
ebookname.com
https://ebookname.com/product/data-modeling-and-database-design-2nd-
edition-narayan-s-umanath/
ebookname.com
https://ebookname.com/product/myths-lies-and-oil-wars-engdahl/
ebookname.com
Joy s LIFE Diet Four Steps to Thin Forever 1st Edition Joy
Bauer
https://ebookname.com/product/joy-s-life-diet-four-steps-to-thin-
forever-1st-edition-joy-bauer/
ebookname.com
Programming
with C++20
Concepts, Coroutines,
Ranges, and more
Andreas Fertig
Andreas Fertig
2. Edition
© 2024 Andreas Fertig
https://AndreasFertig.com
All rights reserved
The work including all its parts is protected by copyright. Any use outside the limits of the copyright law
requires the prior consent of the author. This applies in particular to copying, editing, translating and
saving and processing in electronic systems.
The reproduction of common names, trade names, trade names, etc. in this work does not justify
the assumption that such names are to be regarded as free within the meaning of the trademark
and trademark protection legislation and therefore may be used by everyone, even without special
identification.
Published by:
Fertig Publications
https://andreasfertig.com
ISBN: 978-3-949323-05-8
This book exists to assist you during your daily job life or hobbies. All examples in
this book are released under the MIT license.
The main reason for choosing the MIT license was to avoid uncertainty. It is a
well-established open-source license and comes with few restrictions. That should
make it easy to use it even in closed-source projects. If you need a dedicated license
or have questions about the existing licensing, feel free to contact me.
Code download
Used Compilers
For those of you who would like to try out the code with the same compilers and
revisions I used, here you go:
■ GCC 13.2.0
■ Clang 17.0.0
6
About the Author
Andreas Fertig, CEO of Unique Code GmbH, is an experienced trainer and lecturer
for C++ for standards 11 to 23.
Before training and consulting, he worked for Philips Medizin Systeme GmbH for
ten years as a C++ software developer and architect focusing on embedded systems.
Programming with C++20 teaches programmers with C++ experience the new fea-
tures of C++20 and how to apply them. It does so by assuming C++11 knowledge.
Elements of the standards between C++11 and C++20 will be briefly introduced, if
necessary. However, the focus is on teaching the features of C++20.
You will start with learning about the so-called big four Concepts, Coroutines,
std::ranges, and modules. The big four a followed by smaller yet not less important
features. You will learn about std::format, the new way to format a string in C++.
In chapter 6, you will learn about a new operator, the so-called spaceship operator,
which makes you write less code.
You then will look at various improvements of the language, ensuring more con-
sistency and reducing surprises. You will learn how lambdas improved in C++20 and
what new elements you can now pass as non-type template parameters. Your next
stop is the improvements to the STL.
Of course, you will not end this book without learning about what happened in
the constexpr-world.
The following shows the execution of a program. I used the Linux way here and
skipped supplying the desired output name, resulting in a.out as the program name.
$ ./a.out
Output
From time to time, I use an element from a previous standard after C++11. I ex-
plain these elements in dedicated standard boxes such as the following:
These boxes carry the standard in which this element was introduced and are num-
bered such that I can reference them like this: Std-Box 0.1.
All listings are numbered and sometimes come with annotations which I refer to
like this A .
References carry a page number in case the reference isn’t on the same page. For
example, Std-Box 0.1 has no page number because it appears on the same page.
Feedback
As with most of my material, the book is written in LATEX. The epub version is
generated by a custom script which first translates LATEX into Markdown and then
translates Markdown into epub with the help of pandoc. This comes with some
limitations. Currently, the bibliography does not use the same style as the PDF, and
About the Book 11
Another issue I have with the epub is that I do not own a reader device my-
self. I tested it with Apple’s Books.However, please tell me if you have better
knowledge of optimizing the output.
Thank you
I like to say thank you to everyone who reviewed drafts for this book and gave me
valuable feedback. Thank you! All this feedback helped to improve the book. Here
is a list of people who provided feedback: Vladimir Krivopalov, Hristiyan Nevelinov,
John Plaice, Peter Sommerlad, Salim Pamukcu, Jonathan Di Cosmo, and others.
A special thanks goes to Fran Buontempo, editor of ACCU’s Overload magazine.
She provided extensive feedback from the beginning and was never tired of pointing
out some grammar issues along with poking to the base of my code examples, helping
me make them better.
Revision History
Acronyms 327
Bibliography 329
Index 331
Chapter 1
Concepts:
Predicates for strongly typed
generic code
Templates have been with C++ since the early beginnings. Recent standard updates
have added new facilities, such as variadic templates. Templates enable Generic Pro-
gramming (GP), the idea of abstracting concrete algorithms to get generic algorithms.
They can then be combined and used with different types to produce a wide variety
of software without providing a dedicated algorithm for each type. GP or Template
Meta-Programming (TMP) are powerful tools. For example, the Standard Template
Library (STL) heavily uses them.
However, template code has always been a bit, well, clumsy. When we write a
generic function, we only need to write the function once; then it can be applied to
various different types. Sadly, when using the template with an unsupported type,
finding any error requires a good understanding of the compiler’s error message.
All we needed to face such a compiler error message was a missing operator< that
wasn’t defined for the type. The issue was that we had no way of specifying the re-
quirements to prevent the misuse, and at the same time, give a clear error message.
18
This chapter comes with an additional challenge. The language feature we will discuss in this
chapter is called Concepts. We can also define a concept ourselves, and there is a concept key-
word. When I refer to the feature itself, it is spelled with a capital C, Concepts. The lowercase
version is used when I refer to a single concept definition, and the code-font version concept
refers to the keyword.
Let’s consider a simple generic Add function. This function should be able to add an
arbitrary number of values passed to it and return the result. Much like this:
1 const int x = Add(2,3,4,5);
2 const int y = Add(2,3);
3 const int z = Add(2, 3.0); A This should not compile
While the first two calls to Add, x and y, are fine, the third call should result in a
compile error. With A we are looking at implicit conversions, namely a promotion
from int to double because of 3.0. Implicit conversions can be a good thing, but in
this case, I prefer explicitness over the risk of loss of precision. Here Add should only
accept an arbitrary number of values of the same data type.
To make the implementation a little more challenging, let’s say that we don’t want
a static_assert in Add, which checks that all parameters are of the same type. We
would like to have the option of providing an overload to Add that could handle cer-
tain cases of integer promotions.
We start with an implementation in C++1 to see the power of Concepts. For
the implementation of Add, we obviously need a variadic function template as well
as a couple of helpers. The implementation I present here requires two helpers,
are_same_v and first_arg_t. You can see the implementation in Listing 1.1.
3 std::conjunction_v<std::is_same<T, Ts>...>;
4
5 template<typename T, typename...>
Chapter 1: Concepts: Predicates for strongly typed generic code 19
6 struct first_arg {
7 using type = T;
Listing 1.1
8 };
9
10 template<typename... Args>
11 using first_arg_t = typename first_arg<Args...>::type;
Variable templates were introduced with C++14. They allow us to define a variable, which is a
template. This feature allows us to have generic constants like π :
Listing 1.2
1 template<typename T>
2 constexpr T pi(3.14);
One other use case is to make TMP more readable. Whenever we had a type-trait with a value
we wanted to access, before C++14, we needed to do this: std::is_same<T, int>::value
. Admittingly, the ::value part was not very appealing. Variable templates allow the value of
::value to be stored in a variable.
Listing 1.3
With that, the shorter and more readable version is is_same_v<T, int>. Whenever you see a
_v together with a type-trait, you’re looking at a variable template.
Our second helper, first_arg_t, uses a similar trick. It extracts the first type
from a pack and stores it in a using-alias. That way, we have access to the first data
type in a parameter pack, and since we later ensure that all types in the pack are the
same, this first type is as good as that from any other index choice in the parameter
pack.
20
Great, now that we have our helpers in place, let’s implement Add. Listing 1.4
provides an implementation using C++17.
1 template<typename... Args>
2 std::enable_if_t<are_same_v<Args...>, first_arg_t<Args...>>
Listing 1.4
3 Add(const Args&... args) noexcept
4 {
5 return (... + args);
6 }
Before C++17, whenever we had a parameter pack, we needed to recursively call the function
that received the pack and split up the first parameter. That way, we could traverse a parameter
pack. C++17 allows us to apply an operation to all elements in the pack. For example, int
result = (... + args); applies the + operation to all elements in the pack. Assuming that
the pack consists of three objects, this example will produce int result = arg0 + arg1 +
arg2;. This is much shorter to write than the recursive version. That one needs to be terminated
at some point. With fold expressions, this is done automatically by the compiler. We can use other
operations instead of +, like −, /, ∗, and so on.
The important thing to realize about fold expressions is that it is only a fold expression if the pack
expansion has parentheses around it and an operator like +.
So far, I hope that’s all understandable. The part I heavily object to, despite the
fact that it is my own code, is the line with the enable_if_t. Yes, it is the state-of-
the-art enable_if because, with the _t, we don’t need to say typename in front of
it. However, this single line is very hard to read and understand. Depending on your
knowledge of C++, it can be easy, but remember the days when you started with C++.
There is a lot that one has to learn to understand this single line.
The first part, or argument, is the condition. Here, we pass are_same_v. Should
this condition be true, the next parameter which is first_arg_t, gets enabled. This
then becomes the return type of Add. Right, did you also miss the return type initially?
Chapter 1: Concepts: Predicates for strongly typed generic code 21
Should the condition be false, then this entire expression isn’t instantiable. We speak
of substitution failure is not an error (SFINAE) as the technique used here, and this
version of Add isn’t used for lookups by the compilers. The result is that we can end
up with page-long error messages where the compiler informs us about each and
every overload of Add it tried.
One more subtle thing is that, in this case, enable_if does something slightly
different than just enabling or disabling things. It tells us the requirements for this
function. Yet, the name enable_if doesn’t give many clues about that.
All these things are reasons why people might find templates tremendously diffi-
cult to process. But, yes, I know, those who stayed accommodated to all these short-
comings.
Now it is time to see how things change with C++20.
Sticking with the initial example, we ignore the helpers, as they stay the same. List-
ing 1.5 presents the C++20 implementation of Add.
1 template<typename... Args>
2 A Requires-clause using are_same_v to ensure all Args are of the same
type.
Listing 1.5
3 requires are_same_v<Args...>
4 auto Add(Args&&... args) noexcept
5 {
6 return (... + args);
7 }
Here, we can see that Add remains a variadic function template, probably not the
biggest surprise. Let’s skip two lines again and go to the definition of Add. What first
springs into our eyes is the return type. I chose auto. But the important thing is that
the return type is there! The rest of the function’s signature, as well as the function
body, are unchanged. I see this return type as the first win. Before, the enable_if
obfuscated the return type.
The biggest improvement is the line that says requires. Isn’t that what’s really
going on here? This function Add requires that are_same_v is true. That’s all. I find
22
that pretty easy to read. The intent is clearly expressed without obfuscating anything
or requiring weird tricks. Okay, maybe we must look up what are_same_v does, but
I can live with that.
We are looking at one of the building blocks of Concepts in Listing 1.5 on page 21,
the requires-clause.
Before discussing how we can create Concepts, let’s first see where we can apply
them. Figure 1.1 on page 23 lists all the places in a template declaration where we
can apply Concepts.
We see a type-constraint in C1. In this place, we can only use Concepts. We can use
a type-constraint instead of either class or typename in a template-head to state as
early as possible that this template takes a type deduced by the compiler, but it must
meet some requirements.
The next option is with C2, using a requires-clause. We already applied that in our
Add example in Listing 1.5 on page 21. In a requires-clause, we can use either con-
cepts or type-traits. The expression following the requires must return a boolean
value at compile time. If that value is true, the requirement(s) is (are) fulfilled.
The two places of C3 and C4 are similar. They both apply to placeholder types
constraining them. We can also use Concepts to constrain auto variables, which we
will see later. A constraint placeholder type works only with Concepts. Type-traits
are not allowed. In C4, we see something that you might already know from C++14’s
generic lambdas, Std-Box 7.1 on page 210, auto as a parameter type. Since C++20,
they are no longer limited to generic lambdas.
At the end, we have the trailing requires-clause. This one is similar to the requires-
clause. We can use Concepts or type-traits and can use boolean logic to combine
them. Table 1.1 on page 23 gives guidance on when to use which constraint form.
Chapter 1: Concepts: Predicates for strongly typed generic code 23
type-constraint
requires-clause
template<C1 T>
requires C2<T>
C3 auto Fun(C4 auto param) requires C5<T>
trailing requires-clause
constrained placeholder type
Figure 1.1: The different places where we can constrain a template or template argument.
C1 type-constraint Use this when you already know that a template type
parameter has a certain constraint. For example, not all
types are allowed. In Figure 1.1 the type is limited to a
floating-point type.
C2 requires-clause Use this when you need to add constraints for multiple
template type or non-type template parameters.
We’ve already seen the two forms of a requires-clause. It is time to look at our Add
example again and see what we can improve with the help of Concepts.
The current implementation of Add only prevents mixed types. Let’s call this re-
quirement A of Add. By that, the implementation leaves a lot unspecified:
B Add can nonsensically be called with only one parameter. The function’s name,
on the other hand, implies that things are added together. It would make more
sense if Add would also require to be called with at least two parameters. Ev-
erything else is a performance waste.
C The type used in Args must support the + operation. This is a very subtle re-
quirement that harshly yells at us once we violate it. It is also a design choice of
24
requires(T t, U u)
{ Body of the
// some requirements
requires-expression
}
the implementor of Add. Instead of operator+, one could also require that the
type comes with a member function Addition. That would, of course, rule out
built-in types. Should we miss that, we again get these page-long errors that
are hard to see through. Only documentation helps at this point, and documen-
tation over time may disagree with the implementation. In such a case, I prefer
a check by the compiler over documentation.
D The operation + should be noexcept, since Add itself is noexcept. Did you
spot that initially? The implementation of Add in Listing 1.5 on page 21 and
before was always marked noexcept. Why? Because it mainly adds num-
bers, and I don’t want to have a try-catch-block around something like 3 + 4.
But since Add is a generic function, it also works with, for example, a std::
string, which can throw an exception. Writing a check for the noexceptness
of operator+ pre C++17 is an interesting exercise.
E The return type of operation + should match that of Args. Another interesting
and often overlooked requirement. It is surprising should operator+ of type
T return a type U. Sometimes, there are good reasons for such a behavior, but
it doesn’t seem plausible in the case of Add. Let’s restrict this as well.
IV
The other day I saw a young swimmer in the surf. He was, I
judged, about twenty-two years old and a little less than six feet tall,
splendidly built, and as he stripped I saw that he must have been
swimming since the season began, for he was sunburned and
brown. Standing naked on the steep beach, his feet in the climbing
seethe, he gathered himself for a swimmer’s crouching spring,
watched his opportunity, and suddenly leaped headfirst through a
long arc of air into the wall of a towering and enormous wave. Again
and again he repeated his jest, emerging each time beyond the
breaker with a stare of salty eyes, a shake of the head, and a smile.
It was all a beautiful thing to see: the surf thundering across the
great natural world, the beautiful and compact body in its naked
strength and symmetry, the astounding plunge across the air, arms
extended ahead, legs and feet together, the emerging stroke of the
flat hands, and the alternate rhythms of the sunburned and powerful
shoulders.
Watching this picture of a fine human being free for the moment of
everything save his own humanity and framed in a scene of nature, I
could not help musing on the mystery of the human body and of how
nothing can equal its rich and rhythmic beauty when it is beautiful or
approach its forlorn and pathetic ugliness when beauty has not been
mingled in or has withdrawn. Poor body, time and the long years
were the first tailors to teach you the merciful use of clothes! Though
some scold to-day because you are too much seen, to my mind, you
are not seen fully enough or often enough when you are beautiful. All
my life it has given me pleasure to see beautiful human beings. To
see beautiful young men and women gives one a kind of reverence
for humanity (alas, of how few experiences may this be said), and
surely there are few moods of the spirit more worthy of our care than
those in which we reverence, even for a moment, our tragic and
bewildered kind.
My swimmer having gone his way, out of a chance curiosity I
picked the top of a dune goldenrod, and found at the very bottom of
a cocoon of twisted leaves the embryo head of the late autumnal
flower.
Chapter X
ORION RISES ON THE DUNES
So came August to its close, ending its last day with a night so
luminous and still that a mood came over me to sleep out on the
open beach under the stars. There are nights in summer when
darkness and ebbing tide quiet the universal wind, and this August
night was full of that quiet of absence, and the sky was clear. South
of my house, between the bold fan of a dune and the wall of a
plateau, a sheltered hollow opens seaward, and to this nook I went,
shouldering my blankets sailorwise. In the star-shine the hollow was
darker than the immense and solitary beach, and its floor was still
pleasantly warm with the overflow of day.
I fell asleep uneasily, and woke again as one wakes out-of-doors.
The vague walls about me breathed a pleasant smell of sand, there
was no sound, and the broken circle of grass above was as
motionless as something in a house. Waking again, hours afterward,
I felt the air grown colder and heard a little advancing noise of
waves. It was still night. Sleep gone and past recapture, I drew on
my clothes and went to the beach. In the luminous east, two great
stars aslant were rising clear of the exhalations of darkness gathered
at the rim of night and ocean—Betelgeuse and Bellatrix, the
shoulders of Orion. Autumn had come, and the Giant stood again at
the horizon of day and the ebbing year, his belt still hidden in the
bank of cloud, his feet in the deeps of space and the far surges of
the sea.
The Fo’castle
My year upon the beach had come full circle; it was time to close
my door. Seeing the great suns, I thought of the last time I marked
them in the spring, in the April west above the moors, dying into the
light and sinking. I saw them of old above the iron waves of black
December, sparkling afar. Now, once again, the Hunter rose to drive
summer south before him, once again autumn followed on his steps.
I had seen the ritual of the sun; I had shared the elemental world.
Wraiths of memories began to take shape. I saw the sleet of the
great storm slanting down again into the grass under the thin
seepage of moon, the blue-white spill of an immense billow on the
outer bar, the swans in the high October sky, the sunset madness
and splendour of the year’s terns over the dunes, the clouds of
beach birds arriving, the eagle solitary in the blue. And because I
had known this outer and secret world, and been able to live as I had
lived, reverence and gratitude greater and deeper than ever
possessed me, sweeping every emotion else aside, and space and
silence an instant closed together over life. Then time gathered
again like a cloud, and presently the stars began to pale over an
ocean still dark with remembered night.
During the months that have passed since that September
morning some have asked me what understanding of Nature one
shapes from so strange a year? I would answer that one’s first
appreciation is a sense that the creation is still going on, that the
creative forces are as great and as active to-day as they have ever
been, and that to-morrow’s morning will be as heroic as any of the
world. Creation is here and now. So near is man to the creative
pageant, so much a part is he of the endless and incredible
experiment, that any glimpse he may have will be but the revelation
of a moment, a solitary note heard in a symphony thundering
through debatable existences of time. Poetry is as necessary to
comprehension as science. It is as impossible to live without
reverence as it is without joy.
THE END
Transcriber’s Notes
New original cover art included with this eBook is granted to the public domain.
Obvious typographical errors and punctuation errors have been corrected after
careful comparison with other occurrences within the text and consultation of
external sources. Except for those changes noted below, all misspellings in the
text, and inconsistent or archaic usage, have been retained.
Updated editions will replace the previous one—the old editions will
be renamed.
Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.
ebookname.com