Skip to content

Latest commit

 

History

History
1558 lines (1336 loc) · 61.7 KB

wg21-status.org

File metadata and controls

1558 lines (1336 loc) · 61.7 KB

C++ 23 Status Report

C++ 23 Status Report

This is a summary of what has already been approved for C++23 or has been forwarded to plenary for final vote, which means consensus and is unlikely to not pass.

All of the quoted text and example code is from the papers linked in the headings by the authors of the papers.

I’ve selected text to describe the purpose of the paper, usually quoting the abstract, and taking illustritive code that the paper provides to show the intent. Please see the linked papers for details.

The “Major” Section is my judgement, influenced by a few friends, about what I thought was most interesting or important in C++ 23.

Major (in my opinion)

9 papers total

P0323 std::expected (Vicente Botet, JF Bastien)

Utility class to represent expected object: wording and open questions.

expected<double, errc> safe_divide(double i, double j) {
    if (j == 0)
        return unexpected(arithmetic_errc::divide_by_zero); // (1)
    else
        return i / j; // (2)
}
expected<double, errc> f1(double i, double j, double k) {
    auto q = safe_divide(j, k);
    if (q)
        return i + *q;
    else
        return q;
}

LWG, C++23, IS, lwg-fullreview, B3: Addition, large, plenary-approved

P0798 Monadic operations for std::optional (Sy Brand)

std::optional will be a very important vocabulary type in C++17 and up. Some uses of it can be very verbose and would benefit from operations which allow functional composition. I propose adding map, and_then, and or_else member functions to std::optional to support this monadic style of programming.

Example

std::optional<image> get_cute_cat(const image& img) {
    return crop_to_cat(img)
        .and_then(add_bow_tie)
        .and_then(make_eyes_sparkle)
        .map(make_smaller)
        .map(add_rainbow);
}

Quote

Here is a list of programming languages which have a optional-like type without a monadic interface or syntactic sugar:

  • C++
  • I couldn’t find any others

Monadic interface

map
map applies a function to the value stored in the optional and returns the result wrapped in an optional. If there is no stored value, then it returns an empty optional.
and_then
and_then is like map, but it is used on functions which may not return a value.
or_else
or_else returns the optional if it has a value, otherwise it calls a given function. This allows you do things like logging or throwing exceptions in monadic contexts:

LWG, SG14, C++23, IS, small, plenary-approved

P0847 Deducing this (Gašper Ažman, Sy Brand, Ben Deane, Barry Revzin)

We propose a new mechanism for specifying or deducing the value category of an instance of a class — in other words, a way to tell from within a member function whether the object it’s invoked on is an lvalue or an rvalue; whether it is const or volatile; and the object’s type.

A non-static member function can be declared to take as its first parameter an explicit object parameter, denoted with the prefixed keyword this. Once we elevate the object parameter to a proper function parameter, it can be deduced following normal function template deduction rules:

Example

struct X {
    void foo(this X const& self, int i);

    template <typename Self>
    void bar(this Self&& self);
};

struct D : X {};

void ex(X& x, D const& d) {
    x.foo(42);     // 'self' is bound to 'x', 'i' is 42
    x.bar();       // deduces Self as X&, calls X::bar<X&>
    move(x).bar(); // deduces Self as X, calls X::bar<X>

    d.foo(17); // 'self' is bound to 'd'
    d.bar();   // deduces Self as D const&, calls X::bar<D const&>
}

Example

vector captured = {1, 2, 3, 4};
[captured](this auto&& self) -> decltype(auto) {
  return forward_like<decltype(self)>(captured);
}

[captured]<class Self>(this Self&& self) -> decltype(auto) {
  return forward_like<Self>(captured);
}

CWG, C++23, plenary-approved

P1132 out_ptr - a scalable output pointer abstraction (JeanHeyd Meneide, Todor Buyukliev, Isabella Muerte)

out_ptr is an abstraction to bring both C APIs and smart pointers back into the promised land by creating a temporary pointer-to-pointer that updates the smart pointer when it destructs.

Example

error_num c_api_create_handle(int seed_value, int** p_handle);
void      c_api_delete_handle(int* handle);

struct resource_deleter {
    void operator()(int* handle) { c_api_delete_handle(handle); }
};

std::unique_ptr<int, resource_deleter> resource(nullptr);
error_num err = c_api_create_handle(24, std::out_ptr(resource));
if (err == C_API_ERROR_CONDITION) {
    // handle errors
}
// resource.get() the out-value from the C API function

LWG, C++23, IS, plenary-approved

P1206 ranges::to: A function to convert any range to a container (Corentin Jabot, Eric Niebler, Casey Carter)

We propose a function to copy or materialize any range (containers and views alike) to a container.

Before/After Table

Before:

std::map<int, widget>                           map = get_widgets_map();
std::vector<typename decltype(map)::value_type> vec;
vec.reserve(map.size());
ranges::move(map, std::back_inserter(vec));

After:

auto vec = get_widgets_map() | ranges::to<vector>

LWG, ranges, C++23, IS, plenary-approved

P2286 Formatting Ranges (Barry Revzin)

[LWG3478] addresses the issue of what happens when you split a string and the last character in the string is the delimiter that you are splitting on. One of the things I wanted to look at in research in that issue is: what do other languages do here?

For most languages, this is a pretty easy proposition. Do the split, print the results. This is usually only a few lines of code.

Python

print("xyx".split("x"))
['', 'y', '']

Java

import java.util.Arrays;

class Main {
  public static void main(String args[]) {
    System.out.println("xyx".split("x"));
    System.out.println(Arrays.toString("xyx".split("x")));
  }
}
[Ljava.lang.String;@76ed5528
[, y]

rust

use itertools::Itertools;

fn main() {
    println!("{:?}", "xyx".split('x'));
    println!("[{}]", "xyx".split('x').format(", "));
    println!("{:?}", "xyx".split('x').collect::<Vec<_>>());
}
Split(SplitInternal { start: 0, end: 3, matcher: CharSearcher { haystack: "xyx", finger: 0, finger_back: 3, needle: 'x', utf8_size: 1, utf8_encoded: [120, 0, 0, 0] }, allow_trailing_empty: true, finished: false })
[, y, ]
["", "y", ""]

C++

#include <iostream>
#include <string>
#include <ranges>

int main() {
    // need to predeclare this because we can't split an rvalue string
    std::string s     = "xyx";
    auto        parts = s | std::views::split('x');

    std::cout << "[";
    char const* delim = "";
    for (auto part : parts) {
        std::cout << delim;
        // this finally works
        for (char c : part) {
            std::cout << c;
        }
        delim = ", ";
    }
    std::cout << "]\n";
}
[, y, ]

lib fmt

#include <ranges>
#include <string>
#include <fmt/ranges.h>

int main() {
    std::string s = "xyx";
    auto parts = s | std::views::split('x');

    fmt::print("{}\n", parts);
    fmt::print("<<{}>>\n", fmt::join(parts, "--"));
}
[[], ['y'], []]
<<[]--['y']--[]>>

LWG, ranges, C++23, tentatively-ready-for-plenary, IS, B3: Addition

P2465 Standard Library Modules std and std.all (Stephan T. Lavavej, Gabriel Dos Reis, Bjarne Stroustrup, Jonathan Wakely)

Header files are a major source of complexity, errors caused by dependencies, and slow compilation. Modules address all three problems, but are currently hard to use because the standard library is not offered in a module form. This note presents logical arguments and a few measurements that demonstrates that import std of a module std presenting all of the standard library can compile many times faster than plain old #include <iostream>.

As adopted

This paper provides Standardese for two named modules: std and std.compat.

import std; imports everything in namespace std from C++ headers (e.g. std::sort from <algorithm>) and C wrapper headers (e.g. std::fopen from <cstdio>). It also imports ::operator new etc. from <new>.

import std.compat; imports all of the above, plus the global namespace counterparts for the C wrapper headers (e.g. ::fopen).

CWG, LWG, straw-poll, C++23, tentatively-ready-for-plenary, IS, modular-standard-library, large

P2093 Formatted output (Victor Zverovich)

A new I/O-agnostic text formatting library was introduced in C++20 ([FORMAT]). This paper proposes integrating it with standard I/O facilities via a simple and intuitive API achieving the following goals:

  • Usability
  • Unicode support
  • Good performance
  • Small binary footprint

Before/After Table

Before:

std::cout << std::format("Hello, {}!", name);

After:

std::print("Hello, {}!", name);

LWG, C++23, tentatively-ready-for-plenary, IS, B3: Addition

P2128 Multidimensional subscript operator (Corentin Jabot, Isabella Muerte, Daisy Hollman, Christian Trott, Mark Hoemmen)

We propose that user-defined types can define a subscript operator with multiple arguments to better support multi-dimensional containers and views.

Before

template <class ElementType, class Extents>
class mdspan {
    template <class... IndexType>
    constexpr reference operator()(IndexType...);
};
int main() {
    int  buffer[2 * 3 * 4] = {};
    auto s                 = mdspan<int, extents<2, 3, 4>>(buffer);
    s(1, 1, 1)             = 42;
}

After

template <class ElementType, class Extents>
 class mdspan {
    template <class... IndexType>
    constexpr reference operator[](IndexType...);
};
int main() {
    int  buffer[2 * 3 * 4] = {};
    auto s                 = mdspan<int, extents<2, 3, 4>>(buffer);
    s[1, 1, 1]             = 42;
}

CWG, C++23, plenary-approved

Core Working Group Proposals

constexpr

5 Papers

P0533 constexpr for <cmath> and <cstdlib> (Edward J. Rosten, Oliver J. Rosten)

We propose simple criteria for selecting functions in <cmath> which should be declared constexpr. There is a small degree of overlap with <cstdlib>. The aim is to transparently select a sufficiently large portion of <cmath> in order to be useful but without placing too much burden on compiler vendors.

Example

constexpr int foo(float x) {
int a{}; int* pa{&a};
std::frexpr(x, pa);
return a;
}

constexpr int i{foo(0.5f)}.

CWG, LWG, C++23, IS, B3: Addition, medium, plenary-approved, constexpr

P2448 Relaxing some constexpr restrictions (Barry Revzin)

There are two rules about constexpr programming that make code ill-formed or ill-formed (no diagnostic required) when functions or function templates are marked constexpr that might never evaluate to a constant expression. But… so what if they don’t? The goal of this paper is to stop diagnosing problems that don’t exist.

CWG, straw-poll, C++23

P1938 if consteval (Barry Revzin, Daveed Vandevoorde, Richard Smith)

We propose a new form of if statement which is spelled:

if consteval { }

Example

consteval int f(int i) { return i; }

constexpr int g(int i) {
    if consteval {
        return f(i) + 1; // ok: immediate function context
    } else {
        return 42;
    }
}

consteval int h(int i) {
    return f(i) + 1; // ok: immediate function context
}

CWG, LWG, C++23, plenary-approved

P2242 Non-literal variables (and labels and gotos) in constexpr functions (Ville Voutilainen)

This paper proposes to strike the restriction that a constexpr function cannot contain a definition of a variable of non-literal type (or of static or thread storage duration), or a goto statement, or an identifier label. The rationale is briefly that the mere presence of the aforementioned things in a function is not in and of itself problematic; we can allow them to be present, as long as constant evaluation doesn’t evaluate them.

Example

template <typename T>
constexpr bool f() {
    if (std::is_constant_evaluated()) {
        // ...
        return true;
    } else {
        T t;
        // ...
        return true;
    }
}
struct nonliteral {
    nonliteral();
};
static_assert(f<nonliteral>());

CWG, C++23, plenary-approved

P2280 Using unknown references in constant expressions (Barry Revzin)

template <typename T, size_t N>
constexpr auto array_size(T (&)[N]) -> size_t {
    return N;
}

void check(int const (&param)[3]) {
    int            local[] = {1, 2, 3};
    constexpr auto s0      = array_size(local); // ok
    constexpr auto s1      = array_size(param); // error
}

The proposal is to allow all these cases to just work. That is, if during constant evaluation, we run into a reference with unknown origin, this is still okay, we keep going. Similarly, if we run into a pointer with unknown origin, we allow indirecting through it.

CWG, straw-poll, C++23

Text Translation

9 Papers

P1949 C++ Identifier Syntax using Unicode Standard Annex 31 (Steve Downey)

Adopt Unicode Annex 31 as part of C++ 23.

  • That C++ identifiers match the pattern (XID_Start + _ ) + XID_Continue*.
  • That portable source is required to be normalized as NFC.
  • That using unassigned code points be ill-formed.

In addition adopt this proposal as a Defect Report against C++ 20 and earlier.

Examples

bool 👷 = true; //  Construction Worker
bool 👷‍♀ = false; // Woman Construction Worker ({Construction Worker}{ZWJ}{Female Sign})
int= 0; //not valid
int 🕐 = 0;

int= 0; //not valid
int 💀 = 0;

int= 0; //not valid
int 👊 = 0;

int= 0; //not valid
int 🚀 = 0;

int= 0; //not valid
int 😀 = 0;

All Invalid After p1949

CWG, C++23, plenary-approved

P2071 Named universal character escapes (Tom Honermann, R. Martinho Fernandes, Peter Bindels, Corentin Jabot, Steve Downey)

A proposal to extend universal character names from hexadecimal sequences to include the official names and formal aliases of Unicode codepoints.

Before/After Table

Before:

// UTF-32 character literal with U+0100 {LATIN CAPITAL LETTER A WITH MACRON}
U'\u0100'
// UTF-8 string literal with U+0100 {LATIN CAPITAL LETTER A WITH MACRON} U+0300 {COMBINING GRAVE ACCENT}
u8"\u0100\u0300"

After:

U'\N{LATIN CAPITAL LETTER A WITH MACRON}' // Equivalent to U'\u0100'
u8"\N{LATIN CAPITAL LETTER A WITH MACRON}\N{COMBINING GRAVE ACCENT}" // Equivalent to u8"\u0100\u0300"

CWG, straw-poll, C++23, SG22

P2201 Mixed string literal concatenation (Jens Maurer)

String concatenation involving string-literals with encoding-prefixes mixing L”“, u8”“, u”“, and U”” is currently conditionally-supported with implementation-defined behavior. […] No meaningful use-case for such mixed concatenations is known.

This paper makes such mixed concatenations ill-formed.

CWG, C++23, plenary-approved

P2223 Trimming whitespaces before line splicing (Corentin Jabot)

We propose to make trailing whitespaces after \ non-significant.

int main() {
int i = 1
// \
+ 42
;
return i;
}

CWG, C++23, SG22, plenary-approved

P2246 Character encoding of diagnostic text (Aaron Ballman)

The standard provides a few mechanisms that suggest an implementation issues a diagnostic based on text written in the source code. However, the standard does not uniformly address what should happen if the execution character set of the compiler cannot represent the text in the source character set.

Because the display of diagnostic messages should be merely a matter of Quality of Implementation, the proposal is to place no character set related requirements on the diagnostic output with the understanding that implementations will do what makes the most sense for their situation when issuing diagnostics in terms of which characters need to be escaped or otherwise handled in a special way.

CWG, C++23, plenary-approved

P2290 Delimited escape sequences (Corentin Jabot)

We propose an additional, clearly delimited syntax for octal, hexadecimal and universal character name escape sequences.

We propose new syntaxes \u{}, \o{}, \x{} usable in places where \u, \x, \nnn currently are. \o{} accepts an arbitrary number of octal digits while \u{} and \x{} accept an arbitrary number of hexadecimal digit.

CWG, straw-poll, C++23

P2314 Character sets and encodings (Jens Maurer)

This paper implements the following changes:

  • Switch C++ to a modified “model C” approach for universal-character-names as described in the C99 Rationale v5.10, section 5.2.1.
  • Introduce the term “literal encoding”. For purposes of the C++ specification, the actual set of characters is not relevant, but the sequence of code units (i.e. the encoding) specified by a given character or string literal are. The terms “execution (wide) character set” are retained to describe the locale-dependent runtime character set used by functions such as isalpha.
  • (Not a wording change) Do not attempt to treat all string literals the same; their treatment depends on (phase 7) context.

Before/After Table

Before:

#define S(x) # x
const char * s1 = S(Köppe);       // "K\\u00f6ppe"
const char * s2 = S(K\u00f6ppe);  // "K\\u00f6ppe"

After:

#define S(x) # x
const char * s1 = S(Köppe);       // "Köppe"
const char * s2 = S(K\u00f6ppe);  // "Köppe"

CWG, C++23, plenary-approved

P2316 Consistent character literal encoding (Corentin Jabot)

Character literals in preprocessor conditional should behave like they do in C++ expression.

#if 'A' == '\x41'
//...
#endif
if ('A' == 0x41){}

CWG, C++23, plenary-approved

P2362 Make obfuscating wide character literals ill-formed (Peter Brett, Corentin Jabot)

C++ currently permits writing a wide character literal with multiple characters or characters that cannot fit into a single wchar_t codeunit. For example:

Example

wchar_t a = L'🤦'; // \u{1F926}
wchar_t b = L'ab';
wchar_t c = L'é'; // \u{65}\u{301};

Make these literals ill-formed.

CWG, straw-poll, C++23

Other CWG

20 Papers

P0849 auto(x): DECAY_COPY in the language (Zhihao Yuan)

This paper proposes auto(x) and auto{x} for transforming x into a prvalue with the same value as-if passed as a function argument by value. When users asked for this functionality, we claimed that the DECAY_COPY notion in the standard serves such purpose, but it is for exposition only.

Example

// instead of:
auto subparser = parser;
subparser.add_option(...);

// you can write:
auto subparser = auto(parser).add_option(...);

CWG, LWG, C++23, IS, plenary-approved

P1272 Byteswapping for fun&&nuf (Isabella Muerte)

namespace std {
    template <class IntegerType>
    constexpr IntegerType byteswap (IntegerType value) noexcept;
}
// Where std::is_integral_v<IntegerType> is true.

CWG, LWG, C++23, plenary-approved

P1401 Narrowing contextual conversions to bool (Andrzej Krzemienski)

This paper proposes to allow narrowing conversions in contextually converted constant expressions of type `bool`.

TodayIf accepted
if constexpr(bool(flags & Flags::Exec))if constexpr(flags & Flags::Exec)
if constexpr(flags & Flags::Exec != 0)if constexpr(flags & Flags::Exec)
static_assert(N % 4 != 0);static_assert(N % 4);
static_assert(bool(N));static_assert(N);

CWG, C++23, plenary-approved

P1467 Extended floating-point types (Michał Dominiak, David Olsen)

This paper introduces the notion of extended floating-point types, modeled after extended integer types. To accomodate them, this paper also attempts to rewrite the current rules for floating-point types, to enable well-defined interactions between all the floating-point types. The end goal of this paper, together with [P1468], is to have a language to enable <cstdint>-like aliases for implementation specific floating point types, that can model more binary layouts than just a single fundamental type (the previously proposed short float) can provide for

CWG, LWG, straw-poll, C++23, tentatively-ready-for-plenary, IS, B3:Addition

P1675 rethrow_exception must be allowed to copy (Billy O’Neal)

The current_exception wording was carefully written to allow both ABIs like MSVC++’s where the exception objects are generally constructed on the stack, and ABIs like the Itanium C++ ABI where the exception objects are generally constructed on the heap (and possibly reference counted). Implementations are given the freedom they need to (possibly) copy the exception object into the memory held by the exception_ptr, and similar. See http://eel.is/c++draft/propagation#8.

Unfortunately, such care was not taken for rethrow_exception.

CWG, LWG, C++23, B2: Improvement, small, plenary-approved

P1774 Portable optimisation hints (Timur Doumler)

We propose a standard facility providing the semantics of existing compiler intrinsics such as __builtin_assume (Clang) and __assume (MSVC, Intel) that tell the compiler to assume a given C++ expression without evaluating it, and to optimise based on this assumption. This is very useful for high-performance and low-latency applications in order to generate both faster and smaller code.

CWG, straw-poll, C++23, needs-revision

P1847 Make declaration order layout mandated (Pal Balog)

The current rules allow implementations freedom to reorder members in the layout if they have different access control. To our knowledge no implementation actually used that freedom. We propose to fix this established industry practice in the standard as mandatory.

CWG, C++23, plenary-approved

P2036 Changing scope for lambda trailing-return-type (Barry Revzin)

This paper proposes that name lookup in the trailing-return-type of a lambda first consider that lambda’s captures before looking further outward. We may not know at the time of parsing the return type which names actually are captured, so this paper proposes to treat all capturable entities as if they were captured.

CWG, C++23, plenary-approved

P2156 Allow Duplicate Attributes (Erich Keane)

The standard attributes noreturn, carries dependency, and deprecated all specify that they cannot appear more than once in an attribute-list, but there is no such prohibition if they appear in separate attribute-specifiers within a single attributespecifier-seq. Since intuitively these cases are equivalent, they should be treated the same, accepting duplicates in both or neither.

CWG, C++23, plenary-approved

P2173 Attributes on Lambda-Expressions (Daveed Vandevoorde, Inbal Levi, Ville Voutilainen)

This paper proposes a fix for Core Issue 2097, to allow attributes for lambdas, those attributes appertaining to the function call operator of the lambda.

auto lm = [] [[nodiscard, vendor::attr]] () -> int { return 42; };

CWG, straw-poll, C++23, plenary-approved

P2186 Removing Garbage Collection Support (JF Bastien, Alisdair Meredith)

We propose removing (not deprecating) C++’s Garbage Collection support. Specifically, these five library functions:

  • declare_reachable
  • undeclare_reachable
  • declare_no_pointers
  • undeclare_no_pointers
  • get_pointer_safety

As well as the pointer_safety enum, the \_\_STDCPP_STRICT_POINTER_SAFETY\_\_ macro, and the Core Language wording.

CWG, LWG, C++23, IS, plenary-approved

P2266 Simpler implicit move (Arthur O’Dwyer)

In C++20, return statements can implicitly move from local variables of rvalue reference type; but a defect in the wording means that implicit move fails to apply to functions that return references. C++20’s implicit move is specified via a complicated process involving two overload resolutions, which is hard to implement, causing implementation divergence. We fix the defect and simplify the spec by saying that a returned move-eligible id-expression is always an xvalue.

CWG, straw-poll, C++23

P2324 Labels at the end of compound statements (C compatibility) (Martin Uecker)

WG14 adopted a change for C2X that allows placement of labels everywhere inside a compound statement (N2508). While this improves compatibility with C++ which previously diverged from C by allowing labels in front of declarations, there is still a remaining incompatibility: C now does allow labels at the end of a compound statement, while C++ does not. It is proposed to change the C++ grammar to remove this remaining difference.

Example

void foo(void)
{
first: // allowed in C++, now also allowed in C
int x;
second: // allowed in both C++ and C
x = 1;
last: // not allowed in C++, but now allowed in C
}

CWG, straw-poll, C++23, small

P2327 De-deprecating volatile compound assignment (Paul Bendixen, Jens Maurer, Arthur O’Dwyer, Ben Saks)

The C++ 20 standard deprecated many functionalities of the volatile keyword. This was due to P1152[Bastien, 2019]. The reasoning is given in the R0 version of the paper[Bastien, 2018].

The deprecation was not received too well in the embedded community as volatile is commonly used for communicating with peripheral devices in microcontrollers[van Ooijen, 2020].

The purpose of this paper is to give a solution that will not undo what was achieved with P1152, and still keep the parts that are critical to the embedded community.

CWG, straw-poll, C++23

P2334 Add support for preprocessing directives elifdef and elifndef (Melanie Blower)

This paper is being submitted as a liaison activity from WG14 C Language Working Group. The proposal was discussed in the March 2021 meeting and approved (15 in favor, 1 opposed, 4 abstentions) for inclusion into C23. This paper is being proposed to WG21 to avoid preprocessor incompatibilities with C and because the utility is valuable to C++ users of the preprocessor.

CWG, C++23, plenary-approved

P2360 Extend init-statement to allow alias-declaration (Jens Maurer)

Before:

for (typedef int T; T e : v)
  /* something */;

After:

for (using T = int; T e : v)
  /* something */;

CWG, C++23, plenary-approved

P2437 Support for #warning (Aaron Ballman)

Almost all major C++ compilers support the #warning preprocessing directive to generate a diagnostic message from the preprocessor without stopping translation, as #error does, which can be useful for code authors who want to warn consumers of the code about non-fatal concerns. C

WG14 considered a similar proposal as part of WG14 N2686 at our Sept 2021 meeting and adopted the feature into C23 (straw poll results were: 17 in favor, 0 oppose, 1 abstain). The WG21 proposal is functionally identical to the WG14 proposal, with the only difference being due to existing variance in specification around how #error causes translation to stop.

CWG, straw-poll, C++23, tiny

P2468 The Equality Operator You Are Looking For (Barry Revzin, Bjarne Stroustrup, Cameron DaCamara, Daveed Vandevoorde, Gabriel Dos Reis, Herb Sutter, Jason Merrill, Jonathan Caves, Richard Smith, Ville Voutilainen)

This paper details some changes to make rewriting equality in expressions less of a breaking change

  • If you want an operator== that is used for rewrites (automatically reversed, and != automatically generated), write only an operator==, and make sure its return type is bool.
  • If you want an operator== that is not used for rewrites, write both an operator== and a matching operator!=.
  • operator<=> is always used for rewrites (from <, <=, >, >=); if you don’t want rewrites, don’t write an operator<=>.

CWG, straw-poll, C++23

P2493 Missing feature test macros for C++20 core papers (Barry Revzin)

As Jonathan Wakely pointed out on the SG10 mailing list, neither [P0848R3] (Conditionally Trivial Special Member Functions) nor [P1330R0] ( Changing the active member of a union inside constexpr) provided a feature-test macro.

This paper proposes Richard’s second suggestion: bump __cpp_concepts and __cpp_constexpr to 202002L

CWG, straw-poll, C++23, plenary-approved

P2582 Wording for class template argument deduction from inherited constructors (Timur Doumler)

This paper provides wording for class template argument deduction from inherited constructors.

From P1021R6

Before:

template<class T>
struct Point { T x; T y; };

// Aggregate: Cannot deduce
Point<double> p{3.0, 4.0};
Point<double> p2{.x = 3.0, .y = 4.0};

After:

template<class T>
struct Point { T x; T y; };

// Proposed: Aggregates deduce
Point p{3.0, 4.0};
Point p2{.x = 3.0, .y = 4.0};

CWG, straw-poll, C++23, needs-revision

Library Working Group Proposals

Ranges

21 Papers + 2 from “Major”

P1659 starts_with and ends_with (Christopher Di Bella)

This proposal seeks to add std::ranges::starts_with and std::ranges::ends_with, which would work on arbitrary ranges, and also answer questions such as “are the starting elements of `r1` less than the elements of `r2`?” and “are the final elements of `r1` greater than the elements of `r2`?”

Before/After Table

Before:

auto some_ints      = view::iota(0, 50);
auto some_more_ints = view::iota(0, 30);
if (ranges::mismatch(some_ints, some_more_ints).in2 == end(some_more_ints)) {
    // do something
}

After:

auto some_ints      = view::iota(0, 50);
auto some_more_ints = view::iota(0, 30);
if (ranges::starts_with(some_ints, some_more_ints)) {
    // do something
}

LWG, C++23, IS, small, plenary-approved

P1989 Range constructor for std::string_view 2: Constrain Harder (Corentin Jabot)

template<class R>
basic_string_view(R&&)
-> basic_string_view<ranges::range_value_t<R>>;

LWG, ranges, C++23, plenary-approved

P2321 zip (Tim Song)

This paper proposes

  • four views, zip, zip_transform, adjacent, and adjacent_transform,
  • changes to tuple and pair necessary to make them usable as proxy references (necessary for zip and adjacent), and
  • changes to vector<bool>::reference to make it usable as a proxy reference for writing,

Example

std::vector v1 = {1, 2};
std::vector v2 = {'a', 'b', 'c'};
std::vector v3 = {3, 4, 5};

fmt::print("{}\n", std::views::zip(v1, v2));                              // {(1, 'a'), (2, 'b')}
fmt::print("{}\n", std::views::zip_transform(std::multiplies(), v1, v3)); // {3, 8}
fmt::print("{}\n", v2 | std::views::pairwise);                            // {('a', 'b'), ('b', 'c')}
fmt::print("{}\n", v3 | std::views::pairwise_transform(std::plus()));     // {7, 9}

LWG, ranges, C++23, IS, B3: Addition, plenary-approved

P2302 Prefer std::ranges::contains over std::basic_string_view::contains (Christopher Di Bella)

P2302 proposes two algorithms: one that checks whether or not a range contains an element, and one that checks whether or not a range contains a subrange

Before:

namespace stdr = std::ranges;
stdr::find(haystack.begin(), haystack.end(), 'o') != haystack.end()
stdr::find(haystack, 'o') != stdr::end(haystack)
not stdr::search(haystack, long_needle).empty()
not stdr::search(haystack, long_needle, bind_back(std::modulo(), 4)).empty()

After:

namespace stdr = std::ranges;
stdr::contains(haystack.begin(), haystack.end(), 'o')
stdr::contains(haystack, 'o')
stdr::contains_subrange(haystack, long_needle)
stdr::contains_subrange(haystack, long_needle, bind_back(std::modulo(), 4))

LWG, ranges, C++23, tentatively-ready-for-plenary, IS, B3: Addition

P2322 ranges::fold (Barry Revzin)

While we do have an iterator-based version of fold in the standard library, it is currently named accumulate, defaults to performing + on its operands, and is found in the header <numeric>. But fold is much more than addition, so as described in the linked paper, it’s important to give it the more generic name and to avoid a default operator.

LWG, ranges, C++23, tentatively-ready-for-plenary, IS, B3: Addition

P2387 Pipe support for user-defined range adaptors (Barry Revzin)

Walter Brown made an excellent observation: if we gave users the tools to write their own range adaptors that would properly inter-operate with standard library adaptors (as well as other users’ adaptors), then it becomes less important to provide more adaptors in the standard library.

The goal of this paper is provide that functionality: provide a standard customization mechanism for range adaptors, so that everybody can write their own adaptors.

LWG, ranges, C++23, IS, B2: Improvement, medium, plenary-approved

P2325 Views should not be required to be default constructible (Barry Revzin)

Currently, the view concept is defined in 24.4.4 [range.view] as:

template <class T>
concept view =
    range<T> &&
    movable<T> &&
    default_initializable<T> &&
    enable_view<T>;

Discussion

Three of these four criteria, I understand. A view clearly needs to be a range, and it’s important that they be movable for various operations to work. And the difference between a view and range is largely semantic, and so there needs to be an explicit opt-in in the form of enable_view.

But why does a view need to be default_initializable?

LWG, ranges, C++23, IS, B2: Improvement, plenary-approved

P2367 Remove misuses of list-initialization from Clause 24 (Tim Song)

This paper provides wording for [LWG3524] and resolves related issues caused by the erroneous use of list-initialization in ranges wording.

As discussed in [LWG3524], the use of list-initialization in the ranges specification implies ordering guarantees that are unintended and unimplementable in ordinary C++, as well as narrowing checks that are unnecessary and sometimes unimplementable.

LWG, C++23, plenary-approved

P2432 Fix istream_view (Nicolai Josuttis)

This paper fixes a fundamental design problem with the current helper function std::ranges::istream_view<>() that cause multiple inconsistences and unnecessary code overhead when declaring istream_view objects

Before:

std::ranges::istream_view<int> v{mystream}
 // ERROR

After:

std::ranges::istream_view<int> v{mystream}
 // OK

LWG, ranges, C++23, IS, B2: Improvement, small, plenary-approved

P2415 What is a view? (Barry Revzin, Tim Song)

Once upon a time, a view was a cheaply copyable, non-owning range. We’ve already somewhat lost the “cheaply copyable” requirement since views don’t have to be copyable, and now this paper is suggesting that we also lose the non-owning part.

LWG, ranges, C++23, IS, B2: Improvement, medium, plenary-approved

P2408 Ranges views as inputs to non-Ranges algorithms (David Olsen)

Change the iterator requirements for non-Ranges algorithms. For forward iterators and above that are constant iterators, instead of requiring that iterators meet certain Cpp17…Iterator requirements, require that the iterators model certain iterator concepts. This makes iterators from several standard views usable with non-Ranges algorithms that require forward iterators or above, such as the parallel overloads of most algorithms.

LWG, ranges, C++23, tentatively-ready-for-plenary, IS, B2: Improvement

P2210 Superior String Splitting (Barry Revzin)

Proposal Part 1

This paper proposes the following: Rename the existing views::split / ranges::split_view to views::lazy_split / ranges::lazy_split_view. Add base() member functions to the inner-iterator type to get back to the adapted range’s iterators.

Proposal Part 2

  1. Introduce a new range adapter under the name views::split / ranges::split_view with the following design:
    1. It can only support splitting forward-or-better ranges.
    2. Splitting a V will yield ~subrange<iterator_t<V>>~s, ensuring that the adapted range’s category is preserved. Splitting a bidirectional range gives out bidirectional subranges. Spltiting a contiguous range gives out contiguous subranges.
    3. views::split will not be const-iterable.

Example

auto ip = "127.0.0.1"s;
auto parts = ip | std::views::split('.')
                | std::views::transform([](std::span<char const> s){
                      int i;
                      std::from_chars(s.data(), s.data() + s.size(), i);
                      return i;
                  });

LWG, ranges, C++23, IS, B2: Improvement, plenary-approved

P2440 ranges::iota, ranges::shift_left, and ranges::shift_right (Tim Song)

This paper proposes adding the algorithms ranges::iota, ranges::shift_left, and ranges::shift_right, to match their std counterparts.

LWG, ranges, C++23, IS, B3: Addition, medium, plenary-approved

P2443 views::chunk_by (Tim Song)

This paper proposes the range adaptor views::chunk_by as described in section 4.3 of [P2214R1].

std::vector v = {1, 2, 2, 3, 0, 4, 5, 2};
fmt::print("{}\n", v | std::views::chunk_by(ranges::less_equal{}));   // [[1, 2, 2, 3], [0, 4, 5], [2]]

LWG, ranges, C++23, IS, B3: Addition, medium, plenary-approved

P2328 join_view should join all views of ranges (Tim Song)

This paper proposes relaxing the constraint on join_view to support joining ranges of prvalue non-view ranges.

LWG, ranges, C++23, IS, B2: Improvement, plenary-approved

P2442 Windowing range adaptors:views::chunk and views::slide (Tim Song)

This paper proposes two range adaptors, views::chunk and views::slide, as described in section 3.5 of [P2214R0].

std::vector v = {1, 2, 3, 4, 5};
fmt::print("{}\n", v | std::views::chunk(2));   // [[1, 2], [3, 4], [5]]
fmt::print("{}\n", v | std::views::slide(2));   // [[1, 2], [2, 3], [3, 4], [4, 5]]

LWG, ranges, C++23, IS, B3: Addition, medium, plenary-approved

P2441 views::join_with (Barry Revzin)

The behavior of views::join_with is an inverse of views::split. That is, given a range r and a pattern p, r | views::split(p) | views::join_with(p) should yield a range consisting of the same elements as r.

LWG, ranges, C++23, IS, plenary-approved

P2446 views::move (Barry Revzin)

as_rvalue_view presents a view of an underlying sequence with the same behavior as the underlying sequence except that its elements are rvalues. Some generic algorithms can be called with a as_rvalue_view to replace copying with moving.

The name views::as_rvalue denotes a range adaptor object ([range.adaptor.object]).

LWG, ranges, C++23, tentatively-ready-for-plenary, IS, B3: Addition, medium

P2494 Relaxing range adaptors to allow for move only types (Michał Dominiak)

Currently, many range adaptors require that the user-provided types they store must be copy constructible, which is also required by the assignment wrapper they use, copyable-box.

Similarly to how [P2325R3] turned semiregular-box into copyable-box, this paper proposes to turn copyable-box into movable-box. This name is probably not ideal, because it still turns types that happen to be copy constructible into copyable types, but it follows from the prior changes to the wrapper.

LWG, ranges, C++23, tentatively-ready-for-plenary, IS, B2: Improvement

P2502 std::generator: Synchronous Coroutine Generator for Ranges (Casey Carter)

We propose a standard library type std::generator which implements a coroutine generator that models std::ranges::input_range.

Example

std::generator<int> fib() {
    auto a = 0, b = 1;
    while (true) {
        co_yield std::exchange(a, std::exchange(b, a + b));
    }
}
int answer_to_the_universe() {
    auto rng = fib() | std::views::drop(6) | std::views::take(3);
    return std::ranges::fold_left(std::move(range), 0, std::plus{});
}

LWG, coroutines, ranges, C++23, tentatively-ready-for-plenary, IS, B1:Focus

P2281 Clarifying range adaptor objects (Tim Song)

The wording below clarifies that the partial application performed by range adaptor objects is essentially identical to that performed by bind_front. (Indeed, it is effectively a limited version of bind_back.) In particular, this means that the bound arguments are captured by copy or move, and never by reference. Invocation of the pipeline then either copies or moves the bound entities, depending on the value category of the pipeline.

Example

auto c = /* some range */;
auto f = /* expensive-to-copy function object */;
c | transform(f); // copies f and then move it into the view

auto t = transform(f); // copies f
c | t;                 // copies f again from t
c | std::move(t);      // moves f from t

LWG, C++23, plenary-approved

Output

4 papers + 1 from majors

(or 2 if you count formatting ranges)

P1147 Printing volatile Pointers (Bryce Adelstein Lelbach)

Printing pointers to volatile types with standard library output streams has unexpected results. Consider the following code:

Example

#include <iostream>

int main() {
    int*          p0 = reinterpret_cast<int*>(0xdeadbeef);
    volatile int* p1 = reinterpret_cast<volatile int*>(0xdeadbeef);

    std::cout << p0 << std::endl;
    std::cout << p1 << std::endl;
}

This produces the following output:

0xdeadbeef
  

1

LWG, C++23, IS, plenary-approved

P2216 std::format improvements (Victor Zverovich)

This paper proposes the following improvements to the C++20 formatting facility:

  • Improving safety via compile-time format string checks
  • Reducing binary code size of format_to
std::string s = std::format("{:d}", "I am not a number");

Becomes ill-formed LWG, C++23, IS, plenary-approved

P2372 Fixing locale handling in chrono formatters (Victor Zverovich, Corentin Jabot)

In C++20 “Extending <chrono> to Calendars and Time Zones” ([P0355]) and “Text Formatting” ([P0645]) proposals were integrated ([P1361]). Unfortunately during this integration a design issue was missed: std::format is locale-independent by default and provides control over locale via format specifiers but the new formatter specializations for chrono types are localized by default and don’t provide such control.

Solution

We propose fixing this issue by making chrono formatters locale-independent by default and providing the L specifier to opt into localized formatting in the same way as it is done for all other standard formatters (format.string.std).

Before:

auto s = std::format("{:%S}", sec(4.2));
// s == "04,200"

auto s = std::format("{:L%S}", sec(4.2));
// throws format_error

After:

auto s = std::format("{:%S}", sec(4.2));
// s == "04.200"

auto s = std::format("{:L%S}", sec(4.2));
// s == "04,200"

LWG, C++23, IS, plenary-approved

P2418 Add support for std::generator-like types to std::format (Victor Zverovich)

Unfortunately we cannot make std::generator formattable because it is neither const-iterable nor copyable and std::format takes arguments by const&.

This paper proposes solving the issue by making std::format and other formatting functions take arguments by forwarding references.

LWG, C++23, IS, B2: Improvement, medium, plenary-approved

P2508 Exposing std::basic-format-string (Barry Revzin)

In 20.20.1 [format.syn], replace the exposition-only names basic-format-string, format-string, and wformat-string with the non-exposition-only names basic_format_string, format_string, and wformat_string.

Example

template <typename... Args>
void log(std::format_string<Args...> s, Args&&... args) {
    if (logging_enabled) {
        log_raw(std::format(s, std::forward<Args>(args)...));
    }
}

LWG, C++23, tentatively-ready-for-plenary, IS, B3: Addition

Constexpr

4 papers

P1328 Making std::type_info::operator== constexpr (Peter Dimov)

This paper proposes std::type_info::operator== and operator!= be made constexpr, enabling practical, rather than theoretical, use of typeid in constant expressions.

LWG, C++23, IS, B3: Addition, tiny, plenary-approved

P2231 Missing constexpr in std::optional and std::variant (Barry Revzin)

But even though the language provided the tools to make std::optional and std::variant completely constexpr-able, there was no such update to the library. This paper seeks to remedy that omission by simply adding constexpr to all the relevant places.

LWG, C++23, IS, B2: Improvement, plenary-approved

P2273 Making std::unique_ptr constexpr (Andreas Fertig)

std::unique_ptr is currently not constexpr friendly. With the loosening of requirements on constexpr in [P0784R10] and the ability to use new and delete in a constexpr­context, we should also provide a constexpr std::unique_ptr.

Example

constexpr auto fun() {
    auto p = std::make_unique<int>(4);
    return *p;
}
int main() {
    constexpr auto i = fun();
    static_assert(4 == i);
}

LWG, C++23, B2: Improvement, plenary-approved, constexpr, expedited-library-evolution-electronic-poll

P2291 Add Constexpr Modifiers to Functions to_chars and from_chars for Integral Types in <charconv> Header (Daniil Goncharov, Karaev Alexander)

There is currently no standard way to make conversion between numbers and strings at compile time.

std::to_chars and std::from_chars are fundamental blocks for parsing and formatting being localeindependent and non-throwing without memory allocation, so they look like natural candidates for constexpr string conversions. The paper proposes to make std::to_chars and std::from_chars functions for integral types usable in constexpr context.

LWG, C++23, tentatively-ready-for-plenary, IS, B2: Improvement, small, constexpr, expedited-library-evolution-electronic-poll

Other Types and Utilities

21 papers

P0288 any_invocable (Ryan McDougall, Matt Calabrese)

This paper proposes a conservative, move-only equivalent of std::function.

LWG, C++23, IS, large, plenary-approved

P0401 Providing size feedback in the Allocator interface (Chris Kennelly, Jonathan Wakely)

Utilize size feedback from Allocator to reduce spurious reallocations

LWG, C++23, small, plenary-approved

18 papers

P0448 A strstream replacement using span<charT> as buffer (Peter Sommerlad)

This paper proposes a class template basic_spanbuf and the corresponding stream class templates to enable the use of streams on externally provided memory buffers. No ownership or re-allocation support is given. For those features we have string-based streams

Example

char        input[] = "10 20 30";
ispanstream is{span<char>{input}};
int         i;
is >> i;
ASSERT_EQUAL(10, i);
is >> i;
ASSERT_EQUAL(20, i);
is >> i;
ASSERT_EQUAL(30, i);
is >> i;
ASSERT(!is);

LWG, C++23, large, plenary-approved

P0627 Function to mark unreachable code (Melissa Mears)

This proposal introduces a new standard library function, std::unreachable, for marking locations in code execution as being known by the programmer to be unreachable.

Example

[[noreturn]] void kill_self() {
    kill(getpid(), SIGKILL);
    std::unreachable();
}

LWG, C++23, IS, B3: Addition, small, plenary-approved, expedited-library-evolution-electronic-poll

P1072 basic_string::resize_default_init (Chris Kennelly, Mark Zeren)

Allow access to default initialized elements of basic_string.

Example

std::string GeneratePattern(const std::string& pattern, size_t count) {
    std::string ret;

    const auto step = pattern.size();
    // GOOD: No initialization
    ret.resize_default_init(step * count);
    for (size_t i = 0; i < count; i++) {
        // GOOD: No bookkeeping
        memcpy(ret.data() + i * step, pattern.data(), step);
    }

    return ret;
}

LWG, C++23, IS, plenary-approved

P1413 A safer interface for std::aligned_storage (CJ Johnson)

[] the standard library should provided two more symbols in the form of typedefs that take in a single template type parameter and, on behalf of the user, deduce the size and alignment of that type, passing in the values to std::aligned_storage. The symbols should be std::aligned_storage_for and std::aligned_storage_for_t. Like std::aligned_storage and std::aligned_storage_t, they should be available in the <type_traits> header of the standard library.

LWG, C++23, plenary-approved

P1425 Iterators pair constructors for stack and queue (Corentin Jabot)

This paper proposes to add iterators-pair constructors to std::stack and std::queue

Example

BeforeAfter
std::vector<int> v(42);std::vector<int> v(42);
std::stack<int> s({v.begin(), v.end()});std::stack s(v.begin(), v.end());
std::queue<int> q({v.begin(), v.end()});std::queue q(v.begin(), v.end());

LWG, C++23, B2: Improvement, small, plenary-approved

P1518 Stop overconstraining allocators in container deduction guides (Arthur O’Dwyer, Mike Spertus)

Discussion of flatmap’s deduction guides revealed that the deduction guides for sequence containers and container adaptors are needlessly overconstrained, making use cases such as pmr containers unnecessarily difficult.

LWG, C++23, IS, small, plenary-approved

P1951 Default Arguments for pair’s Forwarding Constructor (Logan R. Smith)

This paper proposes defaulting the template arguments U1 and U2 in pair’s forwarding constructor to T1 and T2 respectively, so that braced initializers may be used as constructor arguments to it.

std::pair<std::string, std::vector<std::string>> p("hello", {});

LWG, C++23, IS, plenary-approved

P2077 Heterogeneous erasure overloads for associative containers (Konstantin Boyarinov, Sergey Vinogradov; Ruslan Arutyunyan)

The authors propose heterogeneous erasure overloads for ordered and unordered associative containers, which add an ability to erase values or extract nodes without creating a temporary key_type object.

LWG, C++23, IS, B2: Improvement, plenary-approved

P2136 invoke<R> (Zhihao Yuan)

This paper proposes invoke_r, a variant of std::invoke that allows specifying the return type, realizing the semantics of INVOKE<R> rather than INVOKE.

LWG, C++23, IS, plenary-approved

P2166 A Proposal to Prohibit std::basic_string and std::basic_string_view construction from nullptr (Yuriy Chernyshov)

the behavior of std::basic_string::basic_string(const CharT* s) constructor is undefined if [s, s + Traits::length(s)) is not a valid range (for example, if s is a null pointer)

LWG, C++23, IS, small, plenary-approved

P2251 Require span & basic_string_view to be Trivially Copyable (Nevin Liber)

Given its definition, it is strongly implied that span & basic_string_view are trivially copyable, but that is not yet a requirement.

LWG, C++23, IS, plenary-approved

P2255 A type trait to detect reference binding to temporary (Tim Song)

This paper proposes adding two new type traits with compiler support to detect when the initialization of a reference would bind it to a lifetime-extended temporary, and changing several standard library components to make such binding ill-formed when it would inevitably produce a dangling reference.

Before

std::tuple<const std::string&>      x("hello");            // dangling
std::function<const std::string&()> f = [] { return ""; }; // OK

f(); // dangling

After

std::tuple<const std::string&>      x("hello");            // ill-formed
std::function<const std::string&()> f = [] { return ""; }; // ill-formed

LWG, C++23, IS, small, plenary-approved, expedited-library-evolution-electronic-poll

P2301 Add a pmr alias for std::stacktrace (Steve Downey)

This paper proposes to add an alias in the pmr namespace defaulting the allocator used by the std::basic_stacktrace template to pmr::allocator. No changes to the api of std::stacktrace are necessary.

Before

char buffer[1024];

std::pmr::monotonic_buffer_resource pool{
    std::data(buffer), std::size(buffer)};

std::basic_stacktrace<
    std::pmr::polymorphic_allocator<std::stacktrace_entry>>
    trace{&pool};

After

char buffer[1024];

std::pmr::monotonic_buffer_resource pool{
    std::data(buffer), std::size(buffer)};

std::pmr::stacktrace trace{&pool};

LWG, C++23, tiny, plenary-approved

P2340 Clarifying the status of the ‘C headers’ (Thomas Köppe)

We propose to move the specification of “[depr.c.headers] C headers” from Annex D into the main document, and changing those headers’ status from “deprecated” to an explicitly discussed state “for foreign-language interoperability only”.

LWG, C++23, policy, IS, B2: Improvement, small, plenary-approved

P2393 Cleaning up integer-class types (Tim Song)

This paper revamps the specification and use of integer-class types to resolve a number of issues, including [LWG3366], [LWG3376], and [LWG3575].

LWG, C++23, plenary-approved

P2401 Add a conditional noexcept specification to std::exchange (Giuseppe D’Angelo)

We propose to add a noexcept-specification to std::exchange , which is currently lacking one.

LWG, C++23, IS, plenary-approved

P2438 std::string::substr() && (Federico Kircheis, Tomasz Kamiński)

auto foo() -> std::string;

auto b = foo().substr(/* */);

Before:

foo() returns a temporary std::string. .substr creates a new string and copies the relevant content. At last, the temporary string returned by foo is released.

After:

foo() returns a std::string. .substr implementation can reuse the storage of the string returned by foo and leave it in a valid but unspecified state. At last, the temporary string returned by foo() is released.

LWG, C++23, tentatively-ready-for-plenary, IS, expedited-library-evolution-electronic-poll

P2445 forward_like (Gašper Ažman)

Deducing This [P0847R7] is expected to land in C++23. Its examples use a hypothetical std::forward_like<decltype(self)>(variable) facility because std::forward<decltype(v)>(v) is insufficient. This paper proposes std::forward_like to cater to this scenario.

Example

auto callback = [m = get_message(), &scheduler](this auto&& self) -> bool {
    return scheduler.submit(std::forward_like<decltype(self)>(m));
};
callback();            // retry(callback)
std::move(callback)(); // try-or-fail(rvalue)

LWG, C++23, tentatively-ready-for-plenary, IS, B3: Addition, small

P2467 Support exclusive mode for fstreams (Jonathan Wakely)

Historically, C++ iostreams libraries had a noreplace open mode that corresponded to the O_EXCL flag for POSIX open. That mode was not included in the C++98 standard, presumably for portability reasons, because it wasn’t in ISO C90.

Since then, ISO C added support for “exclusive” mode to fopen, so now C++’s <fstream> is missing a feature that is present in both ISO C and POSIX. We should fix this for C++23.

LWG, C++23, tentatively-ready-for-plenary, IS, B3: Addition, expedited-library-evolution-electronic-poll