Revised 2022-03-04 at 14:55:46 UTC

## Tentative Issues

### 3579(i). Complexity guarantees for `resize()` and `append()` functions across the library

Section: 21.3.3.5 [string.capacity], 22.3.8.3 [deque.capacity], 22.3.10.3 [list.capacity], 22.3.11.3 [vector.capacity], 22.3.9.5 [forward.list.modifiers], 26.7.2.8 [valarray.members], 21.3.3.7.2 [string.append], 29.12.6.5.3 [fs.path.append] Status: Tentatively NAD Submitter: Louis Dionne Opened: 2021-08-11 Last modified: 2022-02-23

Priority: 3

View other active issues in [string.capacity].

View all other issues in [string.capacity].

View all issues with Tentatively NAD status.

Discussion:

This issue requests to clarify the complexity requirements for `resize` and `append` member functions across the library. Currently, none of them have complexity requirements associated to them, which means that implementations are free to use a geometric growth approach or not. A geometric growth approach (like what's required by `push_back`) implies that calling `resize/append` with successively larger sizes will have amortized `𝒪(N)` complexity, whereas using a `resize`-exactly approach makes that pattern `𝒪(N2)`.

I believe the Standard should either specify that those member functions are required to have behavior that is consistent with `push_back`, or explicitly mention that implementations are allowed to use whatever growth strategy they want. If we do the former, users could start relying on this guarantee in a portable manner. If we do the latter, it would make it clear to users that they should not rely on the amortized `𝒪(N)` guarantee if they want their code to be portable.

The following classes have a `resize()` member function and also a `push_back()` member function:

- 21.3.3.5 [string.capacity]

- 22.3.8.3 [deque.capacity]

- 22.3.10.3 [list.capacity]

- 22.3.11.3 [vector.capacity]

The following classes have a `resize()` member function but do not support `push_back()`:

- 22.3.9.5 [forward.list.modifiers]

- 26.7.2.8 [valarray.members]

The following classes have an `append()` member function:

- 21.3.3.7.2 [string.append]

- 29.12.6.5.3 [fs.path.append]

None of them specify a complexity requirement. I think we should update all of them to describe what is expected or permitted in an implementation.

[2021-08-20; Reflector poll]

Set priority to 3 and status to "LEWG" after reflector poll.

[2022-02-22 LEWG telecon; Status changed: LEWG → Tentatively NAD.]

A paper would be needed. Such a paper would need to include discussion on whether `allocate_at_least` (new for C++23) has an impact.

Proposed resolution:

### 3649(i). [fund.ts.v3] Reinstate and bump `__cpp_lib_experimental_memory_resource` feature test macro

Section: 1.5 [fund.ts.v3::general.feature.test] Status: Tentatively Ready Submitter: Thomas Köppe Opened: 2021-12-03 Last modified: 2022-02-11

Priority: Not Prioritized

View all issues with Tentatively Ready status.

Discussion:

Addresses: fund.ts.v3

The rebase on C++17 in P0996 had the effect of deleting the feature test macro `__cpp_lib_experimental_memory_resource`: the macro was ostensibly tied to the `memory_resource` facility that had become part of C++17, but we overlooked that there was a residual piece that has not been adopted in the IS, namely the `resource_adaptor` class template.

It is still useful to be able to detect the presence of `resource_adaptor`, so we should reinstate the feature test macro and bump its value.

[2022-01-30; Reflector poll]

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

Proposed resolution:

This wording is relative to N4853.

1. Modify 1.5 [fund.ts.v3::general.feature.test], Table 2, as indicated:

   > Table 2 — Significant features in this technical specification
   > Doc. No. | Title | Primary Section | Macro Name Suffix | Value | Header
   > --- | --- | --- | --- | --- | ---
   > `…`
   > N3916 | Type-erased allocator for std::function | 4.2 | `function_erased_allocator` | `201406` | `<experimental/functional>`
   > N3916 | Polymorphic Memory Resources | 5.4 [fund.ts.v3::memory.resource.syn] | `memory_resources` | [new value] | `<experimental/memory_resource>`
   > N4282 | The World's Dumbest Smart Pointer | 8.12 | `observer_ptr` | `201411` | `<experimental/memory>`
   > `…`

### 3667(i). `std::cout << &X::f` prints `1`

Section: 29.7.5.3 [ostream.formatted] Status: Tentatively NAD Submitter: Peter Dimov Opened: 2022-01-31 Last modified: 2022-02-05

Priority: Not Prioritized

View all issues with Tentatively NAD status.

Discussion:

At present, the program

>     #include <iostream>

>     struct X
>     {
>       void f() {}
>     };

>     int main()
>     {
>       std::cout << &X::f;
>     }

prints `1`. That's because member pointers implicitly convert to `bool`, and there's `operator<<` overload for `bool` in 29.7.5.3.2 [ostream.inserters.arithmetic].

This behavior is rarely useful. In C++20, we added deleted overloads to prevent a similar counter-intuitive output for the case in which e.g. `L"str"` is output to `std::cout`, which used to print the pointer value using the `operator<<` overload for `const void*`.

We should similarly consider adding a deleted overload for member pointers.

[2022-03-04; Reflector poll; Status changed: New → Tentatively NAD]

Needs a paper to LEWG if anything should change here.

Proposed resolution:

This wording is relative to N4901.

1. Modify 29.7.5.2.1 [ostream.general], class template `basic_ostream` synopsis, as indicated:

   >     namespace std {
   >       […]

   >       template<class traits>
   >         basic_ostream<wchar_t, traits>&
   >           operator<<(basic_ostream<wchar_t, traits>&, const char16_t*) = delete;
   >       template<class traits>
   >         basic_ostream<wchar_t, traits>&
   >           operator<<(basic_ostream<wchar_t, traits>&, const char32_t*) = delete;

   >       template<class charT, class traits, class T, class C>
   >         basic_ostream<charT, traits>&
   >           operator<<(basic_ostream<charT, traits>&, T C::*) = delete;
   >     }

### 3670(i). Cpp17InputIterators don't have integer-class difference types

Section: 24.6.4.3 [range.iota.iterator] Status: Tentatively Ready Submitter: Casey Carter Opened: 2022-02-04 Last modified: 2022-02-09

Priority: Not Prioritized

View all other issues in [range.iota.iterator].

View all issues with Tentatively Ready status.

Discussion:

24.6.4.3 [range.iota.iterator] defines

>     using iterator_category = input_iterator_tag; // present only if W models incrementable

but when `difference_type` is an integer-class type the iterator does not meet the Cpp17InputIterator requirements.

[2022-02-07; Daniel comments]

As requested by LWG 3376 and wording implemented by P2393R1, integer-class types are no longer required to have class type.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4901.

> 1. Modify 24.6.4.3 [range.iota.iterator], class `iota_view::iterator` synopsis, as indicated:

>    >     namespace std::ranges {
>    >       template<weakly_incrementable W, semiregular Bound>
>    >         requires weakly-equality-comparable-with<W, Bound> && copyable<W>
>    >       struct iota_view<W, Bound>::iterator {
>    >         […]
>    >         using iterator_category = input_iterator_tag; // present only if W models incrementable and
>    >                                                       // IOTA-DIFF-T(W) is not a class type
>    >         using value_type = W;
>    >         using difference_type = IOTA-DIFF-T(W);
>    >         […]
>    >       };
>    >     }

[2022-02-07; Casey Carter provides improved wording]

[2022-03-04; Reflector poll]

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

Proposed resolution:

This wording is relative to N4901.

1. Modify 24.6.4.3 [range.iota.iterator], class `iota_view::iterator` synopsis, as indicated:

   >     namespace std::ranges {
   >       template<weakly_incrementable W, semiregular Bound>
   >         requires weakly-equality-comparable-with<W, Bound> && copyable<W>
   >       struct iota_view<W, Bound>::iterator {
   >         […]
   >         using iterator_category = input_iterator_tag; // present only if W models incrementable and
   >                                                       // IOTA-DIFF-T(W) is an integral type
   >         using value_type = W;
   >         using difference_type = IOTA-DIFF-T(W);
   >         […]
   >       };
   >     }

### 3671(i). `atomic_fetch_xor` missing from `stdatomic.h`

Section: 31.12 [stdatomic.h.syn] Status: Tentatively Ready Submitter: Hubert Tong Opened: 2022-02-09 Last modified: 2022-02-10

Priority: Not Prioritized

View all issues with Tentatively Ready status.

Discussion:

C17 subclause 7.17.7.5 provides `atomic_fetch_xor` and `atomic_fetch_xor_explicit`. `stdatomic.h` in the working draft (N4901) does not.

[2022-02-09; Jonathan comments and provides wording]

C++20 31.2 [atomics.syn] has both of them, too, so it should definitely be in the common subset.

[2022-03-04; Reflector poll]

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

Proposed resolution:

This wording is relative to N4901.

1. Modify 31.12 [stdatomic.h.syn], header `<stdatomic.h>` synopsis, as indicated:

   > [Drafting Note: The editor is kindly requested to reorder these "`atomic_fetch_KEY`" declarations to match the other synopses in Clause 31 [atomics]: `add`, `sub`, `and`, `or`, `xor`.]

   >     […]
   >     using std::atomic_fetch_or;                    // see below
   >     using std::atomic_fetch_or_explicit;           // see below
   >     using std::atomic_fetch_xor;                   // see below
   >     using std::atomic_fetch_xor_explicit;          // see below
   >     using std::atomic_fetch_and;                   // see below
   >     using std::atomic_fetch_and_explicit;          // see below
   >     […]

### 3672(i). `common_iterator::operator->()` should return by value

Section: 23.5.4.4 [common.iter.access] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2022-02-12 Last modified: 2022-03-04

Priority: Not Prioritized

View all other issues in [common.iter.access].

View all issues with Tentatively Ready status.

Discussion:

23.5.4.4 [common.iter.access] p5 (5.1) says that `common_iterator<T*, S>::operator->()` returns `std::get<T*>(v_)` which has type `T* const&`. That means that `iterator_traits::pointer` is `T* const&` as well (this was recently clarified by LWG 3660). We have an actual pointer here, why are we returning it by reference?

For the three bullet points in 23.5.4.4 [common.iter.access] p5, the second and third return by value anyway, so `decltype(auto)` is equivalent to `auto`. For the first bullet, it would make a lot more sense for raw pointers to be returned by value. That leaves the case where the iterator has an `operator->()` member, which could potentially benefit from returning by reference. But it must return something that is iterator-like or pointer-like, which we usually just pass by value. Casey suggested we should just change `common_iterator<I, S>::operator->()` to return by value in all cases.

Libstdc++ has always returned by value, as an unintended consequence of using a union instead of `std::variant<I, S>`, so that it doesn't use `std::get<I>` to return the member.

[2022-03-04; Reflector poll]

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

Proposed resolution:

This wording is relative to N4901.

1. Modify 23.5.4.1 [common.iterator], class template `common_iterator` synopsis, as indicated:

   >     […]
   >     constexpr decltype(auto) operator*();
   >     constexpr decltype(auto) operator*() const
   >       requires dereferenceable<const I>;
   >     constexpr decltype(auto) operator->() const
   >       requires see below;
   >     […]

2. Modify 23.5.4.4 [common.iter.access] as indicated:

   >     constexpr decltype(auto) operator->() const
   >       requires see below;

   > > -3- The expression in the requires-clause is equivalent to: […]

   > > -4- Preconditions: `holds_alternative<I>(v_)` is `true`.

   > > -5- Effects:

   > > 1. (5.1) — If `I` is a pointer type or if the expression `get<I>(v_).operator->()` is well-formed, equivalent to: `return get<I>(v_);`

   > > 2. (5.2) — Otherwise, if `iter_reference_t<I>` is a reference type, equivalent to:

   > >    >     auto&& tmp = *get<I>  (v_);
   > >    >     return addressof(tmp);

   > > 3. (5.3) — Otherwise, equivalent to: `return proxy(*get<I>(v_));` where `proxy` is the exposition-only class:

   > >    >     class proxy {
   > >    >       iter_value_t<I> keep_;
   > >    >       constexpr proxy(iter_reference_t<I>&& x)
   > >    >         : keep_(std::move(x)) {}
   > >    >     public:
   > >    >       constexpr const iter_value_t<I>* operator->() const noexcept {
   > >    >         return addressof(keep_);
   > >    >       }
   > >    >     };