---
title: "C++ Standard Library Ready Issues to be moved in Brno, Jun. 2026"
document: P4258R0
date: 2026-06-08
audience: WG21
reply-to:
  - "Jonathan Wakely <lwgchair@gmail.com>"
---

- Ready Issues
  - 3417. Missing volatile atomic deprecations
  - 4125. move_iterator 's default constructor should be constrained
  - 4158. `packaged_task::operator=` should abandon its shared state
  - 4182. Definition of `NULL` is too broad
  - 4218. Constraint recursion in `basic_const_iterator`'s relational operators due to ADL + CWG 2369
  - 4249. The past end issue for `lazy_split_view`
  - 4267. Uses-allocator construction is meaningless for tuple of references
  - 4359. `as_awaitable(expr, p)` does not define semantics of call if `p` is not an lvalue
  - 4385. Including <simd> doesn't provide `std::begin/end`
  - 4471. Remove test for `get_env noexcept`-ness from `inline_scheduler`
  - 4487. Is member `is_steady` of a *Cpp17Clock* type required to be usable in constant expressions?
  - 4490. Allow calling `std::ranges::size` in ranges algorithms
  - 4521. Improve [atomics.order] p10 to have a consistent way with [intro.races]
- Tentatively Ready Issues
  - 4121. `ranges::to` constructs associative containers via `c.emplace(c.end(), *it)`
  - 4531. Should there be a feature-test macro update for constexpr `std::to_(w)string`?
  - 4567. Feature test macro value for `apply_result`, `is_applicable`
  - 4568. `std::execution::spawn_future` is mishandling dependent senders
  - 4579. *make-state*<Rcvr>::*state-type*::*complete* uses `Env` which is not in scope

## Ready Issues

---

### Missing volatile atomic deprecations

**Section:** 32.5.8.2 [[atomics.types.operations]](https://wg21.link/atomics.types.operations) **Status:** [Voting](https://cplusplus.github.io/LWG/lwg-active.html#Voting) **Submitter:** Alisdair Meredith **Opened:** 2020-03-19 **Last modified:** 2026-04-14

**Priority:**3

**View all other** [issues](https://cplusplus.github.io/LWG/lwg-index.html#atomics.types.operations) in [atomics.types.operations].

**Discussion:**

Paper [P1831R1](https://wg21.link/p1831r1) aimed to deprecate all the atomic overloads for `volatile` qualified member function of `std::atomic` unless `is_always_lock_free` is `true`. There are a few omissions in the wording.

First, `operator++` and `operator--` are correctly constrained, but the deprecated overloads are not restored in Annex D, unlike the other member functions. I confirmed with the paper author this is an accidental oversight, and not an intended change of behavior for C++20.

Secondly, the wait/notify APIs were added after the initial wording For this paper was drafted, and the paper did not catch up. Again, I confirmed with the paper author that these functions should be similarly constrained and deprecated.

*[2020-04-04 Issue Prioritization]*

Priority to 3 after reflector discussion. The suggested wording was generally accepted, but there were considerable doubts that it is necessary to add deprecated functions of the new `wait/notify` functions instead of declaring only the non-volatile overloads. The wish was expressed that both SG1 and LEWG should express their opinion here.

*[Kona 2025-11-05; SG1 had strong consensus for the proposed resolution. Status changed: SG1 → Open.]*

*[2026-04-14; Approved by LWG in Kona, but not added to the plenary polls. Status changed: Open → Ready.]*

**Proposed resolution:**

This wording is relative to [N4861](https://wg21.link/n4861).

1. Modify 32.5.8.2 [[atomics.types.operations]](https://wg21.link/atomics.types.operations) as indicated: void wait(T old, memory_order order = memory_order::seq_cst) const volatile noexcept; void wait(T old, memory_order order = memory_order::seq_cst) const noexcept; <ins>*Constraints:* For the `volatile` overload of this function, `is_always_lock_free` is `true`.</ins> -29- *Preconditions:* […] […] void notify_one() volatile noexcept; void notify_one() noexcept; <ins>*Constraints:* For the `volatile` overload of this function, `is_always_lock_free` is `true`.</ins> -32- *Effects:* […] […] void notify_all() volatile noexcept; void notify_all() noexcept; <ins>*Constraints:* For the `volatile` overload of this function, `is_always_lock_free` is `true`.</ins> -34- *Effects:* […] […]
2. Modify D.24.2 [[depr.atomics.volatile]](https://wg21.link/depr.atomics.volatile), annex D, as indicated: If an atomic specialization has one of the following overloads, then that overload participates in overload resolution even if `atomic<T>::is_always_lock_free` is `false`: void store(T desired, memory_order order = memory_order::seq_cst) volatile noexcept; […] T* fetch_*key*(ptrdiff_t operand, memory_order order = memory_order::seq_cst) volatile noexcept; <ins>value_type operator++(int) volatile noexcept; value_type operator--(int) volatile noexcept; value_type operator++() volatile noexcept; value_type operator--() volatile noexcept; void wait(T old, memory_order order = memory_order::seq_cst) const volatile noexcept; void notify_one() volatile noexcept; void notify_all() volatile noexcept;</ins>

---

### move_iterator's default constructor should be constrained

**Section:** 24.5.4.2 [[move.iterator]](https://wg21.link/move.iterator), 24.5.4.4 [[move.iter.cons]](https://wg21.link/move.iter.cons) **Status:** [Voting](https://cplusplus.github.io/LWG/lwg-active.html#Voting) **Submitter:** Hewill Kang **Opened:** 2024-07-22 **Last modified:** 2026-05-30

**Priority:**3

**View other** [active issues](https://cplusplus.github.io/LWG/lwg-index-open.html#move.iterator) in [move.iterator].

**View all other** [issues](https://cplusplus.github.io/LWG/lwg-index.html#move.iterator) in [move.iterator].

**Discussion:**

Although it is unclear why [P2325](https://wg21.link/P2325) did not apply to `move_iterator`, there is implementation divergence among the current libraries ([demo](https://godbolt.org/z/WdoPcjjv4)):

> ```
> #include <istream>
> #include <iterator>
> #include <ranges>
> 
> using R = std::ranges::istream_view<int>;
> using I = std::ranges::iterator_t<R>;
> using MI = std::move_iterator<I>;
> static_assert(std::default_initializable<MI>); // libstdc++ passes, libc++ fails
> ```

As libc++ additionally requires that its default constructors satisfy `is_constructible_v<Iterator>`.

Although this is not current standard-conforming behavior, such constraint does make sense since `move_iterator` only requires the underlying iterator to be `input_iterator` which may not be `default_initializable`.

*[2024-08-02; Reflector poll]*

Set priority to 3 after reflector poll. Six P0 (tentatively ready) votes but one for NAD: "design change, needs paper. Not constraining this seems to be intended by [P2325R3](https://wg21.link/P2325R3). Even if we want to constrain it, why `default_initializable` rather than just `is_constructible_v`?" Author of [P2325R3](https://wg21.link/P2325R3) had no such intent and voted P0. Issue submitter used `default_initializable` to align with `forward_iterator` requirements, but would not object to implementers using `is_constructible_v` for backported DRs.

*[2026-05-29 LWG telecon; status: New → Ready]*

**Proposed resolution:**

This wording is relative to [N4986](https://wg21.link/N4986).

1. Modify 24.5.4.2 [[move.iterator]](https://wg21.link/move.iterator) as indicated: namespace std { template<class Iterator> class move_iterator { public: […] constexpr move_iterator() <ins>requires default_initializable<Iterator> = default</ins>; […] private: Iterator current <ins>= Iterator()</ins>; // *exposition only* }; }
2. Modify 24.5.4.4 [[move.iter.cons]](https://wg21.link/move.iter.cons) as indicated: <del>constexpr move_iterator();</del> <del>-1- *Effects*: Value-initializes `current`.</del>

---

### packaged_task::operator= should abandon its shared state

**Section:** 32.10.10.2 [[futures.task.members]](https://wg21.link/futures.task.members) **Status:** [Voting](https://cplusplus.github.io/LWG/lwg-active.html#Voting) **Submitter:** Jonathan Wakely **Opened:** 2024-09-19 **Last modified:** 2026-05-19

**Priority:**3

**View all other** [issues](https://cplusplus.github.io/LWG/lwg-index.html#futures.task.members) in [futures.task.members].

**Discussion:**

The `packaged_task` move assignment operator is specified to release the previous shared state. This means it releases ownership, but does not make the shared state ready. Any future that shares ownership of the shared state will never receive a result, because the provider is gone. This means that any thread that waits on the future will block forever.

There is a note on `packaged_task::reset()` which claims that assignment abandons the state, which is not supported by any normative wording:

> ```
> void reset();
> ```
> 
> -26- *Effects*: As if `*this = packaged_task(std::move(f))`, where `f` is the task stored in `*this`.
> 
> [*Note 2*: This constructs a new shared state for `*this`. The old state is abandoned (32.10.5 [[futures.state]](https://wg21.link/futures.state)). — *end note*]

Presumably, the intended behaviour of assignment was to abandon the shared state, i.e. make it ready with a `broken_promise` error, and then release it. That is what the `std::promise` move assignment does (see 32.10.6 [[futures.promise]](https://wg21.link/futures.promise) p9). Both libstdc++ and libc++ abandon the state, despite what the standard says.

*[2024-10-02; Reflector poll]*

Set priority to 3 after reflector poll.

Previous resolution [SUPERSEDED]

This wording is relative to [N4988](https://wg21.link/N4988).

1. Modify 32.10.10.2 [[futures.task.members]](https://wg21.link/futures.task.members) as indicated: packaged_task& operator=(packaged_task&& rhs) noexcept; -11- *Effects*: (11.1) — <del>Releases</del> <ins>Abandons</ins> any shared state (32.10.5 [[futures.state]](https://wg21.link/futures.state)); (11.2) — calls `packaged_task(std::move(rhs)).swap(*this)`. <ins>-?- *Returns*: `*this`.</ins>

*[2024-10-02; Jonathan provides improved wording]*

Following reflector discussion, remove the "Releases any shared state" text completely. The remaining effects imply that the state will be abandoned anyway. This makes it safe against self-assignment.

*[2024-10-02; LWG telecon]*

Agreed to change `promise` the same way, which is safe for self-assignment and matches what all three of libstdc++, libc++ and MSVC do today. Ask SG1 to review.

*[2026-05-19; LWG telecon. Status changed: New → Ready.]*

SG1 agreed with the resolution. LWG moved to Ready.

**Proposed resolution:**

This wording is relative to [N4988](https://wg21.link/N4988).

1. Modify 32.10.6 [[futures.promise]](https://wg21.link/futures.promise) as indicated: promise& operator=(promise&& rhs) noexcept; -9- *Effects*: <del> Abandons any shared state (32.10.5 [[futures.state]](https://wg21.link/futures.state)) and then as if </del> <ins>Equivalent to</ins> `promise(std::move(rhs)).swap(*this)`. -10- *Returns*: `*this`.
2. Modify 32.10.10.2 [[futures.task.members]](https://wg21.link/futures.task.members) as indicated: packaged_task& operator=(packaged_task&& rhs) noexcept; -11- *Effects*: <del>(11.1) — Releases any shared state (32.10.5 [[futures.state]](https://wg21.link/futures.state));</del> <del>(11.2) — calls</del> <ins>Equivalent to</ins> `packaged_task(std::move(rhs)).swap(*this)`. <ins>-?- *Returns*: `*this`.</ins>

---

### Definition of NULL is too broad

**Section:** 17.2.3 [[support.types.nullptr]](https://wg21.link/support.types.nullptr) **Status:** [Voting](https://cplusplus.github.io/LWG/lwg-active.html#Voting) **Submitter:** Janet Cobb **Opened:** 2024-12-09 **Last modified:** 2026-05-30

**Priority:**3

**Discussion:**

7.3.12 [[conv.ptr]](https://wg21.link/conv.ptr)/1 reads in part: "A *null pointer constant* is an integer literal (5.13.2 [[lex.icon]](https://wg21.link/lex.icon)) with value zero or a prvalue of type `std::nullptr_t`.".

17.2.3 [[support.types.nullptr]](https://wg21.link/support.types.nullptr)/2 reads: "The macro `NULL` is an implementation-defined null pointer constant.".

Together, these imply that `#define NULL (::std::unreachable(), nullptr)` is a conforming definition. The expression is a prvalue of type `std::nullptr_t`, so it is a null pointer constant. This makes it implementation-defined whether any program that evaluates `NULL` has undefined behavior.

*[2025-02-07; Reflector poll]*

Set priority to 3 after reflector poll.

"I'd very much like to see `nullptr` added to the footnote."

Previous resolution [SUPERSEDED]

This wording is relative to [N5001](https://wg21.link/N5001).

1. Modify 17.2.3 [[support.types.nullptr]](https://wg21.link/support.types.nullptr) as indicated: -2- The macro `NULL` is an implementation-defined null pointer constant <ins>that is a literal (5.13.2 [[lex.icon]](https://wg21.link/lex.icon), 5.13.8 [[lex.nullptr]](https://wg21.link/lex.nullptr))</ins>.<sup>footnote 161</sup> 161) Possible definitions include `0` and `0L`, but not `(void*)0`.

*[2025-02-07; Jonathan provides improved wording]*

*[2026-05-29 LWG telecon; status: New → Ready]*

**Proposed resolution:**

This wording is relative to [N5001](https://wg21.link/N5001).

1. Modify 17.2.3 [[support.types.nullptr]](https://wg21.link/support.types.nullptr) as indicated: -2- The macro `NULL` is an implementation-defined null pointer constant <ins>that is a literal (5.13.2 [[lex.icon]](https://wg21.link/lex.icon), 5.13.8 [[lex.nullptr]](https://wg21.link/lex.nullptr))</ins>.<sup>footnote 161</sup> 161) Possible definitions include <ins>`nullptr`,</ins> `0` and `0L`, but not `(void*)0`.

---

### Constraint recursion in basic_const_iterator's relational operators due to ADL + CWG 2369

**Section:** 24.5.3.5 [[const.iterators.ops]](https://wg21.link/const.iterators.ops) **Status:** [Voting](https://cplusplus.github.io/LWG/lwg-active.html#Voting) **Submitter:** Patrick Palka **Opened:** 2025-03-03 **Last modified:** 2026-05-19

**Priority:**2

**Discussion:**

Consider the example (devised by Hewill Kang)

> ```
> using RCI = reverse_iterator<basic_const_iterator<vector<int>::iterator>>;
> static_assert(std::totally_ordered<RCI>);
> ```

Checking `RCI` is `totally_ordered` entails checking

> ```
> requires (RCI x) { x RELOP x; } for each RELOP in {<, >, <=, >=}
> ```

which we expect to be straightforwardly satisfied by `reverse_iterator`'s namespace-scope operators (24.5.1.8 [[reverse.iter.cmp]](https://wg21.link/reverse.iter.cmp)):

> ```
> template<class Iterator1, class Iterator2>
>   constexpr bool operator<(
>     const reverse_iterator<Iterator1>& x,
>     const reverse_iterator<Iterator2>& y);
> // etc
> ```

But due to ADL we find ourselves also considering the `basic_const_iterator` relop friends (24.5.3.5 [[const.iterators.ops]](https://wg21.link/const.iterators.ops)/24).

> ```
> template<input_iterator Iterator>
> class basic_const_iterator {
>   template<not-a-const-iterator I>
>     friend constexpr bool operator<(const I& x, const basic_const_iterator& y)
>       requires random_access_iterator<Iterator> && totally_ordered_with<Iterator, I>
>   // etc
> };
> ```

Before [CWG 2369](https://wg21.link/cwg2369) these candidates would quickly get discarded since for the second operand RCI clearly isn't convertible to `basic_const_iterator`. But after CWG 2369 implementations must first check these operators' constraints (with `Iterator = vector<int>::iterator` and `I = RCI`), which entails checking `totally_ordered<RCI>` recursively, causing the example to be ill-formed.

The constraint recursion is diagnosed by GCC ([See godbolt demo](https://godbolt.org/z/dr1dK1dnj)). Other compilers accept the example because they don't implement CWG 2369, as far as I know.

GCC trunk works around this issue by giving these friend relational operators a dependent second operand of the form `basic_const_iterator<J>` where `J` is constrained to match `Iterator`:

> ```
> template<not-a-const-iterator I, same_as<Iterator> J>
>   friend constexpr bool operator<(const I& x, const basic_const_iterator<J>& y)
>     requires random_access_iterator<Iterator> && totally_ordered_with<Iterator, I>
> // etc
> ```

So that deduction fails earlier, before constraints get checked, for a second operand that isn't a specialization of `basic_const_iterator` (or derived from one).

LWG [3769](https://cplusplus.github.io/LWG/lwg-defects.html#3769)<sup>[(i)](https://cplusplus.github.io/LWG/issue3769)</sup> is an earlier issue about constraint recursion in `basic_const_iterator`'s operators, but there the recursion was independent of CWG 2369.

*[2025-06-13; Reflector poll]*

Set priority to 2 after reflector poll.

*[2026-05-19; LWG telecon. Status changed: New → Ready.]*

Something seems to be wrong or missing with CWG 2369 because it's silly to have to keep doing this in the library. We're changing a non-deduced parameter into a deduced one with a constraint that requries it to be the same type as it was anyway. In this particular case, [P2600](https://wg21.link/P2600) might have helped.

**Proposed resolution:**

This wording is relative to [N5001](https://wg21.link/N5001).

1. Modify 24.5.3.3 [[const.iterators.iterator]](https://wg21.link/const.iterators.iterator), class template `basic_const_iterator` synopsis, as indicated: namespace std { […] template<input_iterator Iterator> class basic_const_iterator { […] template<*not-a-const-iterator* I<ins>, same_as<Iterator> J</ins>> friend constexpr bool operator<(const I& x, const basic_const_iterator<ins><J></ins>& y) requires random_access_iterator<Iterator> && totally_ordered_with<Iterator, I>; template<*not-a-const-iterator* I<ins>, same_as<Iterator> J</ins>> friend constexpr bool operator>(const I& x, const basic_const_iterator<ins><J></ins>& y) requires random_access_iterator<Iterator> && totally_ordered_with<Iterator, I>; template<*not-a-const-iterator* I<ins>, same_as<Iterator> J</ins>> friend constexpr bool operator<=(const I& x, const basic_const_iterator<ins><J></ins>& y) requires random_access_iterator<Iterator> && totally_ordered_with<Iterator, I>; template<*not-a-const-iterator* I<ins>, same_as<Iterator> J</ins>> friend constexpr bool operator>=(const I& x, const basic_const_iterator<ins><J></ins>& y) requires random_access_iterator<Iterator> && totally_ordered_with<Iterator, I>; […] }; }
2. Modify 24.5.3.5 [[const.iterators.ops]](https://wg21.link/const.iterators.ops) as indicated: template<*not-a-const-iterator* I<ins>, same_as<Iterator> J</ins>> friend constexpr bool operator<(const I& x, const basic_const_iterator<ins><J></ins>& y) requires random_access_iterator<Iterator> && totally_ordered_with<Iterator, I>; template<*not-a-const-iterator* I<ins>, same_as<Iterator> J</ins>> friend constexpr bool operator>(const I& x, const basic_const_iterator<ins><J></ins>& y) requires random_access_iterator<Iterator> && totally_ordered_with<Iterator, I>; template<*not-a-const-iterator* I<ins>, same_as<Iterator> J</ins>> friend constexpr bool operator<=(const I& x, const basic_const_iterator<ins><J></ins>& y) requires random_access_iterator<Iterator> && totally_ordered_with<Iterator, I>; template<*not-a-const-iterator* I<ins>, same_as<Iterator> J</ins>> friend constexpr bool operator>=(const I& x, const basic_const_iterator<ins><J></ins>& y) requires random_access_iterator<Iterator> && totally_ordered_with<Iterator, I>; -23- Let `*op*` be the operator. -24- *Effects*: Equivalent to: `return x *op* y.*current_*;`

---

### The past end issue for lazy_split_view

**Section:** 25.7.16.3 [[range.lazy.split.outer]](https://wg21.link/range.lazy.split.outer) **Status:** [Voting](https://cplusplus.github.io/LWG/lwg-active.html#Voting) **Submitter:** Hewill Kang **Opened:** 2025-04-26 **Last modified:** 2026-05-22

**Priority:**2

**View other** [active issues](https://cplusplus.github.io/LWG/lwg-index-open.html#range.lazy.split.outer) in [range.lazy.split.outer].

**View all other** [issues](https://cplusplus.github.io/LWG/lwg-index.html#range.lazy.split.outer) in [range.lazy.split.outer].

**Discussion:**

Consider ([demo](https://godbolt.org/z/eeMe8aTqv)):

> ```
> #include <print>
> #include <ranges>
> #include <sstream>
> 
> int main() {
>   std::istringstream is{"1 0 2 0 3"};
>   auto r = std::views::istream<int>(is)
>          | std::views::lazy_split(0)
>          | std::views::stride(2);
>   std::println("{}", r); // should print [[1], [3]]
> }
> ```

The above leads to a hardened precondition failure in libstdc++, the reason is that we are iterating over the nested range as:

> ```
> for (auto&& inner : r) {
>   for (auto&& elem : inner) {
>     // […]
>   }
> }
> ```

which is disassembled as:

> ```
> auto outer_it = r.begin();
> std::default_sentinel_t out_end = r.end();
> for(; outer_it != out_end; ++outer_it) {
>   auto&& inner_r = *outer_it;
>   auto inner_it = inner_r.begin();
>   std::default_sentinel_t inner_end = inner_r.end();
>   for(; inner_it != inner_end; ++inner_it) {
>     auto&& elem = *inner_it;
>     // […]
>   }
> }
> ```

Since `inner_it` and `output_it` actually update the same iterator, when we back to the outer loop, `lazy_split_view::*outer-iterator*` is now equal to `default_sentinel`, which makes `output_it` reach the end, so `++outer_it` will increment the iterator past end, triggering the assertion.

Note that this [also happens](https://godbolt.org/z/6Tx61eeq8) in MSVC-STL when `_ITERATOR_DEBUG_LEVEL` is turned on.

It seems that extra flags are needed to fix this issue because `output_it` should not be considered to reach the end when we back to the outer loop.

*[2025-10-21; Reflector poll.]*

Set priority to 2 after reflector poll.

"This is unfortunate. `lazy_split` is probably not very commonly used, but handling input ranges was half the reason why we kept it around. Can we reuse `trailing_empty_` for this instead of adding a new flag? Both flags have the same meaning, and the two cases where they are true are disjoint: we need `has_next_` when iterating through the inner range exhausted the source range; we need `trailing_empty_` when we find a delimiter at the end of the source range when incrementing the outer iterator, which by definition means that iterating through the inner range *didn't* exhaust it."

Previous resolution [SUPERSEDED]

This wording is relative to [N5008](https://wg21.link/N5008).

1. Modify 25.7.16.3 [[range.lazy.split.outer]](https://wg21.link/range.lazy.split.outer) as indicated: namespace std::ranges { template<input_range V, forward_range Pattern> requires view<V> && view<Pattern> && indirectly_comparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> && (forward_range<V> || *tiny-range*<Pattern>) template<bool Const> struct lazy_split_view<V, Pattern>::*outer-iterator* { private: using *Parent* = *maybe-const*<Const, lazy_split_view>; // *exposition only* using *Base* = *maybe-const*<Const, V>; // *exposition only* *Parent** *parent_* = nullptr; // *exposition only* iterator_t<*Base*> *current_* = iterator_t<*Base*>(); // *exposition only, present only* // *if V models forward_range* bool *trailing_empty_* = false; // *exposition only* <ins>bool *has_next_* = false; // *exposition only, present only*</ins> <ins>// *if forward_range<*V*> is false*</ins> public: […] }; } […] constexpr explicit *outer-iterator*(*Parent*& parent) requires (!forward_range<*Base*>); -2- *Effects:* Initializes `*parent_*` with `addressof(parent)` <ins>and `*has_next_*` with `*current* != ranges::end(*parent_*->*base_*)`</ins>. […] constexpr *outer-iterator*& operator++(); -6- *Effects:* Equivalent to: const auto end = ranges::end(*parent_*->*base_*); if (*current* == end) { *trailing_empty_* = false; <ins>if constexpr (!forward_range<V>) *has_next_* = false;</ins> return `*this`; } const auto [pbegin, pend] = subrange{*parent_*->*pattern_*}; if (pbegin == pend) ++*current*; else if constexpr (*tiny-range*<Pattern>) { *current* = ranges::find(std::move(*current*), end, *pbegin); if (*current* != end) { ++*current*; if (*current* == end) *trailing_empty_* = true; } } else { do { auto [b, p] = ranges::mismatch(*current*, end, pbegin, pend); if (p == pend) { *current* = b; if (*current* == end) *trailing_empty_* = true; break; *// The pattern matched; skip it* } } while (++*current* != end); } <ins>if constexpr (!forward_range<V>) if (*current* == end) *has_next_* = false;</ins> return *this; […] friend constexpr bool operator==(const *outer-iterator*& x, default_sentinel_t); -8- *Effects:* Equivalent to: <ins>if constexpr (!forward_range<V>) return !x.*has_next_* && !x.*trailing_empty_*; else</ins> return x.*current* == ranges::end(x.*parent_*->*base_*) && !x.*trailing_empty_*;

*[2025-10-21; Hewill Kang provides simpler wording]*

*[2026-05-22 LWG telecon; Status changed: New → Ready]*

**Proposed resolution:**

This wording is relative to [N5014](https://wg21.link/N5014).

1. Modify 25.7.16.3 [[range.lazy.split.outer]](https://wg21.link/range.lazy.split.outer) as indicated: constexpr *outer-iterator*& operator++(); -6- *Effects:* Equivalent to: const auto end = ranges::end(*parent_*->*base_*); if (*current* == end) { *trailing_empty_* = false; return `*this`; } const auto [pbegin, pend] = subrange{*parent_*->*pattern_*}; if (pbegin == pend) ++*current*; else if constexpr (*tiny-range*<Pattern>) { *current* = ranges::find(std::move(*current*), end, *pbegin); if (*current* != end) { ++*current*; if (*current* == end) *trailing_empty_* = true; <ins>else if constexpr (!forward_range<V>) *trailing_empty_* = true;</ins> } } else { do { auto [b, p] = ranges::mismatch(*current*, end, pbegin, pend); if (p == pend) { *current* = b; if (*current* == end) *trailing_empty_* = true; break; *// The pattern matched; skip it* } } while (++*current* != end); } return *this;

---

### Uses-allocator construction is meaningless for tuple of references

**Section:** 22.4.4.2 [[tuple.cnstr]](https://wg21.link/tuple.cnstr) **Status:** [Voting](https://cplusplus.github.io/LWG/lwg-active.html#Voting) **Submitter:** Jiang An **Opened:** 2025-05-24 **Last modified:** 2026-05-22

**Priority:**3

**View other** [active issues](https://cplusplus.github.io/LWG/lwg-index-open.html#tuple.cnstr) in [tuple.cnstr].

**View all other** [issues](https://cplusplus.github.io/LWG/lwg-index.html#tuple.cnstr) in [tuple.cnstr].

**Discussion:**

Per 20.2.8.2 [[allocator.uses.construction]](https://wg21.link/allocator.uses.construction)/1, uses-allocator construction is only defined for objects. And presumably, an attempt to construct `std::tuple` of reference from an `allocator_arg_t` constructor causes a hard error.

Since C++23/[P2255R2](https://wg21.link/P2255R2), it seems that these `allocator_arg_t` constructors are conditionally deleted according to 22.4.4.2 [[tuple.cnstr]](https://wg21.link/tuple.cnstr)/33. However, it's confusing that these constructors are sometimes non-deleted when the tuple contains a reference, while there are hard errors in an instantiation instead.

*[2025-10-14; Reflector poll]*

Set priority to 3 after reflector poll.

"There is a defect, but the right fix is to just define uses-allocator construction of references as equivalent to normal construction."

Previous resolution [SUPERSEDED]

This wording is relative to [N5008](https://wg21.link/N5008).

1. Modify 22.4.4.2 [[tuple.cnstr]](https://wg21.link/tuple.cnstr) as indicated: template<class Alloc> constexpr explicit(*see below*) tuple(allocator_arg_t, const Alloc& a); […] template<class Alloc, tuple-like UTuple> constexpr explicit(*see below*) tuple(allocator_arg_t, const Alloc& a, UTuple&&); -32- *Preconditions*: `Alloc` meets the *Cpp17Allocator* requirements (16.4.4.6.1 [[allocator.requirements.general]](https://wg21.link/allocator.requirements.general)). -33- *Effects*: Equivalent to the preceding constructors except that each element is constructed with uses-allocator construction (20.2.8.2 [[allocator.uses.construction]](https://wg21.link/allocator.uses.construction)). <ins>-?- *Remarks*: These constructors are defined as deleted if `is_reference_v<T<sub>*i*</sub>>` is `true` for at least one `T<sub>*i*</sub>`.</ins>

*[2025-10-15; Jonathan provides new wording]*

I don't think we care about uses-allocator construction of references in general. You can't construct a reference using `allocator_traits::construct` nor put references in containers. For a `std::pair` containing a reference, I think `make_obj_using_allocator` and `uses_allocator_construction_args` work fine. The problem only exists in the `std::tuple` wording where we say that the elements are constructed using uses-allocator construction. So let's just fix that.

*[2026-05-22 LWG telecon; Status changed: New → Ready]*

**Proposed resolution:**

This wording is relative to [N5014](https://wg21.link/N5014).

1. Modify 22.4.4.2 [[tuple.cnstr]](https://wg21.link/tuple.cnstr) as indicated: template<class Alloc> constexpr explicit(*see below*) tuple(allocator_arg_t, const Alloc& a); […] template<class Alloc, tuple-like UTuple> constexpr explicit(*see below*) tuple(allocator_arg_t, const Alloc& a, UTuple&&); -32- *Preconditions*: `Alloc` meets the *Cpp17Allocator* requirements (16.4.4.6.1 [[allocator.requirements.general]](https://wg21.link/allocator.requirements.general)). -33- *Effects*: Equivalent to the preceding constructors except that each element <ins>of non-reference type</ins> is constructed with uses-allocator construction (20.2.8.2 [[allocator.uses.construction]](https://wg21.link/allocator.uses.construction)).

---

### as_awaitable(expr, p) does not define semantics of call if p is not an lvalue

**Section:** 33.13.1 [[exec.as.awaitable]](https://wg21.link/exec.as.awaitable) **Status:** [Voting](https://cplusplus.github.io/LWG/lwg-active.html#Voting) **Submitter:** Lewis Baker **Opened:** 2025-08-27 **Last modified:** 2026-05-19

**Priority:**2

**View other** [active issues](https://cplusplus.github.io/LWG/lwg-index-open.html#exec.as.awaitable) in [exec.as.awaitable].

**View all other** [issues](https://cplusplus.github.io/LWG/lwg-index.html#exec.as.awaitable) in [exec.as.awaitable].

**Discussion:**

The wording in 33.13.1 [[exec.as.awaitable]](https://wg21.link/exec.as.awaitable) p7 defines the semantics of a call to `as_awaitable(expr, p)` where `p` is an lvalue. However, it does not specify what the behaviour is if `p` is not an lvalue.

We should probably say that `as_awaitable(expr, p)` is ill-formed if `p` is not an lvalue.

*[2026-01-16; Reflector poll.]*

Set priority to 2 after reflector poll.

Previous resolution [SUPERSEDED]

This wording is relative to [N5014](https://wg21.link/N5014).

1. Modify 33.13.1 [[exec.as.awaitable]](https://wg21.link/exec.as.awaitable) as indicated: -7- `as_awaitable` is a customization point object. For subexpressions `expr` and `p` where <del>`p` is an lvalue,</del> `Expr` names the type `decltype((expr))` and `Promise` names the type `decay_t<decltype((p))>`, <ins>if `p` is not an lvalue, `as_awaitable(expr, p)` is ill-formed, otherwise</ins> `as_awaitable(expr, p)` is expression-equivalent to, except that the evaluations of `expr` and `p` are indeterminately sequenced:

*[2026-01-16; Jonathan provides updated wording]*

*[2026-05-19; LWG telecon. Status changed: New → Ready.]*

**Proposed resolution:**

This wording is relative to [N5032](https://wg21.link/N5032).

1. Modify 33.13.1 [[exec.as.awaitable]](https://wg21.link/exec.as.awaitable) as indicated: -7- `as_awaitable` is a customization point object. For subexpressions `expr` and `p` where <del>`p` is an lvalue,</del> `Expr` names the type `decltype((expr))` and `Promise` names the type `decay_t<decltype((p))>`, <ins> `as_awaitable(expr, p)` is ill-formed if `p` is not an lvalue, otherwise </ins> `as_awaitable(expr, p)` is expression-equivalent to <ins>the expression specified below</ins>, except that the evaluations of `expr` and `p` are indeterminately sequenced:

---

### Including <simd> doesn't provide std::begin/end

**Section:** 24.7 [[iterator.range]](https://wg21.link/iterator.range) **Status:** [Voting](https://cplusplus.github.io/LWG/lwg-active.html#Voting) **Submitter:** Hewill Kang **Opened:** 2025-09-26 **Last modified:** 2026-05-22

**Priority:**3

**View other** [active issues](https://cplusplus.github.io/LWG/lwg-index-open.html#iterator.range) in [iterator.range].

**View all other** [issues](https://cplusplus.github.io/LWG/lwg-index.html#iterator.range) in [iterator.range].

**Discussion:**

`std::simd::basic_vec` and `std::simd::basic_mask` are ranges since [P3480R6](https://wg21.link/P3480R6), it is reasonable to enable range access utilities when introducing `<simd>`.

*[2025-10-17; Reflector poll.]*

Set priority to 3 after reflector poll.

"This will be the first time we add the free-function begin/end interface to support a type where `end` returns a sentinel. I would not want to set precedent here without at least taking the time to think about it, and acknowledge a deliberate intent."

"The intent has been deliberate since [P0184R0](https://wg21.link/P0184R0)."

*[2026-05-22 LWG telecon; Status changed: New → Ready]*

**Proposed resolution:**

This wording is relative to [N5014](https://wg21.link/N5014).

1. Modify 24.7 [[iterator.range]](https://wg21.link/iterator.range) as indicated: -1- In addition to being available via inclusion of the `<iterator>` header, the function templates in 24.7 [[iterator.range]](https://wg21.link/iterator.range) are available when any of the following headers are included: `<array>`, `<deque>`, `<flat_map>`, `<flat_set>`, `<forward_list>`, `<hive>`, `<inplace_vector>`, `<list>`, `<map>`, `<regex>`, `<set>`, <ins>`<simd>`</ins>, `<span>`, `<string>`, `<string_view>`, `<unordered_map>`, `<unordered_set>`, and `<vector>`.

---

### Remove test for get_env noexcept-ness from inline_scheduler

**Section:** 33.13.4 [[exec.inline.scheduler]](https://wg21.link/exec.inline.scheduler) **Status:** [Voting](https://cplusplus.github.io/LWG/lwg-active.html#Voting) **Submitter:** Eric Niebler **Opened:** 2025-11-05 **Last modified:** 2026-05-19

**Priority:**4

**Discussion:**

33.13.4 [[exec.inline.scheduler]](https://wg21.link/exec.inline.scheduler) bullet (3.2) reads:

> - (3.2) — the expression `get_completion_scheduler<set_value_t>(get_env(sndr))` has type `inline_scheduler` and is potentially-throwing if and only if `get_env(sndr)` is potentially-throwing.

`get_env(sndr)` is never potentially-throwing because it mandates that `sndr.get_env()` cannot throw, see 33.5.5 [[exec.get.env]](https://wg21.link/exec.get.env).

also, `get_completion_scheduler<set_*_t>(attrs)` mandates that `attrs.query(get_completion_scheduler<set_*_t>)` cannot throw.

*[2026-01-16; Reflector poll.]*

Set priority to 4 after reflector poll.

"33.12.1.2 [[exec.run.loop.types]](https://wg21.link/exec.run.loop.types) (7.2) has the same redundancy."

Previous resolution [SUPERSEDED]

This wording is relative to [N5014](https://wg21.link/N5014).

1. Modify 33.13.4 [[exec.inline.scheduler]](https://wg21.link/exec.inline.scheduler) as indicated: -3- Let `sndr` be an expression of type `*inline-sender*`, let `rcvr` be an expression such that `receiver_of<decltype((rcvr)), CS>` is `true` where `CS` is `completion_signatures<set_value_t()>`, then: (3.1) — the expression `connect(sndr, rcvr)` has type `*inline-state*<remove_cvref_t<decltype((rcvr))>>` and is potentially-throwing if and only if `((void)sndr, auto(rcvr))` is potentially-throwing, and (3.2) — the expression `get_completion_scheduler<set_value_t>(get_env(sndr))` has type `inline_scheduler` <del>and is potentially-throwing if and only if `get_env(sndr)` is potentially-throwing</del>.

*[2026-01-16; Jonathan provides updated wording]*

LWG believes the original issue discussion is wrong to say that `get_env(sndr)` can never throw, because the expression `sndr` itself could throw. However, we already state that `get_env` and `get_completion_scheduler` do not throw, so it's redundant to say that `get_completion_scheduler(get_env(sndr))` only throws if `sndr` throws. If nothing except `sndr` in that expression is allowed to throw, then it's just stating the obvious.

Previous resolution [SUPERSEDED]

This wording is relative to [N5032](https://wg21.link/N5032).

1. Modify 33.13.4 [[exec.inline.scheduler]](https://wg21.link/exec.inline.scheduler) as indicated: -3- Let `sndr` be an expression of type `*inline-sender*`, let `rcvr` be an expression such that `receiver_of<decltype((rcvr)), CS>` is `true` where `CS` is `completion_signatures<set_value_t()>`, then: (3.1) — the expression `connect(sndr, rcvr)` has type `*inline-state*<remove_cvref_t<decltype((rcvr))>>` and is potentially-throwing if and only if `((void)sndr, auto(rcvr))` is potentially-throwing, and (3.2) — the expression `get_completion_scheduler<set_value_t>(get_env(sndr))` has type `inline_scheduler` <del>and is potentially-throwing if and only if `get_env(sndr)` is potentially-throwing</del>.
2. Modify 33.12.1.2 [[exec.run.loop.types]](https://wg21.link/exec.run.loop.types) as indicated: -7- Let *`sndr`* be an expression of type *`run-loop-sender`*, let *`rcvr`* be an expression such that `receiver_of<decltype((*rcvr*)), CS>` is `true` where `CS` is the `completion_signatures` specialization above. Let `C` be either `set_value_t` or `set_stopped_t`. Then: (7.1) — The expression `connect(*sndr*, *rcvr*)` has type `*run-loop-opstate*<decay_t<decltype((*rcvr*))>>` and is potentially-throwing if and only if `(void(*sndr*), auto(*rcvr*))` is potentially-throwing. (7.2) — The expression `get_completion_scheduler<C>(get_env(*sndr*))` <del> is potentially-throwing if and only if *`sndr`* is potentially-throwing, </del> has type *`run-loop-scheduler`*<del>,</del> and compares equal to the *`run-loop-scheduler`* instance from which *`sndr`* was obtained.

*[2026-05-15; Tim rebases wording to new working draft]*

The `inline_scheduler` change is no longer needed.

*[2026-05-19; LWG telecon. Status changed: New → Ready.]*

**Proposed resolution:**

This wording is relative to [N5046](https://wg21.link/N5046).

1. Modify 33.12.1.2 [[exec.run.loop.types]](https://wg21.link/exec.run.loop.types) as indicated: -8- Let *`sndr`* be an expression of type *`run-loop-sender`*, let *`rcvr`* be an expression such that `*receiver-of*<decltype((*rcvr*)), CS>` is `true` where `CS` is the `completion_signatures` specialization above. Let `C` be either `set_value_t` or `set_stopped_t`. Then: (8.1) — The expression `connect(*sndr*, *rcvr*)` has type `*run-loop-opstate*<decay_t<decltype((*rcvr*))>>` and is potentially-throwing if and only if `(void(*sndr*), auto(*rcvr*))` is potentially-throwing. (8.2) — The expression `get_completion_scheduler<C>(get_env(*sndr*))` <del> is potentially-throwing if and only if *`sndr`* is potentially-throwing, </del> has type *`run-loop-scheduler`*<del>,</del> and compares equal to the *`run-loop-scheduler`* instance from which *`sndr`* was obtained.

---

### Is member is_steady of a Cpp17Clock type required to be usable in constant expressions?

**Section:** 30.3 [[time.clock.req]](https://wg21.link/time.clock.req) **Status:** [Voting](https://cplusplus.github.io/LWG/lwg-active.html#Voting) **Submitter:** Jiang An **Opened:** 2025-11-26 **Last modified:** 2026-05-22

**Priority:**3

**View all other** [issues](https://cplusplus.github.io/LWG/lwg-index.html#time.clock.req) in [time.clock.req].

**Discussion:**

In 30.3 [[time.clock.req]](https://wg21.link/time.clock.req)/[tab:time.clock], the static data member `C1::is_steady` seemingly indicates the property of the clock statically, as the requirements say "always".

However, it is not clear whether `C1::steady` should be usable in a constant expression. A hostile reading may indicate that it is allowed to make `C1::steady` only defined in some separated translated unit and/or initialized from some non-constant expression.

Also, it is not very clear that the "always" means the conditions always hold in all executions, or only always hold in the current execution. The latter reading allows `C1::steady` to vary between executions.

*[2026-01-16; Reflector poll.]*

Set priority to 3 after reflector poll.

Unanimous preference for Option A.

Previous resolution [SUPERSEDED]

This wording is relative to [N5032](https://wg21.link/N5032).

> [*Drafting Note:* Two mutually exclusive options are prepared, depicted below by **Option A** and **Option B**, respectively.]

**Option A**: Requiring usability in constant expressions.

1. Modify Table [tab:time.clock] — *Cpp17Clock* requirements as indicated: Table 131 — Cpp17Clock requirements [tab:time.clock] Expression Return type Operational semantics […] C1::is_steady const bool true if t1 <= t2 is always true and the time between clock ticks is constant, otherwise false . C1::is_steady shall be usable in constant expressions (7.7 [expr.const] ). […]

**Option B**: Allowing varying between executions.

1. Modify Table [tab:time.clock] — *Cpp17Clock* requirements as indicated: Table 131 — Cpp17Clock requirements [tab:time.clock] Expression Return type Operational semantics […] C1::is_steady const bool true if t1 <= t2 is always true and the time between clock ticks is constant for the duration of the current program execution , otherwise false . [ Note ?: C1::is_steady is not required to be usable in constant expressions (7.7 [expr.const] ) and can vary between different executions. — end note ] […]

*[2026-05-22; Tim updates wording to use Option A based on reflector discussion]*

*[2026-05-22 LWG telecon; Status changed: New → Ready]*

**Proposed resolution:**

This wording is relative to [N5032](https://wg21.link/N5032).

1. Modify Table [tab:time.clock] — *Cpp17Clock* requirements as indicated: Table 131 — Cpp17Clock requirements [tab:time.clock] Expression Return type Operational semantics […] C1::is_steady const bool true if t1 <= t2 is always true and the time between clock ticks is constant, otherwise false . C1::is_steady shall be usable in constant expressions (7.7 [expr.const] ). […]

---

### Allow calling std::ranges::size in ranges algorithms

**Section:** 26.2 [[algorithms.requirements]](https://wg21.link/algorithms.requirements) **Status:** [Voting](https://cplusplus.github.io/LWG/lwg-active.html#Voting) **Submitter:** Ruslan Arutyunyan **Opened:** 2025-12-12 **Last modified:** 2026-05-19

**Priority:**3

**View other** [active issues](https://cplusplus.github.io/LWG/lwg-index-open.html#algorithms.requirements) in [algorithms.requirements].

**View all other** [issues](https://cplusplus.github.io/LWG/lwg-index.html#algorithms.requirements) in [algorithms.requirements].

**Discussion:**

26.2 [[algorithms.requirements]](https://wg21.link/algorithms.requirements) paragraph 14 says that the algorithms in `ranges` namespace are implemented as if they are dispatched to the corresponding overload with iterator and sentinel. However, there are two problems with the current wording:

1. We only allow to call either `std::ranges::end(r)` or `std::ranges::next(std::ranges::begin(r)`, `std::ranges::end())` to calculate a corresponding sentinel. However, this is a pessimization for some ranges because we can have sized ranges without sized_sentinel_for. Consider the following example: const char str[] = "something"; ranges::subrange<const char*, null_sentinel_t, subrange_kind::sized> sr(ranges::begin(str), null_sentinel, ranges::size(str) - 1); my::ranges::next(sr.begin(), sr.end()); // this line serially calculates iterator that is equal to sr.end() Despite the fact that we know the size of the range and that the range is the random access one, `std::ranges::next` calculates the iterator serially, because it only has constant time complexity optimization for `sized_sentinel_for`. We could clearly achieve better complexity with a different API or with the different overload of the same API.
2. It is unclear when an algorithm calls `std::ranges::end(r)` and when it calls `std::ranges::next(std::ranges::begin(r), std::ranges::end())` to calculate the corresponding sentinel because there is no established priority between them. Maybe, it's smaller problem but still it's worth clarifying in my opinion.

*[2026-01-16; Reflector poll.]*

Set priority to 3 after reflector poll.

"Should be 'the type of `r` models `sized_range`"

"It's a lot of words, could be shorter. Would prefer not to establish priority, but let implementation decide if/when to use `ranges::next`."

"Would `counted_iterator(ranges::begin(r), ranges::distance(r))` and `default_sentinel` be better?"

Previous resolution [SUPERSEDED]

This wording is relative to [N5032](https://wg21.link/N5032).

1. Modify 26.2 [[algorithms.requirements]](https://wg21.link/algorithms.requirements) as indicated: […] -14- Overloads of algorithms that take `range` arguments (25.4.2 [[range.range]](https://wg21.link/range.range)) behave as if they are implemented by dispatching to the overload in namespace `ranges` that takes separate iterator and sentinel arguments, where for each range argument `r` (14.1) — a corresponding iterator argument is initialized with `ranges::begin(r)` and (14.2) — a corresponding sentinel argument is initialized with <del>`ranges::end(r)`, or `ranges::next(ranges::begin(r), ranges::end(r))` if the type of `r` models `forward_range` and computing `ranges::next` meets the specified complexity requirements.</del><ins>one of the following:</ins> <ins>(14.2.1) — if the type of `r` models `forward_range` and computing `ranges::next` meets the specified complexity requirements then</ins> <ins>(14.2.1.1) — `ranges::next(ranges::begin(r), ranges::size(r))` if `r` models `sized_range`, otherwise</ins> <ins>(14.2.1.2) — `ranges::next(ranges::begin(r), ranges::end(r))`.</ins> <ins>(14.2.2) — Otherwise, `std::ranges::end(s)`.</ins>

*[2026-01-30; Jonathan provides new wording]*

We can just say that the value is either the end iterator, or begin+N, without saying when or how the implementation obtains begin+N. It might use `ranges::next(ranges::begin(r), std::ranges::end(r))` or `ranges::next(ranges::begin(r), ranges::distance(r))` or something else, only the value matters not how it's obtained. Paragraph 11 in the same subclause defines what begin+N means if the iterator is not a random access iterator.

*[2026-01-30; LWG telecon. Status → Open.]*

*[2026-05-19; LWG telecon. Status changed: Open → Ready.]*

**Proposed resolution:**

This wording is relative to [N5032](https://wg21.link/N5032).

1. Modify 26.2 [[algorithms.requirements]](https://wg21.link/algorithms.requirements) as indicated: […] -14- Overloads of algorithms that take `range` arguments (25.4.2 [[range.range]](https://wg21.link/range.range)) behave as if they are implemented by dispatching to the overload in namespace `ranges` that takes separate iterator and sentinel arguments, where for each range argument `r` (14.1) — a corresponding iterator argument is initialized with `ranges::begin(r)` and (14.2) — a corresponding sentinel argument is initialized with `ranges::end(r)`, or <del> `ranges::next(ranges::begin(r), ranges::end(r))` if the type of `r` models `forward_range` and computing `ranges::next` meets the specified complexity requirements. </del> <ins> `ranges::begin(r) + N` where `N` is equal to `ranges::distance(r)`. </ins>

---

### Improve [atomics.order] p10 to have a consistent way with [intro.races]

**Section:** 32.5.4 [[atomics.order]](https://wg21.link/atomics.order) **Status:** [Voting](https://cplusplus.github.io/LWG/lwg-active.html#Voting) **Submitter:** jim x **Opened:** 2026-02-10 **Last modified:** 2026-05-19

**Priority:**4

**View other** [active issues](https://cplusplus.github.io/LWG/lwg-index-open.html#atomics.order) in [atomics.order].

**View all other** [issues](https://cplusplus.github.io/LWG/lwg-index.html#atomics.order) in [atomics.order].

**Discussion:**

32.5.4 [[atomics.order]](https://wg21.link/atomics.order) p10 says:

> Atomic read-modify-write operations shall always read the last value (in the modification order) written before the write associated with the read-modify-write operation.

We do not write side effects to the modification order, instead we write side effects to an atomic object. These modifications occur in a single total order, called the modification order. That is, the modification order describes how these operations are ordered.

Moreover, we called the compared element in the modification order "modification" or "side effect", as shown in 6.10.2.2 [[intro.races]](https://wg21.link/intro.races). In addition, we don't use "a side effect `*X*` written before `*Y*` in the modification order"; we use "`*X*` precedes/follows `*Y*` in the modification order" to describe the relationship of order between two modifications.

Suggested Resolution:

To make the wording more formal and have a consistent way with 6.10.2.2 [[intro.races]](https://wg21.link/intro.races), the proposed wording is:

> An atomic read-modify-write operation shall always read the value of a side effect `*X*`, where `*X*` is the last side effect that precedes the side effect of the read-modify-write operation in the modification order.

Another option is:

> An atomic read-modify-write operation shall always read the value of a side effect that immediately precedes the side effect of the read-modify-write operation in the modification order.

*[2026-02-27; Reflector poll.]*

Set priority to 4 after reflector poll.

The existing wording was considered to be correct. Support for option B as wording improvement was expressed, as making the wording more formal and "de-shalling".

*[2026-03-23: Croydon, SG1]*

Poll: Approve option B to resolve LWG 4521 and send it back to LWG

Outcome: No objection to unanimous consent

Previous resolution [SUPERSEDED]

This wording is relative to [N5032](https://wg21.link/N5032).

> [*Drafting Note:* Two mutually exclusive options are prepared, depicted below by **Option A** and **Option B**, respectively.
> 
> As a drive-by fix, in both options we also replace the "shall" wording by an indicative voice, because 32.5.4 [[atomics.order]](https://wg21.link/atomics.order) p10 already imposes a requirement on the implementation/language. ]

**Option A:**

1. Modify 32.5.4 [[atomics.order]](https://wg21.link/atomics.order) as indicated: -10- A<ins>n a</ins>tomic read-modify-write operation<del>s shall</del> always read<ins>s</ins> the <del>last</del> value <ins>from the side effect `*X*`, where `*X*` is the last side effect that precedes the side effect of the read-modify-write operation</ins> <del>(</del>in the modification order<del>) written before the write associated with the read-modify-write operation</del>.

**Option B:**

1. Modify 32.5.4 [[atomics.order]](https://wg21.link/atomics.order) as indicated: -10- A<ins>n a</ins>tomic read-modify-write operation<del>s shall</del> always read<ins>s</ins> the <del>last</del> value <ins>from the side effect that immediately precedes the side effect of the read-modify-write operation</ins> <del>(</del>in the modification order<del>) written before the write associated with the read-modify-write operation</del>.

*[2026-05-19; LWG telecon. Status changed: New → Ready.]*

**Proposed resolution:**

This wording is relative to [N5032](https://wg21.link/N5032).

> [*Drafting Note:* As a drive-by fix, we also replace the "shall" wording by an indicative voice, because 32.5.4 [[atomics.order]](https://wg21.link/atomics.order) p10 already imposes a requirement on the implementation/language. ]

1. Modify 32.5.4 [[atomics.order]](https://wg21.link/atomics.order) as indicated: -10- A<ins>n a</ins>tomic read-modify-write operation<del>s shall</del> always read<ins>s</ins> the <del>last</del> value <ins>from the side effect that immediately precedes the side effect of the read-modify-write operation</ins> <del>(</del>in the modification order<del>) written before the write associated with the read-modify-write operation</del>.

## Tentatively Ready Issues

---

### ranges::to constructs associative containers via c.emplace(c.end(), *it)

**Section:** 25.5.7.1 [[range.utility.conv.general]](https://wg21.link/range.utility.conv.general) **Status:** [Tentatively Ready](https://cplusplus.github.io/LWG/lwg-active.html#Ready) **Submitter:** Hewill Kang **Opened:** 2024-07-16 **Last modified:** 2026-05-29

**Priority:**2

**Discussion:**

When `ranges::to` constructs an associative container, if there is no range version constructor for `C` and the input range is not common range, `ranges::to` will dispatch to the bullet 25.5.7.2 [[range.utility.conv.to]](https://wg21.link/range.utility.conv.to) (2.1.4), which first default-constructs the container and emplaces the element through `c.emplace(c.end(), *it)`.

However, this is not the correct way to call `emplace()` on an associative container as it does not expect an iterator as the first argument, and since `map::emplace()`, for instance, is not constrained, which turns out a hard error because we are trying to make a `pair` with `{it, pair}`.

Given that libstdc++ currently does not implement the range constructor for associative containers, the following illustrates the [issue](https://godbolt.org/z/q8MzP8bb1):

> ```
> #include <ranges>
> #include <set>
>   
> auto s = std::views::iota(0)
>        | std::views::take(5)
>        | std::ranges::to<std::set>(); // hard error
> ```

The proposed resolution simply removes the `emplace()` branch. Although this means that we always use `insert()` to fill associative containers, such an impact seems negligible.

*[2024-07-23; This was caused by LWG [4016](https://cplusplus.github.io/LWG/lwg-defects.html#4016)<sup>[(i)](https://cplusplus.github.io/LWG/issue4016)</sup>.]*

*[2024-08-02; Reflector poll]*

Set priority to 2 after reflector poll. "Would like to preserve the ability to use `emplace`. Tim suggested trying `emplace_hint` first, then `emplace`." "I tried it, it gets very verbose, because we might also want to try `insert(*it)` instead of `insert(c.end(), *it)` if `emplace(*it)` is not valid for associative containers, because `c.end()` might not be a good hint." "It might be suboptimal, but it still works."

Previous resolution [SUPERSEDED]

This wording is relative to [N4986](https://wg21.link/N4986).

1. Modify 25.5.7.1 [[range.utility.conv.general]](https://wg21.link/range.utility.conv.general) as indicated: -4- Let `*container-appendable*` be defined as follows: template<class Container, class Ref> constexpr bool *container-appendable* = *// exposition only* requires(Container& c, Ref&& ref) { requires (requires { c.emplace_back(std::forward<Ref>(ref)); } || requires { c.push_back(std::forward<Ref>(ref)); } || <del>requires { c.emplace(c.end(), std::forward<Ref>(ref)); } ||</del> requires { c.insert(c.end(), std::forward<Ref>(ref)); }); }; -5- Let `*container-append*` be defined as follows: template<class Container> constexpr auto *container-append*(Container& c) { *// exposition only* return [&c]<class Ref>(Ref&& ref) { if constexpr (requires { c.emplace_back(declval<Ref>()); }) c.emplace_back(std::forward<Ref>(ref)); else if constexpr (requires { c.push_back(declval<Ref>()); }) c.push_back(std::forward<Ref>(ref)); <del>else if constexpr (requires { c.emplace(c.end(), declval<Ref>()); }) c.emplace(c.end(), std::forward<Ref>(ref));</del> else c.insert(c.end(), std::forward<Ref>(ref)); }; };

*[2025-03-13; Jonathan provides improved wording for Tim's suggestion]*

It's true that for some cases it might be optimal to use `c.emplace(ref)` instead of `c.emplace_hint(c.end(), ref)` but I don't think I care. A bad hint is not expensive, it's just an extra comparison then the hint is ignored. And this code path isn't going to be used for `std::set` or `std::map`, only for user-defined associative containers that don't have a `from_range_t` constructor or a `C(Iter,Sent)` constructor. I think just fixing the original issue is all we need, rather than trying to handle every possible way to insert elements.

This is a simpler, portable reproducer that doesn't depend on the current implementation status of `std::set` in libstdc++:

> ```
> #include <ranges>
> #include <set>
> struct Set : std::set<int> {
>   Set() { }; // No other constructors
> };
> int main() {
>   int a[1];
>   auto okay = std::ranges::to<std::set<int>>(a);
>   auto ohno = std::ranges::to<Set>(a);
> }
> ```

Previous resolution [SUPERSEDED]

This wording is relative to [N5001](https://wg21.link/N5001).

1. Modify 25.5.7.1 [[range.utility.conv.general]](https://wg21.link/range.utility.conv.general) as indicated: -4- Let `*container-appendable*` be defined as follows: template<class Container, class Ref> constexpr bool *container-appendable* = *// exposition only* requires(Container& c, Ref&& ref) { requires (requires { c.emplace_back(std::forward<Ref>(ref)); } || requires { c.push_back(std::forward<Ref>(ref)); } || <ins>requires { c.emplace_hint(c.end(), std::forward<Ref>(ref)); } ||</ins> requires { c.emplace(c.end(), std::forward<Ref>(ref)); } || requires { c.insert(c.end(), std::forward<Ref>(ref)); }); }; -5- Let `*container-append*` be defined as follows: template<class Container> constexpr auto *container-append*(Container& c) { *// exposition only* return [&c]<class Ref>(Ref&& ref) { if constexpr (requires { c.emplace_back(declval<Ref>()); }) c.emplace_back(std::forward<Ref>(ref)); else if constexpr (requires { c.push_back(declval<Ref>()); }) c.push_back(std::forward<Ref>(ref)); <ins>else if constexpr (requires { c.emplace_hint(c.end(), declval<Ref>()); }) c.emplace_hint(c.end(), std::forward<Ref>(ref));</ins> else if constexpr (requires { c.emplace(c.end(), declval<Ref>()); }) c.emplace(c.end(), std::forward<Ref>(ref)); else c.insert(c.end(), std::forward<Ref>(ref)); }; };

*[2026-05-22; Jonathan provides new wording]*

Hewill noted that all the standard sequence containers that could use `c.emplace(c.end(), ref)` would already have used the `emplace_back` branch, so there's no point using `c.emplace`. Just change that branch to use `emplace_hint` for associative containers.

*[2026-05-29; Reflector poll.]*

Set status to Tentatively Ready after nine votes in favour during reflector poll.

**Proposed resolution:**

This wording is relative to [N5046](https://wg21.link/N5046).

1. Modify 25.5.7.1 [[range.utility.conv.general]](https://wg21.link/range.utility.conv.general) as indicated: -4- Let `*container-appendable*` be defined as follows: template<class Container, class Ref> constexpr bool *container-appendable* = *// exposition only* requires(Container& c, Ref&& ref) { requires (requires { c.emplace_back(std::forward<Ref>(ref)); } || requires { c.push_back(std::forward<Ref>(ref)); } || requires { c.emplace<ins>_hint</ins>(c.end(), std::forward<Ref>(ref)); } || requires { c.insert(c.end(), std::forward<Ref>(ref)); }); }; -5- Let `*container-append*` be defined as follows: template<class Container> constexpr auto *container-append*(Container& c) { *// exposition only* return [&c]<class Ref>(Ref&& ref) { if constexpr (requires { c.emplace_back(declval<Ref>()); }) c.emplace_back(std::forward<Ref>(ref)); else if constexpr (requires { c.push_back(declval<Ref>()); }) c.push_back(std::forward<Ref>(ref)); else if constexpr (requires { c.emplace<ins>_hint</ins>(c.end(), declval<Ref>()); }) c.emplace<ins>_hint</ins>(c.end(), std::forward<Ref>(ref)); else c.insert(c.end(), std::forward<Ref>(ref)); }; };

---

### Should there be a feature-test macro update for constexpr std::to_(w)string?

**Section:** 17.3.2 [[version.syn]](https://wg21.link/version.syn) **Status:** [Tentatively Ready](https://cplusplus.github.io/LWG/lwg-active.html#Ready) **Submitter:** Jiang An **Opened:** 2026-02-25 **Last modified:** 2026-05-22

**Priority:**2

**View other** [active issues](https://cplusplus.github.io/LWG/lwg-index-open.html#version.syn) in [version.syn].

**View all other** [issues](https://cplusplus.github.io/LWG/lwg-index.html#version.syn) in [version.syn].

**Discussion:**

[P3391R2](https://wg21.link/P3391R2) added `constexpr` to integral overloads of `std::to_string` and `std::to_wstring`. However, the paper only added one feature-test macro `__cpp_lib_constexpr_format`, which doesn't seem clearly related to `std::to_(w)string`.

Given that [P3391R2](https://wg21.link/P3391R2) contained the constexpr additions in [P3438R0](https://wg21.link/P3438R0) which proposed to bump `__cpp_lib_to_string`, perhaps we should bump that FTM. It might be also reasonable to bump `__cpp_lib_constexpr_string` for pure constexpr additions.

*[2026-04-13; Reflector poll.]*

Set priority to 2 after reflector poll.

Previous resolution [SUPERSEDED]

This wording is relative to [N5032](https://wg21.link/N5032).

> [*Drafting Note:* Two mutually exclusive options are prepared, depicted below by **Option A** and **Option B**, respectively.]

**Option A:**

1. Modify 17.3.2 [[version.syn]](https://wg21.link/version.syn) as indicated: […] #define __cpp_lib_to_string <del>202306L</del><ins>202511L</ins> // *also in <string>* […]

**Option B:**

1. Modify 17.3.2 [[version.syn]](https://wg21.link/version.syn) as indicated: […] #define __cpp_lib_constexpr_string <del>201907L</del><ins>202511L</ins> // *also in <string>* […]

*[2026-05-11; Select single resolution.]*

Update wording to option B, that had slight preference in reflector discussion.

*[2026-05-22; Reflector poll.]*

Set status to Tentatively Ready after six votes in favour during reflector poll.

**Proposed resolution:**

This wording is relative to [N5032](https://wg21.link/N5032).

1. Modify 17.3.2 [[version.syn]](https://wg21.link/version.syn) as indicated: […] #define __cpp_lib_constexpr_string <del>201907L</del><ins>202511L</ins> // *also in <string>* […]

---

### Feature test macro value for apply_result, is_applicable

**Section:** 17.3.2 [[version.syn]](https://wg21.link/version.syn) **Status:** [Tentatively Ready](https://cplusplus.github.io/LWG/lwg-active.html#Ready) **Submitter:** Tomasz Kamiński **Opened:** 2026-04-08 **Last modified:** 2026-05-30

**Priority:**Not Prioritized

**View other** [active issues](https://cplusplus.github.io/LWG/lwg-index-open.html#version.syn) in [version.syn].

**View all other** [issues](https://cplusplus.github.io/LWG/lwg-index.html#version.syn) in [version.syn].

**Discussion:**

The paper [P1317R2](https://wg21.link/P1317R2) "Remove return type deduction in `std::apply`", which changed the definition of `std::apply` and introduced the new traits `is_applicable`, `is_nothrow_applicable`, and `apply_result`, was accepted in Sofia.

In Croydon we moved the [P3795R2](https://wg21.link/P3795R2) "Miscellaneous Reflection Cleanup", that adds the reflection equivalents of above, under `__cpp_lib_reflection`.

This leads to situation, when an implementation that does not yet implement [P1317R2](https://wg21.link/P1317R2), and thus does not define the corresponding meta functions, should not define `__cpp_lib_reflection`.

I propose to assign the following `__cpp_lib_apply` macro values to account to above papers:

- `202506L` for [P1317R2](https://wg21.link/P1317R2) also in `<tuple>`, `<type_traits>`
- `202603L` for the corresponding parts of [P3795R2](https://wg21.link/P3795R2) also in `<meta>`

The proposed resolution for the standard working paper represents only the effective end state.

*[2026-05-29; Reflector poll.]*

Set status to Tentatively Ready after six votes in favour during reflector poll.

**Proposed resolution:**

1. Modify 17.3.2 [[version.syn]](https://wg21.link/version.syn) as indicated: #define __cpp_lib_apply <del>202506L</del><ins>202603L</ins> // *freestanding, also in <tuple>, <type_traits><ins>, <meta></ins>*

---

### std::execution::spawn_future is mishandling dependent senders

**Section:** 33.9.12.18 [[exec.spawn.future]](https://wg21.link/exec.spawn.future) **Status:** [Tentatively Ready](https://cplusplus.github.io/LWG/lwg-active.html#Ready) **Submitter:** Eric Niebler **Opened:** 2026-04-11 **Last modified:** 2026-05-30

**Priority:**Not Prioritized

**View all other** [issues](https://cplusplus.github.io/LWG/lwg-index.html#exec.spawn.future) in [exec.spawn.future].

**Discussion:**

In 33.9.12.18 [[exec.spawn.future]](https://wg21.link/exec.spawn.future) p7, we see this:

> -7- Let `*spawn-future-state*` be the exposition-only class template:
> 
> > ```
> > namespace std::execution {
> >   template<class Alloc, scope_token Token, sender Sender, class Env>
> >   struct spawn-future-state                   // exposition only
> >     : spawn-future-state-base<completion_signatures_of_t<future-spawned-sender<Sender, Env>>> {
> >     using sigs-t =                            // exposition only
> >       completion_signatures_of_t<future-spawned-sender<Sender, Env>>;
> >     using receiver-t =                        // exposition only
> >       spawn-future-receiver<sigs-t>;
> >     using op-t =                              // exposition only
> >       connect_result_t<future-spawned-sender<Sender, Env>, receiver-t>;
> >   […]
> >   };
> > […]
> > }
> > ```

where `*spawn-future-sender*<Sender, Env>` is the type of `write_env(*stop-when*(declval<Sender>(), declval<stoken-t>()), declval<Env>())`.

The problem happens in the definition of `*sigs-t*`. There is a difference between asking for a sender's completion signatures with an empty environment, and asking with no environment.

In `*sigs-t*`, we are asking for the completion signatures with no environment. That is asking the sender for its non-dependent completions. But if `Sender` is a dependent sender, then so is `*future-spawned-sender*<Sender, Env>`, and so this line will not compile. A dependent sender cannot provide non-dependent completion signatures.

The `spawn_future` algorithm connects the `*future-spawned-sender*` with a receiver that has an empty environment. Therefore, we should be using the empty environment when computing the `*future-spawned-sender*`'s completion signatures.

*[2026-05-29; Reflector poll.]*

Set status to Tentatively Ready after five votes in favour during reflector poll.

**Proposed resolution:**

1. Modify 33.9.12.18 [[exec.spawn.future]](https://wg21.link/exec.spawn.future) as indicated: -7- Let `*spawn-future-state*` be the exposition-only class template: namespace std::execution { template<class Alloc, scope_token Token, sender Sender, class Env> struct *spawn-future-state* // *exposition only* : *spawn-future-state-base*<completion_signatures_of_t<*future-spawned-sender*<Sender, Env><ins>, env<></ins>>> { using *sigs-t* = // *exposition only* completion_signatures_of_t<*future-spawned-sender*<Sender, Env><ins>, env<></ins>>; using *receiver-t* = // *exposition only* *spawn-future-receiver*<*sigs-t*>; using *op-t* = // *exposition only* connect_result_t<*future-spawned-sender*<Sender, Env>, *receiver-t*>; […] }; […] }

---

### *make-state*<Rcvr>::*state-type*::*complete* uses Env which is not in scope

**Section:** 33.9.12.12 [[exec.when.all]](https://wg21.link/exec.when.all) **Status:** [Tentatively Ready](https://cplusplus.github.io/LWG/lwg-active.html#Ready) **Submitter:** Abhinav Agarwal **Opened:** 2026-05-12 **Last modified:** 2026-05-30

**Priority:**Not Prioritized

**View other** [active issues](https://cplusplus.github.io/LWG/lwg-index-open.html#exec.when.all) in [exec.when.all].

**View all other** [issues](https://cplusplus.github.io/LWG/lwg-index.html#exec.when.all) in [exec.when.all].

**Discussion:**

In 33.9.12.12 [[exec.when.all]](https://wg21.link/exec.when.all), the specification of `*make-state*::*state-type*::*complete*` (paragraph 15, bullet (15.3)) defines `*sends-stopped*` as true if and only if there exists an element `S` of `Sndrs` such that

> ```
> completion_signatures_of_t<S, when-all-env<Env>>
> ```

contains `set_stopped_t()`.

However, no declaration named `Env` is in scope at this point. `*state-type*` is specified in the context of `*make-state*<Rcvr>::operator()<Sndrs...>`; the relevant named template parameters there are `Rcvr` and `Sndrs...`. `Env` is a template parameter of `*check-types*<Sndr, Env...>`, which is a separate member function whose scope does not extend into `*make-state*`.

Other environment-dependent wording within the `*make-state*` scope uses `env_of_t<Rcvr>`:

- The `stop_callback` alias (paragraph 12 within the `*make-state*` class template synopsis) uses `stop_callback_for_t<stop_token_of_t<env_of_t<Rcvr>>, *on-stop-request*>`
- The `values_tuple` alias (paragraph 13) uses `value_types_of_t<Sndrs, *FWD-ENV-T*(env_of_t<Rcvr>), […]>`

The `*sends-stopped*` definition in bullet (15.3) is the only use of bare `Env` in this scope.

This issue was introduced by [P3887R1](https://wg21.link/P3887R1) ("Make when_all a Ronseal Algorithm"), whose wording contains the same text.

*[2026-05-29; Reflector poll.]*

Set status to Tentatively Ready after five votes in favour during reflector poll.

**Proposed resolution:**

This wording is relative to [N5046](https://wg21.link/N5046).

1. Modify 33.9.12.12 [[exec.when.all]](https://wg21.link/exec.when.all) as indicated: -15- The member `void *state-type*::*complete*(Rcvr& rcvr) noexcept` behaves as follows: (15.1) — If `disp` is equal to `*disposition*::*started*`, evaluates: […] (15.2) — Otherwise, if `disp` is equal to `*disposition*::*error*`, evaluates: […] (15.3) — Otherwise, evaluates: if constexpr (*sends-stopped*) { *on_stop*.reset(); set_stopped(std::move(rcvr)); } where `*sends-stopped*` equals true if and only if there exists an element `S` of `Sndrs` such that `completion_signatures_of_t<S, *when-all-env*<<del>Env</del><ins>env_of_t<Rcvr></ins>>>` contains `set_stopped_t()`.
