C 20 The Complete Guide Nicolai M. Josuttis Install Download
C 20 The Complete Guide Nicolai M. Josuttis Install Download
Josuttis
install download
https://ebookmeta.com/product/c-20-the-complete-guide-nicolai-m-
josuttis/
https://ebookmeta.com/product/c-20-the-complete-
guide-1-2022-10-30-edition-nicolai-m-josuttis/
https://ebookmeta.com/product/c-move-semantics-the-complete-
guide-1st-edition-nicolai-m-josuttis/
https://ebookmeta.com/product/c-17-the-complete-
guide-1-2022-01-11-edition-nicolai-m-josuttis/
https://ebookmeta.com/product/of-fire-and-stars-1st-edition-
audrey-coulthurst/
Genetics Essentials Concepts and Connections 5th
Edition Benjamin Pierce
https://ebookmeta.com/product/genetics-essentials-concepts-and-
connections-5th-edition-benjamin-pierce/
https://ebookmeta.com/product/sunrisesunset-solargraphs-from-
plum-creek-wittliff-collections-photography-series-bill-wittliff/
https://ebookmeta.com/product/mountain-mans-captive-an-ott-
mountain-man-romance-men-of-maple-mountain-book-2-1st-edition-
sadie-king/
https://ebookmeta.com/product/surprise-kissmas-my-roommate-guy-
next-door-romance-all-i-want-for-kissmas-1st-edition-brynn-hale/
https://ebookmeta.com/product/reality-1st-edition-layla-heart/
Garrett s Obsession A Curvy Girl Instalove Romance 1st
Edition Loni Nichole
https://ebookmeta.com/product/garrett-s-obsession-a-curvy-girl-
instalove-romance-1st-edition-loni-nichole-2/
Nicolai M. Josuttis
First Edition
To the nation of Ukraine
and all the children, women, men, and soldiers
killed in a terrible war driven by a Russian dictator
Nicolai M. Josuttis
This book was typeset by Nicolai M. Josuttis using the LATEX document processing system.
iii
iv Contents
9 Spans 295
9.1 Using Spans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
9.1.1 Fixed and Dynamic Extent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
9.1.2 Example Using a Span with a Dynamic Extent . . . . . . . . . . . . . . . . . . . . . . 296
9.1.3 Example Using a Span with Non-const Elements . . . . . . . . . . . . . . . . . . . . 301
9.1.4 Example Using a Span with Fixed Extent . . . . . . . . . . . . . . . . . . . . . . . . . 303
9.1.5 Fixed vs. Dynamic Extent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
9.2 Spans Considered Harmful . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
9.3 Design Aspects of Spans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
9.3.1 Lifetime Dependencies of Spans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
9.3.2 Performance of Spans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
9.3.3 const Correctness of Spans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
9.3.4 Using Spans as Parameters in Generic Code . . . . . . . . . . . . . . . . . . . . . . . 310
9.4 Span Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
9.4.1 Span Operations and Member Types Overview . . . . . . . . . . . . . . . . . . . . . . 312
9.4.2 Constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
9.4.3 Operations for Sub-Spans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
9.5 Afternotes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
14 Coroutines 459
14.1 What Are Coroutines? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459
14.2 A First Coroutine Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461
14.2.1 Defining the Coroutine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461
14.2.2 Using the Coroutine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462
14.2.3 Lifetime Issues with Call-by-Reference . . . . . . . . . . . . . . . . . . . . . . . . . . 466
14.2.4 Coroutines Calling Coroutines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 468
14.2.5 Implementing the Coroutine Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . 471
14.2.6 Bootstrapping Interface, Handle, and Promise . . . . . . . . . . . . . . . . . . . . . . 477
14.2.7 Memory Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479
14.3 Coroutines That Yield or Return Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481
14.3.1 Using co_yield . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481
14.3.2 Using co_return . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 487
14.4 Coroutine Awaitables and Awaiters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491
14.4.1 Awaiters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491
14.4.2 Standard Awaiters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493
14.4.3 Resuming Sub-Coroutines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 494
14.4.4 Passing Values From Suspension Back to the Coroutine . . . . . . . . . . . . . . . . 498
14.5 Afternotes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503
16 Modules 559
16.1 Motivation for Modules Using a First Example . . . . . . . . . . . . . . . . . . . . . . . . . . . 559
16.1.1 Implementing and Exporting a Module . . . . . . . . . . . . . . . . . . . . . . . . . . 559
16.1.2 Compiling Module Units . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561
16.1.3 Importing and Using a Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 562
16.1.4 Reachable versus Visible . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 563
16.1.5 Modules and Namespaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 564
16.2 Modules with Multiple Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566
16.2.1 Module Units . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566
16.2.2 Using Implementation Units . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566
16.2.3 Internal Partitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571
xiv Contents
Glossary 703
Index 709
Preface
C++20 is the next evolution in modern C++ programming, and it is already (partially) supported by the
latest version of GCC, Clang, and Visual C++. The move to C++20 is at least as big a step as the move to
C++11. C++20 contains a significant number of new language features and libraries that will again change
the way we program in C++. This applies to both application programmers and programmers who provide
foundation libraries.
An Experiment
This book is an experiment in two ways:
• I am writing an in-depth book that covers complex new features invented and provided by different
programmers and C++ working groups. However, I can ask questions and I do.
• I am publishing the book myself on Leanpub and for printing on demand. That is, this book is written
step by step and I will publish new versions as soon there is a significant improvement that makes the
publication of a new version worthwhile.
The good thing is:
• You get the view of the language features from an experienced application programmer—somebody who
feels the pain a feature might cause and asks the relevant questions to be able to explain the motivation
for a feature, its design, and all consequences for using it in practice.
• You can benefit from my experience with C++20 while I am still learning and writing.
• This book and all readers can benefit from your early feedback.
This means that you are also part of the experiment. So help me out: give feedback about flaws, errors,
features that are not explained well, or gaps, so that we all can benefit from these improvements.
Acknowledgments
This book would not have been possible without the help and support of a huge number of people.
First of all, I would like to thank you, the C++ community, for making this book possible. The incredible
design of all the features of C++20, the helpful feedback, and your curiosity are the basis for the evolution
of a successful language. In particular, thanks for all the issues you told me about and explained and for the
feedback you gave.
xix
xx Preface
I would especially like to thank everyone who reviewed drafts of this book or corresponding slides and
provided valuable feedback and clarification. These reviews increased the quality of the book significantly,
again proving that good things are usually the result of collaboration between many people. Therefore, so
far (this list is still growing) huge thanks to Carlos Buchart, Javier Estrada, Howard Hinnant, Yung-Hsiang
Huang, Daniel Krügler, Dietmar Kühl, Jens Maurer, Paul Ranson, Thomas Symalla, Steve Vinoski, Ville
Voutilainen. Andreas Weis, Hui Xie, Leor Zolman, and Victor Zverovich.
In addition, I would like to thank everyone on the C++ standards committee. In addition to all the work
involved in adding new language and library features, these experts spent many, many hours explaining and
discussing their work with me, and they did so with patience and enthusiasm. Special thanks here go to
Howard Hinnant, Tom Honermann, Tomasz Kaminski, Peter Sommerlad, Tim Song, Barry Revzin, Ville
Voutilainen, and Jonathan Wakely.
Special thanks go to the LaTeX community for a great text system and to Frank Mittelbach for solving
my LATEX issues (it was almost always my fault).
And finally, many thanks go to my proofreader, Tracey Duffy, who has again done a tremendous job of
converting my “German English” into native English.
• 2022-05-07: Describe jthread and stop token support for condition variables.
• 2022-04-28: Describe owning views, which were added to C++20 as a late fix.
• 2022-04-24: Describe significant details of coroutines and their awaiters.
• 2022-04-21: Describe functions for safe integral comparisons.
• 2022-04-21: Describe std::ranges::swap().
• 2022-04-20: Describe the new shift algorithms and the new min/max algorithms for ranges.
• 2022-04-20: Describe compare_three_way and lexicographical_compare_three_way().
• 2022-04-19: Describe feature test macros.
• 2022-04-18: Describe several additional details and clarifications about modules.
• 2022-04-09: Describe deferred evaluation with auto parameters.
• 2022-03-26: Describe awaiters, memory management, and other details of coroutines.
• 2022-03-08: Describe details of utilities of the ranges library.
• 2022-03-03: Rewrite the coroutines chapter with several more details.
• 2022-02-20: Describe the range-based for loop with initialization.
• 2022-02-17: Reorganize book chapters.
• 2022-02-16: Describe new attributes and attribute extensions.
• 2022-02-15: Describe conditional explicit.
• 2022-02-15: Fix the way user-defined formatters should be implemented.
• 2022-02-12: Describe using for enumeration values.
• 2022-02-09: Add figure with subset of the subsumptions of the standard concepts.
• 2022-01-08: Describe class template argument deduction for aggregates.
• 2022-01-05: Describe modified definition of aggregates.
• 2022-01-04: Describe aggregate initialization with parentheses.
• 2021-12-31: Describe the new iterator traits (such as std::iter_value_t).
• 2021-12-31: Describe where typename is no longer required for type members of template parameters.
• 2021-12-30: Describe new bit operations (including bit_cast<>()).
• 2021-12-29: Describe improvements for string types (including std::u8string and using strings at compile time).
• 2021-12-28: Describe the unseq execution policy for algorithms.
• 2021-12-25: Describe all other missing lambda features.
• 2021-12-11: Describe consteval lambdas.
• 2021-12-06: Describe std::endian.
• 2021-12-06: Describe synchronized output streams.
• 2021-12-04: Describe the header file <version>.
• 2021-11-21: Describe compile-time use of vectors and constexpr extensions.
• 2021-10-25: Describe designated initializers.
• 2021-10-14: Describe severe compatibility issues with operator==.
• 2021-10-14: Describe mathematical constants.
• 2021-10-12: Describe constinit, consteval, and std::is_constant_evaluated().
• 2021-10-07: Describe char8_t for UTF-8 (and its compatibility issues).
• 2021-10-02: Clarify which const views you cannot iterate over.
• 2021-10-01: Provide details about the formatting library.
• 2021-09-21: Add updates and fixes according to several reviews.
• 2021-09-20: Provide a first description of features for modules.
xxii Preface
This book presents all the new language and library features of C++20. It covers the motivation and context
of each new feature with examples and background information.
As usual for my books, the focus lies on the application of the new features in practice and the book
demonstrates how features impact day-to-day programming and how you can benefit from them in projects.
This applies to both application programmers and programmers who provide generic frameworks and foun-
dation libraries.
xxiii
xxiv About This Book
Initializations
I usually use the modern form of initialization (introduced in C++11 as uniform initialization) with curly
braces or with = in trivial cases:
int i = 42;
std::string s{"hello"};
The brace initialization has the following advantages:
• It can be used with fundamental types, class types, aggregates, enumeration types, and auto
• It can be used to initialize containers with multiple values
• It can detect narrowing errors (e.g., initialization of an int by a floating-point value)
• It cannot be confused with function declarations or calls
If the braces are empty, the default constructors of (sub)objects are called and fundamental data types are
guaranteed to be initialized with 0/false/nullptr.
Error Terminology
I often talk about programming errors. If there is no special hint, the term error or a comment such as
... // ERROR
means a compile-time error. The corresponding code should not compile (with a conforming compiler).
If I use the term runtime error, the program might compile but not behave correctly or result in undefined
behavior (thus, it might or might not do what is expected).
The C++ Standards xxv
Code Simplifications
I try to explain all features with helpful examples. However, to concentrate on the key aspects to be taught,
I might often skip other details that should be part of the code.
• Most of the time I use an ellipsis (“...”) to signal additional code that is missing. Note that I do not use
code font here. If you see an ellipsis with code font, code must have these three dots as a language feature
(such as for “typename...”).
• In header files, I usually skip the preprocessor guards. All header files should have something like the
following:
#ifndef MYFILE_HPP
#define MYFILE_HPP
...
#endif // MYFILE_HPP
Therefore, please beware and fix the code when using these header files in your projects.
Feedback
I welcome your constructive input—both negative and positive. I have worked very hard to bring you what
I hope you will find to be an excellent book. However, at some point I had to stop writing, reviewing, and
tweaking to “release the new revision.” You may therefore find errors, inconsistencies, presentations that
could be improved, or topics that are missing altogether. Your feedback gives me a chance to fix these issues,
inform all readers about the changes through the book’s website, and improve any subsequent revisions or
editions.
The best way to reach me is by email. You will find the email address on the website for this book:
http://www.cppstd20.com
If you use the ebook, you might want to ensure you to have the latest version of this book available (remem-
ber it is written and published incrementally). You should also check the book’s website for the currently
known errata before submitting reports. Please always refer to the publishing date of this version when
giving feedback. The current publishing date is 2022-10-30 (you can also find it on page ii, the page directly
after the cover).
Many thanks.
Chapter 1
Comparisons and Operator <=>
C++20 simplifies the definition of comparisons for user-defined types and introduces better ways of dealing
with them. The new operator <=> (also called the spaceship operator) was introduced for this purpose.
This chapter explains how to define and deal with comparisons since C++20 using these new features.
1
2 Chapter 1: Comparisons and Operator <=>
// relational operators:
bool operator< (const Value& rhs) const {
return id < rhs.id; // basic check for ordering
}
bool operator<= (const Value& rhs) const {
return !(rhs < *this); // derived check
}
bool operator> (const Value& rhs) const {
return rhs < *this; // derived check
}
bool operator>= (const Value& rhs) const {
return !(*this < rhs); // derived check
}
};
This enables you to call any of the six comparison operators for a Value (the object the operator is defined
for) with another Value (passed as parameter rhs). For example:
Value v1, v2;
... ;
if (v1 <= v2) { // calls v1.operator<=(v2)
...
}
The operators might also be called indirectly (e.g., by calling sort()):
std::vector<Value> coll;
... ;
std::sort(coll.begin(), coll.end()); // uses operator < to sort
Since C++20 , the call might alternatively use ranges:
std::ranges::sort(coll); // uses operator < to sort
The problem is that even though most of the operators are defined in terms of other operators (they are all
based on either operator == or operator <), the definitions are tedious and they add a lot of visual clutter.
In addition, for a well-implemented type, you might need more:
• Declare the operators with noexcept if they cannot throw
• Declare the operators with constexpr if they can be used at compile time
• Declare the operators as “hidden friends” (declare them with friend inside the class structure so that both
operands become parameters and support implicit type conversions) if the constructors are not explicit
• Declare the operators with [[nodiscard]] to force warnings if the return value is not used
1.1 Motivation for Operator<=> 3
For example:
lang/valueold.hpp
class Value {
private:
long id;
...
public:
constexpr Value(long i) noexcept // supports implicit type conversion
: id{i} {
}
...
// equality operators:
[[nodiscard]] friend constexpr
bool operator== (const Value& lhs, const Value& rhs) noexcept {
return lhs.id == rhs.id; // basic check for equality
}
[[nodiscard]] friend constexpr
bool operator!= (const Value& lhs, const Value& rhs) noexcept {
return !(lhs == rhs); // derived check for inequality
}
// relational operators:
[[nodiscard]] friend constexpr
bool operator< (const Value& lhs, const Value& rhs) noexcept {
return lhs.id < rhs.id; // basic check for ordering
}
[[nodiscard]] friend constexpr
bool operator<= (const Value& lhs, const Value& rhs) noexcept {
return !(rhs < lhs); // derived check
}
[[nodiscard]] friend constexpr
bool operator> (const Value& lhs, const Value& rhs) noexcept {
return rhs < lhs; // derived check
}
[[nodiscard]] friend constexpr
bool operator>= (const Value& lhs, const Value& rhs) noexcept {
return !(lhs < rhs); // derived check
}
};
4 Chapter 1: Comparisons and Operator <=>
Operator <=>
There is no equivalent rule that for all relational operators it is enough to have operator < defined. However,
you only have to define the new operator <=>.
In fact, the following is enough to enable programmers to use all possible comparators:
lang/value20.hpp
#include <compare>
class Value {
private:
long id;
...
public:
constexpr Value(long i) noexcept
: id{i} {
}
...
// enable use of all equality and relational operators:
auto operator<=> (const Value& rhs) const = default;
};
In general, operator == handles the equality of objects by defining == and !=, while operator <=> handles
the order of objects by defining the relational operators. However, by declaring an operator<=> with
=default, we use a special rule that a defaulted member operator<=>:
class Value {
...
auto operator<=> (const Value& rhs) const = default;
};
generates a corresponding member operator==, so that we effectively get:
class Value {
...
auto operator<=> (const Value& rhs) const = default;
auto operator== (const Value& rhs) const = default; // implicitly generated
};
The effect is that both operators use their default implementation, which compares objects member by
member. This means that the order of the members in the class matters.
Thus, with
class Value {
...
auto operator<=> (const Value& rhs) const = default;
};
we get all we need to be able to use all six comparison operators.
6 Chapter 1: Comparisons and Operator <=>
In addition, even when declaring the operator as a member function, the following applies for the gener-
ated operators:
• They are noexcept if comparing the members never throws
• They are constexpr if comparing the members is possible at compile time
• Thanks to rewriting, implicit type conversions for the first operand are also supported
This reflects that, in general, operator== and operator<=> handle different but related things:
• operator== defines equality and can be used by the equality operators == and !=.
• operator<=> defines the ordering and can be used by the relational operators <, <=, >, and >=.
Note that you have to include header <compare> when defaulting or using operator <=>.
#include <compare>
However, most header files for standard types (strings, containers, <utility>) include this header anyway.
class Value {
private:
long id;
...
public:
constexpr Value(long i) noexcept
: id{i} {
}
...
// for equality operators:
bool operator== (const Value& rhs) const {
return id == rhs.id; // defines equality (== and !=)
}
// for relational operators:
auto operator<=> (const Value& rhs) const {
return id <=> rhs.id; // defines ordering (<, <=, >, and >=)
}
};
This means that you can specify which members in which order matter or implement special behavior.
The way these basic operators work is that if an expression uses one of the comparison operators and
does not find a matching direct definition, the expression is rewritten so that it can use these operators.
1.2 Defining and Using Comparisons 7
Corresponding to rewriting calls of equality operators, rewriting might also change the order of relational
operands, which might enable implicit type conversion for the first operand. For example, if
x <= y
does not find a matching definition of operator<=, it might be rewritten as
(x <=> y) <= 0
or even
0 <= (y <=> x)
As you can see by this rewriting, the new operator<=> performs a three-way comparison, which yields a
value you can compare with 0:
• If the value of x<=>y is equal to 0, x and y are equal or equivalent.
• If the value of x<=>y is less than 0, x is less than y.
• If the value of x<=>y is greater than 0, x is greater than y.
However, note that the return type of operator<=> is not an integral value. The return type is a type that
signals the comparison category, which could be strong ordering, weak ordering, or partial ordering. These
types support the comparison with 0 to deal with the result.
Comparison Categories
When comparing two values to put them in an order, we have different categories of behavior that could
happen:
• With strong ordering (also called total ordering), any value of a given type is less than or equal to or
greater than any other value of this type (including itself).
Typical examples of this category are integral values or common string types. A string s1 is less than
or equal to or greater than a string s2.
If a value of this category is neither less than nor greater than another value, both values are equal. If
you have multiple objects, you can sort them in ascending or descending order (with equal values having
any order among each other).
• With weak ordering, any value of a given type is less than or equivalent to or greater than any other
value of this type (including itself). However, equivalent values do not have to be equal (have the same
value).
A typical example of this category is a type for case-insensitive strings. A string "hello" is less than
"hello1" and greater than "hell". However, "hello" is equivalent to "HELLO" although these two
strings are not equal.
If a value of this category is neither less than nor greater than another value, both values are at least
equivalent (they might even be equal). If you have multiple objects, you can sort them in ascending or
descending order (with equivalent values having any order among each other).
• With partial ordering, any value of a given type could be less than or equivalent to or greater than any
other value of this type (including itself). However, in addition, it may not be possible to specify a specific
order between two values at all.
A typical example of this category are floating-point types, because they might have the special value
NaN (“not a number”). Any comparison with NaN yields false. Therefore, in this case a comparison
might yield that two values are unordered and the comparison operator might return one of four values.
If you have multiple objects, you might not be able to sort them in ascending or descending order
(unless you ensure that values that cannot be ordered are not there).
However, it is usually easier to define the operator by mapping it to results of underlying types. Therefore,
it would be better for the member operator<=> above to just yield the value and category of its member
value:
10 Chapter 1: Comparisons and Operator <=>
class MyType {
...
auto operator<=> (const MyType& rhs) const {
return value <=> rhs.value;
}
};
This not only returns the right value; it also ensures that the return value has the right comparison category
type depending on the type of the member value.
Or:
if (x <= y && y <= x) // might call operator<=> to check for equality
Note that operator!= is never rewritten to call operator<=>. However, it might call an operator==
member that is implicitly generated due to a defaulted operator<=> member.
If you do not know the comparison types (e.g., their type is a template parameter), you can use a new type
trait std::common_comparison_category<> that computes the strongest comparison category:
class Person {
std::string name;
double value;
...
auto operator<=> (const Person& rhs) const // OK
-> std::common_comparison_category_t<decltype(name <=> rhs.name),
decltype(value <=> rhs.value)> {
auto cmp1 = name <=> rhs.name;
if (cmp1 != 0) return cmp1; // used as or converted to common comparison type
return value <=> rhs.value; // used as or converted to common comparison type
}
};
By using the trailing return type syntax (with auto in front and the return type after ->), we can use the
parameters to compute the comparison types. Even though in this case, you could just use name instead of
rhs.name, this approach works in general (e.g., also for free-standing functions).
If you want to provide a stronger category than the one that is used internally, you have to map all possible
values of the internal comparsions to values of the return type. This might include some error handling if
you cannot map some values. For example:
class Person {
std::string name;
double value;
...
std::strong_ordering operator<=> (const Person& rhs) const {
auto cmp1 = name <=> rhs.name;
if (cmp1 != 0) return cmp1; // return strong_ordering for std::string
auto cmp2 = value <=> rhs.value; // might be partial_ordering for double
// map partial_ordering to strong_ordering:
assert(cmp2 != std::partial_ordering::unordered); // RUNTIME ERROR if unordered
return cmp2 == 0 ? std::strong_ordering::equal
: cmp2 > 0 ? std::strong_ordering::greater
: std::strong_ordering::less;
}
};
The C++ standard library provides some helper function objects for this. For example, to map floating-point
values, you can call std::strong_order() for the two values to be compared:
class Person {
std::string name;
double value;
...
std::strong_ordering operator<=> (const Person& rhs) const {
auto cmp1 = name <=> rhs.name;
1.3 Defining operator<=> and operator== 13
struct Coord {
double x{};
double y{};
double z{};
auto operator<=>(const Coord&) const = default;
};
Note again that the member function must be const and that the parameter must be declared to be a const
lvalue reference (const &).
You can use this data structure as follows:
lang/coord.cpp
#include "coord.hpp"
#include <iostream>
#include <algorithm>
int main()
{
std::vector<Coord> coll{ {0, 5, 5}, {5, 0, 0}, {3, 5, 5},
{3, 0, 0}, {3, 5, 7} };
std::sort(coll.begin(), coll.end());
for (const auto& elem : coll) {
std::cout << elem.x << '/' << elem.y << '/' << elem.z << '\n';
}
}
16 Chapter 1: Comparisons and Operator <=>
struct D : public B {
std::strong_ordering operator<=> (const D&) const = default;
};
Then:
D d1, d2;
d1 > d2; // calls B::operator== and possibly B::operator<
If operator== yields true, we know that the result of > is false and that is it. Otherwise, operator< is
called to find out whether the expression is true or false.
With
struct D : public B {
std::partial_ordering operator<=> (const D&) const = default;
};
the compiler might even call operator< twice to find out whether there is any order at all.
With
struct B {
bool operator==(const B&) const;
bool operator<(const B&) const;
};
1.4 Overload Resolution with Rewritten Expressions 17
struct D : public B {
auto operator<=> (const D&) const = default;
};
the compiler does not compile any call with relational operators because it cannot decide which ordering
category the base class has. In that case, you need operator<=> in the base class too.
However, checks for equality work, because in D, operator== is automatically declared equivalent to
the following:
struct D : public B {
auto operator<=> (const D&) const = default;
bool operator== (const D&) const = default;
};
This means that we have the following behavior:
D d1, d2;
d1 > d2; // ERROR: cannot deduce comparison category of operator<=>
d1 != d2; // OK (note: only tries operator<=> and B::operator== of a base class)
Equality checks always use only operator== of a base class (which might be generated according to a
defaulted operator<=> though). Any operator< or operator!= in the base class is ignored.
The same applies, if D has a member of type B.
1 The original C++20 standard was fixed here slightly with http://wg21.link/p2468r2.
1.5 Using Operator <=> in Generic Code 19
1.5.1 compare_three_way
std::compare_three_way is a new function object type for calling operator <=>, just like std::less is
a function object type for calling operator <.
You can use it as follows:
• To compare values of a generic type
• As a default type when you have to specify the type of a function object
For example:
template<typename T>
struct Value {
T val{};
...
auto operator<=> (const Value& v) const noexcept(noexcept(val<=>val)) {
return std::compare_three_way{}(val<=>v.val);
}
};
Using std::compare_three_way has (like std::less) the benefit that it even defines a total order for
raw pointers (which is not the case for operators <=> or <). Therefore, you should use it when generic types
are used that can be raw pointer types.
To allow programmers to forward declare operator<=>(), C++20 also introduces the type trait
std::compare_three_way_result with the alias template std::compare_three_way_result_t:
template<typename T>
struct Value {
T val{};
...
std::compare_three_way_result_t<T,T>
operator<=> (const Value& v) const noexcept(noexcept(val<=>val));
};
I have not the precise date in 1811 when Fuentes and I set out for
Salamanca, but it must have been either in the third or fourth week
of July.
In Portugal just then Lord Wellington was fencing, so to speak, with
the points of three French armies at once. On the south he had
Soult, on the north Dorsenne, and between them Marmont's troops
were scattered along the valley of the Tagus, with Madrid as their far
base. Being solidly concentrated, by short and rapid movements he
could keep these three armies impotent for offence; but en
revanche, he could make no overmastering attack upon any one of
them. If he advanced far against Soult or against Dorsenne he must
bring Marmont down on his flank, left or right; while, if he reached
out and struck for the Tagus Valley, Marmont could borrow from
right and left without absolutely crippling his colleagues, and roll up
seventy thousand men to bar the road on Madrid. In short, the
opposing armies stood at a deadlock, and there were rumours that
Napoleon, who was pouring troops into Spain from the north, meant
to follow and take the war into his own hands.
Now, the strength and the weakness of the whole position lay with
Marmont; while the key of it, curiously enough, was Ciudad Rodrigo,
garrisoned by Dorsenne—as in due time appeared. For the present,
Wellington, groping for the vital spot, was learning all that could be
learnt about Marmont's strength, its disposition, and (a matter of
first importance) its victualling, Spain being a country where large
armies starve. How many men were being drafted down from the
north? How was Marmont scattering his cantonments to feed them?
What was the state of the harvest? What provisions did Salamanca
contain? And what stores were accumulating at Madrid, Valladolid,
Burgos?
I had just arrived at Lisbon in a chassemarée of San Sebastian,
bringing a report of the French troops, which for a month past had
been pouring across the bridge of Irun: and how I had learnt this is
worth telling. There was a cobbler, Martinez by name—a little man
with a green shade over his eyes—who plied his trade in a wooden
hutch at the end of the famous bridge. While he worked he counted
every man, horse, standard, wagon, or gun that passed, and
forwarded the numbers without help of speech or writing (for he
could not even write his own name). He managed it all with his
hammer, tapping out a code known to our fellows who roamed the
shore below on the pretence of hunting for shellfish, but were
prevented by the French cordon from getting within sight of the
bridge. As for Martinez, the French Generals themselves gossipped
around his hutch while he cobbled industriously at the soldiers'
shoes.
I had presented my report to Lord Wellington, who happened to be
in Lisbon quarrelling with the Portuguese Government and re-
embarking (apparently for Cadiz) a battering train of guns and
mortars which had just arrived from England: and after two days'
holiday I was spending an idle morning in a wine-shop by the quay,
where the proprietor, a fervid politician, kept on file his copies of the
Government newspaper, the Lisbon Gazette. A week at sea had
sharpened my appetite for news; and I was wrapped in study of the
Gazette when an orderly arrived from headquarters with word that
Lord Wellington requested my attendance there at once.
I found him in conference with a handsome, slightly built man—a
Spaniard by his face—who stepped back as I entered, but without
offering to retire. Instead, he took up his stand with his back to one
of the three windows overlooking the street, and so continued to
observe me, all the while keeping his own face in shade.
The General, as his habit was, came to business at once.
"I have sent for you," said he, "on a serious affair. Our
correspondents in Salamanca have suddenly ceased to write."
"If your Excellency's correspondents are the same as the
Government's," said I, "'tis small wonder," and I glanced at the
newspaper in his hand—a copy of the same Gazette I had been
reading.
"Then you also think this is the explanation?" He held out the paper
with the face of a man handling vermin.
"The Government publishes its reports, the English newspapers copy
them: these in turn reach Paris; the Emperor reads them: and,"
concluded I, with a shrug, "your correspondents cease to write,
probably for the good reason that they are dead."
"That is just what I want you to find out," said he.
"Your Excellency wishes me to go to Salamanca? Very good. And,
supposing these correspondents to be dead?"
"You will find others."
"That may not be easy: nevertheless, I can try. Your Excellency, by
the way, will allow me to promise that future reports are not for
publication?"
Wellington smiled grimly, doubtless from recollection of a recent
interview with Silveira and the Portuguese Ministry. "You may rest
assured of that," said he; and added: "There may be some delay, as
you suggest, in finding fresh correspondents: and it is very
necessary for me to know quickly how Salamanca stands for stores."
"Then I must pick up some information on my own account."
"The service will be hazardous——"
"Oh, as for that——" I put in, with another shrug.
"—and I propose to give you a companion," pursued Wellington,
with a half-turn toward the man in the recess of the window. "This is
Señor Fuentes. You are not acquainted, I believe?—as you ought to
be."
Now from choice I have always worked alone: and had the General
uttered any other name I should have been minded to protest, with
the old Greek, that two were not enough for an army, while for any
other purpose they were too many. But on hearsay the
performances of this man Fuentes and his methods and his
character had for months possessed a singular fascination for me.
He was at once a strolling guitar-player and a licentiate of the
University of Salamanca, a consorter with gypsies, and by birth a
pure-blooded Castilian hidalgo. Some said that patriotism was a
passion with him; with a face made for the love of women, he had a
heart only for the woes of Spain. Others averred that hatred of the
French was always his master impulse; that they, by demolishing the
colleges of his University, and in particular his own beloved College
of San Lorenzo, had broken his heart and first driven him to wander.
Rewards he disdained; dangers he laughed at: his feats in the
service had sometimes a touch of high comedy and always a touch
of heroic grace. In short, I believe that if Spain had held a poet in
those days, Fuentes would have passed into song and lived as one
of his country's demigods.
He came forward now with a winning smile and saluted me cordially,
not omitting a handsome compliment on my work. You could see
that the man had not an ounce of meanness in his nature.
"We shall be friends," said he, turning to the Commander-in-Chief.
"And that will be to the credit of both, since Señor MacNeill has an
objection to comrades."
"I never said so."
"Excuse me, but I have studied your methods."
"Well, then," I replied, "I had the strongest objection, but you have
made me forget it—as you have forgotten your repugnance to visit
Salamanca." For although Fuentes flitted up and down and across
Spain like a will-o'-the-wisp, I had heard that he ever avoided the
city where he had lived and studied.
His fine eyes clouded, and he muttered some Latin words as it were
with a voice indrawn.
"I beg your pardon?" put in Wellington sharply.
"Cecidit, cecidit Salmantica illa fortis," Fuentes repeated.
"'Cecidit'—ah! I see—a quotation. Yes, they are knocking the place
about: as many as fifteen or sixteen colleges razed to the ground."
He opened the newspaper again and ran his eyes down the report.
"You'll excuse me: in England we have our own way of pronouncing
Latin, and for the moment I didn't quite catch——Yes, sixteen
colleges; a clean sweep! But before long, Señor Fuentes, we'll return
the compliment upon their fortifications."
"That must be my consolation, your Excellency," Fuentes made
answer with a smile which scarcely hid its irony.
The General began to discuss our route: our precautions he left to
us. He was well aware of the extreme risk we ran, and once again
made allusion to it as he dismissed us.
"If that were all your Excellency demanded!"
Fuentes' gaiety returned as we found ourselves in the street. "We
shall get on together like a pair of schoolboys," he assured me. "We
understand each other, you and I. But oh, those islanders!"
We left Lisbon that same evening on muleback, taking the road for
Abrantes. So universally were the French hated that the odds were
we might have dispensed with precautions at this stage, and indeed
for the greater part of the journey. The frontier once passed we
should be travelling in our native country—Fuentes as a gypsy and I
as an Asturian, moving from one harvest-job to another. We carried
no compromising papers: and if the French wanted to arrest folks on
mere suspicion they had the entire population to practise on.
Nevertheless, having ridden north-east for some leagues beyond
Abrantes—on the direct road leading past Ciudad Rodrigo to
Salamanca—we halted at Amendoa, bartered one of our mules for a
couple of skins of wine and ten days' provisions, and, having made
our new toilet in a chestnut grove outside the town, headed back for
the road leading east through Villa Velha into the Tagus valley.
Beyond the frontier we were among Marmont's cantonments: but
these lay scattered, and we avoided them easily. Keeping to the hill-
tracks on the northern bank of the river, and giving a wide berth to
the French posts in front of Alcantara, we struck away boldly for the
north through the Sierras: reached the Alagon, and, following up its
gorges, crossed the mountains in the rear of Bejar, where a French
force guarded the military pass.
So far we had travelled unmolested, if toilsomely; and a pleasanter
comrade than Fuentes no man could ask for. His gaiety never failed
him: yet it was ever gentle, and I suspected that it covered either a
native melancholy or some settled sorrow—sorrow for his country,
belike—but there were depths he never allowed me to sound. He did
everything well, from singing a love-song to tickling a trout and
cooking it for our supper: and it was after such a supper, as we lay
and smoked on a heathery slope beyond Bejar, that he unfolded his
further plans.
"My friend", said he, "there were once two brothers, students of
Salamanca, and not far removed in age. Of these the elder was
given to love-making and playing on the guitar; while the other
stuck to his books—which was all the more creditable because his
eyes were weak. I hope you are enjoying this story?"
"It begins to be interesting."
"Yet these two brothers—they were nearly of one height, by the way
—obtained their bachelor's degrees, and in time their licentiates,
though as rewards for different degrees of learning. They were from
Villacastin, beyond Avila in Old Castille: but their father, a hidalgo of
small estates there, possessed also a farm and the remains of a
castle across the frontier in the kingdom of Leon, a league to the
west of Salvatierra on the Tormes. It had come to him as security for
a loan which was never paid: and, dying, he left this property to his
younger son Andrea. Now when the French set a Corsican upon the
throne of our kingdoms, these two brothers withdrew from
Salamanca; but while Andrea took up his abode on his small
heritage, and gave security for his good behaviour, Eugenio, the
elder, turned his back on the paternal home (which the French had
ravaged), and became a rebel, a nameless, landless man and a
wanderer, with his guitar for company. You follow me?"
"I follow you, Señor Don Eugenio——"
"Not 'de Fuentes,'" he put in with a smile. "The real name you shall
read upon certain papers and parchments of which I hope to
possess myself to-night. In short, my friend, since we are on the
way to Salamanca, why should I not apply there for my doctor's
degree?"
"It requires a thesis, I have always understood."
"That is written."
"May I ask upon what subject?"
"The fiend take me if I know yet! But it is written, safe enough."
"Ah, I see! We go to Salvatierra? Yes, yes, but what of me, who
know scarcely any Latin beyond my credo?"
"Why, that is where I feel a certain delicacy. Having respect to your
rank, caballero, I do not like to propose that you should become my
servant."
"I am your servant already, and for a week past I have been an
Asturian. It will be promotion."
He sprang up gaily. "What a comrade is mine!" he cried, flinging
away the end of his cigarette. "To Salvatierra, then—Santiago, and
close Spain!"
Darkness overtook us as we climbed down the slopes: but we
pushed on, Fuentes leading the way boldly. Evidently he had come
to familiar ground. But it was midnight before he brought me, by an
abominable road, to a farmstead the walls of which showed
themselves ruinous even in the starlight—for moon there was none.
At an angle of the building, which once upon a time had been
whitewashed, rose a solid tower, with a doorway and an iron-
studded door, and a narrow window overlooking it. In spite of the
hour, Fuentes advanced nonchalantly and began to bang the door,
making noise enough to wake the dead. The window above was
presently opened—one could hear, with a shaking hand. "Who is
there?" asked a man's voice no less tremulous. "Who are you, for
the love of God?"
"Gente de paz, my dear brother!—not your friends the French. I
hope, by the way, you are entertaining none."
"I have been in bed these four hours or five. 'Peace,' say you? I wish
you would take your own risks and leave me in peace! What is it you
want, this time?"
"'Tis a good six weeks, brother, since my last visit: and, as you
know, I never call without need."
"Well, what is it you need?"
"I need," said Fuentes with great gravity, "the loan of your
spectacles."
"Be serious, for God's sake! And do not raise your voice so: the
French may be following you——"
"Dear Andrea, and if the French were to hear it, surely mine is an
innocent request. A pair of spectacles!"
"The French——" began Don Andrea and broke off, peering down
short-sightedly into the courtyard. "Ah, there is someone else! Who
is it? Who is it you have there in the darkness?"
"Dios! A moment since you were begging for silence, and now you
want me to call out my friend's name—to who knows what ears? He
has a mule, here, and I—oh yes, beside the spectacles I shall require
a horse: a horse, and—let me see—a treatise."
"Have you been drinking, brother?"
"No: and, since you mention it, a cup of wine, too, would not come
amiss. Is this a way to treat the caballero my friend? For the honour
of the family, brother, step down and open the door."
Don Andrea closed the window, and by-and-by we heard the bolts
withdrawn, one by one—and they were heavy. The door opened at
length, and a thin man in a nightcap peered out upon us with an oil-
lamp held aloft over the hand shading his eyes.
"You had best call Juan," said his brother easily, "and bid him stable
the mule. For the remainder of the night we are your guests; and, to
ensure our sleeping well, you shall fetch out the choicest of the
theses you have composed for your doctorate and read us a portion
over our wine."
We lay that night, after a repast of thin wine and chestnuts, in a
spare chamber, and on beds across the feet of which the rats
scudded. I did not see Don Andrea again: but his brother, who had
risen betimes, awakened me from uneasy slumber and showed me
his spoil. Sure enough it included a pair of spectacles and a bulky roll
of manuscript, a leathern jerkin, a white shirt, and a pair of velvet-
fustian breeches, tawny yellow in hue and something the worse for
wear. Below-stairs, in the courtyard, we found a white-haired
retainer waiting, with his grip on the bridles of my mule and a raw-
boned grey mare.
"The caballero will bring them back when he has done with them?"
said this old man as I mounted. The request puzzled me for a
moment until I met his eyes and found them fastened wistfully on
my breeches.
Assuredly Fuentes was an artist. Besides the spectacles, which in
themselves transformed him, he had borrowed a broad-brimmed hat
and a rusty black sleeveless mancha, which, by the way he contrived
it to hang, gave his frame an extraordinary lankiness. But his final
and really triumphant touch was simply a lengthening of the stirrups,
so that his legs dangled beneath the mare's belly like a couple of
ropes with shoes attached. If Don Andrea watched us out of sight
from his tower—as I doubt not he did—his emotions as he
recognised his portrait must have been lively.
In this guise we ambled steadily all day along the old Roman road
leading to Salamanca, and came within sight of the city as the sun
was sinking. It stood on the eastern bank of the river, fronting the
level rays, its walls rising tier upon tier, its towers and cupolas of
cream-coloured stone bathed in gold, with recesses of shadowy
purple. A bridge of twenty-five or six arches spanned the cool river-
beds, and towards this we descended between cornfields, of which
the light swept the topmost ears while the stalks stood already in
twilight. Truly it was a noble city yet, and so I cried aloud to
Fuentes. But his eyes, I believe, saw only what the French had
marred or demolished.
A group of their soldiery idled by the bridge-end, waiting for the
guard to be relieved, and lolled against the parapet watching the
bathers, whose shouts came up to me from the chasm below. But
instead of riding up and presenting our passes, Fuentes, a furlong
from the bridge, turned his mare's head to the left and reined up at
the door of a small riverside tavern.
The innkeeper—a brisk, athletic man, with the air of a retired
servant—appeared at the door as we dismounted. He scanned
Fuentes narrowly, while giving him affable welcome. Plainly he
recognised him as an old patron, yet plainly the recognition was
imperfect.
"Eh, my good Bartolomé, and so you still cling above the river? I
hope custom clings here too?"
"But—but can it be the Señor Don——"
"Eugenio, my friend. The spectacles puzzle you: they belong to my
brother, Don Andrea, and I may tell you that after a day's wear I find
them trying to the eyes. But, you understand, there are reasons ...
and so you will suppose me to be Don Andrea, while bringing a cup
of wine, and another for my servant, to Don Eugenio's favourite
seat, which was at the end of the garden beyond the mulberry-tree,
if you remember."
"Assuredly this poor house is your Lordship's, and all that belongs to
it. The wine shall be fetched with speed. But as for the table at the
end of the garden, I regret to tell your Lordship that it is occupied
for a while. If for this evening, I might recommend the parlour——"
The innkeeper made his excuse with a certain quick trepidation
which Fuentes did not fail to note.
"What is this? Your garden full? It appears then, my good Bartolomé,
that your custom has not suffered in these bad times."
"On the contrary, Señor, it has fallen off woefully! My garden has
been deserted for months, and is empty now, save for two
gentlemen, who, as luck will have it, have chosen to seat themselves
in your Lordship's favourite corner. Ah, yes, the old times were the
best! and I was a fool to grumble, as I sometimes did, when my
patrons ran me off my legs."
"But steady, Bartolomé: not so fast! Surely there used to be three
tables beyond the mulberry-tree, or my memory is sadly at fault."
"Three tables? Yes, it is true there are three tables. Nevertheless
——"
"I cannot see," pursued Fuentes with a musing air—"no, for the life
of me I cannot see how two gentlemen should require three tables
to drink their wine at."
"Nor I, Señor. It must, as you say, be a caprice: nevertheless they
charged me that on all accounts they were to have that part of the
garden to themselves."
"A very churlish caprice, then! They are Frenchmen, doubtless?"
"No, indeed, your Lordship: but two lads of good birth, gentlemen of
Spain, the one a bachelor, the other a student of the University."
"All the more, then, they deserve a lesson. Bartolomé, you will tell
your tapster to bring my wine to the vacant table beyond the
mulberry-tree."
"But, Señor——" As Fuentes moved off, the innkeeper put forth a
hand to entreat if not to restrain him.
"Eh?" Fuentes halted as if amazed at his impudence. "Ah, to be sure,
I am Don Andrea: but do not forget, my friend, that Don Eugenio
used to be quick-tempered, and that in members of one family these
little likenesses crop up in the most unexpected fashion." He strode
away down the shadowy garden-path over which in the tree-tops a
last beam or two of sunset lingered: and I, having hitched up our
beasts, followed him, carrying the saddle-bags and his guitar-case.
Three tables, as he had premised, stood in the patch of garden
beyond the mulberry-tree, hedged in closely on three sides, giving a
view in front upon the towers and fortifications across the river; a
nook secluded as a stage-box facing a scene that might have been
built and lit up for our delectation. The tables, with benches
alongside, stood moderately close together—two by the river-wall,
the third in the rear, where the hedge formed an angle: and the two
gentlemen so jealous of their privacy were seated at the nearer of
the two tables overlooking the river, and on the same bench—
though at the extreme ends of it and something more than a yard
apart.
They stared up angrily at our intrusion, and for the moment the
elder of the pair seemed about to demand our business. But Fuentes
walked calmly by, took his seat at the next table, pulled out his
bundle of manuscript, adjusted his spectacles, and began to read.
Having deposited my baggage, I took up a respectful position behind
him, ignoring—somewhat ostentatiously perhaps—the strangers'
presence, yet not without observing them from the corner of my
eye.
They were young: the elder, maybe, three-and-twenty, short, thick-
set, with features just now darkened by his ill-humour, but probably
sullen enough at the best of times: the younger, tall and nervous
and extraordinarily fair for a Spaniard, with a weak, restless mouth
and restless, passionate eyes. Indeed, either this restlessness was a
disease with him or he was suffering just now from an uncontrollable
agitation. Eyes, mouth, feet, fingers—the whole man seemed to be
twitching. I set down his age at eighteen. On the table stood a large
flask of wine, from which he helped himself fiercely, and beside the
flask lay a long bundle wrapped in a cloak.
This young man, having drained his glass at a gulp, let out an oath
and sprang up suddenly with a glare upon Fuentes, who had
stretched out his legs and was already absorbed in his reading.
"Señor Stranger," he began impetuously, "we would have you to
know, if the innkeeper has not already told you——"
"Gently!" interposed his comrade. "You are going the wrong way to
work. My friend, Sir"—he addressed Fuentes, who looked up with a
mild surprise—"my friend, Sir, was about to suggest that the light is
poor for reading."
"Oh," answered Fuentes, smiling easily, "for a minute or two—until
they bring my wine. Moreover, I wear excellent glasses."
"But the place is not too well chosen."
Fuentes appeared to digest this for a moment, then turned around
upon me with a puzzled air.
"My good Pedro, you have not misled me, I hope? I am short-
sighted, gentlemen; and if we have strayed into a private garden I
offer you my profoundest apologies." He gathered his manuscript
into a roll and stood up.
"To be plain with you, Sir," said the dark man sullenly, "this is not
precisely a private garden, and yet we desire privacy."
"Oho?" After a glance around, Fuentes fixed his eyes on the bundle
lying on the table. "And at the point of the sword—eh?"
The two young men started and at once began to eye each other
suspiciously.
"No, no," Fuentes assured them, smiling; "this is no trap, believe
me, but a chance encounter; and I am no alguacil in disguise, but a
poor scholar returning to Salamanca for his doctorate. Nor do I seek
to know the cause of your quarrel. But here comes the wine!" He
waited until the tapster had set flask and glasses on the table and
withdrawn. "In the interval before your friends arrive you will not
grudge me, Sirs, the draining of a glass to remembrance in a garden
where I too have loved my friends, and quarrelled with them, in
days gone by—days older now than I care to reckon." He raised the
wine and held it up for a moment against the sunset. "Youth—
youth!" he sighed.
"You are welcome, Sir," said the younger man a trifle more
graciously; "but we expect no seconds, and, believe me, we shall
presently be pressed for time."
Fuentes raised his eyebrows. "You surprise and shock me, Sirs. In
the days to which I drank just now it was not customary for
gentlemen of the University of Salamanca to fight without witnesses.
We left that to porters and grooms."
"And pray," sneered the darker young man, "may we know the name
of him who from the height of his years and experience presumes to
intrude this lecture on us?"
"You may address me, if you will, as Don Andrea Galazza de
Villacastin, a licentiate of your University——"
To my astonishment the younger man stopped him with a short
offensive laugh. "You may spare us the rest, Sir. Don Andrea Galazza
is known to us and to all honest patriots by repute: we can supply
the rest of his titles for ourselves, beginning with renegado——"
"Hist!" interposed his comrade, at the same time catching up the
swords from the table. "Don't be a fool, Sebastian—speak lower, for
God's sake!—the very soldiers at the bridge will hear you!"
"Ay, Sir," chimed in Fuentes gravely; "listen to your friend's advice,
and do not increase the peril of your remarks by the foolishness of
shouting them."
But the youngster, flushed with wine and overstrung, had lost for the
moment all self-control. "I accept that risk," cried he, "for the
pleasure of telling Don Andrea Galazza what kind of man he passes
for among honourable folk. He, the brother of Don Eugenio—of our
hero, the noble Fuentes! He, that signed his peace while that noble
heart preferred to break!" He spat in furious contempt.
Fuentes turned to me quietly. "Behold one of the enthusiasts we
came to seek," he murmured; "and one who will not fear risks. But
these testimonials are embarrassing, and this fame of mine swells to
a nuisance." He faced his accuser. "Nevertheless," answered he
aloud, "you make a noise that must disconcert your friend, who is in
two minds about assassinating me. Why spoil his game by arousing
the neighbourhood?"
"Señor Don Andrea, you know too much—thanks to my friend here,"
said the dark man slowly.
"But we are not assassins," put in the youngster. "Renegade though
you be, Don Andrea, I give you your chance." He snatched the foil
from his senior's hand and presented it solemnly, hilt foremost, to
Fuentes.
"Youth—youth!" murmured Fuentes with an appreciative laugh, as
he tucked the foil under his arm, took off his spectacles and rubbed
them, laughing again. He readjusted them carefully and, saluting,
fell on guard. "I am at your service, Sir."
The youth stepped forward hotly, touched blades, and almost
immediately lunged. An instant later his sword, as though it had
been a bird released from his hand, flew over his shoulder into the
twilight behind.
"That was ill-luck for you, Señor," said Fuentes lowering his point.
"But who can be sure of himself in this confounded twilight?" He
swung half-about towards the river-wall, with a glance across at the
city, where already a few lights began to twinkle in the dusk. And, so
turning, he seemed on a sudden to catch his breath.
And almost on that instant the youngster, who had fallen back
disconcerted, sprang forward in a fresh fury and gripped his
comrade by the arm, pointing excitedly towards a group of houses
above the fortifications, whence from a high upper storey, deeply
recessed between flanking walls, a light redder than the rest
twinkled across to us.
"The proof!" cried he. "She knew you would be here, and that is the
proof! You at least I will kill before I leave this garden, as I came to
kill you to-night."
In his new gust of fury he seemed to have forgotten his discomfiture
—to have forgotten even the existence of Fuentes, who now faced
them both with a smile which (unless the dusk distorted it) had
some bitterness in its raillery.
"If I mistake not, Sirs, the light you were discussing signals to us
from an upper chamber in the Lesser Street of the Virgins. It can
only be seen from this garden and from the far end of it, where we
now stand. I will not ask you who lights it now: but she who lit it in
former days was named Luisa. Oh yes, she was circumspect—a good
maid then, and no doubt a good maid now: in that street of the
Virgins there was at least one prudent. Youth flies, ay de mi! But
youth also, as I perceive to-night, repeats itself; and Luisa—who was
always circumspect, though a conspirator—apparently repeats
herself too."
"Luisa? What do you know of Luisa?" stammered the younger man.
The name seemed to have fallen on him like the touch of an
enchanter's wand, stiffening him to stone. Like a statue he stood
there, peering forward with a white face.
"My friend"—Fuentes turned to me—"be so good as to unstrap the
case yonder and hand me my guitar."
He laid his foil on the table, took the guitar from me, and, having
seated himself on the bench, tried the strings softly, all the while
looking up with grave raillery at the two young men.
"What do I know of Luisa? Listen!" Under his voice he began a light-
hearted little song, which in English might run like this, or as nearly
as I can contrive—
My love, she lives in Salamanca
All up a dozen flights of stairs;
There with the sparrows night and morning
Under the roof she chirps her prayers.
They say her wisdom comes from heaven—
So near the clouds and chimneys meet—
I rather think Luisa's sparrows
Fetch it aloft there from the street!