Book-en-us
- Preface
- Chapter 01: Towards Modern C++
- Chapter 02: Language Usability Enhancements
- Chapter 03: Language Runtime Enhancements
- Chapter 04: Containers
- Chapter 05: Smart Pointers and Memory Management
- Chapter 06: Regular Expression
- Chapter 07: Parallelism and Concurrency
- Chapter 08: File System
- Chapter 10: C++20
- Chapter 11: C++23
- Chapter 12: C++26 (Outlook)
- Appendix 1: Further Study Materials
- Appendix 2: Modern C++ Best Practices
- Appendix 3: Modern C++ Feature Index
Chapter 11: C++23
If C++20 was another "major" release in the spirit of C++11, C++23 is more of an incremental update focused on consolidation and polish: it completes some features that were rushed into C++20 and adds many long-requested library facilities. This chapter introduces a selection of its more important and practical features.
The examples in this chapter use C++23 features and must be compiled with
-std=c++2b(or-std=c++23). In addition, depending on the progress of each standard-library implementation, some library features (such asstd::generator,std::move_only_function,<stacktrace>, andimport std;) may not yet be available on your toolchain; this is noted where relevant.
11.1 Language features
Deducing this (explicit object parameter)
Before C++23, making a member function serve const/non-const and lvalue/rvalue cases at once usually meant writing several nearly identical overloads. C++23 introduces an explicit object parameter, allowing this to be written as the function's first parameter and its cv-/ref-qualification to be deduced via a template, so a single function template covers every case:
struct Counter { |
This also makes previously awkward patterns, such as recursive lambdas, natural to write.
if consteval
C++23 introduces if consteval, which distinguishes within a function body whether the current context is constant evaluation, letting you choose different implementations for compile time and run time:
constexpr int compute(int x) { |
Multidimensional subscript operator
C++23 lets operator[] take multiple subscript arguments, so multidimensional containers can use the intuitive m[i, j] syntax instead of falling back to operator():
struct Matrix2x3 { |
auto(x) and static operator()
C++23 provides the auto(x) / auto{x} syntax to explicitly produce a decay-copy — a prvalue copy of the same type as x — which is handy when you specifically want a copy:
std::vector<int> v{1, 2, 3}; |
In addition, the call operator of a function object (including a lambda) can now be declared static, dropping the implicit object parameter, which can improve performance in some scenarios:
struct Add { |
[[assume]]
[[assume(expr)]] is a C++23 standardized attribute that tells the compiler an expression is guaranteed to be true at that point, allowing the optimizer to take advantage of it. Note that if the assumption does not actually hold at run time, the behavior is undefined, so use it with care:
int divide_by(int x) { |
Other small language improvements
C++23 also includes several smaller language improvements:
- Preprocessor directives: added
#elifdef/#elifndef(shorthands for#elif defined/#elif !defined) and#warningfor emitting a diagnostic on purpose. - Named universal character escapes: a character can be written by its Unicode name, e.g.
"\N{GREEK SMALL LETTER ALPHA}", which is more readable than memorizing code points. - Extended floating-point types:
<stdfloat>introduces fixed-width floating-point types such asstd::float16_t,std::float32_t,std::float64_t, andstd::bfloat16_t(their availability likewise depends on the platform and standard-library implementation). - Further
constexprrelaxations: constant evaluation now permitsgotoand labeled statements, as well as declaring (but not using during constant evaluation) variables of non-literal type andstaticvariables.
11.2 The standard library
std::expected
std::expected<T, E> represents a result that is "either a value T or an error E", providing a type-safe, expressive way to handle errors without exceptions, similar to the Result type in other languages:
#include <expected> |
std::print and std::println
C++23's <print> provides std::print and std::println, which build on C++20's std::format to produce output via a type-safe format string — more concise and more efficient than the traditional chained iostream <<:
#include <print> |
std::mdspan
std::mdspan is a non-owning multidimensional view over contiguous storage. It does not allocate; it merely reinterprets the layout of an underlying one-dimensional array according to the given extents, and is widely used in scientific and high-performance computing:
#include <mdspan> |
std::flat_map and std::flat_set
std::flat_map / std::flat_set are associative containers backed by sorted contiguous storage (by default two vectors). Compared with the red-black-tree-based std::map, insertion is slower, but lookup and iteration are more cache-friendly and the memory overhead is smaller:
#include <flat_map> |
Ranges additions
C++23 added many useful range adaptors, such as views::zip (iterates several ranges in lockstep, element by element), views::enumerate (attaches an index to each element), views::chunk, views::slide, and views::join_with, as well as the general-purpose std::ranges::to (materializes a range into a concrete container):
#include <ranges> |
Other improvements
C++23 also includes many small but practical improvements, for example:
std::string/std::string_viewgained acontainsmember to directly test for a substring or character;<bit>addedstd::byteswap, which reverses the byte order of an integer;std::optionalgained monadic operations such asand_then,transform, andor_else.
11.3 A note on library support
Most C++23 language features are already well supported by mainstream compilers, but the availability of some library features varies by implementation. For instance, std::generator (coroutine ranges), std::move_only_function, <stacktrace>, and the standard-library module import std; may not yet be implemented, or may still be experimental, in some standard libraries (especially libc++). Before using these features, check the cppreference compiler support page to confirm the support status of your toolchain.
Conclusion
Although C++23 does not bring the disruptive changes of C++11 or C++20, features such as std::expected, std::print, std::mdspan, and the explicit object parameter genuinely improve the day-to-day experience of writing C++. Together with the upcoming C++26, modern C++ continues to evolve.
Further Readings
Changkun Ou © 2016-2026. The book is licensed under Creative Commons Attribution-NonCommercial-NoDerivatives 4.0, code is open sourced under the MIT License.
If you like the book, you could donate the author.