C++ Annotations Version 12.4.0

Frank B. Brokken

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


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

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:

and/or at

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.4.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 C++ under MS-Windows 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 Designated initialization
3.3.6: Initializers for bit-fields
3.3.7: Type inference using `auto' 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: The data type `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 Declaring entities in namespaces A closed namespace
4.1.2: Referring to entities The `using' directive `Koenig lookup'
4.1.3: The standard namespace
4.1.4: Nesting namespaces and namespace aliasing 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 Accessors, modifiers and operators Free functions
4.3.4: Handling directories: directory_entry Visiting directory entries: (recursive_)directory_iterator
4.3.5: Types (file_type) and permissions (perms) of file system elements: file_status 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 Format modifying member functions Formatting flags

6.4: Output

6.4.1: Basic output: the class `ostream' Writing to `ostream' objects `ostream' positioning `ostream' flushing
6.4.2: Output to files: the class `ofstream' 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' Reading from `istream' objects `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 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 Subtleties with anonymous objects

7.8: The keyword `inline'

7.8.1: Defining members inline
7.8.2: When to use inline functions 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) 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 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 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 unable to 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.9.4: Exception propagation: std::exception_ptr

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

10.13: Exceptions in destructors

Chapter 11: More Operator Overloading

11.1: Overloading `operator[]()'

11.1.1: Multi-argument `operator[]()'

11.2: Overloading insertion and extraction operators

11.3: Conversion operators

11.4: An alternative implementation of the `byte' type

11.5: The keyword `explicit'

11.5.1: Explicit conversion operators

11.6: Overloading increment and decrement operators

11.7: Overloading binary operators

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

11.8: Overloading `operator new(size_t)'

11.9: Overloading `operator delete(void *)'

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

11.10.1: Overloading `new[]'
11.10.2: Overloading `delete[]'
11.10.3: The `operator delete(void *, size_t)' family
11.10.4: `new[]', `delete[]' and exceptions

11.11: Function Objects

11.11.1: Constructing manipulators Manipulators requiring arguments

11.12: Lambda expressions

11.12.1: Lambda expressions: syntax
11.12.2: Using lambda expressions

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

11.14: User-defined literals

11.15: 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 The `map' constructors The `map' operators The `map' public members 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') The `unordered_map' constructors The `unordered_map' public members The `unordered_multimap' container
12.4.13: The `unordered_set' container 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 Protected members for input operations Protected members for output operations Protected members for buffer manipulation 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 Iterators for `istreambuf' objects
18.2.4: Iterators for `ostream' objects Iterators for `ostreambuf' objects
18.2.5: Moving elements to another container

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 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 The std::regex_constants::match_flag_type flags Matching full texts: std::regex_match Partially matching text: std::regex_search The member std::match_results::format Modifying target strings: std::regex_replace

18.9: Randomization and Statistical Distributions

18.9.1: Random Number Generators
18.9.2: Statistical distributions Bernoulli distribution Binomial distribution Cauchy distribution Chi-squared distribution Extreme value distribution Exponential distribution Fisher F distribution Gamma distribution Geometric distribution Log-normal distribution Normal distribution Negative binomial distribution Poisson distribution Student t distribution Uniform int distribution Uniform real distribution Weibull distribution

18.10: tie

18.11: Optional return values

Chapter 19: The STL Generic Algorithms

19.1: The Generic Algorithms

19.1.1: Execution policies
19.1.2: accumulate
19.1.3: adjacent_difference
19.1.4: adjacent_find
19.1.5: all_of / any_of / none_of
19.1.6: begin / end
19.1.7: binary_search
19.1.8: copy / copy_if
19.1.9: copy_backward
19.1.10: count / count_if
19.1.11: equal
19.1.12: equal_range
19.1.13: exchange
19.1.14: fill / fill_n
19.1.15: find / find_if / find_if_not
19.1.16: find_end
19.1.17: find_first_of
19.1.18: for_each
19.1.19: generate / generate_n
19.1.20: includes
19.1.21: inner_product
19.1.22: inplace_merge
19.1.23: iota
19.1.24: is_partitioned
19.1.25: is_permutation
19.1.26: is_sorted
19.1.27: is_sorted_until
19.1.28: iter_swap
19.1.29: lexicographical_compare
19.1.30: lower_bound
19.1.31: max / min
19.1.32: max_element / min_element / minmax_element
19.1.33: merge
19.1.34: minmax
19.1.35: mismatch
19.1.36: move / move_backward
19.1.37: next_permutation / prev_permutation
19.1.38: nth_element
19.1.39: partial_sort / partial_sort_copy
19.1.40: partial_sum
19.1.41: partition / partition_point / stable_partition
19.1.42: partition_copy
19.1.43: reduce
19.1.44: remove / remove_if / remove_copy / remove_copy_if
19.1.45: replace / replace_if / replace_copy / replace_copy_if
19.1.46: reverse / reverse_copy
19.1.47: rotate / rotate_copy
19.1.48: sample
19.1.49: search / search_n
19.1.50: set_difference
19.1.51: set_intersection
19.1.52: set_symmetric_difference
19.1.53: set_union
19.1.54: sort / stable_sort
19.1.55: swap / swap_ranges
19.1.56: transform
19.1.57: transform_reduce
19.1.58: handling uninitialized memory
19.1.59: unique
19.1.60: unique_copy
19.1.61: upper_bound
19.1.62: Heap algorithms The `make_heap' function The `pop_heap' function The `push_heap' function The `sort_heap' function 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 Static data and threads: thread_local Exceptions and join()
20.1.3: The class std::jthread 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.3.3: Scoped 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.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 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 Simple Definitions 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 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: Type resolution for base class members
23.1.2: ::template, .template and ->template

23.2: Template Meta Programming

23.2.1: Values according to templates Converting integral types to types
23.2.2: Selecting alternatives using templates Defining overloading members Class structure as a function of template parameters 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 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 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 Erasing the first occurrence Erasing a type by its index Erasing all occurrences of a type 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 Simple requirements Type requirements Compound requirements Nested requirements
23.13.3: Predefined concepts Concepts specifying one template type parameter Concepts specifying two template type parameters 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 Function- and class template declarations Bound free-operators

Chapter 24: Coroutines

24.1: Defining a coroutine

24.1.1: The coroutine's State class (promise_type) 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 Using a one-character buffer Using an n-character buffer Seeking positions in `streambuf' objects Multiple `unget' calls in `streambuf' objects
25.1.3: Fixed-sized field extraction from istream objects 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 The class `Selector': interface The class `Selector': implementation The class `Monitor': interface The class `Monitor': s_handler The class `Monitor': the member `run' The class `Monitor': example The class `Child'

25.3: Adding binary operators to classes

25.3.1: Merely using operators 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 The derived class `Scanner' The lexical scanner specification file Implementing `Scanner' Using a `Scanner' object Building the program
25.6.2: Using `bisonc++' and `flexc++' The `bisonc++' specification file The `flexc++' specification file Building the program