Revised 2017-12-14 at 04:21:49 UTC

Tentative Issues


2243(i). istream::putback problem

Section: 30.7.4.3 [istream.unformatted] Status: Tentatively Ready Submitter: Juan Soulie Opened: 2013-03-01 Last modified: 2017-12-14

Priority: 3

View all other issues in [istream.unformatted].

View all issues with Tentatively Ready status.

Discussion:

In 30.7.4.3 [istream.unformatted] / 34, when describing putback, it says that "rdbuf->sputbackc()" is called. The problem are not the obvious typos in the expression, but the fact that it may lead to different interpretations, since nowhere is specified what the required argument to sputbackc is.

It can be guessed to be "rdbuf()->sputbackc(c)", but "rdbuf()->sputbackc(char_type())" or just anything would be as conforming (or non-conforming) as the first guess.

[2017-12-12, Jonathan comments and provides wording]

Fix the bogus expression, and change sputbackc() to just sputbackc since we're talking about the function, not an expression sputbackc() (which isn't a valid expression any more than rdbuf->sputbackc() is). Make the corresponding change to the equivalent wording in p36 too.

[ 2017-12-14 Moved to Tentatively Ready after 6 positive votes on c++std-lib. ]

Proposed resolution:

This wording is relative to N4713.

  1. Change 30.7.4.3 [istream.unformatted] as shown:

    basic_istream<charT, traits>& putback(char_type c);
    

    -34- Effects: Behaves as an unformatted input function (as described above), except that the function first clears eofbit. After constructing a sentry object, if !good() calls setstate(failbit) which may throw an exception, and return. If rdbuf() is not null, calls rdbuf()->sputbackc(c). If rdbuf() is null, or if sputbackc() returns traits::eof(), calls setstate(badbit) (which may throw ios_base::failure (30.5.5.4 [iostate.flags])). [Note: This function extracts no characters, so the value returned by the next call to gcount() is 0. — end note]

    -35- Returns: *this.

    basic_istream<charT, traits>& unget();
    

    -36- Effects: Behaves as an unformatted input function (as described above), except that the function first clears eofbit. After constructing a sentry object, if !good() calls setstate(failbit) which may throw an exception, and return. If rdbuf() is not null, calls rdbuf()->sungetc(). If rdbuf() is null, or if sungetc() returns traits::eof(), calls setstate(badbit) (which may throw ios_base::failure (30.5.5.4 [iostate.flags])). [Note: This function extracts no characters, so the value returned by the next call to gcount() is 0. — end note]

    -37- Returns: *this.


3000(i). monotonic_memory_resource::do_is_equal uses dynamic_cast unnecessarily

Section: 23.12.6.2 [mem.res.monotonic.buffer.mem] Status: Tentatively Ready Submitter: Pablo Halpern Opened: 2017-07-14 Last modified: 2017-11-01

Priority: 0

View all issues with Tentatively Ready status.

Discussion:

Section [mem.res.monotonic.buffer.mem], paragraph 11 says

bool do_is_equal(const memory_resource& other) const noexcept override;

Returns: this == dynamic_cast<const monotonic_buffer_resource*>(&other).

The dynamic_cast adds nothing of value. It is an incorrect cut-and-paste from an example do_is_equal for a more complex resource.

[2017-07-16, Tim Song comments]

The pool resource classes appear to also have this issue.

[2017-09-18, Casey Carter expands PR to cover the pool resources.]

Previous resolution: [SUPERSEDED]
  1. Edit 23.12.6.2 [mem.res.monotonic.buffer.mem] as indicated:

    bool do_is_equal(const memory_resource& other) const noexcept override;
    

    Returns: this == dynamic_cast<const monotonic_buffer_resource*>(&other).

[ 2017-11-01 Moved to Tentatively Ready after 7 positive votes for P0 on c++std-lib. ]

Proposed resolution:

This resolution is relative to N4687.

  1. Edit 23.12.5.4 [mem.res.pool.mem] as indicated:

    bool synchronized_pool_resource::do_is_equal(const memory_resource& other) const noexcept override;
        const memory_resource& other) const noexcept override;
    

    Returns: this == dynamic_cast<const synchronized_pool_resource*>(&other).

  2. Strike 23.12.5.4 [mem.res.pool.mem] paragraph 10, and the immediately preceding declaration of unsynchronized_pool_resource::do_is_equal.

  3. Edit 23.12.6.2 [mem.res.monotonic.buffer.mem] as indicated:

    bool do_is_equal(const memory_resource& other) const noexcept override;
    

    Returns: this == dynamic_cast<const monotonic_buffer_resource*>(&other).


3002(i). [networking.ts] basic_socket_acceptor::is_open() isn't noexcept

Section: 99 [networking.ts::socket.acceptor.ops] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2017-07-14 Last modified: 2017-11-01

Priority: 0

View all issues with Tentatively Ready status.

Discussion:

Addresses: networking.ts

basic_socket::is_open() is noexcept, but the corresponding function on basic_socket_acceptor is not. This is a simple observer with a wide contract and cannot fail.

[ 2017-11-01 Moved to Tentatively Ready after 7 positive votes for P0 on c++std-lib. ]

Proposed resolution:

This resolution is relative to N4656.

  1. Edit [networking.ts::socket.acceptor], class template basic_socket_acceptor synopsis, as indicated:

    template<class AcceptableProtocol> 
    class basic_socket_acceptor {
    public:
      […]
      bool is_open() const noexcept;
      […]
    };
    
  2. Edit 99 [networking.ts::socket.acceptor.ops] as indicated:

    bool is_open() const noexcept;
    

    -10- Returns: A bool indicating whether this acceptor was opened by a previous call to open or assign.


3004(i). §[string.capacity] and §[vector.capacity] should specify time complexity for capacity()

Section: 24.3.2.4 [string.capacity], 26.3.11.3 [vector.capacity] Status: Tentatively Ready Submitter: Andy Giese Opened: 2017-07-24 Last modified: 2017-11-01

Priority: 0

View other active issues in [string.capacity].

View all other issues in [string.capacity].

View all issues with Tentatively Ready status.

Discussion:

basic_string and vector both have a capacity function that returns the size of the internally allocated buffer. This function does not specify a time complexity nor does it have an implied time complexity. However, given the complexities for data() to be 𝒪(1) and size() to be 𝒪(1), we can imagine that it's reasonable to also require capacity() to be 𝒪(1), since the implementation will most likely be caching the size of the allocated buffer so as to check for the need to reallocate on insertion.

[ 2017-11-01 Moved to Tentatively Ready after 10 positive votes for P0 on c++std-lib. ]

Proposed resolution:

This resolution is relative to N4659.

  1. Edit 24.3.2.4 [string.capacity] as indicated:

    size_type capacity() const noexcept;
    

    -9- Returns: The size of the allocated storage in the string.

    -?- Complexity: Constant time.

  2. Edit 26.3.11.3 [vector.capacity] as indicated:

    size_type capacity() const noexcept;
    

    -1- Returns: The total number of elements that the vector can hold without requiring reallocation.

    -?- Complexity: Constant time.


3005(i). Destruction order of arrays by make_shared/allocate_shared only recommended?

Section: 23.11.3.6 [util.smartptr.shared.create] Status: Tentatively Ready Submitter: Richard Smith Opened: 2017-08-01 Last modified: 2017-11-02

Priority: 0

View other active issues in [util.smartptr.shared.create].

View all other issues in [util.smartptr.shared.create].

View all issues with Tentatively Ready status.

Discussion:

In [util.smartptr.shared.create]/7.9 we find this:

"When the lifetime of the object managed by the return value ends, or when the initialization of an array element throws an exception, the initialized elements should be destroyed in the reverse order of their construction."

Why is this only a "should be" and not a "shall be" (or, following usual conventions for how we write requirements on the implementation, "are")? Is there some problem that means we can't require an implementation to destroy in reverse construction order in all cases?

Previous resolution: [SUPERSEDED]

This resolution is relative to N4687.

  1. Edit 23.11.3.6 [util.smartptr.shared.create] as indicated:

    template<class T, ...>
    shared_ptr<T> make_shared(args);
    template<class T, class A, ...>
    shared_ptr<T> allocate_shared(const A& a, args);
    

    […]

    -7- Remarks:

    1. […]

    2. (7.9) — When the lifetime of the object managed by the return value ends, or when the initialization of an array element throws an exception, the initialized elements areshould be destroyed in decreasing index orderthe reverse order of their construction.

[2017-11-01, Alisdair comments and suggests wording improvement]

I dislike the change of how we specify the order of destruction, which is clear (but non-normative) from the preceding paragraph making the order of construction explicit. We are replacing that with a different specification, so now I need to match up ""decreasing index order" to "ascending order of address" to infer the behavior that is worded more directly today.

P0 to change "should be" to "are" though.

Previous resolution: [SUPERSEDED]

This resolution is relative to N4700.

  1. Edit 23.11.3.6 [util.smartptr.shared.create] as indicated:

    template<class T, ...>
    shared_ptr<T> make_shared(args);
    template<class T, class A, ...>
    shared_ptr<T> allocate_shared(const A& a, args);
    

    […]

    -7- Remarks:

    1. […]

    2. (7.9) — When the lifetime of the object managed by the return value ends, or when the initialization of an array element throws an exception, the initialized elements areshould be destroyed in the reverse order of their construction.

[2017-11-01]

The rationale for the "decreasing index order" change in the original P/R suggested by Richard Smith had been presented as that user code may destroy one or more array elements and construct new ones in their place. In those cases shared_ptr has no way of knowing the construction order, so it cannot ensure that the destruction order reverses it.
Richard: Perhaps something like:

the initialized elements are should be destroyed in the reverse order of their original construction.

would work?

[ 2017-11-02 Moved to Tentatively Ready after 10 positive votes for P0 on c++std-lib. ]

Proposed resolution:

This resolution is relative to N4700.

  1. Edit 23.11.3.6 [util.smartptr.shared.create] as indicated:

    template<class T, ...>
    shared_ptr<T> make_shared(args);
    template<class T, class A, ...>
    shared_ptr<T> allocate_shared(const A& a, args);
    

    […]

    -7- Remarks:

    1. […]

    2. (7.9) — When the lifetime of the object managed by the return value ends, or when the initialization of an array element throws an exception, the initialized elements areshould be destroyed in the reverse order of their original construction.


3007(i). allocate_shared should rebind allocator to cv-unqualified value_type for construction

Section: 23.11.3.6 [util.smartptr.shared.create] Status: Tentatively Ready Submitter: Glen Joseph Fernandes Opened: 2017-08-06 Last modified: 2017-11-01

Priority: 0

View other active issues in [util.smartptr.shared.create].

View all other issues in [util.smartptr.shared.create].

View all issues with Tentatively Ready status.

Discussion:

The remarks for the allocate_shared family of functions specify that when constructing a (sub)object of type U, it uses a rebound copy of the allocator a passed to allocate_shared such that its value_type is U. However U can be a const or volatile qualified type, and [allocator.requirements] specify that the value_type must be cv-unqualified.

[ 2017-11-01 Moved to Tentatively Ready after 6 positive votes for P0 on c++std-lib. ]

Proposed resolution:

This resolution is relative to N4687.

  1. Edit 23.11.3.6 [util.smartptr.shared.create] as indicated:

    template<class T, ...>
    shared_ptr<T> make_shared(args);
    template<class T, class A, ...>
    shared_ptr<T> allocate_shared(const A& a, args);
    

    […]

    -7- Remarks:

    1. […]

    2. (7.5) — When a (sub)object of a non-array type U is specified to have an initial value of v, or U(l...), where l... is a list of constructor arguments, allocate_shared shall initialize this (sub)object via the expression

      1. (7.5.1) — allocator_traits<A2>::construct(a2, pv, v) or

      2. (7.5.2) — allocator_traits<A2>::construct(a2, pv, l...)

      respectively, where pv points to storage suitable to hold an object of type U and a2 of type A2 is a rebound copy of the allocator a passed to allocate_shared such that its value_type is remove_cv_t<U>.

    3. (7.6) — When a (sub)object of non-array type U is specified to have a default initial value, make_shared shall initialize this (sub)object via the expression ::new(pv) U(), where pv has type void* and points to storage suitable to hold an object of type U.

    4. (7.7) — When a (sub)object of non-array type U is specified to have a default initial value, allocate_shared shall initialize this (sub)object via the expression allocator_traits<A2>::construct(a2, pv), where pv points to storage suitable to hold an object of type U and a2 of type A2 is a rebound copy of the allocator a passed to allocate_shared such that its value_type is remove_cv_t<U>.

    5. […]


3009(i). Including <string_view> doesn't provide std::size/empty/data

Section: 27.8 [iterator.container] Status: Tentatively Ready Submitter: Tim Song Opened: 2017-08-11 Last modified: 2017-11-01

Priority: 0

View all issues with Tentatively Ready status.

Discussion:

basic_string_view has size(), empty(), and data() members, but including <string_view> isn't guaranteed to give you access to the corresponding free function templates. This seems surprising.

[ 2017-11-01 Moved to Tentatively Ready after 7 positive votes for P0 on c++std-lib. ]

Proposed resolution:

This resolution is relative to N4687.

  1. Edit 27.8 [iterator.container] as indicated:

    -1- In addition to being available via inclusion of the <iterator> header, the function templates in 27.8 are available when any of the following headers are included: <array>, <deque>, <forward_list>, <list>, <map>, <regex>, <set>, <string>, <string_view>, <unordered_map>, <unordered_set>, and <vector>.


3010(i). [networking.ts] uses_executor says "if a type T::executor_type exists"

Section: 99 [networking.ts::async.uses.excecutor.trait] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2017-08-17 Last modified: 2017-11-01

Priority: 0

View all issues with Tentatively Ready status.

Discussion:

Addresses: networking.ts

[async.uses.executor.trait] p1 says "if a type T::executor_type exists" but we don't want it to be required to detect private or ambiguous types.

[ 2017-11-01 Moved to Tentatively Ready after 7 positive votes for P0 on c++std-lib. ]

Proposed resolution:

This resolution is relative to N4656.

  1. Edit [networking.ts::async.uses.executor.trait] as indicated:

    -1- Remark: Detects whether T has a nested executor_type that is convertible from Executor. Meets the BinaryTypeTrait requirements (C++Std [meta.rqmts]). The implementation provides a definition that is derived from true_type if a typethe qualified-id T::executor_type existsis valid and denotes a type and is_convertible<Executor, T::executor_type>::value != false, otherwise it is derived from false_type. A program may specialize this template […].


3013(i). (recursive_)directory_iterator construction and traversal should not be noexcept

Section: 30.11.12.1 [fs.dir.itr.members], 30.11.13.1 [fs.rec.dir.itr.members], 30.11.14.3 [fs.op.copy], 30.11.14.19 [fs.op.is_empty] Status: Tentatively Ready Submitter: Tim Song Opened: 2017-08-23 Last modified: 2017-11-03

Priority: 0

View other active issues in [fs.dir.itr.members].

View all other issues in [fs.dir.itr.members].

View all issues with Tentatively Ready status.

Discussion:

Constructing a (recursive_)directory_iterator from a path requires, at a minimum, initializing its underlying directory_entry object with the path formed from the supplied path and the name of the first entry, which requires a potentially throwing memory allocation; every implementation I've looked at also allocates memory to store additional data as well.

Similarly, increment() needs to update the path stored in directory_entry object to refer to the name of the next entry, which may require a memory allocation. While it might conceivably be possible to postpone the update in this case until the iterator is dereferenced (the dereference operation is not noexcept due to its narrow contract), it seems highly unlikely that such an implementation is intended (not to mention that it would require additional synchronization as the dereference operations are const).

This further calls into question whether the error_code overloads of copy and is_empty, whose specification uses directory_iterator, should be noexcept. There might be a case for keeping the noexcept for is_empty, although that would require changes in all implementations I checked (libstdc++, libc++, and Boost). copy appears to be relentlessly hostile to noexcept, since its specification forms a path via operator/ in two places (bullets 4.7.4 and 4.8.2) in addition to the directory_iterator usage. The proposed resolution below removes both.

[ 2017-11-03 Moved to Tentatively Ready after 7 positive votes for P0 on c++std-lib. ]

Proposed resolution:

This wording is relative to N4700.

  1. Edit 30.11.12 [fs.class.directory_iterator], class directory_iterator synopsis, as indicated:

    […]
    explicit directory_iterator(const path& p);
    directory_iterator(const path& p, directory_options options);
    directory_iterator(const path& p, error_code& ec) noexcept;
    directory_iterator(const path& p, directory_options options,
                       error_code& ec) noexcept;
    […]
    
    directory_iterator& operator++();
    directory_iterator& increment(error_code& ec) noexcept;
    
  2. Edit 30.11.12.1 [fs.dir.itr.members] before p2 as indicated:

    explicit directory_iterator(const path& p);
    directory_iterator(const path& p, directory_options options);
    directory_iterator(const path& p, error_code& ec) noexcept;
    directory_iterator(const path& p, directory_options options, error_code& ec) noexcept;
    

    -2- Effects: […]

    -3- Throws: As specified in 30.11.6 [fs.err.report].

    -4- [Note: […] — end note]

  3. Edit 30.11.12.1 [fs.dir.itr.members] before p10 as indicated:

    directory_iterator& operator++();
    directory_iterator& increment(error_code& ec) noexcept;
    

    -10- Effects: As specified for the prefix increment operation of Input iterators (24.2.3).

    -11- Returns: *this.

    -12- Throws: As specified in 30.11.6 [fs.err.report].

  4. Edit 30.11.13 [fs.class.rec.dir.itr], class recursive_directory_iterator synopsis, as indicated:

    […]
    explicit recursive_directory_iterator(const path& p);
    recursive_directory_iterator(const path& p, directory_options options);
    recursive_directory_iterator(const path& p, directory_options options,
                                 error_code& ec) noexcept;
    recursive_directory_iterator(const path& p, error_code& ec) noexcept;
    […]
    
    recursive_directory_iterator& operator++();
    recursive_directory_iterator& increment(error_code& ec) noexcept;
    
  5. Edit 30.11.13.1 [fs.rec.dir.itr.members] before p2 as indicated:

    explicit recursive_directory_iterator(const path& p);
    recursive_directory_iterator(const path& p, directory_options options);
    recursive_directory_iterator(const path& p, directory_options options, error_code& ec) noexcept;
    recursive_directory_iterator(const path& p, error_code& ec) noexcept;
    

    -2- Effects: […]

    -3- Postconditions: […]

    -4- Throws: As specified in 30.11.6 [fs.err.report].

    -5- [Note: […] — end note]

    -6- [Note: […] — end note]

  6. Edit 30.11.13.1 [fs.rec.dir.itr.members] before p23 as indicated:

    recursive_directory_iterator& operator++();
    recursive_directory_iterator& increment(error_code& ec) noexcept;
    

    -23- Effects: As specified for the prefix increment operation of Input iterators (24.2.3), except that: […]

    -24- Returns: *this.

    -25- Throws: As specified 30.11.6 [fs.err.report].

  7. Edit 30.11.5 [fs.filesystem.syn], header <filesystem> synopsis, as indicated:

    namespace std::filesystem {
    
      […]
    
      void copy(const path& from, const path& to);
      void copy(const path& from, const path& to, error_code& ec) noexcept;
      void copy(const path& from, const path& to, copy_options options);
      void copy(const path& from, const path& to, copy_options options,
                error_code& ec) noexcept;
    
      […]
    
      bool is_empty(const path& p);
      bool is_empty(const path& p, error_code& ec) noexcept;
      
      […]
    
    }
    
  8. Edit 30.11.14.3 [fs.op.copy] as indicated:

    void copy(const path& from, const path& to, error_code& ec) noexcept;
    

    -2- Effects: Equivalent to copy(from, to, copy_options::none, ec).

    void copy(const path& from, const path& to, copy_options options);
    void copy(const path& from, const path& to, copy_options options,
              error_code& ec) noexcept;
    

    -3- Requires: […]

    -4- Effects: […]

    -5- Throws: […]

    -6- Remarks: […]

    -7- [Example: […] — end example]

  9. Edit 30.11.14.19 [fs.op.is_empty] as indicated:

    bool is_empty(const path& p);
    bool is_empty(const path& p, error_code& ec) noexcept;
    

    -1- Effects: […]

    -2- Throws: […]


3017(i). list splice functions should use addressof

Section: 26.3.9.6 [forwardlist.ops], 26.3.10.5 [list.ops] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2017-09-05 Last modified: 2017-11-03

Priority: 0

View all other issues in [forwardlist.ops].

View all issues with Tentatively Ready status.

Discussion:

26.3.9.6 [forwardlist.ops] p1 and 26.3.10.5 [list.ops] p3 say &x != this, but should use addressof. We really need front matter saying that when the library says &x it means std::addressof(x).

[ 2017-11-03 Moved to Tentatively Ready after 9 positive votes for P0 on c++std-lib. ]

Proposed resolution:

This wording is relative to N4687.

  1. Edit 26.3.9.6 [forwardlist.ops] p1 as indicated:

    void splice_after(const_iterator position, forward_list& x);
    void splice_after(const_iterator position, forward_list&& x);
    

    -1- Requires: position is before_begin() or is a dereferenceable iterator in the range [begin(), end()). get_allocator() == x.get_allocator(). &addressof(x) != this.

  2. Edit 26.3.10.5 [list.ops] p3 as indicated:

    void splice(const_iterator position, list& x);
    void splice(const_iterator position, list&& x);
    

    -3- Requires: &addressof(x) != this.

  3. Edit 26.3.10.5 [list.ops] p3 as indicated:

    template <class Compare> void merge(list& x, Compare comp);
    template <class Compare> void merge(list&& x, Compare comp);
    

    -22- Requires: comp shall define a strict weak ordering (28.7 [alg.sorting]), and both the list and the argument list shall be sorted according to this ordering.

    -23- Effects: If (&addressof(x) == this) does nothing; otherwise, merges the two sorted ranges [begin(), end()) and [x.begin(), x.end()). The result is a range in which the elements will be sorted in non-decreasing order according to the ordering defined by comp; that is, for every iterator i, in the range other than the first, the condition comp(*i, *(i - 1)) will be false. Pointers and references to the moved elements of x now refer to those same elements but as members of *this. Iterators referring to the moved elements will continue to refer to their elements, but they now behave as iterators into *this, not into x.

    -24- Remarks: Stable (20.5.5.7 [algorithm.stable]). If (&addressof(x) != this) the range [x.begin(), x.end()) is empty after the merge. No elements are copied by this operation. The behavior is undefined if get_allocator() != x.get_allocator().

    -25- Complexity: At most size() + x.size() - 1 applications of comp if (&addressof(x) != this); otherwise, no applications of comp are performed. If an exception is thrown other than by a comparison there are no effects.


3020(i). [networking.ts] Remove spurious nested value_type buffer sequence requirement

Section: 99 [networking.ts::buffer.reqmts] Status: Tentatively Ready Submitter: Vinnie Falco Opened: 2017-09-20 Last modified: 2017-10-22

Priority: Not Prioritized

View all issues with Tentatively Ready status.

Discussion:

Addresses: networking.ts

The post-condition requirements for ConstBufferSequence and MutableBufferSequence refer to X::value_type, but no such nested type is required. The lambda expression passed to equal can use auto const& parameter types instead.

Previous resolution: [SUPERSEDED]

This wording is relative to N4588.

  1. Modify 99 [networking.ts::buffer.reqmts.mutablebuffersequence] Table 12 "MutableBufferSequence requirements" as indicated:

    Table 12 — MutableBufferSequence requirements
    expression return type assertion/note pre/post-condition
    […]
    X u(x); post:
    equal(
      net::buffer_sequence_begin(x),
      net::buffer_sequence_end(x),
      net::buffer_sequence_begin(u),
      net::buffer_sequence_end(u),
      [](const typename X::value_typeauto& v1,
         const typename X::value_typeauto& v2)
        {
          mutable_buffer b1(v1);
          mutable_buffer b2(v2);
          return b1.data() == b2.data()
              && b1.size() == b2.size();
        })
    
  2. Modify 99 [networking.ts::buffer.reqmts.constbuffersequence] Table 13 "ConstBufferSequence requirements" as indicated:

    Table 13 — ConstBufferSequence requirements
    expression return type assertion/note pre/post-condition
    […]
    X u(x); post:
    equal(
      net::buffer_sequence_begin(x),
      net::buffer_sequence_end(x),
      net::buffer_sequence_begin(u),
      net::buffer_sequence_end(u),
      [](const typename X::value_typeauto& v1,
         const typename X::value_typeauto& v2)
        {
          const_buffer b1(v1);
          const_buffer b2(v2);
          return b1.data() == b2.data()
              && b1.size() == b2.size();
        })
    

[2017-10-19, Peter Dimov provides improved wording]

The alternative wording prevents the need for auto parameters because it takes advantage of the "convertible to" requirement.

[ 2017-10-20 Moved to Tentatively Ready after 5 positive votes on c++std-lib. ]

Proposed resolution:

This wording is relative to N4588.

  1. Modify 99 [networking.ts::buffer.reqmts.mutablebuffersequence] Table 12 "MutableBufferSequence requirements" as indicated:

    Table 12 — MutableBufferSequence requirements
    expression return type assertion/note pre/post-condition
    […]
    X u(x); post:
    equal(
      net::buffer_sequence_begin(x),
      net::buffer_sequence_end(x),
      net::buffer_sequence_begin(u),
      net::buffer_sequence_end(u),
      [](const typename X::value_type& v1mutable_buffer& b1,
         const typename X::value_type& v2mutable_buffer& b2)
        {
          mutable_buffer b1(v1);
          mutable_buffer b2(v2);
          return b1.data() == b2.data()
              && b1.size() == b2.size();
        })
    
  2. Modify 99 [networking.ts::buffer.reqmts.constbuffersequence] Table 13 "ConstBufferSequence requirements" as indicated:

    Table 13 — ConstBufferSequence requirements
    expression return type assertion/note pre/post-condition
    […]
    X u(x); post:
    equal(
      net::buffer_sequence_begin(x),
      net::buffer_sequence_end(x),
      net::buffer_sequence_begin(u),
      net::buffer_sequence_end(u),
      [](const typename X::value_type& v1const_buffer& b1,
         const typename X::value_type& v2const_buffer& v2)
        {
          const_buffer b1(v1);
          const_buffer b2(v2);
          return b1.data() == b2.data()
              && b1.size() == b2.size();
        })
    

3026(i). filesystem::weakly_canonical still defined in terms of canonical(p, base)

Section: 30.11.14.39 [fs.op.weakly_canonical] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2017-10-14 Last modified: 2017-10-16

Priority: Not Prioritized

View all issues with Tentatively Ready status.

Discussion:

LWG 2956 fixed canonical to no longer use a base path, but weakly_canonical should have been changed too:

Effects: Using status(p) or status(p, ec), respectively, to determine existence, return a path composed by operator/= from the result of calling canonical() without a base argument and with a […]

Since canonical doesn't accept a base argument, it doesn't make sense to talk about calling it without one.

[ 2017-10-16 Moved to Tentatively Ready after 5 positive votes on c++std-lib. ]

Proposed resolution:

This wording is relative to N4687.

  1. Change 30.11.14.39 [fs.op.weakly_canonical] as indicated:

    path weakly_canonical(const path& p);
    path weakly_canonical(const path& p, error_code& ec);
    

    -1- Returns: […]

    -2- Effects: Using status(p) or status(p, ec), respectively, to determine existence, return a path composed by operator/= from the result of calling canonical() without a base argument and with a path argument composed of the leading elements of p that exist, if any, followed by the elements of p that do not exist, if any. For the first form, canonical() is called without an error_code argument. For the second form, canonical() is called with ec as an error_code argument, and path() is returned at the first error occurrence, if any.

    […]


3034(i). P0767R1 breaks previously-standard-layout types

Section: 23.15.7.6 [meta.trans.other] Status: Tentatively Ready Submitter: Casey Carter Opened: 2017-11-12 Last modified: 2017-11-17

Priority: 0

View all other issues in [meta.trans.other].

View all issues with Tentatively Ready status.

Discussion:

P0767R1 "Expunge POD" changed the requirement for several library types from "POD" to "trivial." Since these types no longer provide/require the standard-layout portion of "POD," the change breaks:

It appears this breakage was not intentional and not discussed in LWG.

The fix is straight-forward: apply an additional standard-layout requirement to the affected types:

(Albeit the potential for breakage with max_align_t is admittedly small.)

[ 2017-11-14 Moved to Tentatively Ready after 8 positive votes for P0 on c++std-lib. ]

Proposed resolution:

This wording is relative to N4700 + P0767R1.

  1. Change in 21.2.4 [support.types.layout] paragraph 5:

    The type max_align_t is a trivial standard-layout type whose alignment requirement is at least as great as that of every scalar type, and whose alignment requirement is supported in every context (6.6.5 [basic.align]).

  2. Change the table in 23.15.7.6 [meta.trans.other] as indicated:

    aligned_storage
    The member typedef type shall be a trivial standard-layout type suitable for use as uninitialized storage for any object whose size is at most Len and whose alignment is a divisor of Align.

    aligned_union
    The member typedef type shall be a trivial standard-layout type suitable for use as uninitialized storage for any object whose type is listed in Types; its size shall be at least Len.

  3. Change 24.1 [strings.general] paragraph 1 as indicated:

    This Clause describes components for manipulating sequences of any non-array trivial standard-layout (6.7 [basic.types]) type. Such types are called char-like types, and objects of char-like types are called char-like objects or simply characters.


3035(i). std::allocator's constructors should be constexpr

Section: 23.10.10 [default.allocator] Status: Tentatively Ready Submitter: Geoffrey Romer Opened: 2017-11-11 Last modified: 2017-11-25

Priority: Not Prioritized

View all other issues in [default.allocator].

View all issues with Tentatively Ready status.

Discussion:

std::allocator's constructors should be constexpr. It's expected to be an empty class as far as I know, so this should impose no implementation burden, and it would be useful to permit guaranteed static initialization of objects that need to hold a std::allocator, but don't have to actually use it until after construction.

[ 2017-11-25 Moved to Tentatively Ready after 7 positive votes for P0 on c++std-lib. ]

Proposed resolution:

This wording is relative to N4700.

  1. Change in 23.10.10 [default.allocator] as indicated:

    namespace std {
      template <class T> class allocator {
      public:
        using value_type = T;
        using propagate_on_container_move_assignment = true_type;
        using is_always_equal = true_type;
        constexpr allocator() noexcept;
        constexpr allocator(const allocator&) noexcept;
        constexpr template <class U> allocator(const allocator<U>&) noexcept;
        ~allocator();
        T* allocate(size_t n);
        void deallocate(T* p, size_t n);
      };
    }
    

3039(i). Unnecessary decay in thread and packaged_task

Section: 33.3.2.2 [thread.thread.constr], 33.6.10.1 [futures.task.members] Status: Tentatively Ready Submitter: Stephan T. Lavavej Opened: 2017-11-17 Last modified: 2017-11-29

Priority: Not Prioritized

View all other issues in [thread.thread.constr].

View all issues with Tentatively Ready status.

Discussion:

Following P0777R1 "Treating Unnecessary decay", more occurrences can be fixed. When constraints are checking for the same type as thread or a specialization of packaged_task, decaying functions to function pointers and arrays to object pointers can't affect the result.

[28-Nov-2017 Moved to Tentatively Ready after five positive votes on the ML.]

Proposed resolution:

Wording relative to N4700.

  1. Edit 33.3.2.2 [thread.thread.constr] as indicated:

    template <class F, class... Args> explicit thread(F&& f, Args&&... args);
    

    -3- Requires: […]

    -4- Remarks: This constructor shall not participate in overload resolution if decay_tremove_cvref_t<F> is the same type as std::thread.

  2. Edit 33.6.10.1 [futures.task.members] as indicated:

    template <class F>
      packaged_task(F&& f);
    

    -2- Requires: […]

    -3- Remarks: This constructor shall not participate in overload resolution if decay_tremove_cvref_t<F> is the same type as packaged_task<R(ArgTypes...)>.


3040(i). basic_string_view::starts_with Effects are incorrect

Section: 24.4.2.6 [string.view.ops] Status: Tentatively Ready Submitter: Marshall Clow Opened: 2017-11-29 Last modified: 2017-12-13

Priority: 0

View all other issues in [string.view.ops].

View all issues with Tentatively Ready status.

Discussion:

The effects of starts_with are described as equivalent to return compare(0, npos, x) == 0.

This is incorrect, because it returns false when you check to see if any sequence begins with the empty sequence. (There are other failure cases, but that one's easy)

As a drive-by fix, we can make the Effects: for starts_with and ends_with clearer.

Those are the second and proposed third changes, and they are not required.

[ 2017-12-13 Moved to Tentatively Ready after 8 positive votes for P0 on c++std-lib. ]

Proposed resolution:

This wording is relative to N4713.

  1. Change 24.4.2.6 [string.view.ops] p20 as indicated:

    constexpr bool starts_with(basic_string_view x) const noexcept;

    -20- Effects: Equivalent to: return size() >= x.size() && compare(0, nposx.size(), x) == 0;

  2. Change 24.4.2.6 [string.view.ops] p21 as indicated:

    constexpr bool starts_with(charT x) const noexcept;

    -21- Effects: Equivalent to: return !empty() && traits::eq(front(), x)starts_with(basic_string_view(&x, 1));

  3. Change 24.4.2.6 [string.view.ops] p24 as indicated:

    constexpr bool ends_with(charT x) const noexcept;

    -24- Effects: Equivalent to: return !empty() && traits::eq(back(), x)ends_with(basic_string_view(&x, 1));