C++23
A focused consolidation release built on C++20's foundations. std::print and std::expected become the standard for I/O and error handling. Deducing this solves long-standing patterns. import std; makes headers optional.
Core Language
Allows member functions to receive *this explicitly, enabling CRTP without inheritance, recursive lambdas, and const-agnostic implementations.
struct Widget {
// Deduce cv-qualifier and ref-qualifier from caller
template<typename Self>
auto& value(this Self&& self) {
return std::forward<Self>(self).value_;
}
int value_;
};
// Recursive lambda — no std::function wrapper needed
auto fib = [](this auto self, int n) -> int {
return n < 2 ? n : self(n-1) + self(n-2);
};Distinguishes compile-time evaluation from runtime. Enables different behavior in constant expressions without std::is_constant_evaluated().
constexpr double sqrt_impl(double x) {
if consteval {
// compile-time path (e.g., Newton-Raphson)
return compile_time_sqrt(x);
} else {
// runtime path — use hardware instruction
return __builtin_sqrt(x);
}
}operator[] can now take multiple arguments. Enables clean multi-dimensional array syntax: mdspan[i, j, k].
#include <mdspan>
template<typename T, std::size_t N, std::size_t M>
struct Matrix {
T data[N][M];
T& operator[](std::size_t i, std::size_t j) {
return data[i][j];
}
};
Matrix<int, 3, 3> m;
m[1, 2] = 42; // clean multi-indexDirect index into parameter packs with pack...[N] syntax. No longer need recursive templates to get the Nth element.
template<typename... Ts>
auto first(Ts... args) {
return args...[0];
}
template<typename... Ts>
auto third(Ts... args) {
return args...[2];
}
auto x = first(10, 20, 30); // 10
auto z = third(10, 20, 30); // 30Library
std::format + I/O in one. Type-safe, UTF-8 aware, no locale surprises. The preferred output mechanism in modern C++.
#include <print>
std::print("Hello, {}!\n", "world");
std::println("x = {}, y = {}", 3, 4.5); // adds newline
// Print to a stream
std::println(std::cerr, "Error: {}", msg);
// Unicode — correct even on Windows
std::println("\u03C0 \u2248 {:.6f}", std::numbers::pi);Error-return value without exceptions. Monadic interface with and_then, transform, or_else for composable error handling.
#include <expected>
#include <string>
std::expected<int, std::string> parse_int(std::string_view s) {
if (s.empty()) return std::unexpected("empty input");
try { return std::stoi(std::string(s)); }
catch (...) { return std::unexpected("not a number"); }
}
auto result = parse_int("42")
.and_then([](int n) -> std::expected<double, std::string> {
if (n < 0) return std::unexpected("negative");
return std::sqrt(double(n));
})
.value_or(0.0);Import the entire standard library as a module. Dramatically faster builds than #include <...> headers.
import std; // replaces ALL standard headers
int main() {
std::vector<int> v = {3, 1, 4, 1, 5};
std::ranges::sort(v);
std::println("{}", v);
}
// Compiles significantly faster than 20+ #includesSorted, flat (contiguous) associative containers backed by two vectors. Better cache performance than std::map for iteration-heavy workloads.
#include <flat_map>
std::flat_map<std::string, int> scores;
scores["Alice"] = 95;
scores["Bob"] = 87;
// Cache-friendly: keys and values in separate contiguous arrays
// insert: O(n), lookup: O(log n), iteration: O(n) — faster than mapCoroutine-based lazy range generator. The standard library's first coroutine type. Replaces custom promise boilerplate.
#include <generator>
#include <ranges>
std::generator<int> fibonacci() {
int a = 0, b = 1;
while (true) {
co_yield a;
std::tie(a, b) = std::pair{b, a + b};
}
}
int main() {
for (int n : fibonacci() | std::views::take(10)) {
std::print("{} ", n); // 0 1 1 2 3 5 8 13 21 34
}
}C++23 brings a large batch of new range views and adaptors to complement the C++20 ranges library.
#include <ranges>
#include <vector>
#include <print>
std::vector a{1, 2, 3};
std::vector b{'a', 'b', 'c'};
// zip — pair elements from multiple ranges
for (auto [x, c] : std::views::zip(a, b))
std::print("({},{}) ", x, c); // (1,a) (2,b) (3,c)
// chunk — split range into fixed-size groups
for (auto chunk : std::views::chunk(a, 2))
std::print("[{}] ", chunk); // [1,2] [3]
// slide — sliding window
for (auto win : std::views::slide(a, 2))
std::print("[{}] ", win); // [1,2] [2,3]