C++ Annotations Version 12.2.0

Frank B. Brokken

University of Groningen,
PO Box 407,
9700 AK Groningen
The Netherlands
ISBN 90 367 0470 7

1994-2022

This document is intended for knowledgeable users of C (or any other language using a C-like grammar, like Perl or Java) who would like to know more about, or make the transition to, C++. This document is the main textbook for Frank's C++ programming courses, which are yearly organized at the University of Groningen. The C++ Annotations do not cover all aspects of C++, though. In particular, C++'s basic grammar is not covered when equal to C's grammar. Any basic book on C may be consulted to refresh that part of C++'s grammar.

If you want a hard-copy version of the C++ Annotations: printable versions are available in zip-archives containing files in postscript, pdf and other formats at

https://gitlab.com/fbb-git/cppannotations-zip
Pages of files having names starting with cplusplus are in A4 paper size, pages of files having names starting with cplusplusus are in the US legal paper size. The C++ Annotations are also available as a Kindle book.

The latest version of the C++ Annotations in html-format can be browsed at:

https://fbb-git.gitlab.io/cppannotations/
and/or at
http://www.icce.rug.nl/documents/

Don't hesitate to send in feedback: send an e-mail if you like the C++ Annotations; if you think that important material was omitted; if you find errors or typos in the text or the code examples; or if you just feel like e-mailing. Send your e-mail to Frank B. Brokken.

Please state the document version you're referring to, as found in the title (in this document: 12.2.0) and please state chapter and paragraph name or number you're referring to.

All received mail is processed conscientiously, and received suggestions for improvements are usually processed by the time a new version of the Annotations is released. Except for the incidental case I will normally not acknowledge the receipt of suggestions for improvements. Please don't interpret this as me not appreciating your efforts.

Table of Contents

Chapter 1: Overview Of The Chapters

Chapter 2: Introduction

2.1: What's new in the C++ Annotations

2.2: C++'s history

2.2.1: History of the C++ Annotations
2.2.2: Compiling a C program using a C++ compiler
2.2.3: Compiling a C++ program
2.2.3.1: C++ under MS-Windows
2.2.3.2: Compiling a C++ source text

2.3: C++: advantages and claims

2.4: What is Object-Oriented Programming?

2.5: Differences between C and C++

2.5.1: The function `main'
2.5.2: End-of-line comment
2.5.3: Strict type checking
2.5.4: Function Overloading
2.5.5: Default function arguments
2.5.6: NULL-pointers vs. 0-pointers and nullptr
2.5.7: The `void' parameter list
2.5.8: The `#define __cplusplus'
2.5.9: Using standard C functions
2.5.10: Header files for both C and C++
2.5.11: Defining local variables
2.5.12: The keyword `typedef'
2.5.13: Functions as part of a struct
2.5.14: Evaluation order of operands

Chapter 3: A First Impression Of C++

3.1: Notable differences with C

3.1.1: Using the keyword `const'
3.1.2: Namespaces
3.1.3: The scope resolution operator ::
3.1.4: `cout', `cin', and `cerr'

3.2: Functions as part of structs

3.2.1: Data hiding: public, private and class
3.2.2: Structs in C vs. structs in C++

3.3: Several additions to C's grammar

3.3.1: References
3.3.2: Rvalue References
3.3.3: Lvalues, rvalues and more
3.3.4: Strongly typed enumerations
3.3.5: Initializer lists
3.3.5.1: Designated initialization
3.3.6: Initializers for bit-fields
3.3.7: Type inference using `auto'
3.3.7.1: Structured binding declarations
3.3.8: Defining types and `using' declarations
3.3.9: Range-based for-loops
3.3.10: Raw String Literals
3.3.11: Binary constants
3.3.12: Selection statements with initializers
3.3.13: Attributes
3.3.14: Three-way comparison (<=>)

3.4: New language-defined data types

3.4.1: The data type `bool'
3.4.2: The data type `wchar_t'
3.4.3: Unicode encoding
3.4.4: The data type `long long int'
3.4.5: The data type `size_t'
3.4.6: std::byte
3.4.7: Digit separators

3.5: A new syntax for casts

3.5.1: The `static_cast'-operator
3.5.2: The `const_cast'-operator
3.5.3: The `reinterpret_cast'-operator
3.5.4: The `dynamic_cast'-operator
3.5.5: Casting 'shared_ptr' objects

3.6: Keywords and reserved names in C++

Chapter 4: Namespaces

4.1: Namespaces

4.1.1: Defining namespaces
4.1.1.1: Declaring entities in namespaces
4.1.1.2: A closed namespace
4.1.2: Referring to entities
4.1.2.1: The `using' directive
4.1.2.2: `Koenig lookup'
4.1.3: The standard namespace
4.1.4: Nesting namespaces and namespace aliasing
4.1.4.1: Defining entities outside of their namespaces

4.2: The std::chrono namespace (handling time)

4.2.1: Time resolutions: std::ratio
4.2.2: Amounts of time: std::chrono::duration
4.2.3: Clocks measuring time
4.2.4: Points in time: std::chrono::time_point

4.3: The std::filesystem namespace

4.3.1: the '__file_clock' type
4.3.2: The class 'error_code'
4.3.3: Names of file system entries: path
4.3.3.1: Accessors, modifiers and operators
4.3.3.2: Free functions
4.3.4: Handling directories: directory_entry
4.3.4.1: Visiting directory entries: (recursive_)directory_iterator
4.3.5: Types (file_type) and permissions (perms) of file system elements: file_status
4.3.5.1: Obtaining the status of file system entries
4.3.6: Information about the space of file systems: space_info
4.3.7: File system exceptions: filesystem_error

Chapter 5: The `string' Data Type

5.1: Operations on strings

5.2: A std::string reference

5.2.1: Initializers
5.2.2: Iterators
5.2.3: Operators
5.2.4: Member functions
5.2.5: Conversion functions

5.3: std::string_view

Chapter 6: The IO-stream Library

6.1: Special header files

6.2: The foundation: the class `ios_base'

6.3: Interfacing `streambuf' objects: the class `ios'

6.3.1: Condition states
6.3.2: Formatting output and input
6.3.2.1: Format modifying member functions
6.3.2.2: Formatting flags

6.4: Output

6.4.1: Basic output: the class `ostream'
6.4.1.1: Writing to `ostream' objects
6.4.1.2: `ostream' positioning
6.4.1.3: `ostream' flushing
6.4.2: Output to files: the class `ofstream'
6.4.2.1: Modes for opening stream objects
6.4.3: Output to memory: the class `ostringstream'
6.4.4: The `put_time' manipulator

6.5: Input

6.5.1: Basic input: the class `istream'
6.5.1.1: Reading from `istream' objects
6.5.1.2: `istream' positioning
6.5.2: Input from files: the class `ifstream'
6.5.3: Input from memory: the class `istringstream'
6.5.4: Copying streams
6.5.5: Coupling streams

6.6: Advanced topics

6.6.1: Moving streams
6.6.2: Redirecting streams
6.6.3: Reading AND Writing streams

Chapter 7: Classes

7.1: The constructor

7.1.1: A first application
7.1.2: Constructors: with and without arguments
7.1.2.1: The order of construction

7.2: Ambiguity resolution

7.2.1: Types `Data' vs. `Data()'
7.2.2: Superfluous parentheses
7.2.3: Existing types

7.3: Objects inside objects: composition

7.3.1: Composition and (const) objects: (const) member initializers
7.3.2: Composition and reference objects: reference member initializers

7.4: Data member initializers

7.4.1: Delegating constructors

7.5: Uniform initialization

7.6: Defaulted and deleted class members

7.7: Const member functions and const objects

7.7.1: Anonymous objects
7.7.1.1: Subtleties with anonymous objects

7.8: The keyword `inline'

7.8.1: Defining members inline
7.8.2: When to use inline functions
7.8.2.1: A prelude: when NOT to use inline functions
7.8.3: Inline variables

7.9: Local classes: classes inside functions

7.10: The keyword `mutable'

7.11: Header file organization

7.11.1: Using namespaces in header files
7.11.2: Modules

7.12: Sizeof applied to class data members

Chapter 8: Static Data And Functions

8.1: Static data

8.1.1: Private static data
8.1.2: Public static data
8.1.3: Initializing static const data
8.1.4: Generalized constant expressions (constexpr)
8.1.4.1: Constant expression data

8.2: Static member functions

8.2.1: Calling conventions

Chapter 9: Classes And Memory Allocation

9.1: Operators `new' and `delete'

9.1.1: Allocating arrays
9.1.2: Deleting arrays
9.1.3: Enlarging arrays
9.1.4: Managing `raw' memory
9.1.5: The `placement new' operator

9.2: The destructor

9.2.1: Object pointers revisited
9.2.2: The function set_new_handler()

9.3: The assignment operator

9.3.1: Overloading the assignment operator
9.3.1.1: The member 'operator=()'

9.4: The `this' pointer

9.4.1: Sequential assignments and this

9.5: The copy constructor: initialization vs. assignment

9.6: Revising the assignment operator

9.6.1: Swapping
9.6.1.1: Fast swapping

9.7: Moving data

9.7.1: The move constructor (dynamic data)
9.7.2: The move constructor (composition)
9.7.3: Move-assignment
9.7.4: Revising the assignment operator (part II)
9.7.5: Moving and the destructor
9.7.6: Move-only classes
9.7.7: Default move constructors and assignment operators
9.7.8: Moving: implications for class design

9.8: Copy Elision and Return Value Optimization

9.9: Unrestricted Unions

9.9.1: Implementing the destructor
9.9.2: Embedding an unrestricted union in a surrounding class
9.9.3: Swapping unrestricted unions
9.9.4: Assignment

9.10: Aggregate Data Types

9.11: Conclusion

Chapter 10: Exceptions

10.1: Exception syntax

10.2: An example using exceptions

10.2.1: Anachronisms: `setjmp' and `longjmp'
10.2.2: Exceptions: the preferred alternative

10.3: Throwing exceptions

10.3.1: The empty `throw' statement

10.4: The try block

10.5: Catching exceptions

10.5.1: The default catcher

10.6: Functions that cannot throw exceptions: the `noexcept' keyword

10.7: Iostreams and exceptions

10.8: Standard exceptions

10.8.1: Standard exceptions: to use or not to use?

10.9: System error, error_category, and error_condition

10.9.1: The class `std::error_category'
10.9.2: The class `std::error_condition'
10.9.3: The class system_error

10.10: Exception guarantees

10.10.1: The basic guarantee
10.10.2: The strong guarantee
10.10.3: The nothrow guarantee

10.11: Function try blocks

10.12: Exceptions in constructors and destructors

Chapter 11: More Operator Overloading

11.1: Overloading `operator[]()'

11.2: Overloading insertion and extraction operators

11.3: Conversion operators

11.4: The keyword `explicit'

11.4.1: Explicit conversion operators

11.5: Overloading increment and decrement operators

11.6: Overloading binary operators

11.6.1: Member function reference bindings (& and &&)
11.6.2: The three-way comparison operator `<=>'

11.7: Overloading `operator new(size_t)'

11.8: Overloading `operator delete(void *)'

11.9: Operators `new[]' and `delete[]'

11.9.1: Overloading `new[]'
11.9.2: Overloading `delete[]'
11.9.3: The `operator delete(void *, size_t)' family
11.9.4: `new[]', `delete[]' and exceptions

11.10: Function Objects

11.10.1: Constructing manipulators
11.10.1.1: Manipulators requiring arguments

11.11: Lambda expressions

11.11.1: Lambda expressions: syntax
11.11.2: Using lambda expressions

11.12: The case of [io]fstream::open()

11.13: User-defined literals

11.14: Overloadable operators

Chapter 12: Abstract Containers

12.1: Notations used in this chapter

12.2: The `pair' container

12.3: Allocators

12.4: Available Containers

12.4.1: The `array' container
12.4.2: The `vector' container
12.4.3: The `list' container
12.4.4: The `queue' container
12.4.5: The `priority_queue' container
12.4.6: The `deque' container
12.4.7: The `map' container
12.4.7.1: The `map' constructors
12.4.7.2: The `map' operators
12.4.7.3: The `map' public members
12.4.7.4: The `map': a simple example
12.4.8: The `multimap' container
12.4.9: The `set' container
12.4.10: The `multiset' container
12.4.11: The `stack' container
12.4.12: The `unordered_map' container (`hash table')
12.4.12.1: The `unordered_map' constructors
12.4.12.2: The `unordered_map' public members
12.4.12.3: The `unordered_multimap' container
12.4.13: The `unordered_set' container
12.4.13.1: The `unordered_multiset' container
12.4.14: Heterogeneous lookup

12.5: The `complex' container

Chapter 13: Inheritance

13.1: Related types

13.1.1: Inheritance depth: desirable?

13.2: Access rights: public, private, protected

13.2.1: Public, protected and private derivation
13.2.2: Promoting access rights

13.3: The constructor of a derived class

13.3.1: Move construction
13.3.2: Move assignment
13.3.3: Inheriting constructors
13.3.4: Aggregate Initializations

13.4: The destructor of a derived class

13.5: Redefining member functions

13.6: Multiple inheritance

13.7: Conversions between base classes and derived classes

13.7.1: Conversions with object assignments
13.7.2: Conversions with pointer assignments

13.8: Using non-default constructors with new[]

Chapter 14: Polymorphism

14.1: Virtual functions

14.2: Virtual destructors

14.3: Pure virtual functions

14.3.1: Implementing pure virtual functions

14.4: Explicit virtual overrides

14.5: Virtual functions and multiple inheritance

14.5.1: Ambiguity in multiple inheritance
14.5.2: Virtual base classes
14.5.3: When virtual derivation is not appropriate

14.6: Run-time type identification

14.6.1: The dynamic_cast operator
14.6.2: The `typeid' operator

14.7: Inheritance: when to use to achieve what?

14.8: The `streambuf' class

14.8.1: Protected `streambuf' members
14.8.1.1: Protected members for input operations
14.8.1.2: Protected members for output operations
14.8.1.3: Protected members for buffer manipulation
14.8.1.4: Deriving classes from `streambuf'
14.8.2: The class `filebuf'
14.8.3: Safely interfacing streams to another std::streambuf

14.9: A polymorphic exception class

14.10: How polymorphism is implemented

14.11: Undefined reference to vtable ...

14.12: Virtual constructors

Chapter 15: Friends

15.1: Friend functions

15.2: Extended friend declarations

Chapter 16: Classes Having Pointers To Members

16.1: Pointers to members: an example

16.2: Defining pointers to members

16.3: Using pointers to members

16.4: Pointers to static members

16.5: Pointer sizes

Chapter 17: Nested Classes

17.1: Defining nested class members

17.2: Declaring nested classes

17.3: Accessing private members in nested classes

17.4: Nesting enumerations

17.4.1: Empty enumerations

17.5: Revisiting virtual constructors

Chapter 18: The Standard Template Library

18.1: Predefined function objects

18.1.1: Arithmetic function objects
18.1.2: Relational function objects
18.1.3: Logical function objects
18.1.4: The `std::not_fn' negator

18.2: Iterators

18.2.1: std::distance and std::size
18.2.2: Insert iterators
18.2.3: Iterators for `istream' objects
18.2.3.1: Iterators for `istreambuf' objects
18.2.4: Iterators for `ostream' objects
18.2.4.1: Iterators for `ostreambuf' objects

18.3: The class 'unique_ptr'

18.3.1: Defining `unique_ptr' objects
18.3.2: Creating a plain `unique_ptr'
18.3.3: Moving another `unique_ptr'
18.3.4: Pointing to a newly allocated object
18.3.5: Operators and members
18.3.6: Using `unique_ptr' objects for arrays

18.4: The class `shared_ptr'

18.4.1: Defining `shared_ptr' objects
18.4.2: Creating a plain `shared_ptr'
18.4.3: Pointing to a newly allocated object
18.4.4: Operators and members
18.4.5: Casting shared pointers
18.4.6: Using `shared_ptr' objects for arrays

18.5: Smart `smart pointer' construction: `make_shared' and `make_unique'

18.6: Classes having pointer data members

18.7: Comparison classes

18.7.1: The class `weak_equality'
18.7.2: The class `strong_equality'
18.7.3: The class `partial_ordering'
18.7.4: The class `weak_ordering'
18.7.5: The class `strong_ordering'

18.8: Regular Expressions

18.8.1: The regular expression mini language
18.8.1.1: Character classes
18.8.2: Defining regular expressions: std::regex
18.8.3: Retrieving matches: std::match_results
18.8.4: Regular expression matching functions
18.8.4.1: The std::regex_constants::match_flag_type flags
18.8.4.2: Matching full texts: std::regex_match
18.8.4.3: Partially matching text: std::regex_search
18.8.4.4: The member std::match_results::format
18.8.4.5: Modifying target strings: std::regex_replace

18.9: Randomization and Statistical Distributions

18.9.1: Random Number Generators
18.9.2: Statistical distributions
18.9.2.1: Bernoulli distribution
18.9.2.2: Binomial distribution
18.9.2.3: Cauchy distribution
18.9.2.4: Chi-squared distribution
18.9.2.5: Extreme value distribution
18.9.2.6: Exponential distribution
18.9.2.7: Fisher F distribution
18.9.2.8: Gamma distribution
18.9.2.9: Geometric distribution
18.9.2.10: Log-normal distribution
18.9.2.11: Normal distribution
18.9.2.12: Negative binomial distribution
18.9.2.13: Poisson distribution
18.9.2.14: Student t distribution
18.9.2.15: Uniform int distribution
18.9.2.16: Uniform real distribution
18.9.2.17: Weibull distribution

18.10: tie

18.11: Optional return values

Chapter 19: The STL Generic Algorithms

19.1: The Generic Algorithms

19.1.1: accumulate
19.1.2: adjacent_difference
19.1.3: adjacent_find
19.1.4: binary_search
19.1.5: copy
19.1.6: copy_backward
19.1.7: count
19.1.8: count_if
19.1.9: equal
19.1.10: equal_range
19.1.11: exchange
19.1.12: fill
19.1.13: fill_n
19.1.14: find
19.1.15: find_end
19.1.16: find_first_of
19.1.17: find_if
19.1.18: for_each
19.1.19: generate
19.1.20: generate_n
19.1.21: includes
19.1.22: inner_product
19.1.23: inplace_merge
19.1.24: iota
19.1.25: iter_swap
19.1.26: lexicographical_compare
19.1.27: lower_bound
19.1.28: max
19.1.29: max_element
19.1.30: merge
19.1.31: min
19.1.32: min_element
19.1.33: mismatch
19.1.34: next_permutation
19.1.35: nth_element
19.1.36: partial_sort
19.1.37: partial_sort_copy
19.1.38: partial_sum
19.1.39: partition
19.1.40: prev_permutation
19.1.41: remove
19.1.42: remove_copy
19.1.43: remove_copy_if
19.1.44: remove_if
19.1.45: replace
19.1.46: replace_copy
19.1.47: replace_copy_if
19.1.48: replace_if
19.1.49: reverse
19.1.50: reverse_copy
19.1.51: rotate
19.1.52: rotate_copy
19.1.53: search
19.1.54: search_n
19.1.55: set_difference
19.1.56: set_intersection
19.1.57: set_symmetric_difference
19.1.58: set_union
19.1.59: sort
19.1.60: stable_partition
19.1.61: stable_sort
19.1.62: swap
19.1.63: swap_ranges
19.1.64: transform
19.1.65: unique
19.1.66: unique_copy
19.1.67: upper_bound
19.1.68: Heap algorithms
19.1.68.1: The `make_heap' function
19.1.68.2: The `pop_heap' function
19.1.68.3: The `push_heap' function
19.1.68.4: The `sort_heap' function
19.1.68.5: An example using the heap functions

Chapter 20: Multi Threading

20.1: Multi Threading

20.1.1: The namespace std::this_thread
20.1.2: The class std::thread
20.1.2.1: Static data and threads: thread_local
20.1.2.2: Exceptions and join()
20.1.3: The class std::jthread
20.1.3.1: std::stop_callback

20.2: Synchronization (mutexes)

20.2.1: Initialization in multi-threaded programs
20.2.2: Shared mutexes

20.3: Locks and lock handling

20.3.1: Deadlocks
20.3.2: Shared locks

20.4: Event handling (condition variables)

20.4.1: The class std::condition_variable
20.4.2: The class std::condition_variable_any
20.4.3: An example using condition variables

20.5: Atomic actions: mutexes not required

20.6: An example: threaded quicksort

20.7: Shared States

20.8: Asynchronous return objects: std::future

20.8.1: The std::future_error exception and the std::future_errc enum

20.9: Shared asynchronous return objects: std::shared_future

20.10: Starting a new thread: std::async

20.11: Preparing a task for execution: std::packaged_task

20.12: The class `std::promise'

20.12.1: Exception propagation: std::exception_ptr

20.13: An example: multi-threaded compilations

20.14: Transactional Memory

20.15: Synchronizing output to streams

20.15.1: The `std::syncbuf' streambuf
20.15.2: Multi-threaded compilations using `osyncstream'

Chapter 21: Function and Variable Templates

21.1: Defining function templates

21.1.1: Considerations regarding template parameters
21.1.2: Auto and decltype
21.1.2.1: declval
21.1.3: Late-specified return type

21.2: Passing arguments by reference (reference wrappers)

21.3: Using local and unnamed types as template arguments

21.4: Template parameter deduction

21.4.1: Lvalue transformations
21.4.2: Qualification transformations
21.4.3: Transformation to a base class
21.4.4: The template parameter deduction algorithm
21.4.5: Template type contractions

21.5: Declaring function templates

21.5.1: Instantiation declarations

21.6: Instantiating function templates

21.6.1: Instantiations: no `code bloat'

21.7: Using explicit template types

21.8: Overloading function templates

21.8.1: An example using overloaded function templates
21.8.2: Ambiguities when overloading function templates
21.8.3: Declaring overloaded function templates

21.9: Specializing templates for deviating types

21.9.1: Avoiding too many specializations
21.9.2: Declaring specializations
21.9.3: Complications when using the insertion operator

21.10: Static assertions

21.11: Numeric limits

21.12: Polymorphous wrappers for function objects

21.13: Compiling template definitions and instantiations

21.14: The function selection mechanism

21.14.1: Determining the template type parameters

21.15: SFINAE: Substitution Failure Is Not An Error

21.16: Conditional function definitions using `if constexpr'

21.17: Summary of the template declaration syntax

21.18: Variables as templates (template variables)

Chapter 22: Class Templates

22.0.1: Template Argument Deduction
22.0.1.1: Simple Definitions
22.0.1.2: Explicit Conversions

22.1: Defining class templates

22.1.1: Constructing the circular queue: CirQue
22.1.2: Non-type parameters
22.1.3: Member templates
22.1.4: CirQue's constructors and member functions
22.1.5: Using CirQue objects
22.1.6: Default class template parameters
22.1.7: Declaring class templates
22.1.8: Preventing template instantiations
22.1.9: Generic lambda expressions

22.2: Static data members

22.2.1: Extended use of the keyword `typename'

22.3: Specializing class templates for deviating types

22.3.1: Example of a class specialization

22.4: Partial specializations

22.4.1: Intermezzo: some simple matrix algebraic concepts
22.4.2: The Matrix class template
22.4.3: The MatrixRow partial specialization
22.4.4: The MatrixColumn partial specialization
22.4.5: The 1x1 matrix: avoid ambiguity

22.5: Variadic templates

22.5.1: Defining and using variadic templates
22.5.2: Perfect forwarding
22.5.3: The unpack operator
22.5.4: Non-type variadic templates
22.5.5: Folding expressions

22.6: Tuples

22.6.1: Tuples and structured bindings

22.7: Computing the return type of function objects

22.8: Instantiating class templates

22.9: Processing class templates and instantiations

22.10: Declaring friends

22.10.1: Non-templates used as friends in templates
22.10.2: Templates instantiated for specific types as friends
22.10.2.1: Free operators as friends of nested classes
22.10.3: Unbound templates as friends
22.10.4: Extended friend declarations

22.11: Class template derivation

22.11.1: Deriving ordinary classes from class templates
22.11.2: Deriving class templates from class templates
22.11.3: Deriving class templates from ordinary classes

22.12: Static Polymorphism

22.12.1: An example of static polymorphism
22.12.2: Converting dynamic polymorphic classes to static polymorphic classes
22.12.3: Using static polymorphism to avoid reimplementations

22.13: Class templates and nesting

22.14: Constructing iterators

22.14.1: Implementing a `RandomAccessIterator'
22.14.2: Implementing a `reverse_iterator'

Chapter 23: Advanced Template Use

23.1: Subtleties

23.1.1: Returning types nested under class templates
23.1.2: Type resolution for base class members
23.1.3: ::template, .template and ->template

23.2: Template Meta Programming

23.2.1: Values according to templates
23.2.1.1: Converting integral types to types
23.2.2: Selecting alternatives using templates
23.2.2.1: Defining overloading members
23.2.2.2: Class structure as a function of template parameters
23.2.2.3: An illustrative example
23.2.3: Templates: Iterations by Recursion

23.3: User-defined literals

23.4: Template template parameters

23.4.1: Policy classes - I
23.4.2: Policy classes - II: template template parameters
23.4.2.1: The destructor of Policy classes
23.4.3: Structure by Policy

23.5: Alias Templates

23.6: Trait classes

23.6.1: Distinguishing class from non-class types
23.6.2: Available type traits

23.7: Defining `ErrorCodeEnum' and 'ErrorConditionEnum' enumerations

23.7.1: Deriving classes from std::error_category

23.8: Using `noexcept' when offering the `strong guarantee'

23.9: More conversions to class types

23.9.1: Types to types
23.9.2: An empty type
23.9.3: Type convertibility
23.9.3.1: Determining inheritance

23.10: Template TypeList processing

23.10.1: The length of a TypeList
23.10.2: Searching a TypeList
23.10.3: Selecting from a TypeList
23.10.4: Prefixing/Appending to a TypeList
23.10.5: Erasing from a TypeList
23.10.5.1: Erasing the first occurrence
23.10.5.2: Erasing a type by its index
23.10.5.3: Erasing all occurrences of a type
23.10.5.4: Erasing duplicates

23.11: Using a TypeList

23.11.1: The Wrap and Multi class templates
23.11.2: The MultiBase class template
23.11.3: Support templates
23.11.4: Using Multi

23.12: Expression Templates

23.12.1: Designing an Expression Template
23.12.2: Implementing an Expression Template
23.12.3: The BasicType trait class and ordering classes

23.13: Concepts

23.13.1: Defining concepts
23.13.2: Requirements
23.13.2.1: Simple requirements
23.13.2.2: Type requirements
23.13.2.3: Compound requirements
23.13.2.4: Nested requirements
23.13.3: Predefined concepts
23.13.3.1: Concepts specifying one template type parameter
23.13.3.2: Concepts specifying two template type parameters
23.13.3.3: Concepts specifying multiple template type parameters
23.13.4: Applying concepts to template parameter packs
23.13.5: Applying concepts to free functions
23.13.6: Implementing constrained class members
23.13.7: Constrained partial specializations
23.13.7.1: Function- and class template declarations
23.13.7.2: Bound free-operators

Chapter 24: Coroutines

24.1: Defining a coroutine

24.1.1: The coroutine's State class (promise_type)
24.1.1.1: What if `suspend_never' is used?
24.1.2: Simplifying the state class

24.2: Embedding coroutines in classes

24.2.1: The `Reader' coroutine handler
24.2.2: The `Writer' coroutine handler

24.3: `Awaitables', `Awaiters' and `co_await'

24.4: The class `Awaiter'

24.5: Accessing State from inside coroutines

24.6: Finite State Automatons via coroutines

24.6.1: The `Start' handler class
24.6.2: Completing the Finite State Automaton

24.7: Recursive coroutines

24.7.1: Recursively calling recursiveCoro
24.7.2: Beyond a single recursive call

24.8: Coroutine iterators

24.9: Visiting directories using coroutines

24.9.1: The `Dir' class showing directory entries
24.9.2: Visiting directories using coroutines
24.9.3: Functions vs. coroutines

Chapter 25: Concrete Examples

25.1: Using file descriptors with `streambuf' classes

25.1.1: Classes for output operations
25.1.2: Classes for input operations
25.1.2.1: Using a one-character buffer
25.1.2.2: Using an n-character buffer
25.1.2.3: Seeking positions in `streambuf' objects
25.1.2.4: Multiple `unget' calls in `streambuf' objects
25.1.3: Fixed-sized field extraction from istream objects
25.1.3.1: Member functions and example

25.2: The `fork' system call

25.2.1: A basic Fork class
25.2.2: Parents and Children
25.2.3: Redirection revisited
25.2.4: The `Daemon' program
25.2.5: The class `Pipe'
25.2.6: The class `ParentSlurp'
25.2.7: Communicating with multiple children
25.2.7.1: The class `Selector': interface
25.2.7.2: The class `Selector': implementation
25.2.7.3: The class `Monitor': interface
25.2.7.4: The class `Monitor': s_handler
25.2.7.5: The class `Monitor': the member `run'
25.2.7.6: The class `Monitor': example
25.2.7.7: The class `Child'

25.3: Adding binary operators to classes

25.3.1: Merely using operators
25.3.1.1: To namespace or not to namespace?
25.3.2: The CRTP and defining operator function templates
25.3.3: Insertion and extraction

25.4: Distinguishing lvalues from rvalues with operator[]()

25.5: Implementing a `reverse_iterator'

25.6: Using `bisonc++' and `flexc++'

25.6.1: Using `flexc++' to create a scanner
25.6.1.1: The derived class `Scanner'
25.6.1.2: The lexical scanner specification file
25.6.1.3: Implementing `Scanner'
25.6.1.4: Using a `Scanner' object
25.6.1.5: Building the program
25.6.2: Using `bisonc++' and `flexc++'
25.6.2.1: The `bisonc++' specification file
25.6.2.2: The `flexc++' specification file
25.6.2.3: Building the program