Skip to content
C++
C++23
Published ISO/IEC 14882:2024
Consolidation release

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.

std::print
std::expected
Deducing this
import std
std::generator
std::flat_map
Ranges++

Core Language

Deducing this (explicit object parameter)

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);
};
if consteval

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);
    }
}
Multidimensional subscript operator

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-index
Pack indexing

Direct 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);  // 30

Library

std::print / std::println

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);
std::expected<T, E>

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 std; (Standard Library Module)

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+ #includes
std::flat_map / std::flat_set

Sorted, 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 map
std::generator<T>

Coroutine-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
    }
}
Ranges: zip, chunk, slide, adjacent

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]