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:

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

The following classes have an append() member function:

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_);
        }
      };