Hubbry Logo
C++23C++23Main
Open search
C++23
Community hub
C++23
logo
7 pages, 0 posts
0 subscribers
Be the first to start a discussion here.
Be the first to start a discussion here.
Contribute something
C++23
C++23
from Wikipedia

C++23, formally ISO/IEC 14882:2024,[1] is the current open standard for the C++ programming language that follows C++20. The final draft of this version is N4950.[2][3]

In February 2020, at the final meeting for C++20 in Prague, an overall plan for C++23 was adopted:[4][5] planned features for C++23 were library support for coroutines, a modular standard library, executors, and networking.

The first WG21 meeting focused on C++23 was intended to take place in Varna in early June 2020, but was cancelled due to the COVID-19 pandemic,[6][7] as was the November 2020 meeting in New York[8][7] and the February 2021 meeting in Kona, Hawaii.[8] All meetings until November 2022 were virtual while the November 2022 meeting until the final meeting in February 2023 was hybrid.[8] The standard was technically finalized by WG21 at the hybrid meeting in Issaquah in February 2023.[9]

Modern "Hello, world" Example

[edit]

After many library changes applied to the working draft, the new "Hello, world" program will be: [1]

import std;

int main() {
    std::println("Hello, world!");
}

Features

[edit]

Changes that have been accepted into C++23 include:

Language

[edit]
  • explicit this object parameter[10]
  • if consteval[11]
  • multidimensional subscript operator[12]
  • static call and subscript operators and static lambdas[13][14]
  • simplifying implicit move[15]
  • auto(x) and auto{x}[16]
  • new preprocessor directives:
  • extending the lifetime of some temporaries in range-based for loop[19]
  • new standard attribute [[assume(expression)]][20]
  • class template argument deduction from inherited constructors[21]
  • labels at the end of the compound statement[22]
  • alias declarations in init-statements[23]
  • literal suffixes for std::size_t and the corresponding signed type[24]
  • extended floating-point types with literals (conditionally supported)[25]
  • optional () from nullary lambda expressions[26]
  • attributes on lambda expressions[27]
  • constexpr changes:
    • non-literal variables, labels, and gotos in constexpr functions[28]
    • allowing static and thread_local variables that are usable in constant expressions in constexpr functions[29]
    • constexpr function does not need its return type and parameter types to be literal type
    • it is now possible to write a constexpr function for which no invocation satisfies the requirements of a core constant expression[30]
  • narrowing contextual conversions to bool in static_assert and if constexpr[31]
  • trimming whitespaces before line splicing[32]
  • make declaration order layout mandated[33]
  • delimited escape sequences[34]
  • named universal character escapes[35]
  • text encoding changes:
    • support for UTF-8 as a portable source file encoding[36]
    • consistent character literal encoding[37]
    • character sets and encodings[38]
  • New meaning added to some keywords, such as for this.[39]

Library

[edit]

Standard Library Module Support

[edit]

Coroutine Library Support

[edit]
  • synchronous coroutine std::generator for ranges[41]

General Utilities Support

[edit]
  • result type std::expected[42]
  • monadic operations for std::optional[43] and std::expected[44]
  • utility function std::to_underlying to get the underlying value of enum[45]
  • move-only callable wrapper std::move_only_function[46]
  • std::forward_like[47]
  • std::invoke_r[48]
  • std::bind_back[49]
  • std::byteswap[50]
  • std::unreachable: a function to mark unreachable code[51]
  • made std::tuple compatible with other tuple-like objects[52]
  • std::basic_common_reference specialization for std::reference_wrapper yielding reference types[53]
  • adding default arguments for std::pair's forwarding constructor[54]

Compile-time Support

[edit]
  • constexpr support for:
    • std::type_info::operator==[55]
    • std::bitset[56]
    • std::unique_ptr[57]
    • for some <cmath> functions[58]
    • for integral overloads of std::to_chars and std::from_chars[59]
  • metaprogramming utilities:
    • type traits std::is_scoped_enum,[60] std::is_implicit_lifetime,[61] std::reference_constructs_from_temporary, and std::reference_converts_from_temporary.[62]
  • adding move-only types support for comparison concepts[63]

Iterators, Ranges, and Algorithm Support

[edit]
  • new range conversion function std::ranges::to[64]
  • new constrained ranges algorithm:
    • std::ranges::starts_with
    • std::ranges::ends_with[65]
    • std::ranges::contains
    • std::ranges::contains_subrange[66]
    • std::ranges::find_last and other variants[67]
    • rangified versions of iota, shift_left, and shift_right[68]
    • range fold algorithms[69]
  • new std::ranges::range_adaptor_closure, a helper for defining user-defined range adaptor closures[49]
  • new range adaptors:
    • std::views::zip and other variants
    • std::views::adjacent and other variants[70]
    • std::views::join_with[71]
    • std::views::slide
    • std::views::chunk[72]
    • std::views::chunk_by[73]
    • std::views::as_rvalue[74]
    • std::views::as_const[75]
    • std::views::repeat[76]
    • std::views::stride[77]
    • std::views::cartesian_product[78]
    • std::views::enumerate[79]
  • rectifying constant iterators, sentinels, and ranges, that is, std::ranges::cbegin and other similar utilities returning constant iterators should be fully guaranteed even for shallow-const views (such as std::span)[75]
  • ranges iterators as inputs to non-ranges algorithms[80]
  • relaxing range adaptors to allow for move only types[81]
  • making multi-param constructors of some views explicit[82]

Memory Management Support

[edit]
  • std::out_ptr and std::inout_ptr for C interoperability[83]
  • std::allocate_at_least and std::allocator::allocate_at_least[84]
  • explicit lifetime management function std::start_lifetime_as for implicit-lifetime types[85]
  • disallowing user specialization of std::allocator_traits[86]

String and Text Processing Support

[edit]
  • new member functions and changes in string types:
    • std::basic_string_view::contains and std::basic_string::contains[87]
    • disabling construction from nullptr for std::basic_string and std::basic_string_view[88]
    • explicit range constructor for std::basic_string_view[89]
    • std::basic_string::resize_and_overwrite[90]
    • rvalue reference overload of std::basic_string::substr for efficient slicing[91]
  • formatting ranges, tuples, escaped presentation of characters and strings, std::thread::id, and stacktraces.[92][93][94]

Diagnostic Support

[edit]
  • stacktrace library[95]

I/O Support

[edit]
  • formatted output functions std::print and std::println from new header <print>[96]
  • spanstream library (std::span-based string stream) from new header <spanstream>[97]
  • a support for exclusive mode in std::fstreams[98]
  • std::basic_ostream::operator<<(const volatile void*)[99]

Containers Support

[edit]
  • multidimensional-span std::mdspan[100][101][102][103]
  • constructability and assignability of containers from other compatible ranges[64]
  • flat set and flat map container adapters[104][105]
  • non-deduction context for allocators in container deduction guides[106]
  • heterogeneous erasure overloads for associative containers[107]
  • allowing iterator pair construction in stack and queue[108]
  • requiring std::span and std::basic_string_view to be trivially copyable[109]

C-Compatibility Support

[edit]
  • new header <stdatomic.h>[110]

Language defect reports

[edit]
  • C++ identifier syntax using Unicode Standard Annex 31[111]
  • allowing duplicate attributes[112]
  • changing scope of lambda trailing return type[113]
  • making overloaded comparison operators less breaking change[114]
  • undeprecating volatile compound assignments[115][116]
  • fixing the compatibility and portability of char8_t[117]
  • relaxing requirements on wchar_t to match existing practices[118]
  • allowing some pointers and references of this or unknown origin in constant expressions[119]
  • introduction of immediate-escalating functions promoted to immediate functions[120]
  • allowing static_assert(false) in uninstantiated template contexts

Library defect reports

[edit]
  • changes in ranges library:
    • conditionally borrowed ranges[121]
    • repairing input range adaptors and std::counted_iterator[122]
    • relaxing the constraint on std::ranges::join_view[123]
    • renamed std::ranges::split_view to std::ranges::lazy_split_view and new split_view[124]
    • removed std::default_initializable constraint from concept std::ranges::view[125]
    • view with ownership and new std::ranges::owning_view[126]
    • fixed std::ranges::istream_view[127]
  • changes in text formatting library:
    • std::basic_format_string[128]
    • compile-time format string checks
    • reducing binary code size of std::format_to[129]
    • fixing locale handling in chrono formatters[130]
    • improving width estimation[131] and fill character allowances of std::format[132]
    • use of forwarding references in format arguments to allow non-const-formattable types[133]
  • fully constexpr std::variant and std::optional[134]
  • supporting types derived from std::variant in std::visit[135]

Removed features and deprecation

[edit]

Removed features:

  • Garbage Collection Support and (strict) Pointer Safety[136] (meaning only relaxed pointer safety is to be relied upon[137]). This minimal garbage collection support (and pointer safety, needed for it), was added to C++11 but no compilers have ever supported it so the support was removed in C++23.[138] However, that doesn't mean many GC implementations haven't been used, and continue to be used with C++, such as Boehm GC (and it can also just be used for leak detection in leak detection, when in debug mode), and such GC is often implemented in C++, for other languages to use.
  • Mixed wide-string literal concatenation.[139]
  • Non-encodable wide character literals and multicharacter wide character literals.[140]

Deprecated features:

  • std::aligned_storage and std::aligned_union[141]
  • std::numeric_limits::has_denorm[142]

Reverted deprecated features:

  • Use of comma operator in subscript expressions was no longer deprecated but the semantics has been changed to support overloadable n-adic operator[].
  • C headers (The corresponding <*.h> headers for compatibility with C)

Published as Technical Specifications

[edit]

Compiler support

[edit]
  • Clang progressively added partial C++23 support from 2021 in version 13 through to version 18 in 2024, available through the option -std=c++23.[144]
  • GCC added partial, experimental C++23 support in 2021 in version 11 through the option -std=c++2b or -std=c++23 It also has an option to enable GNU extensions in addition to the experimental C++23 support, -std=gnu++2b.[145]

History

[edit]

In the absence of face-to-face WG21 meetings, the following changes were applied after several virtual WG21 meetings, where they were approved by straw polls.

November 2020

[edit]

The following were added after the virtual WG21 meeting of 9 November 2020, where they were approved by straw polls:[146]

  • Literal suffixes for std::size_t and the corresponding signed type
  • A member function contains for std::basic_string and std::basic_string_view, to check whether or not the string contains a given substring or character
  • A stacktrace library (<stacktrace>), based on Boost.Stacktrace
  • A type trait std::is_scoped_enum
  • The header <stdatomic.h>, for interoperability with C atomics

February 2021

[edit]

After the virtual WG21 meeting of 22 February 2021, following features are added where they were approved by straw polls:[147]

  • Removing unnecessary empty parameter list () from lambda expressions.
  • Repairing input range adaptors and counted_iterator.
  • Relax the requirements for time_point::clock.[148]
  • std::visit for classes that are derived from std::variant.
  • Locks lock lockables.[149]
  • Conditionally borrowed ranges.
  • std::to_underlying.

June 2021

[edit]

After the summer 2021 ISO C++ standards plenary virtual meeting of June 2021, new features and defect reports were approved by straw polls:[150]

  • Consteval if (if consteval).
  • Narrowing contextual conversions to bool.
  • Allowing duplicate attributes.
  • std::span-based string-stream (<spanstream>).
  • std::out_ptr() and std::inout_ptr().
  • constexpr for std::optional, std::variant, and std::type_info::operator==.
  • Iterators pair constructors for std::stack (stack) and std::queue (queue).
  • Few changes of the ranges library:
    • Generalized starts_with and ends_with for arbitrary ranges.
    • Renamed split_view to lazy_split_view and new split_view.
    • Relaxing the constraint on join_view.
    • Removing default_initializable constraint from concept view.
    • Range constructor for std::basic_string_view.
  • Prohibiting std::basic_string and std::basic_string_view construction from nullptr.
  • std::invoke_r.
  • Improvements on std::format.
  • Adding default arguments for std::pair's forwarding constructor.

October 2021

[edit]

After the autumn 2021 ISO C++ standards plenary virtual meeting of October 2021, new features and defect reports were approved by straw polls:[151]

  • Non-literal variables, labels, and gotos in constexpr functions, but still ill-formed to evaluate them at compile-time.
  • Explicit this object parameter.
  • Changes on character sets and encodings.
  • New preprocessors: #elifdef and #elifndef. Both directives were added to C23 (C language update) and GCC 12.[152]
  • Allowing alias declarations in init-statement.
  • Overloading multidimensional subscript operator (e.g. arr[1, 2]).
  • Decay copy in language: auto(x) or auto{x}.
  • Changes in text formatting library:
    • Fixing locale handling in chrono formatters.
    • Use of forwarding references in format arguments to allow std::generator-like types.
  • Addition of type alias std::pmr::stacktrace which is equivalent to std::basic_stacktrace<std::pmr::polymorphic_allocator>.[153]
  • Changes in ranges library:
    • Refined definition of a view.
    • Replacing function template std::ranges::istream_view with alias templates std::ranges::istream_view, std::ranges::wistream_view, and customization point object std::views::istream.
    • zip range adaptor family:
      • zip_view
      • zip_transform_view
      • adjacent_view (and std::views::pairwise being equivalent to std::views::adjacent<2>)
      • adjacent_transform_view (and std::views::pairwise_transform being equivalent to std::views::adjacent_transform<2>)
  • std::move_only_function.
  • Monadic operations for std::optional.
  • Member function template std::basic_string::resize_and_overwrite.
  • Printing volatile pointers (volatile T*).
  • std::byteswap.
  • Heterogeneous erasure overloads for associative containers.
  • Every specialization of std::span and std::basic_string_view is trivially copyable.
  • Adding conditional noexcept specifications to std::exchange.[154]
  • Revamped specification and use of integer-class types.[155]
  • Clarify C headers. "The headers are not useful in code that is only required to be valid C++. Therefore, the C headers should be provided by the C++ standard library as a fully-supported, not deprecated part, but they should also be discouraged for use in code that is not polyglot interoperability code. [..] This proposal makes the C headers no longer deprecated, so there is no formal threat of future removal. The effective discouragement to use the C headers in pure C++ code is now spelled out explicitly as normative discouragement."[156]

February 2022

[edit]

After the virtual WG21 meeting of 7 February 2022, the following features are added where they were approved by straw polls:[157]

  • Allowed attributes on the function call operator of a lambda
  • std::expected
  • constexpr for cmath and cstdlib
  • Function to mark unreachable code
  • ranges::to
  • A type trait to detect reference binding to temporary
  • Making std::unique_ptr constexpr
  • Pipe support for user-defined range adaptors
  • ranges::iota, ranges::shift_left and ranges::shift_right
  • views::join_with
  • Windowing range adaptors: views::chunk and views::slide
  • views::chunk_by

July 2022

[edit]

After the virtual WG21 meeting of 25 July 2022, the following features and defect reports are added where they were approved by straw polls:[158]

  • Made rewriting equality in expressions less of a breaking change.
  • Reverted the deprecation of bitwise assignment to volatile variables.
  • Added the #warning preprocessor directive.
  • Removed non-encodable wide character literals and multicharacter wide character literals.
  • Allowed labels to appear at the end of compound statements.
  • Added escape sequences delimited with curly braces for octal and hexadecimal numbers and universal character names.
  • Allowed constexpr functions to never be constant expressions.
  • Simplified some implicit move rules from C++20 and allowed implicit move when returning an rvalue reference.
  • Add a way to specify unicode characters by name. For example, U'\N{LATIN CAPITAL LETTER A WITH MACRON}' // Equivalent to U'\u0100'
  • Allowed operator() and lambdas to be static.
  • Allowed the this pointer and references of unknown origin to appear in constant expressions.
  • Allowed implementations to define extended floating-point types in addition to the three standard floating-point types. Added the type aliases std::float16_t, std::float32_t, std::float64_t, std::float128_t, std::bfloat16_t for these extended types accessible through the header <stdfloat>, their corresponding literal suffixes f16 f32 f64 f128 bf16or F16 F32 F64 F128 BF16 and added overloads to various standard library functions that take floats as arguments.
  • Added the [[assume(expression)]] attribute which allows the compiler to assume the provided expression is true to allow optimizations.
  • Made support for UTF-8 source files mandatory, providing a portable encoding for source files.
  • Allowed arrays of char and unsigned char to be initialized with UTF-8 string literals.
  • Removed the requirement that wchar_t can encode all characters of the extended character set, in effect allowing UTF-16 to be used for wide string literals.
  • Added std::mdspan, a multidimensional array view analogous to std::span.
  • flat_map and flat_set were added to the standard library.
  • Added the std::print and std::println functions for printing formatted text to stdout.
  • Provide the named modules std and std.compat for importing the standard library.
  • Added support for exclusive mode fstreams, analogous to the "x" flag in fopen.
  • Allowed std::format to handle ranges, tuples, and other containers.
  • Added std::forward_like.
  • Made std::string::substr use move semantics.
  • Added std::generator which implements a coroutine generator that models std::ranges::input_range
  • views::cartesian_product, views::repeat, views::stride, views::as_const, views::as_rvalue.
  • Added new algorithms: ranges::find_last, ranges::contains, and ranges fold algorithms.
  • Made std::tuple compatible with other tuple-like objects.
  • Explicit lifetime management for implicit-lifetime types.
  • Made std::bitset and integral overloads of std::to_chars and std::from_chars constexpr-compatible.
  • Adding move-only types support for comparison concepts.
  • Ranges iterators as inputs to non-ranges algorithms.
  • Relaxing range adaptors to allow for move-only types.

November 2022

[edit]

After the hybrid WG21 meeting of 7 November 2022, the following features and defect reports are added where they were approved by straw polls:[159]

  • Allowed operator[] to be static.
  • Allowed static and thread_local variables to appear in constexpr functions if they are usable in constant expressions.
  • consteval propagates upwards, that is, certain existing constexpr functions become consteval functions when those functions can already only be invoked during compile time.
  • Extended the lifetime of temporaries that appear in the for-range-initializer of a range-based for loop to cover the entire loop.
  • Reverted the deprecation of (all, not just bitwise) compound assignment to volatile variables.
  • Monadic functions for std::expected.
  • Synchronize the output of std::print with the underlying stream if the native Unicode API is used.[160]

February 2023

[edit]

After the final hybrid WG21 meeting of 6-11 February 2023, the following features and defect reports are added where they were approved by straw polls:[161]

  • Referencing the Unicode Standard.[162]
  • Stashing stashing iterators for proper flattening.[163]
  • views::enumerate
  • making multi-param constructors of views explicit
  • relaxing ranges just a smidge
  • escaping improvements in std::format
  • improving std::format's width estimation
  • std::format fill character allowances
  • formatting thread::id and stacktrace
  • A type trait std::is_implicit_lifetime
  • std::common_reference_t of std::reference_wrapper should be a reference type
  • disallowing user specialization of std::allocator_traits
  • std::pmr::generator
  • deprecating std::numeric_limits::has_denorm
  • std::barrier's phase completion guarantees

References

[edit]
[edit]
Revisions and contributorsEdit on WikipediaRead on Wikipedia
from Grokipedia
C++23, formally known as ISO/IEC 14882:2024, is the seventh edition of the international standard specifying requirements for implementations of the C++ programming language, a general-purpose language extending the ISO/IEC 9899:2018 C standard with object-oriented and generic programming facilities such as classes, templates, exceptions, namespaces, and operator overloading. Published by the International Organization for Standardization (ISO) in October 2024, it succeeds the C++20 standard (ISO/IEC 14882:2020) and incorporates technical corrections alongside new features designed to enhance code expressiveness, safety, performance, and modularity in areas like constant evaluation and error handling.

Core Language Enhancements

C++23 introduces several refinements to the language syntax and semantics to address modern programming needs. Notable additions include support for explicit object member functions (also known as "explicit this"), which allow non-static member functions to explicitly declare their object parameter for improved clarity in generic code and forwarding scenarios. The standard also adds multidimensional subscript operators, enabling operator[] to accept multiple arguments for more intuitive access to multi-dimensional data structures like arrays or matrices. Other key language features encompass new preprocessing directives #elifdef and #elifndef for conditional compilation based on macro definitions, the auto(x) decay-copying declaration for initializing variables with decayed types, and explicit lifetime extension mechanisms to prevent dangling references in temporary expressions. Additionally, C++23 improves support for better handling of international text and extends constexpr evaluation to more library functions, allowing compile-time computations in a broader range of contexts.

Standard Library Improvements

The C++23 standard library receives significant updates focused on usability and efficiency, including the introduction of standard library modules that export the core library contents (excluding macros) to facilitate faster compilation and better encapsulation in modular codebases. New types such as std::expected provide a standardized way to handle errors and optional results, similar to monadic patterns in other languages, while std::generator supports coroutine-based iteration for and asynchronous data production. Library enhancements also feature string formatting and printing facilities inspired by std::format from but expanded for more flexible output, new container and view types like std::mdspan for multi-dimensional arrays, and algorithms optimized for ranges. Further additions include the <spanstream> header for stream-like operations on spans and the std::stacktrace library for capturing and inspecting call stacks at runtime. These changes deliver targeted advancements in productivity and reliability for , embedded development, and high-performance applications. Compiler support for C++23 features is progressively rolling out in major implementations like GCC, , and MSVC, with full conformance expected in subsequent releases.

Introduction

Overview

C++23 is the current ISO standard for , formally designated as ISO/IEC 14882:2024 and published in October 2024. The technical work on the standard was completed in February 2023 by the ISO/IEC JTC1/SC22/WG21 committee, marking the culmination of efforts to evolve the language while maintaining . This edition succeeds and represents a measured advancement in the language's development. The primary goals of C++23 include enhancing executability through better integration of existing features, simplifying common programming patterns to improve developer productivity, and bolstering compile-time capabilities for more efficient code generation. It also prioritizes the incorporation of prior Technical Specifications, such as modules and ranges, into the core standard to promote stability and avoid introducing highly experimental elements that could complicate adoption. In scope, C++23 offers a smaller yet more focused evolution compared to the transformative changes in C++20, with an emphasis on library enhancements for greater productivity and refinements to language precision for safer and more expressive code. Its impact on the C++ ecosystem includes enabling improved support for modern hardware via optimized data structures and multidimensional views, facilitating safer code through refined error handling, and diminishing dependence on traditional headers through mature module support. These advancements collectively streamline development workflows and enhance in contemporary applications.

Modern "Hello, World!" Example

A quintessential demonstration of C++23's advancements is the simplified "Hello, World!" program, which leverages the new module and formatted output functions to eliminate traditional header inclusions and stream manipulations.

cpp

import std; int main() { std::println("Hello, world!"); }

import std; int main() { std::println("Hello, world!"); }

In this example, import std; brings in the entire as a module, replacing the conventional #include directives and providing faster compilation times with better encapsulation by avoiding global from macros. Modules support for the standard library, including std, is detailed in the dedicated section on Modules and Import Support. Meanwhile, std::println from the <print> header outputs the formatted string to stdout followed by a , streamlining I/O operations that previously required std::cout, insertion operators, and explicit flushing via std::endl. To compile this program, a C++23-compliant compiler is required, such as GCC 13 or later invoked with the -std=c++23 flag (e.g., g++ -std=c++23 hello.cpp -o hello), though full module support may vary by implementation and could necessitate additional build system configurations like for prebuilt standard modules. As of 2025, GCC 15 or later offers full support for modules and std::println. For comparison, the C++20 equivalent relies on headers and streams, resulting in more verbose code:

cpp

#include <iostream> int main() { std::cout << "Hello, world!" << std::endl; }

#include <iostream> int main() { std::cout << "Hello, world!" << std::endl; }

This contrast underscores C++23's emphasis on conciseness and modernity, reducing the program's length while maintaining equivalent functionality.

Standardization Process

Development Timeline

Following the finalization of C++20 at the WG21 meeting in Prague from February 10 to 15, 2020, the committee shifted focus to , adopting a development plan outlined in paper P0592R4 that emphasized completing foundational work on modules—initially introduced in C++20—and enhancing ranges support to improve library usability. The COVID-19 pandemic disrupted in-person gatherings, leading to the cancellation of the planned June 2020 meeting in Varna, Bulgaria, and a transition to virtual meetings throughout 2020 and 2021. During this period, key proposals advanced significantly, including explicit object parameters (P0849R8) for simplifying member function calls and std::expected (P0323R15) for error-handling utilities, both of which progressed toward adoption in C++23 through reflector discussions and virtual plenaries, such as the November 9, 2020, Zoom meeting. In 2022, the committee continued with virtual sessions early in the year, including the February virtual meeting, before resuming hybrid in-person formats with the November 7-12 meeting in Kona, Hawaii, hosted by the Standard C++ Foundation. This period approached feature freeze, achieved at the July 25 virtual plenary, where core features like coroutines library support (including std::generator) and multidimensional arrays via std::mdspan were finalized for inclusion. The February 6-11, 2023, meeting in Issaquah, Washington, marked the completion of C++23's technical specifications, leading to the final committee draft N4950 dated May 10, 2023. Subsequent meetings in Varna, Bulgaria (June 12-17), and Kona, Hawaii (November 6-11), handled defect reports, wording refinements, and ballot preparations, leading to national body ratification. In 2024, the International Organization for Standardization (ISO) published C++23 as ISO/IEC 14882:2024 on October 1, formalizing the standard after editorial review. Post-publication, major compilers integrated C++23 support progressively; as of November 2025, GCC 15, Clang 19, and Visual Studio 2022 version 17.14 offer substantial to near-complete implementation, enabling widespread adoption.

Key Milestones and Meetings

The ISO/IEC JTC1/SC22/WG21 working group, known as the C++ standards committee, is responsible for evolving the C++ programming language standard through a collaborative process involving national body representatives and individual experts. This group reviews technical papers submitted by members, conducts discussions in working group sessions during triannual meetings, and uses polls to gauge consensus on proposed changes before forwarding recommendations for inclusion in the working draft. Key decisions shaping C++23 included several pivotal votes at WG21 meetings. At the February 2023 meeting in Issaquah, Washington, USA, the committee approved the final draft of the C++23 standard by unanimous consent after resolving all national body comments, marking the technical completion of the specification. Earlier, in June 2022 at the St. Louis meeting, WG21 polled in favor of including P2465R3, which introduced standard library modules such as std and std.compat to facilitate modular imports of the C++ library. However, the Contracts Technical Specification was rejected for integration into C++23 due to insufficient consensus stemming from concerns over semantic complexity and implementation challenges. C++23 incorporated features from several Technical Specifications (TS) into the core standard, promoting stability and adoption. The Library Fundamentals V3 TS contributed components like std::expected for error handling and std::mdspan for multidimensional array views. Enhancements from the Ranges TS, including additional views and algorithms, were fully integrated to extend C++20's ranges foundation. The Coroutines TS provided the basis for std::generator, enabling lazy sequence generation in standard library coroutines. These integrations were approved via polls in LEWG (Library Evolution Working Group) sessions leading up to the feature freeze in July 2022. Following the February 2023 feature freeze, WG21 addressed post-freeze defects through targeted resolutions. The Core Working Group (CWG) and Library Working Group (LWG) reviewed and fixed ambiguities in ranges, such as iterator invalidation rules, and attributes, including clarification of [[likely]] and [[unlikely]] semantics, via immediate-issue polls at the Issaquah meeting. WG21's evolution policy employs a decoupled model, where experimental features are first previewed in separate Technical Specifications to allow real-world testing and refinement without delaying the main standard's publication cycle. This approach enabled the progressive maturation of , coroutines, and library fundamentals from TS to full standardization in C++23.

Language Features

Core Syntax Enhancements

C++23 introduces core syntax enhancements that streamline member function definitions, operator overloads, literal expressions, and namespace declarations, thereby increasing code expressiveness while minimizing redundancy in common programming patterns. A key feature is deducing this (P0847R8), which permits non-static member functions to deduce their return type based on the cv- and ref-qualifiers of the implicit this parameter, eliminating the need for separate overloads to handle lvalue and rvalue contexts. This enables a unified implementation for operations like assignment or chaining, where the return type adjusts automatically—for instance, returning a reference for lvalues and an rvalue reference for rvalues. Consider this example in a class definition:

cpp

struct Widget { auto operator+=(const auto& rhs) { /* implementation */ return *this; } };

struct Widget { auto operator+=(const auto& rhs) { /* implementation */ return *this; } };

Here, the deduced return type adapts seamlessly, fostering more concise fluent interfaces without sacrificing type safety. The explicit object parameter syntax, integral to the same proposal, further refines this by allowing this to be named as the first explicit parameter in member function signatures, treating the function akin to a free function for improved template forwarding and lambda integration. For example:

cpp

struct Foo { void print(this Foo& self) { /* use self */ } };

struct Foo { void print(this Foo& self) { /* use self */ } };

This approach enhances generic programming by enabling perfect forwarding of the object parameter and simplifies capturing in lambdas, where explicit object handling aligns with non-member function patterns. The multidimensional subscript operator (P2128R6) extends operator[] to accept multiple arguments, supporting direct multi-index access for multidimensional data structures without relying on deprecated comma expressions or nested calls. This syntactic upgrade is particularly beneficial for user-defined types representing arrays or views, allowing overloads with fixed or variadic parameters that include the explicit object for consistency. An illustrative declaration is:

cpp

struct Matrix { double& operator[](this Matrix&& self, size_t row, size_t col); };

struct Matrix { double& operator[](this Matrix&& self, size_t row, size_t col); };

Usage such as matrix[1, 2] = 3.14; becomes idiomatic, promoting readability in numerical and scientific computing while integrating with library features like multidimensional views. To mitigate common type promotion issues with size-related constants, C++23 adds literal suffixes for std::size_t and its signed counterpart (std::ptrdiff_t or equivalent), as specified in P0330R8. The 'uz' (or 'UZ') suffix denotes an unsigned size_t literal, while 'z' (or 'Z') indicates the signed variant, preventing implicit conversions and associated warnings. For instance:

cpp

std::vector<int> vec(42uz);

std::vector<int> vec(42uz);

This precise typing ensures safer array sizing and indexing operations across platforms, where size_t may differ from built-in unsigned integers. C++23 also clarifies and reinforces support for nested inline namespaces within enclosing inline namespaces, enhancing library evolution through transitive visibility for versioned APIs. Inline declarations propagate through nesting levels, allowing unqualified access to inner members as if declared in the outer scope, which simplifies maintaining backward-compatible hierarchies without altering lookup rules. This builds on foundations to facilitate cleaner, scalable namespace organization in large projects.

Compile-Time Improvements

C++23 introduces several enhancements to compile-time evaluation, enabling more sophisticated computations during compilation while maintaining runtime efficiency. These improvements build on prior standards by expanding the scope of constant expressions, allowing developers to perform operations that were previously deferred to runtime. Key advancements include conditional branching based on evaluation context, mechanisms for ensuring immediate evaluation in functions, and extended support for containers in constant expressions. One significant addition is the if consteval construct, which permits conditional compilation depending on whether a function is invoked in a constant evaluation context. This feature addresses limitations in distinguishing between compile-time and runtime invocations within constexpr and consteval functions, reducing reliance on the std::is_constant_evaluated() function and enabling more flexible code that behaves differently at compile time versus runtime. For example, the following code snippet demonstrates its use:

cpp

consteval int compute(int x) { if consteval { return x * 2; // Optimized for [compile-time](/page/Compile_time) } else { return x * 3; // Fallback for runtime } }

consteval int compute(int x) { if consteval { return x * 2; // Optimized for [compile-time](/page/Compile_time) } else { return x * 3; // Fallback for runtime } }

This allows for compile-time-only paths that might involve heavier computations, such as those simulating dynamic allocation, without affecting runtime . To facilitate immediate functions—those required to evaluate at —C++23 introduces parenthesized auto(x) initialization. This syntax creates a prvalue from x as if it were passed by value to a function, ensuring the expression is suitable for constant evaluation without odr-use () violations. It is particularly useful in expressions or function definitions where guarantees are needed. Consider this example for a compile-time square function:

cpp

constexpr auto square = [](auto(x)) { return x * x; }; static_assert(square(5) == 25);

constexpr auto square = [](auto(x)) { return x * x; }; static_assert(square(5) == 25);

This mechanism simplifies writing immediate functions by avoiding explicit casting or temporary materialization, promoting safer and more intuitive compile-time programming. C++23 builds on C++20's support for using standard library containers like std::vector and std::string in constant expressions under the transient allocation model, where any simulated dynamic allocation must be deallocated within the same constant evaluation. This enables temporary use of these containers for compile-time computations, such as generating data, but they cannot persist beyond the evaluation (persistent allocation is proposed for future standards). For instance, a constexpr function can use a vector internally to compute a value:

cpp

constexpr int fib(int n) { std::vector<int> v{0, 1}; for (int i = 2; i < n; ++i) { v.push_back(v[i-1] + v[i-2]); } return v.back(); } static_assert(fib(6) == 8);

constexpr int fib(int n) { std::vector<int> v{0, 1}; for (int i = 2; i < n; ++i) { v.push_back(v[i-1] + v[i-2]); } return v.back(); } static_assert(fib(6) == 8);

This capability supports advanced metaprogramming, such as parsing or generating lookup tables at compile time, while adhering to the transient model to avoid actual runtime allocation. Similar support applies to std::string for compile-time string operations like concatenation. To enhance portability in internationalized code, C++23 mandates UTF-8 as the portable source file encoding, ensuring compilers accept UTF-8 input by default. This change standardizes handling of Unicode characters in source code, reducing encoding-related portability issues across platforms and compilers. It affects literal encoding and execution character sets, making it easier to write code with non-ASCII identifiers and strings without vendor-specific flags. Additionally, C++23 allows static operator[] as a member function, enabling array-like subscript access in constant expressions without requiring an object instance or triggering odr-use. This is valuable for stateless classes or constexpr contexts where traditional non-static operators would necessitate unnecessary object creation. For example:

cpp

struct ArrayView { static constexpr int operator[](size_t i) { return data[i]; } static constexpr int data[5] = {1, 2, 3, 4, 5}; }; static_assert(ArrayView::operator[](2) == 3);

struct ArrayView { static constexpr int operator[](size_t i) { return data[i]; } static constexpr int data[5] = {1, 2, 3, 4, 5}; }; static_assert(ArrayView::operator[](2) == 3);

This feature streamlines compile-time data access patterns, particularly in template metaprogramming, by treating the operator as a static utility without instance overhead.

Attribute and Diagnostic Features

C++23 introduces several attributes and diagnostic enhancements designed to provide programmers with finer control over compiler optimizations and improved error reporting during compilation. These features build on prior standards by standardizing optimization hints and refining how diagnostics are generated and displayed, particularly in template contexts. The [[assume]] attribute, for instance, enables developers to inform the compiler of assumed conditions without runtime evaluation, facilitating aggressive optimizations while introducing undefined behavior if the assumption proves false. Similarly, the [[likely]] and [[unlikely]] attributes, now applicable in broader contexts, offer branch prediction hints to guide code generation for performance-critical paths. The [[assume]] attribute allows a to assert that a given constant expression evaluates to true at a specific point in the code, enabling the compiler to optimize accordingly without verifying the condition at runtime. For example, consider the following code snippet where the assumption optimizes away unnecessary checks:

int process_positive(int x) { [[assume(x > 0)]]; return x * 2; // Compiler can assume x > 0, potentially simplifying operations }

int process_positive(int x) { [[assume(x > 0)]]; return x * 2; // Compiler can assume x > 0, potentially simplifying operations }

If execution reaches a point where the assumed expression is false, the behavior is undefined, placing the responsibility on the to ensure correctness. This feature standardizes compiler-specific extensions like MSVC's __assume and is particularly useful in performance-sensitive algorithms where guarantees certain invariants. Branch prediction hints are provided by the [[likely]] and [[unlikely]] attributes, which advise the on the expected frequency of paths to improve and cache utilization. These attributes can be applied to labels, statements, or if statements, with [[likely]] indicating a path that is anticipated to be taken most often and [[unlikely]] the opposite. An illustrative example is handling in a function:

void handle_request(bool error) { if ([[unlikely]](error)) { // Rare error path: compiler may place this code out-of-line log_error(); return; } // Common success path process_data(); }

void handle_request(bool error) { if ([[unlikely]](error)) { // Rare error path: compiler may place this code out-of-line log_error(); return; } // Common success path process_data(); }

By hinting at branch probabilities, these attributes help generate more efficient , especially in loops or conditionals with skewed distributions, though their impact depends on the compiler's implementation. Diagnostics in C++23 see enhancements through clarifications to static_assert, particularly in how messages are reported within template instantiations and dependent contexts. Previously ambiguous behaviors in templates are now well-defined, allowing static_assert declarations to trigger diagnostics more reliably even when the assertion is conditionally evaluated. This includes support for attaching contextual notes to error messages, improving readability for complex template errors. For instance:

template<typename T> void check_type() { static_assert(sizeof(T) == 4, "T must be a 32-bit type"); // Now reliably emits in dependent contexts }

template<typename T> void check_type() { static_assert(sizeof(T) == 4, "T must be a 32-bit type"); // Now reliably emits in dependent contexts }

Such improvements aid authors in providing informative compile-time feedback without relying on non-standard extensions. In response to feedback from national bodies during the standardization process, C++23 reverts the of compound assignment operators on volatile-qualified objects, restoring their original semantics for compatibility with embedded systems and hardware-interfacing . This decision addresses concerns that the would break legacy in domains like device drivers, where volatile ensures memory operations are not optimized away. The affected operators, such as += and -= on volatile lvalues, now behave as before, performing a read-modify-write sequence atomically with respect to the . This reversion maintains support for low-level programming without introducing new undefined behaviors.

Library Features

Modules and Import Support

C++23 advances the modules feature originally introduced in C++20 by standardizing support for the entire as a module, enabling more efficient and encapsulated code organization without relying on traditional header inclusions. This integration resolves lingering issues from the earlier Modules Technical Specification, such as inconsistent behaviors and limited exposure, providing a production-ready mechanism for . Modules promote faster build times by compiling interface information once and reusing it, while reducing macro-related side effects and name collisions inherent in header files. A major addition in C++23 is the named module std, accessible via import std;, which exposes all declarations within namespace std from C++ standard headers (e.g., std::vector from <vector>) and C wrapper headers (e.g., std::fopen from <cstdio>), along with global operators like ::operator new from <new>. This design excludes global namespace equivalents to prevent namespace pollution, offering a clean import path for new code. For legacy compatibility, the std.compat module, imported as import std.compat;, includes everything from std plus the corresponding global namespace functions (e.g., ::fopen), easing the transition for codebases that rely on C-style globals. These modules are defined in the C++23 standard to balance adoption and modernity, with minimal impact on compilation throughput due to modular optimizations. Module partitions enhance scalability by allowing a single named module to be divided into a primary interface unit and multiple partition interface units, where partitions can be internal (non-exported) for private implementation or interface partitions for shared components. This structure supports better encapsulation in large projects by isolating details within partitions that are not visible outside the module. The global module fragment, delimited by module; before the module declaration, permits inclusions of headers (e.g., system headers like <windows.h>) that remain visible to importers without being exported, facilitating compatibility with non-modular code. Complementing this, the private module fragment—declared with module :private; and restricted to the primary module interface unit—hides internal declarations and definitions from importers, further strengthening encapsulation by preventing unintended exposure of implementation specifics. Header units in C++23 provide a bridge for existing headers, allowing them to be imported directly as import <header-name>; without full rewriting into module syntax. This treats the header's content as a self-contained module unit, preserving macro definitions and inline functions while benefiting from module caching for repeated uses. C++23 refines header unit compatibility, improving integration with named modules and reducing parsing overhead in mixed header-module environments. Export mechanisms in C++23 offer refined handling of templates within modules, permitting template declarations and definitions to be exported via the module interface without requiring full instantiation in every importing unit, unlike traditional headers where definitions must often be visible at the point of use. This enables more efficient template distribution, as the module's binary interface includes necessary template information for instantiation on demand, addressing prior limitations in the Modules TS.

Ranges and Algorithms

C++23 introduces several enhancements to the Ranges library, building on the foundation laid in C++20 by standardizing additional views and algorithms from the Ranges Technical Specification (TS) while adding new functionality to improve and expressiveness in . These changes emphasize , better support for heterogeneous data, and efficient reduction operations, enabling more idiomatic and performant code for iterating and transforming sequences without unnecessary copies. The updates follow the prioritization outlined in the C++23 Ranges plan, which categorizes features into tiers based on maturity and utility, ensuring that core views and algorithms are fully integrated into the . One key addition is the family of fold algorithms, which provide flexible ways to reduce a range to a single value using a . The primary functions are std::ranges::fold_left and std::ranges::fold_right, which perform left-associative and right-associative folds, respectively, starting from an initial value. For example, std::ranges::fold_left applies the operation cumulatively from left to right, equivalent to the expression init op x1 op x2 op ... op xn, and is particularly useful for operations like summing or concatenating elements where order matters. These algorithms support both forwarding and input ranges, with overloads that deduce the initial value from the first element if not provided, and they reside in <algorithm> to align with general-purpose reductions rather than numeric-specific ones. Additionally, std::ranges::fold_left_with_iter allows specifying a starting for partial folds, enhancing control over the reduction process. This design addresses limitations in prior standards, such as the lack of guaranteed left-to-right evaluation in std::reduce, and promotes safer, more predictable computations in parallel contexts when combined with execution policies in future standards. The std::views::join view is another significant enhancement, allowing the flattening of a nested range of ranges into a single flat sequence. It takes a view of ranges—such as a vector of vectors—and produces a concatenated view where inner ranges are seamlessly iterated as if they were a continuous sequence, preserving the input range's category (e.g., input or random access). For instance, applying views::join to a range of strings yields a single stream of characters, useful for text processing or aggregating subcollections without materialization. This view requires the outer range to model input_range and each inner range to model input_range as well, with support for prvalue non-views through relaxed constraints to avoid unnecessary temporaries. An extension, std::views::join_with, inserts a between joined elements, such as commas in CSV-like data, further aiding tasks. These features stem from efforts to make nested data handling more composable, directly addressing common patterns in functional-style programming. Improvements to the zip view in C++23 enhance its utility for combining multiple heterogeneous ranges into , supporting variadic numbers of input views with better type deduction and proxy integration. The std::views::zip adaptor produces a view of tuple-like elements, where each holds the i-th element from each zipped range, stopping at the shortest range's end to prevent out-of-bounds access. Unlike earlier experimental versions, the C++23 implementation uses std::tuple for more than two ranges and std::pair for exactly two, ensuring compatibility with structured bindings and generic code; it also supports heterogeneous types by allowing arbitrary view arguments without common type requirements. This enables scenarios like parallel over disparate containers, such as zipping a vector of keys with a of values for operations. The design includes optimizations for proxy references in common views like transform, making it efficient for lazy pipelines. New range-based algorithms expand search capabilities, including std::ranges::find_last and its variants (find_last_if, find_last_if_not), which locate the last occurrence of a value or predicate-satisfying element in a range. These return an to the found position or std::ranges::dangling if none exists, supporting bidirectional and random-access ranges for efficiency. For example, std::ranges::find_last_if can identify the last even number in a sequence, complementing forward-only searches. Similarly, std::ranges::adjacent_find detects the first pair of consecutive elements satisfying a binary predicate, rangified from the legacy version to work with views and return a subrange or pair for easier chaining. These additions fill gaps in backward and pairwise searching, promoting more expressive code without manual reverse iteration. C++23 fully standardizes several features from the Ranges TS, notably std::views::zip and std::views::enumerate, integrating them as Tier 1 views for immediate usability. The enumerate view pairs each element with its zero-based index in a , facilitating indexed operations like mapping with position awareness, and models the same range category as its underlying view. This standardization ensures these adaptors are lightweight, composable, and free of the TS's experimental constraints, allowing seamless use in standard containers and algorithms.

Utilities and Formatting

C++23 introduces several enhancements to the standard library's utilities, focusing on improved error handling, formatted output, associative containers, and management. These additions aim to provide more robust, type-safe, and efficient tools for common programming tasks, building on prior standards while addressing longstanding needs in text processing and data organization. One key addition is std::print and std::println, which offer type-safe formatted output directly to like stdout or stderr, avoiding the overhead of intermediate construction required by std::format. These functions use a printf-like syntax with compile-time checks for format specifiers, ensuring arguments match the placeholders. For instance, the code std::print("Value: {:d}\n", 42); outputs "Value: 42" followed by a , while std::println automatically appends a . This design supports output portably and integrates with the <print> header, providing a convenient alternative to std::cout for simple and . To improve error handling, C++23 standardizes std::expected<T, E>, a monadic type that encapsulates either a successful value of type T or an error of type E, akin to optional results in other languages. It supports operations like value_or to retrieve the value with a default on error, and or_else for error recovery, promoting functional-style error propagation without exceptions. Constructors allow in-place construction of the value or error, and it integrates with for generic usage. For example, a function might return std::expected<int, std::error_code>, enabling callers to handle or explicitly. This feature addresses the need for lightweight error handling in performance-critical code. Format string handling receives refinements through enhanced support in std::format, incorporating concepts for compile-time validation of user-defined formatters and better integration with standard types. Proposals extend formatting for ranges and tuples with customizable debug output. These changes leverage C++20's std::format foundation, adding specializations for library types like std::span and improving locale-aware formatting without altering core syntax. New associative containers std::flat_map and std::flat_set provide sorted, unique key-based storage using a contiguous underlying vector, offering faster iteration and smaller memory footprints compared to tree-based std::map and std::set for small-to-medium datasets. Elements are kept sorted by key, with insertion maintaining order via binary search, achieving O(log n) lookups and O(n log n) construction. Unlike traditional maps, they support reserving capacity to avoid reallocations, and provide views like keys() for key-only access. An example usage is std::flat_map<std::string, int> m; m.emplace("key", 42);, ideal for cache-friendly scenarios where iteration speed matters more than frequent insertions. Variants std::flat_multimap and std::flat_multiset allow duplicates. Time zone support in <chrono> is bolstered by std::chrono::zoned_time, which pairs a time_point with a time_zone for unambiguous local time representation, including automatic handling of ambiguities like daylight saving transitions. C++23 clarifies locale-dependent formatting for zoned times. This enables code like auto zt = zoned_time{current_zone(), sys_time{std::chrono::system_clock::now()}}; std::print("{:%F %T %Z}", zt); to output locale-aware dates with zone abbreviations, enhancing cross-platform date-time applications. Brief integration with ranges allows formatting sequences of times, as detailed elsewhere.

Multidimensional Arrays and Views

C++23 introduces std::mdspan, a non-owning multidimensional view that provides a multi-index over a contiguous sequence of objects in memory, enabling efficient representation of arrays with multiple without owning the underlying data. This class template is defined in the <mdspan> header and interprets the memory as a domain defined by extents in each , facilitating portable and performant access patterns in multidimensional data structures. The extents of an mdspan can be specified at compile time using std::extents, such as std::mdspan<int, std::extents<std::size_t, 3, 4>> view(arr);, which creates a view over a contiguous arr representing a 3-by-4 matrix. Dynamic extents are supported through the std::dynamic_extent , allowing runtime specification of sizes; for example, std::mdspan<float, std::dynamic_extent, std::dynamic_extent> dynamic_view(data, rows, cols); constructs a view with dimensions provided at runtime. Extents can mix static and dynamic specifications, such as std::mdspan<float, 20, std::dynamic_extent> mixed_view(data, num_cols);, where the first dimension is fixed at 20 while the second varies. Layout policies in std::mdspan control the mapping of multidimensional indices to linear memory offsets, with std::layout_right providing row-major order (last index varies fastest, as in C-style arrays) and std::layout_left providing column-major order (first index varies fastest, as in Fortran). These policies are specified as template parameters, e.g., std::mdspan<int, std::extents<std::size_t, 3, 4>, std::layout_right> row_major_view(arr);, ensuring compatibility with diverse hardware and numerical libraries. Integration with C++23's multidimensional subscript operator allows intuitive access like view[i][j], where the language feature (detailed in Core Syntax Enhancements) enables operator[] to accept multiple arguments, returning nested views for subsequent indexing. This syntax supports zero or more arguments in operator[] overloads, aligning mdspan access with familiar array notations while preserving and efficiency. In (HPC) and scientific computing, std::mdspan addresses the need for lightweight, non-owning views over large datasets, avoiding the overhead of full array copies and enabling performance portability across accelerators and CPUs without vendor-specific extensions. It facilitates kernel algorithms in domains like linear algebra and simulations by providing a standard interface for multidimensional indexing, reducing boilerplate and improving interoperability with libraries such as those in the Kokkos ecosystem.

Other Library Additions

C++23 introduces the <stacktrace> header as part of the diagnostics library, providing facilities to capture, store, and output information at runtime. The core class std::stacktrace represents a sequence of stack frames, obtained via std::stacktrace::current() to capture the current or constructed from an exception object for error handling. Each frame is described by std::stacktrace_entry, which includes the source file name, function name, and , enabling detailed output through for streams like std::cout. To support in ranges using s—building on the syntax introduced in C++20—std::generator is added to the . This class template generates a sequence of values on demand by suspending and resuming the returned from a generator function, integrating seamlessly with range-based algorithms via co_yield statements. For example, a generator can produce elements of type T or optionally std::optional<T> to signal completion, avoiding the need for custom types in common iterable scenarios. The <bit> header gains std::byteswap, a constexpr function that reverses the byte order of an value, aiding conversions in network protocols and without platform-specific code. It participates in overload resolution only for types and produces the same type as its argument, ensuring and compile-time evaluation where possible. Complementing this, std::ranges::views::as_rvalue (also known as std::views::as_rvalue) provides a range view adaptor that treats each element as an rvalue reference, equivalent to wrapping the range's iterators in std::move_iterator, to facilitate moving from containers in algorithms without explicit wrapping. For C compatibility and low-level string conversion, std::to_chars for integral types is made constexpr in C++23, enabling allocation-free, compile-time conversion of integers to character buffers in a specified base (, , or ). This update, per proposal P2291R3, ensures round-trip guarantees and locale independence, useful for embedded systems or performance-critical parsing without dynamic memory use.

Deprecations and Removals

Removed Language Features

In C++23, the ISO/IEC 14882 standard removed support for garbage collection interfaces that had been part of the language since , as these features were never implemented in major implementations and provided limited practical value. Specifically, the functions std::declare_reachable, std::undeclare_reachable, std::declare_no_pointers, std::undeclare_no_pointers, and std::get_pointer_safety from the <gc> header were eliminated, along with the std::pointer_safety enumeration and the __STDCPP_STRICT_POINTER_SAFETY__ macro. Additionally, core language wording related to strict pointer , which aimed to support conservative garbage collectors by guaranteeing pointer validity, was excised. This removal stemmed from the absence of any known or support for strict pointer over the past decade, with all major implementations defaulting to relaxed mode, rendering the feature obsolete and unhelpful for real-world garbage collection in virtual machines or custom allocators. Another language cleanup in C++23 involved the elimination of non-encodable literals and multicharacter literals, which were previously allowed but led to inconsistent behavior across implementations due to varying execution character set assumptions. Under the , attempts to form such literals, like L'non-encodable-char' where the character cannot be represented in the execution set, or L'abc' with multiple characters, now result in ill-formed code, requiring a diagnostic from the . This change simplifies the and reduces portability issues without impacting common use cases, as narrow character literals or user-defined literals serve equivalent purposes. C++23 also removed support for concatenating mixed wide string literals, such as u"q" U"p", which previously allowed inconsistent combinations of encoding prefixes (e.g., u8, u, U, L). These are now ill-formed, promoting consistent encoding practices and aligning with enhanced Unicode support in the standard. This cleanup addresses ambiguities in literal formation without affecting typical string usage. These removals contribute to streamlining the C++ core language by excising unused or contradictory provisions accumulated from prior standards, particularly those in Annex D (compatibility) that no longer align with modern hardware and implementation realities. For instance, certain legacy rules conflicting with cache-coherent multiprocessor systems were pruned to focus the specification on practical, widely-adopted behaviors, thereby reducing complexity and specification bloat without breaking existing codebases. The overall rationale emphasizes enhancing maintainability and clarity for developers and implementers, prioritizing features with demonstrated utility over vestigial elements.

Deprecated Library Components

In C++23, the standard library deprecates several legacy components to promote safer, more efficient alternatives, continuing a process started in previous standards. The <codecvt> header, introduced in C++11 to support conversions between different character encodings via facets like std::codecvt_utf8, remains deprecated as established in C++17. This deprecation stems from the header's underspecification, absence of robust error handling, and potential security vulnerabilities in conversion operations. Although not removed in C++23, it is slated for elimination in C++26, with implementers advised to maintain in the interim. Developers are encouraged to migrate to third-party libraries such as ICU for comprehensive handling or leverage emerging standard facilities like std::text_encoding for basic encoding needs. C++23 newly deprecates std::aligned_storage and std::aligned_union from the <type_traits> header, which provided types for aligned storage allocation but are redundant with the more flexible std::align algorithm and modern alignment specifications introduced in C++11. These deprecations encourage use of aligned allocation functions and structured bindings for similar purposes, reducing reliance on utility classes that overlap with core language features. Additionally, the member std::numeric_limits::has_denorm is deprecated in C++23, as its behavior was underspecified for certain floating-point models and rarely used in practice. Developers should instead query support via std::numeric_limits::tininess_before or implementation-specific checks, aligning with updates to floating-point semantics in the standard. For migration from these deprecated components, C++23 emphasizes modern utilities like std::format for string and I/O operations that once relied on legacy encoding or shuffling patterns, offering type-safe and locale-aware formatting without the pitfalls of older facilities. Comprehensive tooling support in compilers flags these deprecations, facilitating gradual upgrades in large codebases.

Compiler and Tooling Support

Major Compiler Implementations

GCC provides robust support for C++23, with core language features largely implemented starting in GCC 14, released in May 2024. Substantial completion, including advanced modules and multidimensional array support via std::mdspan, arrived in GCC 15.1 (April 2025), with further enhancements in GCC 15.2 (August 2025). This version enhances experimental modules with built-in std and std.compat modules, alongside library additions like std::flat_map and std::flat_set. Clang, part of the LLVM project, began progressive implementation of C++23 features from Clang 13 in 2021, reaching substantial coverage by Clang 16 in 2023. Full support, enabling the -std=c++23 flag for comprehensive compliance, was achieved in 18, released in September 2024. This includes modules import syntax and standard library integrations, with ongoing refinements in subsequent point releases. Microsoft Visual C++ (MSVC) introduced C++23 support in 2022 version 17.10, released in May 2024, via the /std:c++23 compiler flag. By mid-2025, in version 17.14 (May 2025), key features such as modules and the <print> header with std::print and std::println became fully available, along with support for new lambda attributes, if consteval, and static operators, aligning with ISO conformance goals. Other compilers exhibit varying degrees of adoption. oneAPI DPC++/C++ Compiler version 2025.0, leveraging the 19 frontend, provides full C++23 support across host and device code. HPC SDK compilers, formerly PGI, offer complete C++23 compatibility in release 25.9 (September 2025), including GPU-accelerated elements. EDG-based frontends, used in tools like MSVC's IntelliSense, deliver partial C++23 implementation, covering core language but lagging on modules. To invoke C++23 mode, compilers typically require explicit flags: g++ -std=c++23 for GCC, clang++ -std=c++23 for Clang, and cl /std:c++23 for MSVC. These enable the standard's features while maintaining backward compatibility with prior modes.

Conformance Status

As of November 2025, major C++ compilers have achieved near-complete conformance to the C++23 core language features, with GCC 15.2, Clang 21, and MSVC in Visual Studio 2022 version 17.14 supporting approximately 95-100% of the standard's language requirements, though minor lags persist in niche areas such as nested inline namespaces and certain constexpr extensions. For instance, Clang 21 provides full implementation of core features like explicit object parameters (P0847R7) and if consteval (P1938R3), while MSVC 17.14 has completed support for declaration order layout (P1847R4) and removed garbage collection provisions (P2186R2). These advancements stem from ongoing efforts by the LLVM, GCC, and Microsoft teams to align with the ISO/IEC 14882:2024 standard finalized in 2023. Library conformance shows more variability, with the std module reaching about 95% implementation across vendors—fully supported in Clang's libc++ 21 for import std usage, enabling modular standard library access without traditional includes. The multidimensional array view std::mdspan is complete in all major libraries, including libstdc++ (GCC 15.2), libc++ (Clang 21), and MSVC STL, facilitating efficient multidimensional data handling in scientific computing. In contrast, the stacktrace library support varies by platform and implementation; it is fully available on with GCC and but remains partial or platform-dependent on Windows with MSVC due to debugging API integrations. Known gaps include partial support for coroutine generators like std::generator in versions prior to MSVC 17.14 updates, where full resumption and yield mechanics are now stable, though core coroutines (P0912R5) are implemented since VS 2019. source file encoding (P2295R6), mandating portable support, is fully implemented across all major compilers, ensuring consistent handling in . Conformance is verified through ISO WG21 test suites and community-maintained resources like cppreference's compiler support tables, which track feature adoption via vendor reports and automated testing. Looking ahead, full C++23 conformance is anticipated across all major implementations by mid-2026, coinciding with early previews of C++26 features, as vendors prioritize ABI stability and library completeness in upcoming releases like GCC 16 and 22.

References

Add your contribution
Related Hubs
Contribute something
User Avatar
No comments yet.