C++26 is the informal name for the version of the International Organization for Standardization (ISO) and International Electrotechnical Commission (IEC) 14882 standard for the C++ programming language that follows C++23. The current working draft of this version is N5008.[1]

An ISO C++ committee chair Herb Sutter has characterized the revision as the most impactful release since C++11, asserting that this revision is likely to change the way programmers develop software in C++. The revision marks the pivotal evolution for the language's compile-time and safety capabilities.

The revision included major additions, such as contracts, first-class reflection, and the new asynchronous model.

[TODO: all sources and examples came straight from cppreference]

Core Language Features

edit

Most of the newly introduced language features are designed to alleviate the reliance on verbose idioms, workarounds, and excessive boilerplate code. These features offer direct and standardized constructs in place of previously ad hoc solutions while expanding the expressiveness and flexibility of the language.

Runtime Safety

edit

Reading from uninitialized automatic variables now yields erroneous behavior, a formally defined category. The new standard specifies how they behave rather than treating them as undefined behavior.

The new attribute [[indeterminate]] restores the undefined behavior that was implicitly introduced until C++26. It may make compilers consider a code path reading an indeterminate value unreachable.

void f(int);
 
void g()
{
    int x [[indeterminate]]; // indeterminate value
    int y;                   // erroneous value
 
    f(x); // undefined behavior
    f(y); // erroneous behavior
}
 
struct T
{
    T() {}
    int x;
};
 
void h(T a [[indeterminate]], T b)
{
    f(a.x); // undefined behavior when called below
    f(b.x); // erroneous behavior when called below
}
 
h(T(), T());

Trivial Relocation

edit

TODO: source wg21.link/p2786r13

A new operation named relocation is defined as the act of moving an object from one memory ___location to another. The operation is akin to ending the lifetime of the source object, but not necessarily calling the destructor of the source object, and starting the lifetime of a new object at a new ___location. For most types that support move construction and destruction, a relocation can be accomplished by calling the move constructor of the target object from the source object, followed by invoking the destructor of the source object.

More importantly, trivial relocation is mostly used operation defined as a relocation accomplished by performing a bitwise copy (such as std::memcpy) of the source object's object representation to a new memory ___location that ends the lifetime of that source object.

Trivial relocation can be used to optimize std::vector moving elements into a new buffer when the allocator does not implement construct and destroy.

Extensions to Compile-time Programming

edit

Binary Resource Inclusion

edit

Previously, programmers have been using softwares such as xxd or python scripts to generate static array data from a binary resource file. The new preprocessor directive #embed now allows for direct binary resource inclusion to the executable whether it be icons, scripts, or images.

const unsigned char icon_display_data[] = {
    #embed "art.png"
};

User-defined Static Assertion Messages

edit

The error message of a static_assert could now be any constant expression producing a sequence of characters rather than be limited to string literals. This would allow libraries doing work at compile-time be able to better diagnose the exact problem.

consteval std::string_view get_error_msg();

template <typename T>
void check_add(T a, T b)
{
    static_assert(std::is_integral_v<T>, get_error_msg()); 
}

Promotion to Static Data

edit

New functions std::define_static_array, std::define_static_string, and std::define_static_object promote objects to static data.

The new transient allocation introduced in C++20 are too strict because it does not allow the allocated data from the new to persist at runtime:

consteval std::vector<int> get_numbers() { /* ... */ }
constexpr auto numbers = get_numbers(); // error

This new feature allows the data of get_numbers() to persist at runtime at the cost of increasing the binary size.

constexpr auto numbers = std::define_static_array(get_numbers()); // ok

The function std::define_static_array returns a std::span object instead of std::vector.

Constexpr References and Structured Bindings

edit

TODO: add

Constant Evaluated Blocks

edit

Newly introduced consteval blocks that can be inserted in any declaration. This is needed to work with the new injected declaration feature.

Relaxing Constant Evaluation Restrictions

edit

Each new standard loosens the restrictions of the evaluation of the constant evaluation such as dynamic allocation and dynamic polymorphism in C++20. In C++26, this continues to relax the restrictions of constant evaluations.

Since C++26, the constant evaluation now allows:

  • cast from void* to T* such that the pointer must be either a null pointer value or an address pointing to an object whose type is similar to T,
  • placement new,
  • caught, and
  • virtual inheritance.

Extensions to Templates

edit

Variable template and concepts as template parameters

edit

The template-template parameter now accepts variable templates and concepts.

template <template <typename T> concept C, template <typename T> auto V>
struct S {};

template <typename T>
concept Concept = true;

template <typename T>
constexpr auto Var = 42;

S<Concept, Var> s;

Structured Binding Pack

edit

Structured binding pack is a new kind of pack that allows objects to be decomposed into packs. However, these packs can only be declared in a template definition, like in the function template.

template <typename Tuple>
constexpr auto into_tuple(Tuple& t) {
  auto& [...args] = t;
  return std::tie(args...);
}

Pre-C++26 code involved boilerplates to construct a tuple from any aggregate object to mimic the same behavior. This behavior is used as a workaround to iterate over members of a struct.

Pack Indexing

edit

Every element of the pack can now be accessed through pack indexing with the syntax pack...[Index].

Expansion Statements

edit

This is a new kind of statement, which is just a template expansion of the body mimicking the behavior of a range-based for loop. This is another way to iterate over members of a struct and any tuple-like object instead of idiomatic workarounds.

template <typename Tuple>
constexpr auto print_tuple(const Tuple& tup) {
  template for (const auto& item : tup)
    std::println("{}", item);
}

The same behavior can be achieved without expansion statements, but with a different code and also involves pack expansion:

template <typename Tuple>
constexpr auto print_tuple(const Tuple& tup) {
  std::apply([](const auto&... items) {
    (std::println("{}", items), ...);
  }, tup);
}

Other Template Features

edit
  • Variadic friends.
  • Ordering of constraints involving fold expressions.

Reflection

edit

TODO: reference wg21.link/p2996

Reflection Operator and Splicing

edit

Metafunctions

edit

Injected Declarations

edit

Annotations

edit

Most declarations can now be attached with annotations, which are just values associated with that declaration. Annotations are different from attributes because they allow arbitrary constants to be attached, making them customizable to programs, unlike attributes. This allows for bridging the communication between the library API and the user.

enum class [[=custom::enum_flag]] Toggle {
  Off, On
};

struct [[=custom::debug]] Person {
  [[=custom::rename("full name")]] std::string full_name;
  int age;
};

The annotations have no initial meaning unless some implementations use those annotations to identify some characteristics and features.

Other Language Features

edit
  • Unevaluated strings.
  • Adding @, $, and ` to the basic character set.
  • Placeholder variables with no name.
  • Attributes for structured bindings.
  • = delete("reason");
  • Structured binding declaration as a condition.
  • Deleting a pointer to an incomplete type should be ill-formed.
  • constexpr structured bindings and references to constexpr variables.
  • Oxford variadic comma, i.e. "Deprecate ellipsis parameters without a preceding comma. The syntax (int...) is incompatible with C, detrimental to C++, and easily replaceable with (int, ...)."[3]
  • Removing deprecated array comparisons.

Standard Library Features

edit
  • Hashing support for std::chrono value classes
  • std::is_within_lifetime
  • Native handles in file streams
  • Interfacing string streams with std::string_view
  • Interfacing std::bitset with std::string_view
  • More constexpr for <cmath> and <complex>
  • Adding the new 2022 SI prefixes on ratios: std::quecto, std::ronto, std::ronna, and std::quetta
  • std::copyable_function
  • std::submdspan()
  • <contracts>: Design-by-contract support
  • <debugging>: Debugging support and language features to aid debugger programs
  • <hazard_pointer>: Hazard pointers for threading
  • <hive>: Hive data structure support which reuses erased elements' memory
  • <inplace_vector>: In-place vector data structure support, which is a resizable, fixed capacity, inplace contiguous array
  • <linalg>: A free function linear algebra interface based on the BLAS
  • <meta>: Compile-time reflection support
  • <rcu>: Support for safe reclamation read-copy-update mechanism
  • <simd>: Data-parallel access (Single instruction, multiple data or SIMD) support
  • <text_encoding>: Support for accessing the IANA Character Sets registry
  • Support for annotations to be used in reflection which behave differently from the existing attribute system used by the compiler
  • Added tuple protocol to std::complex
  • views::concat
  • Concatenation of strings and string views
  • std::ranges::generate_random
  • Printing blank lines with std::println()
  • std::formatter<std::filesystem::path>
  • Saturation arithmetic with, among others, std::add_sat, std::div_sat
edit

References

edit
  1. ^ "Working Draft, Standard for Programming Language C++" (PDF). Open Standards. ISO/IEC. 2025-03-15.
  2. ^ "Contract assertions (since C++26) - cppreference.com". en.cppreference.com. Retrieved 2025-03-09.
  3. ^ "P3176R1: The Oxford variadic comma". eisenwave.github.io. Retrieved 2024-12-09.