Revised 2016-05-30 at 02:05:30 UTC

Tentative Issues


760. The emplace issue

Section: 23.2 [container.requirements] Status: Tentatively NAD Submitter: Paolo Carlini Opened: 2007-11-11 Last modified: 2016-02-12

Priority: 2

View other active issues in [container.requirements].

View all other issues in [container.requirements].

View all issues with Tentatively NAD status.

Discussion:

In an emplace member function the function parameter pack may be bound to a priori unlimited number of objects: some or all of them can be elements of the container itself. Apparently, in order to conform to the blanket statement 23.2 [container.requirements]/11, the implementation must check all of them for that possibility. A possible solution can involve extending the exception in 23.2 [container.requirements]/12 also to the emplace member. As a side note, the push_back and push_front member functions are luckily not affected by this problem, can be efficiently implemented anyway.

[ Related to 767 and to 2164 ]

[ Bellevue: ]

The proposed addition (13) is partially redundant with the existing paragraph 12. Why was the qualifier "rvalues" added to paragraph 12? Why does it not cover subelements and pointers?

Resolution: Alan Talbot to rework language, then set state to Review.

[ 2009-07 Frankfurt ]

The problem is broader than emplace. The LWG doesn't feel that it knows how to write wording that prohibits all of the problematic use cases at this time.

NAD Future.

[2015-02 Cologne]

LWG believes that 2164 addresses this issue and therefore considers 760 as NAD.

Proposed resolution:

Add after 23.2 [container.requirements]/12:

-12- Objects passed to member functions of a container as rvalue references shall not be elements of that container. No diagnostic required.

-13- Objects bound to the function parameter pack of the emplace member function shall not be elements or sub-objects of elements of the container. No diagnostic required.


2179. enable_shared_from_this and construction from raw pointers

Section: 20.10.2.5 [util.smartptr.enab], 20.10.2.2.1 [util.smartptr.shared.const] Status: Tentatively Resolved Submitter: Daniel Krügler Opened: 2012-08-16 Last modified: 2016-05-17

Priority: 3

View other active issues in [util.smartptr.enab].

View all other issues in [util.smartptr.enab].

View all issues with Tentatively Resolved status.

Discussion:

On reflector message c++std-lib-32927, Matt Austern asked whether the following example should be well-defined or not

struct X : public enable_shared_from_this<X> { };
auto xraw = new X;
shared_ptr<X> xp1(xraw);
shared_ptr<X> xp2(xraw);

pointing out that 20.10.2.2.1 [util.smartptr.shared.const] does not seem to allow it, since xp1 and xp2 aren't allowed to share ownership, because each of them is required to have use_count() == 1. Despite this wording it might be reasonable (and technical possible) to implement that request.

On the other hand, there is the non-normative note in 20.10.2.5 [util.smartptr.enab] p11 (already part of TR1):

The shared_ptr constructors that create unique pointers can detect the presence of an enable_shared_from_this base and assign the newly created shared_ptr to its __weak_this member.

Now according to the specification in 20.10.2.2.1 [util.smartptr.shared.const] p3-7:

template<class Y> explicit shared_ptr(Y* p);

the notion of creating unique pointers can be read to be included by this note, because the post-condition of this constructor is unique() == true. Evidence for this interpretation seems to be weak, though.

Howard Hinnant presented the counter argument, that actually the following is an "anti-idiom" and it seems questionable to teach it to be well-defined in any case:

auto xraw = new X;
shared_ptr<X> xp1(xraw);
shared_ptr<X> xp2(xraw);

He also pointed out that the current post-conditions of the affected shared_ptr constructor would need to be reworded.

It needs to be decided, which direction to follow. If this idiom seems too much broken to be supported, the note could be improved. If it should be supported, the constructors in 20.10.2.2.1 [util.smartptr.shared.const] need a careful analysis to ensure that post-conditions are correct.

Several library implementations currently do not support this example, instead they typically cause a crash. Matt points out that there are currently no explicit requirements imposed on shared_ptr objects to prevent them from owning the same underlying object without sharing the ownership. It might be useful to add such a requirement.

[2013-03-15 Issues Teleconference]

Moved to Open.

More discussion is needed to pick a direction to guide a proposed resolution.

[2013-05-09 Jonathan comments]

The note says the newly created shared_ptr is assigned to the weak_ptr member. It doesn't say before doing that the shared_ptr should check if the weak_ptr is non-empty and possibly share ownership with some other pre-existing shared_ptr.

[2015-08-26 Daniel comments]

LWG issue 2529 is independent but related to this issue.

[2016-03-16, Alisdair comments]

This issues should be closed as Resolved by paper p0033r1 at Jacksonville.

Proposed resolution:


2208. std::reverse_iterator should be a literal type

Section: 24.5.1 [reverse.iterators] Status: Tentatively Resolved Submitter: Jeffrey Yasskin Opened: 2012-10-30 Last modified: 2016-05-17

Priority: 3

View all other issues in [reverse.iterators].

View all issues with Tentatively Resolved status.

Discussion:

std::reverse_iterator::reverse_iterator(Iterator) should be constexpr so that other constexpr functions can return reverse_iterators. Of the other methods, the other constructors, base(), operator+, operator-, operator[], and the non-member operators can probably also be constexpr.

operator* cannot be constexpr because it involves an assignment to a member variable. Discussion starting with c++std-lib-33282 indicated that it would be useful to make reverse_iterator a literal type despite this restriction on its use at compile time.

Proposed resolution:

This issue was Resolved by paper P0031R0 adopted at Jacksonville, 2016.

2337. shared_ptr operator*() should not be noexcept

Section: 20.10.2.2.5 [util.smartptr.shared.obs] Status: Tentatively NAD Submitter: Stephan T. Lavavej Opened: 2013-10-05 Last modified: 2016-02-12

Priority: 2

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

View all issues with Tentatively NAD status.

Discussion:

20.10.1.2.4 [unique.ptr.single.observers]/3: "pointer operator->() const noexcept; Requires: get() != nullptr."

20.10.2.2.5 [util.smartptr.shared.obs]/2: "T& operator*() const noexcept; Requires: get() != 0."

20.10.2.2.5 [util.smartptr.shared.obs]/5: "T* operator->() const noexcept; Requires: get() != 0."

Narrow-contract functions should not be noexcept.

[2014-02-15 Issaquah]

Issue is contentious, raise to P2.

[2015-02 Cologne]

AM: This ship has sailed. JM: What's the issue? AM: operator-> has narrow contract and should never have had noexcept. DK: Not quite. We explicitly called out that for shared_ptr this is fine. You said so in your "narrow contract" paper. GR: This would be a fairly major regression in the design of {unique,shared}_ptr over raw pointers; raw pointer dereferencing is noexcept. It's not a performance regression but a usability regression. AM: Do we expect users to query noexpect on dereference expressions? Room: Yes. VV: We don't just expect it, we have seen it. JM: Yes, users may be querying something like noexcept(x->y) and expect to be checking y, but silently end up checking x->.

Close as NAD, with explanation from GR.

Previous resolution [SUPERSEDED]:

This wording is relative to N3691.

  1. In 20.10.1.2 [unique.ptr.single]/1, class template unique_ptr synopsis for single objects, change as indicated:

    pointer operator->() const noexcept;
    
  2. In 20.10.1.2.4 [unique.ptr.single.observers] change as indicated:

    pointer operator->() const noexcept;
    

    -3- Requires: get() != nullptr.

    -4- Returns: get().

    -?- Throws: Nothing.

    -5- Note: use typically requires that T be a complete type.

  3. In 20.10.2.2 [util.smartptr.shared]/1, class template shared_ptr synopsis, change as indicated:

    T& operator*() const noexcept;
    T* operator->() const noexcept;
    
  4. In 20.10.2.2.5 [util.smartptr.shared.obs] change as indicated:

    T& operator*() const noexcept;
    

    -2- Requires: get() != 0.

    -3- Returns: *get().

    -?- Throws: Nothing.

    -4- Remarks: When T is void, it is unspecified whether this member function is declared. If it is declared, it is unspecified what its return type is, except that the declaration (although not necessarily the definition) of the function shall be well formed.

    T* operator->() const noexcept;
    

    -5- Requires: get() != 0.

    -6- Returns: get().

    -?- Throws: Nothing.

[2015-03-03, Geoffrey provides rationale]

Rationale:

It is by design that these members are noexcept, and changing that now would be a substantial regression in functionality. These classes were designed to substitute for plain pointers as transparently as possible, so since those operations are effectively noexcept on plain pointers, they should be noexcept on unique_ptr and shared_ptr as well. This matters in practice because we expect these members to be used fairly often inside the noexcept operator, and such code could be broken by this change. These design considerations override our general policy against noexcept for narrow-contract functions.

It is notable that N3279, which proposed this policy, did not propose striking noexcept from these operations. It's not clear if the omission of operator* and operator-> was an oversight, or an intentional reflection of the above considerations. N3279 was based on N3248 by the same authors, which states that:

"Most applications of noexcept for unique_ptr and shared_ptr are on functions with wide contracts. However, there are preconditions on the atomic access functions, so these should lose the specification."

Proposed resolution:


2391. basic_string is missing non-const data()

Section: 21.3.1 [basic.string] Status: Tentatively Resolved Submitter: Michael Bradshaw Opened: 2014-05-27 Last modified: 2016-05-22

Priority: 3

View other active issues in [basic.string].

View all other issues in [basic.string].

View all issues with Tentatively Resolved status.

Discussion:

Regarding 21.3.1 [basic.string], std::basic_string<charT>::data() returns a const charT* 21.3.1.7.1 [string.accessors]. While this method is convenient, it doesn't quite match std::array<T>::data() 23.3.7.5 [array.data] or std::vector<T>::data() 23.3.11.4 [vector.data], both of which provide two versions (that return T* or const T*). An additional data() method can be added to std::basic_string that returns a charT* so it can be used in similar situations that std::array and std::vector can be used. Without a non-const data() method, std::basic_string has to be treated specially in code that is otherwise oblivious to the container type being used.

Adding a charT* return type to data() would be equivalent to doing &str[0] or &str.front().

Small discussion on the issue can be found here and in the std-discussion thread (which didn't get too much attention).

This requires a small change to std::basic_string's definition in 21.3.1 [basic.string] to add the method to std::basic_string, and another small change in 21.3.1.7.1 [string.accessors] to define the new method.

[2015-02 Cologne]

Back to LEWG.

[2016-05-22]

Marshall says: this issue has been resolved by P0272R1.

Proposed resolution:

This wording is relative to N3936.

  1. Change class template basic_string synopsis, 21.3.1 [basic.string], as indicated:

    namespace std {
      template<class charT, class traits = char_traits<charT>,
      class Allocator = allocator<charT> >
      class basic_string {
      public:
        […]
        // 21.4.7, string operations:
        const charT* c_str() const noexcept;
        const charT* data() const noexcept;
        charT* data() noexcept;
        allocator_type get_allocator() const noexcept;
        […]
      };
    }
    
  2. Add the following sequence of paragraphs following 21.3.1.7.1 [string.accessors] p3, as indicated:

    charT* data() noexcept;
    

    -?- Returns: A pointer p such that p + i == &operator[](i) for each i in [0,size()].

    -?- Complexity: Constant time.

    -?- Requires: The program shall not alter the value stored at p + size().


2509. [fund.ts.v2] any_cast doesn't work with rvalue reference targets and cannot move with a value target

Section: 6.4 [fund.ts.v2::any.nonmembers] Status: Tentatively Ready Submitter: Ville Voutilainen Opened: 2015-06-13 Last modified: 2016-04-15

Priority: 2

View all issues with Tentatively Ready status.

Discussion:

Addresses: fund.ts.v2

In Library Fundamentals v1, [any.nonmembers]/5 says:

For the first form, *any_cast<add_const_t<remove_reference_t<ValueType>>>(&operand). For the second and third forms, *any_cast<remove_reference_t<ValueType>>(&operand).

  1. This means that

    any_cast<Foo&&>(whatever_kind_of_any_lvalue_or_rvalue);
    

    is always ill-formed. That's unfortunate, because forwarding such a cast result of an any is actually useful, and such uses do not want to copy/move the underlying value just yet.

  2. Another problem is that that same specification prevents an implementation from moving to the target when

    ValueType any_cast(any&& operand);
    

    is used. The difference is observable, so an implementation can't perform an optimization under the as-if rule. We are pessimizing every CopyConstructible and MoveConstructible type because we are not using the move when we can. This unfortunately includes types such as the library containers, and we do not want such a pessimization!

[2015-07, Telecom]

Jonathan to provide wording

[2015-10, Kona Saturday afternoon]

Eric offered to help JW with wording

Move to Open

[2016-01-30, Ville comments and provides wording]

Drafting note: the first two changes add support for types that have explicitly deleted move constructors. Should we choose not to support such types at all, the third change is all we need. For the second change, there are still potential cases where Requires is fulfilled but Effects is ill-formed, if a suitably concocted type is thrown into the mix.

Proposed resolution:

This wording is relative to N4562.

  1. In 6.3.1 [any.cons] p11+p12, edit as follows:

    template<class ValueType>
      any(ValueType&& value);
    

    -10- Let T be equal to decay_t<ValueType>.

    -11- Requires: T shall satisfy the CopyConstructible requirements, except for the requirements for MoveConstructible. If is_copy_constructible_v<T> is false, the program is ill-formed.

    -12- Effects: If is_constructible_v<T, ValueType&&> is true, cConstructs an object of type any that contains an object of type T direct-initialized with std::forward<ValueType>(value). Otherwise, constructs an object of type any that contains an object of type T direct-initialized with value.

    […]

  2. In 6.4 [any.nonmembers] p5, edit as follows:

    template<class ValueType>
      ValueType any_cast(const any& operand);
    template<class ValueType>
      ValueType any_cast(any& operand);
    template<class ValueType>
      ValueType any_cast(any&& operand);
    

    -4- Requires: is_reference_v<ValueType> is true or is_copy_constructible_v<ValueType> is true. Otherwise the program is ill-formed.

    -5- Returns: For the first form, *any_cast<add_const_t<remove_reference_t<ValueType>>>(&operand). For the second and third forms, *any_cast<remove_reference_t<ValueType>>(&operand). For the third form, if is_move_constructible_v<ValueType> is true and is_lvalue_reference_v<ValueType> is false, std::move(*any_cast<remove_reference_t<ValueType>>(&operand)), otherwise, *any_cast<remove_reference_t<ValueType>>(&operand).

    […]


2529. Assigning to enable_shared_from_this::__weak_this twice

Section: 20.10.2.5 [util.smartptr.enab] Status: Tentatively Resolved Submitter: Jonathan Wakely Opened: 2015-08-26 Last modified: 2016-05-17

Priority: 3

View other active issues in [util.smartptr.enab].

View all other issues in [util.smartptr.enab].

View all issues with Tentatively Resolved status.

Discussion:

It is unclear what should happen if a pointer to an object with an enable_shared_from_this base is passed to two different shared_ptr constructors.

#include <memory>

using namespace std;

int main()
{
  struct X : public enable_shared_from_this<X> { };
  auto xraw = new X;
  shared_ptr<X> xp1(xraw);  // #1
  {
    shared_ptr<X> xp2(xraw, [](void*) { });  // #2
  }
  xraw->shared_from_this();  // #3
}

This is similar to LWG 2179, but involves no undefined behaviour due to the no-op deleter, and the question is not whether the second shared_ptr should share ownership with the first, but which shared_ptr shares ownership with the enable_shared_from_this::__weak_this member.

With all three of the major std::shared_ptr implementations the xp2 constructor modifies the __weak_this member so the last line of the program throws bad_weak_ptr, even though all the requirements on the shared_from_this() function are met (20.10.2.5 [util.smartptr.enab])/7:

Requires: enable_shared_from_this<T> shall be an accessible base class of T. *this shall be a subobject of an object t of type T. There shall be at least one shared_ptr instance p that owns &t.

Boost doesn't update __weak_this, leaving it sharing with xp1, so the program doesn't throw. That change was made to boost::enable_shared_from_this because someone reported exactly this issue as a bug, see Boost issue 2584.

On the reflector Peter Dimov explained that there are real-world use cases that rely on the Boost behaviour, and none which rely on the behaviour of the current std::shared_ptr implementations. We should specify the behaviour of enable_shared_from_this more precisely, and resolve this issue one way or another.

[2016-03-16, Alisdair comments]

This issues should be closed as Resolved by paper p0033r1 at Jacksonville.

Proposed resolution:


2596. vector::data() should use addressof

Section: 23.3.11.4 [vector.data] Status: Tentatively Ready Submitter: Marshall Clow Opened: 2016-02-29 Last modified: 2016-04-15

Priority: 0

View all other issues in [vector.data].

View all issues with Tentatively Ready status.

Discussion:

In 23.3.11.4 [vector.data], we have:

Returns: A pointer such that [data(),data() + size()) is a valid range. For a non-empty vector, data() == &front().

This should be:

Returns: A pointer such that [data(),data() + size()) is a valid range. For a non-empty vector, data() == addressof(front()).

Proposed resolution:

This wording is relative to N4582.

  1. Change 23.3.11.4 [vector.data] p1 as indicated:

    T* data() noexcept;
    const T* data() const noexcept;
    

    -1- Returns: A pointer such that [data(), data() + size()) is a valid range. For a non-empty vector, data() == addressof(&front()).


2674. Bidirectional iterator requirement on path::iterator is very expensive

Section: 27.10.8.5 [path.itr] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2015-09-15 Last modified: 2016-05-17

Priority: 2

View all issues with Tentatively Ready status.

Discussion:

27.10.8.5 [path.itr] requires path::iterator to be a BidirectionalIterator, which also implies the ForwardIterator requirement in [forward.iterators] p6 for the following assertion to pass:

path p("/");
auto it1 = p.begin();
auto it2 = p.begin();
assert( &*it1 == &*it2 );

This prevents iterators containing a path, or constructing one on the fly when dereferenced, the object they point to must exist outside the iterators and potentially outlive them. The only practical way to meet the requirement is for p to hold a container of child path objects so the iterators can refer to those children. This makes a path object much larger than would naïvely be expected.

The Boost and MSVC implementations of Filesystem fail to meet this requirement. The GCC implementation meets it, but it makes sizeof(path) == 64 (for 64-bit) or sizeof(path) == 40 for 32-bit, and makes many path operations more expensive.

[21 Nov 2015 Beman comments:]

The ForwardIterator requirement in [forward.iterators] "If a and b are both dereferenceable, then a == b if and only if *a and *b are bound to the same object." will be removed by N4560, Working Draft, C++ Extensions for Ranges. I see no point in requiring something for the File System TS that is expensive, has never to my knowledge been requested by users, and is going to go away soon anyhow. The wording I propose below removes the requirement.

[Apr 2016 Issue updated to address the C++ Working Paper. Previously addressed File System TS]

Proposed resolution:

This wording is relative to N4582.

  1. Change 27.10.8.5 [path.itr] paragraph 2:

    A path::iterator is a constant iterator satisfying all the requirements of a bidirectional iterator (C++14 §24.1.4 Bidirectional iterators) except that there is no requirement that two equal iterators be bound to the same object. Its value_type is path.


2683. filesystem::copy() says "no effects"

Section: 27.10.15.3 [fs.op.copy] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2016-04-19 Last modified: 2016-05-22

Priority: 0

View other active issues in [fs.op.copy].

View all other issues in [fs.op.copy].

View all issues with Tentatively Ready status.

Discussion:

In 27.10.15.3 [fs.op.copy]/8 the final bullet says "Otherwise, no effects" which implies there is no call to ec.clear() if nothing happens, nor any error condition, is that right?

Proposed resolution:

Change 27.10.15.3 [fs.op.copy]/8 as indicated:

Otherwise no effects. For the signature with argument ec, ec.clear().

2684. priority_queue lacking comparator typedef

Section: 23.6.5 [priority.queue] Status: Tentatively Ready Submitter: Robert Haberlach Opened: 2016-05-02 Last modified: 2016-05-22

Priority: 0

View all other issues in [priority.queue].

View all issues with Tentatively Ready status.

Discussion:

The containers that take a comparison functor (set, multiset, map, and multimap) have a typedef for the comparison functor. priority_queue does not.

Proposed resolution:

Augment [priority.queue] as indicated:

 typedef Container container_type;
 typedef Compare value_compare;


2685. shared_ptr deleters must not not throw on move construction

Section: 20.10.2.2.1 [util.smartptr.shared.const] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2016-05-03 Last modified: 2016-05-22

Priority: 0

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

View all issues with Tentatively Ready status.

Discussion:

In 20.10.2.2.1 [util.smartptr.shared.const] p8 the shared_ptr constructors taking a deleter say:

The copy constructor and destructor of D shall not throw exceptions.

It's been pointed out that this doesn't forbid throwing moves, which makes it difficult to avoid a leak here:

struct D {
  D() = default;
  D(const D&) noexcept = default;
  D(D&&) { throw 1; }
  void operator()(int* p) const { delete p; }
};

shared_ptr<int> p{new int, D{}};

"The copy constructor" should be changed to reflect that the chosen constructor might not be a copy constructor, and that copies made using any constructor must not throw.

N.B. the same wording is used for the allocator argument, but that's redundant because the Allocator requirements already forbid exceptions when copying or moving.

Proposed resolution:

[Drafting note: the relevant expressions we're concerned about are enumerated in the CopyConstructible and MoveConstructible requirements, so I see no need to repeat them by saying something clunky like "Initialization of an object of type D from an expression of type (possibly const) D shall not throw exceptions", we can just refer to them. An alternative would be to define NothrowCopyConstructible, which includes CopyConstructible but requires that construction and destruction do not throw.]

Change 20.10.2.2.1 [util.smartptr.shared.const] p8:

D shall be CopyConstructible and such construction shall not throw exceptions. The copy constructor and destructor of D shall not throw exceptions.


2688. clamp misses preconditions and has extraneous condition on result

Section: 25.5.8 [alg.clamp] Status: Tentatively Ready Submitter: Martin Moene Opened: 2016-03-23 Last modified: 2016-05-22

Priority: 0

View all issues with Tentatively Ready status.

Discussion:

In Jacksonville (2016), P0025R0 was voted in instead of the intended P0025R1. This report contains the necessary mending along with two other improvements.

This report:

Thanks to Carlo Assink and David Gaarenstroom for making us aware of the extraneous condition in the returns: specification and for suggesting the fix and to Jeffrey Yasskin for suggesting to add a note like p3.

[2016-05 Issues Telecom]

Reworded p3 slightly.

Proposed resolution:

This wording is relative to N4582.

Previous resolution [SUPERSEDED]:

  1. Edit 25.5.8 [alg.clamp] as indicated:

    template<class T>
      constexpr const T& clamp(const T& v, const T& lo, const T& hi);
    template<class T, class Compare>
      constexpr const T& clamp(const T& v, const T& lo, const T& hi, Compare comp);
    

    -1- Requires: The value of lo shall be no greater than hi. For the first form, type T shall be LessThanComparable (Table 18).

    -2- Returns: lo if v is less than lo, hi if hi is less than v, otherwise vThe larger value of v and lo if v is smaller than hi, otherwise the smaller value of v and hi.

    -3- NoteRemarks: If NaN is avoided, T can be float or doubleReturns the first argument when it is equivalent to one of the boundary arguments.

    -4- Complexity: At most two comparisons.

  1. Edit 25.5.8 [alg.clamp] as indicated:

    template<class T>
      constexpr const T& clamp(const T& v, const T& lo, const T& hi);
    template<class T, class Compare>
      constexpr const T& clamp(const T& v, const T& lo, const T& hi, Compare comp);
    

    -1- Requires: The value of lo shall be no greater than hi. For the first form, type T shall be LessThanComparable (Table 18).

    -2- Returns: lo if v is less than lo, hi if hi is less than v, otherwise vThe larger value of v and lo if v is smaller than hi, otherwise the smaller value of v and hi.

    -3- NoteRemarks: If NaN is avoided, T can be a floating point type Returns the first argument when it is equivalent to one of the boundary arguments.

    -4- Complexity: At most two comparisons.


2689. Parallel versions of std::copy and std::move shouldn't be in order

Section: 25.4.1 [alg.copy], 25.4.2 [alg.move] Status: Tentatively Ready Submitter: Tim Song Opened: 2016-03-23 Last modified: 2016-05-22

Priority: 0

View other active issues in [alg.copy].

View all other issues in [alg.copy].

View all issues with Tentatively Ready status.

Discussion:

25.2.5 [algorithms.parallel.overloads]/2 says that "Unless otherwise specified, the semantics of ExecutionPolicy algorithm overloads are identical to their overloads without."

There's no "otherwise specified" for the ExecutionPolicy overloads for std::copy and std::move, so the requirement that they "start[] from first and proceed[] to last" in the original algorithm's description would seem to apply, which defeats the whole point of adding a parallel overload.

[2016-05 Issues Telecom]

Marshall noted that all three versions of copy have subtly different wording, and suggested that they should not.

Proposed resolution:

This wording is relative to N4582.

  1. Insert the following paragraphs after 25.4.1 [alg.copy]/4:

    template<class ExecutionPolicy, class InputIterator, class OutputIterator>
      OutputIterator copy(ExecutionPolicy&& policy, InputIterator first, InputIterator last,
                          OutputIterator result);
    

    -?- Requires: The ranges [first, last) and [result, result + (last - first)) shall not overlap.

    -?- Effects: Copies elements in the range [first, last) into the range [result, result + (last - first)). For each non-negative integer n < (last - first), performs *(result + n) = *(first + n).

    -?- Returns: result + (last - first).

    -?- Complexity: Exactly last - first assignments.

  2. Insert the following paragraphs after 25.4.2 [alg.move]/4:

    template<class ExecutionPolicy, class InputIterator, class OutputIterator>
      OutputIterator move(ExecutionPolicy&& policy, InputIterator first, InputIterator last,
                          OutputIterator result);
    

    -?- Requires: The ranges [first, last) and [result, result + (last - first)) shall not overlap.

    -?- Effects: Moves elements in the range [first, last) into the range [result, result + (last - first)). For each non-negative integer n < (last - first), performs *(result + n) = std::move(*(first + n)).

    -?- Returns: result + (last - first).

    -?- Complexity: Exactly last - first assignments.


2692. Overspecification of lvalueness of bitmask elements

Section: 17.5.2.1.3 [bitmask.types] Status: Tentatively NAD Submitter: Hubert Tong Opened: 2016-04-14 Last modified: 2016-05-22

Priority: 3

View all other issues in [bitmask.types].

View all issues with Tentatively NAD status.

Discussion:

The usual pattern now used for identifying where bitmask elements are declared, namely, as variables, preclude declaring them as enumerators.

Compare: ctype_base::space in C++03 subclause 22.2.1 [lib.category.ctype] versus the same in N4582 subclause 22.4.1 [category.ctype].

It is unclear whether this is intentional. Further it is unclear if odr-use of bitmask elements is intended to be allowed.

[2016-05 Issues Telecom]

Jonathan believes that this was intentional, and was done by N3110. Jonathan will provide more precise references.

Proposed resolution:


2698. Effect of assign() on iterators/pointers/references

Section: 23.2.3 [sequence.reqmts] Status: Tentatively Ready Submitter: Tim Song Opened: 2016-04-25 Last modified: 2016-05-22

Priority: 0

View other active issues in [sequence.reqmts].

View all other issues in [sequence.reqmts].

View all issues with Tentatively Ready status.

Discussion:

The sequence container requirements table says nothing about the effect of assign() on iterators, pointers or references into the container. Before LWG 2209 (and LWG 320 for std::list), assign() was specified as "erase everything then insert", which implies wholesale invalidation from the "erase everything" part. With that gone, the blanket "no invalidation" wording in 23.2.1 [container.requirements.general]/12 would seem to apply, which makes absolutely no sense.

The proposed wording below simply spells out the invalidation rule implied by the previous "erase everything" wording.

[2016-05 Issues Telecom]

This is related to 2256

Proposed resolution:

This wording is relative to N4582.

  1. In 23.2.3 [sequence.reqmts], edit Table 107 (Sequence container requirements) as indicated:

    Table 107 — Sequence container requirements (in addition to container)
    Expression Return type Assertion/note
    pre-/post-condition
    […]
    a.assign(i, j) void Requires: T shall be EmplaceConstructible into X from *i and assignable from *i.
    For vector, if the iterator does not meet the forward iterator requirements (24.2.5),
    T shall also be MoveInsertable into X.
    Each iterator in the range [i, j) shall be dereferenced exactly once.
    pre: i, j are not iterators into a.
    Replaces elements in a with a copy of [i, j).
    Invalidates all references, pointers and iterators referring to the elements of a.
    For vector and deque, also invalidates the past-the-end iterator.
    […]
    a.assign(n, t) void Requires: T shall be CopyInsertable into X and CopyAssignable.
    pre: t is not a reference into a.
    Replaces elements in a with n copies of t.
    Invalidates all references, pointers and iterators referring to the elements of a.
    For vector and deque, also invalidates the past-the-end iterator.

2706. Error reporting for recursive_directory_iterator::pop() is under-specified

Section: 27.10.14 [class.rec.dir.itr] Status: Tentatively Ready Submitter: Eric Fiselier Opened: 2016-05-09 Last modified: 2016-05-22

Priority: 0

View all issues with Tentatively Ready status.

Discussion:

Unlike increment, pop() does not specify how it reports errors nor does it provide a std::error_code overload. However implementing pop() all but requires performing an increment, so it should handle errors in the same way.

Proposed resolution:

This wording is relative to N4582.

  1. Change 27.10.14 [class.rec.dir.itr], class recursive_directory_iterator synopsis, as indicated:

    namespace std::filesystem {
      class recursive_directory_iterator {
      public:
        […]
        void pop();
        void pop(error_code& ec);
        void disable_recursion_pending();
        […]
      };
    }
    
  2. Change 27.10.14.1 [rec.dir.itr.members] as indicated:

    void pop();
    void pop(error_code& ec);
    

    -30- Requires: *this != recursive_directory_iterator().

    -31- Effects: If depth() == 0, set *this to recursive_directory_iterator(). Otherwise, cease iteration of the directory currently being iterated over, and continue iteration over the parent directory.

    -?- Throws: As specified in Error reporting (27.5.6.5 [error.reporting]).


2707. path construction and assignment should have "string_type&&" overloads

Section: 27.10.8 [class.path] Status: Tentatively Ready Submitter: Eric Fiselier Opened: 2016-05-09 Last modified: 2016-05-22

Priority: 0

View other active issues in [class.path].

View all other issues in [class.path].

View all issues with Tentatively Ready status.

Discussion:

Currently construction of a path from the native string_type always performs a copy, even when that string is passed as a rvalue. This is a large pessimization as paths are commonly constructed from temporary strings.

One pattern I frequently see is:

path foo(path const& p) {
  auto s = p.native();
  mutateString(s);
  return s;
}

Implementations should be allowed to move from s and avoid an unnecessary allocation. I believe string_type&& constructor and assignment operator overloads should be added to support this.

Proposed resolution:

This wording is relative to N4582.

  1. Change 27.10.8 [class.path], class path synopsis, as indicated:

    [Drafting note: Making the string_type&& constructors and assignment operators noexcept would over-constrain implementations which may need to perform construct additional state]

    namespace std::filesystem {
      class path {
      public:
        […]
        // 27.10.8.4.1, constructors and destructor
        path() noexcept;
        path(const path& p);
        path(path&& p) noexcept;
        path(string_type&& source);
        template <class Source>
        path(const Source& source);
        […]
        
        // 27.10.8.4.2, assignments
        path& operator=(const path& p);
        path& operator=(path&& p) noexcept;
        path& operator=(string_type&& source);
        path& assign(string_type&& source);
        template <class Source>
        path& operator=(const Source& source);
        template <class Source>
        path& assign(const Source& source)
        template <class InputIterator>
        path& assign(InputIterator first, InputIterator last);    
        […]
      };
    }
    
  2. Add a new paragraph following 27.10.8.4.1 [path.construct]/3:

    path(string_type&& source);
    

    -?- Effects: Constructs an object of class path with pathname having the original value of source. source is left in a valid but unspecified state.

  3. Add a new paragraph following 27.10.8.4.2 [path.assign]/4:

    path& operator=(string_type&& source);
    path& assign(string_type&& source);
    

    -?- Effects: Modifies pathname to have the original value of source. source is left in a valid but unspecified state.

    -?- Returns:*this


2710. "Effects: Equivalent to ..." doesn't count "Synchronization:" as determined semantics

Section: 17.5.1.4 [structure.specifications] Status: Tentatively Ready Submitter: Kazutoshi Satoda Opened: 2016-05-08 Last modified: 2016-05-22

Priority: 0

View other active issues in [structure.specifications].

View all other issues in [structure.specifications].

View all issues with Tentatively Ready status.

Discussion:

From N4582 17.5.1.4 [structure.specifications] p3 and p4

-3- Descriptions of function semantics contain the following elements (as appropriate):

-4- Whenever the Effects: element specifies that the semantics of some function F are Equivalent to some code sequence, then the various elements are interpreted as follows. If F's semantics specifies a Requires: element, then that requirement is logically imposed prior to the equivalent-to semantics. Next, the semantics of the code sequence are determined by the Requires:, Effects:, Postconditions:, Returns:, Throws:, Complexity:, Remarks:, Error conditions:, and Notes: specified for the function invocations contained in the code sequence. The value returned from F is specified by F's Returns: element, or if F has no Returns: element, a non-void return from F is specified by the Returns: elements in the code sequence. If F's semantics contains a Throws:, Postconditions:, or Complexity: element, then that supersedes any occurrences of that element in the code sequence.

The third sentence of p4 says "the semantics of the code sequence are determined by ..." and lists all elements in p3 except "Synchronization:".

I think it was just an oversight because p4 was added by library issue 997, and its proposed resolution was drafted at the time (2009) before "Synchronization:" was added into p3 for C++11.

However, I'm not definitely sure that it is really intended and safe to just supply "Synchronization:" in the list. (Could a library designer rely on this in writing new specifications, or could someone rely on this in writing user codes, after some years after C++11?)

Proposed resolution:

This wording is relative to N4582.

  1. Change 17.5.1.4 [structure.specifications] as indicated:

    -4- Whenever the Effects: element specifies that the semantics of some function F are Equivalent to some code sequence, then the various elements are interpreted as follows. If F's semantics specifies a Requires: element, then that requirement is logically imposed prior to the equivalent-to semantics. Next, the semantics of the code sequence are determined by the Requires:, Effects:, Synchronization:, Postconditions:, Returns:, Throws:, Complexity:, Remarks:, Error conditions:, and Notes: specified for the function invocations contained in the code sequence. The value returned from F is specified by F's Returns: element, or if F has no Returns: element, a non-void return from F is specified by the Returns: elements in the code sequence. If F's semantics contains a Throws:, Postconditions:, or Complexity: element, then that supersedes any occurrences of that element in the code sequence.