Revised 2017-02-06 at 04:02:38 UTC

Tentative Issues


760. The emplace issue

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

Priority: 2

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.


839. Maps and sets missing splice operation

Section: 23.4 [associative], 23.5 [unord] Status: Tentatively Resolved Submitter: Alan Talbot Opened: 2008-05-18 Last modified: 2017-02-03

Priority: Not Prioritized

View all other issues in [associative].

View all issues with Tentatively Resolved status.

Discussion:

Splice is a very useful feature of list. This functionality is also very useful for any other node based container, and I frequently wish it were available for maps and sets. It seems like an omission that these containers lack this capability. Although the complexity for a splice is the same as for an insert, the actual time can be much less since the objects need not be reallocated and copied. When the element objects are heavy and the compare operations are fast (say a map<int, huge_thingy>) this can be a big win.

Suggested resolution:

Add the following signatures to map, set, multimap, multiset, and the unordered associative containers:

 
void splice(list<T,Allocator>&& x);
void splice(list<T,Allocator>&& x, const_iterator i);
void splice(list<T,Allocator>&& x, const_iterator first, const_iterator last);

Hint versions of these are also useful to the extent hint is useful. (I'm looking for guidance about whether hints are in fact useful.)

 
void splice(const_iterator position, list<T,Allocator>&& x);
void splice(const_iterator position, list<T,Allocator>&& x, const_iterator i);
void splice(const_iterator position, list<T,Allocator>&& x, const_iterator first, const_iterator last);

[ Sophia Antipolis: ]

Don't try to splice "list" into the other containers, it should be container-type.

forward_list already has splice_after.

Would "splice" make sense for an unordered_map?

Jens, Robert: "splice" is not the right term, it implies maintaining ordering in lists.

Howard: adopt?

Jens: absorb?

Alan: subsume?

Robert: recycle?

Howard: transfer? (but no direction)

Jens: transfer_from. No.

Alisdair: Can we give a nothrow guarantee? If your compare() and hash() doesn't throw, yes.

Daniel: For unordered_map, we can't guarantee nothrow.

[ San Francisco: ]

Martin: this would possibly outlaw an implementation technique that is currently in use; caching nodes in containers.

Alan: if you cache in the allocator, rather than the individual container, this proposal doesn't interfere with that.

Martin: I'm not opposed to this, but I'd like to see an implementation that demonstrates that it works.

[ 2009-07 Frankfurt: ]

NAD Future.

[ 2009-09-19 Howard adds: ]

I'm not disagreeing with the NAD Future resolution. But when the future gets here, here is a possibility worth exploring:

Add to the "unique" associative containers:

typedef details      node_ptr;

node_ptr             remove(const_iterator p);
pair<iterator, bool> insert(node_ptr&& nd);
iterator             insert(const_iterator p, node_ptr&& nd);

And add to the "multi" associative containers:

typedef details node_ptr;

node_ptr remove(const_iterator p);
iterator insert(node_ptr&& nd);
iterator insert(const_iterator p, node_ptr&& nd);

Container::node_ptr is a smart pointer much like unique_ptr. It owns a node obtained from the container it was removed from. It maintains a reference to the allocator in the container so that it can properly deallocate the node if asked to, even if the allocator is stateful. This being said, the node_ptr can not outlive the container for this reason.

The node_ptr offers "const-free" access to the node's value_type.

With this interface, clients have a great deal of flexibility:

Here is how the customer might use this functionality:

The "node insertion" API maintains the API associated with inserting value_types so the customer can use familiar techniques for getting an iterator to the inserted node, or finding out whether it was inserted or not for the "unique" containers.

Lightly prototyped. No implementation problems. Appears to work great for the client.

[08-2016, Post-Chicago]

Move to Tentatively Resolved

Proposed resolution:

This functionality is provided by P0083R3


1041. Add associative/unordered container functions that allow to extract elements

Section: 23.2.6 [associative.reqmts] Status: Tentatively Resolved Submitter: Alisdair Meredith Opened: 2009-03-12 Last modified: 2017-02-03

Priority: Not Prioritized

View other active issues in [associative.reqmts].

View all other issues in [associative.reqmts].

View all issues with Tentatively Resolved status.

Discussion:

Addresses UK 239 [CD1]

It is not possible to take a move-only key out of an unordered container, such as (multi)set or (multi)map, or the new unordered containers.

Add below a.erase(q), a.extract(q), with the following notation:

a.extract(q)>, Return type pair<key, iterator> Extracts the element pointed to by q and erases it from the set. Returns a pair containing the value pointed to by q and an iterator pointing to the element immediately following q prior to the element being erased. If no such element exists,returns a.end().

[ Summit: ]

We look forward to a paper on this topic. We recommend no action until a paper is available. The paper would need to address exception safety.

[ Post Summit Alisdair adds: ]

Would value_type be a better return type than key_type?

[ 2009-07 post-Frankfurt: ]

Leave Open. Alisdair to contact Chris Jefferson about this.

[ 2009-09-20 Howard adds: ]

See the 2009-09-19 comment of 839 for an API which accomplishes this functionality and also addresses several other use cases which this proposal does not.

[ 2009-10 Santa Cruz: ]

Mark as NAD Future. No consensus to make the change at this time.

Original resolution [SUPERSEDED]:

In 23.2.6 [associative.reqmts] Table 85, add:

Table 85 -- Associative container requirements (in addition to container)
Expression Return type Assertion/note
pre-/post-condition
Complexity
a.erase(q) ... ... ...
a.extract(q) pair<key_type, iterator> Extracts the element pointed to by q and erases it from the set. Returns a pair containing the value pointed to by q and an iterator pointing to the element immediately following q prior to the element being erased. If no such element exists, returns a.end(). amortized constant

In 23.2.7 [unord.req] Table 87, add:

Table 87 -- Unordered associative container requirements (in addition to container)
Expression Return type Assertion/note
pre-/post-condition
Complexity
a.erase(q) ... ... ...
a.extract(q) pair<key_type, iterator> Extracts the element pointed to by q and erases it from the set. Returns a pair containing the value pointed to by q and an iterator pointing to the element immediately following q prior to the element being erased. If no such element exists, returns a.end(). amortized constant

[08-2016, Post-Chicago]

Move to Tentatively Resolved

Proposed resolution:

This functionality is provided by P0083R3


2179. enable_shared_from_this and construction from raw pointers

Section: 20.11.2.5 [util.smartptr.enab], 20.11.2.2.1 [util.smartptr.shared.const] Status: Tentatively Resolved Submitter: Daniel Krügler Opened: 2012-08-16 Last modified: 2017-02-03

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.11.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.11.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.11.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.11.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: 2017-02-03

Priority: 3

View other active issues in [reverse.iterators].

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.

2241. <cstdalign> and #define of alignof

Section: 18.10 [support.runtime] Status: Tentatively Resolved Submitter: Richard Smith Opened: 2013-02-14 Last modified: 2017-02-03

Priority: 2

View other active issues in [support.runtime].

View all other issues in [support.runtime].

View all issues with Tentatively Resolved status.

Discussion:

According to 18.10 [support.runtime] p2:

The contents of these headers are the same as the Standard C library headers [..], <stdalign.h>, [..]

Since our base C standard is C99, which doesn't have a <stdalign.h>, the reference to a non-existing C header is irritating (In this context <stdalign.h> doesn't refer to the deprecated C++ header <stdalign.h> described in D.4 [depr.c.headers]).

Furthermore, it would be also important that it doesn not define a macro named alignof, which C11 also defines in this header.

Currently we only have the following guarantee as part of 18.10 [support.runtime] p7:

The header <cstdalign> and the header <stdalign.h> shall not define a macro named alignas.

It is unclear what the better strategy is: Striking the reference to <stdalign.h> in 18.10 [support.runtime] p2 or upgrading to C11 as new base C standard.

[2014-02-15 Issaquah]

STL: related to earlier issue on C4, 2201, and now we get a C11 header
JY: find _Alignof as keyword C11 FDIS has four defines in stdalign.h
AM: need paper for C11 as base library we should really do that
STL: really need vendor input
STL: don't think we need to do anything right now not P1
AM: any objections to downscale to P2 (no objections)

[2016-03 Jacksonville]

Walter: this is on track to go away if we adopt Clark's paper to rebase to C11
Room: tentatively resolved; revisit after C11 paper: P0063

[2016-03 Oulu]

P0063 was adopted.

Change status to Tentatively Resolved

Proposed resolution:


2260. Missing requirement for Allocator::pointer

Section: 17.5.3.5 [allocator.requirements] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2013-05-14 Last modified: 2017-02-03

Priority: 3

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with Tentatively Ready status.

Discussion:

For an allocator A<T> which defines A<T>::pointer to a class type, i.e. not T*, I see no requirement that A<T>::pointer is convertible to A<U>::pointer, even if T* is convertible to U*. Such conversions are needed in containers to convert from e.g. ListNodeBase* to ListNode<T>*.

The obvious way to do such conversions appears to be pointer_traits::pointer_to(), but that's ill-formed if the static member function A<T>::pointer::pointer_to() doesn't exist and the allocator requirements don't mention that function, so you need to cast A<T>::pointer to A<T>::void_pointer then cast that to A<U>::pointer.

Is converting via void_pointer really intended, or are we missing a requirement that pointer_traits<A<T>::pointer>::pointer_to() be well-formed?

Proposed resolution:

Add to the Allocator requirements table the following requirement:

The expression pointer_traits<XX::pointer>::pointer_to(r) is well-defined.

[2013-09 Chicago]

Pablo to come back with proposed wording

[2015-07 Telecon]

Marshall to ping Pablo for proposed wording and disable current wording.

Previous resolution [SUPERSEDED]:
  1. Edit Table 28 as indicated:

    Table 28 — Allocator requirements (continued)
    Expression Return type Assertion/note pre-/post-condition Default
    static_cast<X::const_pointer>(z) X::const_pointer static_cast<X::const_pointer>(z) == q  
    pointer_traits<X::pointer>::pointer_to(r) X::pointer    

[2016-11-12, Issaquah]

This is related to 1521.

Sat PM: Restore original P/R and move to tentatively ready.

Proposed resolution:

  1. Edit Table 28 as indicated:

    Table 28 — Allocator requirements (continued)
    Expression Return type Assertion/note pre-/post-condition Default
    static_cast<X::const_pointer>(z) X::const_pointer static_cast<X::const_pointer>(z) == q  
    pointer_traits<X::pointer>::pointer_to(r) X::pointer    

2294. <cstdlib> should declare abs(double)

Section: 26.9 [c.math] Status: Tentatively Resolved Submitter: Pete Becker Opened: 2013-09-04 Last modified: 2017-02-03

Priority: 2

View all other issues in [c.math].

View all issues with Tentatively Resolved status.

Discussion:

… and abs(float) and abs(long double). And <cmath> should declare abs(int), abs(long), and abs(long long).

As things currently stand, this program is illegal:

#include <cstdlib>

int main() {
  double d = -1.23;
  double dd = std::abs(d);
  return 0;
}

The call is ambiguous because of the various integer overloads, that's because <cstdlib> provides abs(int) but not abs(double).

This lead one commenter on Stackoverflow to state that abs is dangerous, and to recommend using fabs instead.

In general, it makes sense to declare overloaded functions that take user-defined types in the same header as the definition of the user-defined types; it isn't necessary to declare all of the overloads in the same place. But here we're not dealing with any user-defined types; we're dealing with builtin types, which are always defined; all of the overloads should be defined in the same place, to avoid mysterious problems like the one in the code above.

The standard library has six overloads for abs:

int abs(int);  // <cstdlib>
long abs(long); // <cstdlib>
long long abs(long long); // <cstdlib>

float abs(float); // <cmath>
double abs(double); // <cmath>
long double abs(long double); // <cmath>

These should all be declared in both headers.

I have no opinion on <stdlib.h> and <math.h>.

[2013-09 Chicago]

This issue is related to LWG 2192

Move to open

[2014-02-13 Issaquah — Nicolai Josuttis suggest wording]

[2015-03-03, Geoffrey Romer provides improved wording]

See proposed resolution of LWG 2192.

[2015-09-11, Telecon]

Geoff provided combined wording for 2192 after Cologne, Howard to provide updated wording for Kona.

Howard: my notes say I wanted to use is_unsigned instead of 'unsigned integral type'.

Previous resolution from Nicolai [SUPERSEDED]:
  1. Edit 26.9 [c.math] after p7 as indicated:

    -6- In addition to the int versions of certain math functions in <cstdlib>, C++ adds long and long long overloaded versions of these functions, with the same semantics.

    -7- The added signatures are:

    long abs(long);                    // labs()
    long long abs(long long);          // llabs()
    ldiv_t div(long, long);            // ldiv()
    lldiv_t div(long long, long long); // lldiv()
    

    -?- To avoid ambiguities, C++ also adds the following overloads of abs() to <cstdlib>, with the semantics defined in <cmath>:

    float abs(float);
    double abs(double);
    long double abs(long double);
    

    -?- To avoid ambiguities, C++ also adds the following overloads of abs() to <cmath>, with the semantics defined in <cstdlib>:

    int abs(int);
    long abs(long);
    long long abs(long long);
    

[2015-08 Chicago]

Resolved by 2192

Proposed resolution:

See proposed resolution of LWG 2192.


2337. shared_ptr operator*() should not be noexcept

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

Priority: 2

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

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

View all issues with Tentatively NAD status.

Discussion:

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

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

20.11.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.11.1.2 [unique.ptr.single]/1, class template unique_ptr synopsis for single objects, change as indicated:

    pointer operator->() const noexcept;
    
  2. In 20.11.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.11.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.11.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:


2343. Is the value of the ECMA-262 RegExp object's multiline property really false?

Section: 28.13 [re.grammar] Status: Tentatively Resolved Submitter: Nayuta Taga Opened: 2013-10-30 Last modified: 2017-02-03

Priority: 2

View other active issues in [re.grammar].

View all other issues in [re.grammar].

View all issues with Tentatively Resolved status.

Discussion:

In the following "Multiline" is the value of the ECMA-262 RegExp object's multiline property.

In ECMA-262, there are some definitions that relate to Multiline:

So, the C++11 standard says that Multiline is false. As it is false, ^ matches only the beginning of the string, and $ matches only the end of the string.

However, two flags are defined in 28.5.2 [re.matchflag] Table 139:

match_not_bol: the character ^ in the regular expression shall not match [first,first).

match_not_eol: the character "$" in the regular expression shall not match [last,last).

As Multiline is false, the match_not_bol and the match_not_eol are meaningless because they only make ^ and $ match none.

In my opinion, Multiline should be true.

FYI, Multiline of the existing implementations are as follows:

Multiline=false:

Multiline=true:

[2015-05-22, Daniel comments]

This issue interacts with LWG 2503.

[2016-08 Chicago]

Resolving 2503 will resolve this as well.

Proposed resolution:

Resolved by LWG 2503.


2370. Operations involving type-erased allocators should not be noexcept in std::function

Section: 20.14.12.2 [func.wrap.func] Status: Tentatively Resolved Submitter: Pablo Halpern Opened: 2014-02-27 Last modified: 2017-02-03

Priority: 3

View other active issues in [func.wrap.func].

View all other issues in [func.wrap.func].

View all issues with Tentatively Resolved status.

Discussion:

The following constructors in 20.14.12.2 [func.wrap.func] are declared noexcept, even though it is not possible for an implementation to guarantee that they will not throw:

template <class A> function(allocator_arg_t, const A&) noexcept;
template <class A> function(allocator_arg_t, const A&, nullptr_t) noexcept;

In addition, the following functions are guaranteed not to throw if the target is a function pointer or a reference_wrapper:

template <class A> function(allocator_arg_t, const A& a, const function& f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);

In all of the above cases, the function object might need to allocate memory (an operation that can throw) in order to hold a copy of the type-erased allocator itself. The first two constructors produce an empty function object, but the allocator is still needed in case the object is later assigned to. In this case, we note that the propagation of allocators on assignment is underspecified for std::function. There are three possibilities:

  1. The allocator is never copied on copy-assignment, moved on move-assignment, or swapped on swap.

  2. The allocator is always copied on copy-assignment, moved on move-assignment, and swapped on swap.

  3. Whether or not the allocator is copied, moved, or swapped is determined at run-time based on the propagate_on_container_copy_assignment and propagate_on_container_move_assignment traits of the allocators at construction of the source function, the target function, or both.

Although the third option seems to be the most consistent with existing wording in the containers section of the standard, it is problematic in a number of respects. To begin with, the propagation behavior is determined at run time based on a pair of type-erased allocators, instead of at compile time. Such run-time logic is not consistent with the rest of the standard and is hard to reason about. Additionally, there are two allocator types involved, rather than one. Any set of rules that attempts to rationally interpret the propagation traits of both allocators is likely to be arcane at best, and subtly wrong for some set of codes at worst.

The second option is a non-starter. Historically, and in the vast majority of existing code, an allocator does not change after an object is constructed. The second option, if adopted, would undermine the programmer's ability to construct, e.g., an array of function objects, all using the same allocator.

The first option is (in Pablo's opinion) the simplest and best. It is consistent with historical use of allocators, is easy to understand, and requires minimal wording. It is also consistent with the wording in N3916, which formalizes type-erased allocators.

For cross-referencing purposes: The resolution of this issue should be harmonized with any resolution to LWG 2062, which questions the noexcept specification on the following member functions of std::function:

template <class F> function& operator=(reference_wrapper<F>) noexcept;
void swap(function&) noexcept;

[2015-05 Lenexa]

MC: change to P3 and status to open.

STL: note that noexcept is an issue and large chunks of allocator should be destroyed.

[2015-12-16, Daniel comments]

See 2564 for a corresponding issue addressing library fundamentals v2.

Previous resolution [SUPERSEDED]:

This wording is relative to N3936.

  1. Change 20.14.12.2 [func.wrap.func], class template function synopsis, as indicated:

    template <class A> function(allocator_arg_t, const A&) noexcept;
    template <class A> function(allocator_arg_t, const A&, nullptr_t) noexcept;
    
  2. Change 20.14.12.2.1 [func.wrap.func.con] as indicated:

    -1- When any function constructor that takes a first argument of type allocator_arg_t is invoked, the second argument shall have a type that conforms to the requirements for Allocator (Table 17.6.3.5). A copy of the allocator argument is used to allocate memory, if necessary, for the internal data structures of the constructed function object. For the remaining constructors, an instance of allocator<T>, for some suitable type T, is used to allocate memory, if necessary, for the internal data structures of the constructed function object.

    function() noexcept;
    template <class A> function(allocator_arg_t, const A&) noexcept;
    

    -2- Postconditions: !*this.

    function(nullptr_t) noexcept;
    template <class A> function(allocator_arg_t, const A&, nullptr_t) noexcept;
    

    -3- Postconditions: !*this.

    function(const function& f);
    template <class A> function(allocator_arg_t, const A& a, const function& f);
    

    -4- Postconditions: !*this if !f; otherwise, *this targets a copy of f.target().

    -5- Throws: shall not throw exceptions if f's target is a callable object passed via reference_wrapper or a function pointer. Otherwise, may throw bad_alloc or any exception thrown by the copy constructor of the stored callable object. [Note: Implementations are encouraged to avoid the use of dynamically allocated memory for small callable objects, for example, where f's target is an object holding only a pointer or reference to an object and a member function pointer. — end note]

    template <class A> function(allocator_arg_t, const A& a, const function& f);
    

    -?- Postconditions: !*this if !f; otherwise, *this targets a copy of f.target().

    function(function&& f);
    template <class A> function(allocator_arg_t, const A& a, function&& f);
    

    -6- Effects: If !f, *this has no target; otherwise, move-constructs the target of f into the target of *this, leaving f in a valid state with an unspecified value. If an allocator is not specified, the constructed function will use the same allocator as f.

    template<class F> function(F f);
    template <class F, class A> function(allocator_arg_t, const A& a, F f);
    

    -7- Requires: F shall be CopyConstructible.

    -8- Remarks: These constructors shall not participate in overload resolution unless f is Callable (20.9.11.2) for argument types ArgTypes... and return type R.

    -9- Postconditions: !*this if any of the following hold:

    • f is a null function pointer value.

    • f is a null member pointer value.

    • F is an instance of the function class template, and !f

    -10- Otherwise, *this targets a copy of f initialized with std::move(f). [Note: Implementations are encouraged to avoid the use of dynamically allocated memory for small callable objects, for example, where f's target is an object holding only a pointer or reference to an object and a member function pointer. — end note]

    -11- Throws: shall not throw exceptions when an allocator is not specified and f is a function pointer or a reference_wrapper<T> for some T. Otherwise, may throw bad_alloc or any exception thrown by F's copy or move constructor or by A's allocate function.

[2016-08 Chicago]

Tues PM: Resolved by P0302R1

Proposed resolution:

Resolved by acceptance of P0302R1.


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: 2017-02-03

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().


2424. 29.5 should state that atomic types are not trivially copyable

Section: 29.5 [atomics.types.generic] Status: Tentatively Resolved Submitter: Jens Maurer Opened: 2014-08-14 Last modified: 2017-02-03

Priority: 2

View other active issues in [atomics.types.generic].

View all other issues in [atomics.types.generic].

View all issues with Tentatively Resolved status.

Discussion:

Otherwise, one could use memcpy to save and restore the value according to 3.9p2.

It seems the core language rules in 9 [class]p6 with 12.8 [class.copy]p12 (trivial copy constructor) etc. and 8.4.2 [dcl.fct.def.default]p5 (user-provided) say that the atomic types are trivially copyable, which is bad. We shouldn't rely on future core changes in that area and simply say in the library section 29.5 [atomics.types.generic] that these very special types are not trivially copyable.

[2014-11 Urbana]

Lawrence:Definition of "trivially copyable" has been changing.

Doesn't hurt to add proposed change, even if the sentence is redundant

Move to Review.

[2015-02 Cologne]

GR has a minor problem with the style of the wording. VV has major issues with implementability.

[2015-03-22, Jens Maurer responses to Cologne discussion]

A library implementation could provide a partial specialization for is_trivially_copyable<atomic<T>>, to ensure that any such type query would return false.

Assuming such a specialization would be provided, how could a conforming program observe that per language rules an atomic specialization would actually be trivially copyable if there is no way to call the (deleted) copy constructor or copy assignment operator?

The sole effect of the suggested addition of the constraining sentence is that it would make a user program non-conforming that attempts to invoke memcpy (and the like) on atomic types, since that would invoke undefined behaviour.

[2015-05 Lenexa, SG1 response]

SG1 is fine with P/R (and agrees it's needed), but LWG may want to check the details; it's not entirely an SG1 issue.

[2015-05-05 Lenexa]

Marshall: This was discussed on the telecon. Alisdair was going to write something to Mike and send it to Core.

Hwrd: Core says that deleted copies are trivially copyable, which makes no sense to Library people.

STL: There doesn't appear to be a Core issue about it.

[2015-09-11 Telecon]

Howard: currently std::is_trivially_copyable<std::atomic> is true, so this resolution would contradict reality

Jonathan: changing that is good, we don't want it to be trivially copyable, otherwise users can memcpy them, which we really don't want

Howard: is it reasonable to memcpy something that isn't trivially copy constructible or trivially assignable?

Jonathan: no, it's not, but Core says you can, so this resolution is needed to stop people memcpying atomic

Howard: we should fix the core rule

Marshall: there is a separate issue of whether trivially-copyable makes sense, but this resolution is a net good purely because it stops memcpy of atomics

Howard: so should implementations specialize is_trivially_copyable the trait to meet this?

Jonathan: or add an empty, user-defined destructor.

Howard: should the spec specify that then?

Over-specification.

Howard: without that I fear implementation divergence.

Ville and Jonathan to investigate potential implementation options.

Ville: request a note on the issue saying we need review other types such as condition_variable to see if they are also unintentionally trivially-copyable. N4460 mentions some such types.

[2016-03 Jacksonville]

We think there is something coming from Core to resolve that, and that this will be NAD.
Until then, defer.

[2016-03 Jacksonville]

This was resolved by Core Issue 1496

[2017-01-19 Jens Maurer comments, issue state to Review]

The previous entry "[2016-03 Jacksonville] This was resolved by Core Issue 1496" is wrong; Core issue 1496 only modified the definition of "trivial class", not of "trivially copyable". However, as Ville Voutilainen observed, Core Issue 1734 made all atomics not trivially copyable, because they do not have at least one non-deleted copy/move constructor or copy/move assignment operator.

Previous resolution [SUPERSEDED]:

  1. Change 29.5 [atomics.types.generic]p3 as indicated:

    Specializations and instantiations of the atomic template shall have a deleted copy constructor, a deleted copy assignment operator, and a constexpr value constructor. They are not trivially copyable types (3.9 [basic.types]).

[2017-01-27 Telecon]

Resolved as NAD.

[2017-02-02 Daniel comments and adjusts status]

The NAD resolution is inappropriate, because the group didn't argue against the actual issue, instead the situation was that core wording changes in an unrelated area had resolved the previous problem indirectly. In this cases the correct resolution is Resolved by core wording changes as described by Jens Maurer in the 2017-01-19 comment.

Proposed resolution:


2443. std::array member functions should be constexpr

Section: 23.3.7 [array] Status: Tentatively Resolved Submitter: Peter Sommerlad Opened: 2014-10-06 Last modified: 2017-02-03

Priority: Not Prioritized

View other active issues in [array].

View all other issues in [array].

View all issues with Tentatively Resolved status.

Discussion:

When experimenting with C++14 relaxed constexpr functions I made the observation that I couldn't use std::array to create a table of data at compile time directly using loops in a function. However, a simple substitute I could use instead:

template <typename T, size_t n>
struct ar {
  T a[n];
  constexpr ar() : a{{}}{}
  constexpr auto data() const { return &a[0];}
  constexpr T const & operator[](size_t i) const { return a[i]; }
  constexpr T & operator[](size_t i) { return a[i]; }
};

template <size_t n>
using arr = ar<size_t, n>; // std::array<size_t, n>;

template <size_t n>
constexpr auto make_tab(){
  arr<n> result;
  for(size_t i=0; i < n; ++i)
    result[i] = (i+1)*(i+1); // cannot define operator[] for mutable array...
  return result;
}

template <size_t n>
constexpr auto squares=make_tab< n>();

int main() {
  int dummy[squares<5>[3]];
}

Therefore, I suggest that all member functions of std::array should be made constexpr to make the type usable in constexpr functions.

Wording should be straight forward, may be with the exception of fill, which would require fill_n to be constexpr as well.

[2014-11 Urbana]

Move to LEWG

The extent to which constexpr becomes a part of the Library design is a policy matter best handled initially by LEWG.

[08-2016, Post-Chicago]

Move to Tentatively Resolved

Proposed resolution:

This functionality is provided by P0031R0


2501. std::function requires POCMA/POCCA

Section: 20.14.12.2 [func.wrap.func] Status: Tentatively Resolved Submitter: David Krauss Opened: 2015-05-20 Last modified: 2017-02-03

Priority: 3

View other active issues in [func.wrap.func].

View all other issues in [func.wrap.func].

View all issues with Tentatively Resolved status.

Discussion:

The idea behind propagate_on_container_move_assignment is that you can keep an allocator attached to a container. But it's not really designed to work with polymorphism, which introduces the condition where the current allocator is non-POCMA and the RHS of assignment, being POCMA, wants to replace it. If function were to respect the literal meaning, any would-be attached allocator is at the mercy of every assignment operation. So, std::function is inherently POCMA, and passing a non-POCMA allocator should be ill-formed.

The other alternative, and the status quo, is to ignore POCMA and assume it is true. This seems just dangerous enough to outlaw. It is, in theory, possible to properly support POCMA as far as I can see, albeit with difficulty and brittle results. It would require function to keep a throwing move constructor, which otherwise can be noexcept.

The same applies to propagate_on_container_copy_assignment. This presents more difficulty because std::allocator does not set this to true. Perhaps it should. For function to respect this would require inspecting the POCCA of the source allocator, slicing the target from the erasure of the source, slicing the allocation from the erasure of the destination, and performing a copy with the destination's allocator with the source's target. This comes out of the blue for the destination allocator, which might not support the new type anyway. Theoretically possible, but brittle and not very practical. Again, current implementations quietly ignore the issue but this isn't very clean.

The following code example is intended to demonstrate the issue here:

#include <functional>
#include <iostream>
#include <vector>

template <typename T>
struct diag_alloc 
{
  std::string name;

  T* allocate(std::size_t n) const 
  {
    std::cout << '+' << name << '\n';
    return static_cast<T*>(::operator new(n * sizeof(T)));
  }
  
  void deallocate(T* p, std::size_t) const 
  {
    std::cout << '-' << name << '\n';
    return ::operator delete(p);
  }

  template <typename U>
  operator diag_alloc<U>() const { return {name}; }

  friend bool operator==(const diag_alloc& a, const diag_alloc& b)
  { return a.name == b.name; }
  
  friend bool operator!=(const diag_alloc& a, const diag_alloc& b)
  { return a.name != b.name; }

  typedef T value_type;
  
  template <typename U>
  struct rebind { typedef diag_alloc<U> other; };
};

int main() {
  std::cout << "VECTOR\n";
  std::vector<int, diag_alloc<int>> foo({1, 2}, {"foo"}); // +foo
  std::vector<int, diag_alloc<int>> bar({3, 4}, {"bar"}); // +bar

  std::cout << "move\n";
  foo = std::move(bar); // no message

  std::cout << "more foo\n";
  foo.reserve(40); // +foo -foo
  std::cout << "more bar\n";
  bar.reserve(40); // +bar -bar

  std::cout << "\nFUNCTION\n";
  int bigdata[100];
  auto bigfun = [bigdata]{};
  typedef decltype(bigfun) ft;
  std::cout << "make fizz\n";
  std::function<void()> fizz(std::allocator_arg, diag_alloc<ft>{"fizz"}, bigfun); // +fizz
  std::cout << "another fizz\n";
  std::function<void()> fizz2;
  fizz2 = fizz; // +fizz as if POCCA
  std::cout << "make buzz\n";
  std::function<void()> buzz(std::allocator_arg, diag_alloc<ft>{"buzz"}, bigfun); // +buzz
  std::cout << "move\n";
  buzz = std::move(fizz); // -buzz as if POCMA

  std::cout << "\nCLEANUP\n";
}

[2016-08, Chicago]

Tues PM: Resolved by P0302R1.

Proposed resolution:

Resolved by P0302R1.


2502. std::function does not use allocator::construct

Section: 20.14.12.2 [func.wrap.func] Status: Tentatively Resolved Submitter: David Krauss Opened: 2015-05-20 Last modified: 2017-02-03

Priority: 3

View other active issues in [func.wrap.func].

View all other issues in [func.wrap.func].

View all issues with Tentatively Resolved status.

Discussion:

It is impossible for std::function to construct its target object using the construct method of a type-erased allocator. More confusingly, it is possible when the allocator and the target are created at the same time. The means of target construction should be specified.

[2016-08 Chicago]

Tues PM: Resolved by P0302R1.

Proposed resolution:

Resolved by P0302R1.


2505. auto_ptr_ref creation requirements underspecified

Section: 99 [auto.ptr.conv] Status: Tentatively Resolved Submitter: Hubert Tong Opened: 2015-05-28 Last modified: 2017-02-03

Priority: 4

View all other issues in [auto.ptr.conv].

View all issues with Tentatively Resolved status.

Discussion:

In C++14 sub-clause 99 [auto.ptr.conv], there appears to be no requirement that the formation of an auto_ptr_ref<Y> from an auto_ptr<X> is done only when X* can be implicitly converted to Y*.

For example, I expect formation of the auto_ptr_ref<A> from the prvalue of type auto_ptr<B> to be invalid in the case below (but the wording does not seem to be there):

#include <memory>

struct A { };
struct B { } b;

std::auto_ptr<B> apB() { return std::auto_ptr<B>(&b); }
int main() {
  std::auto_ptr<A> apA(apB());
  apA.release();
}

The behaviour of the implementation in question on the case presented above is to compile and execute it successfully (which is what the C++14 wording implies). The returned value from apA.release() is essentially reinterpret_cast<A*>(&b).

There is nothing in the specification of

template <class X>
template <class Y> operator auto_ptr<X>::auto_ptr_ref<Y>() throw();

which implies that X* should be implicitly convertible to Y*.

The implementation in question uses the reinterpret_cast interpretation even when Y is an accessible, unambiguous base class of X; the result thereof is that no offset adjustment is performed.

[2015-07, Telecon]

Marshall to resolve.

[2016-03-16, Alisdair Meredith comments]

This issue is a defect in a component we have actively removed from the standard. I can't think of a clearer example of something that is no longer a defect!

[2016-08-03, Alisdair Meredith comments]

As C++17 removes auto_ptr, I suggest closing this issue as closed by paper N4190.

Previous resolution [SUPERSEDED]:

This wording is relative to ISO/IEC 14882:2014(E).

  1. Change 99 [auto.ptr.conv] as indicated:

    template<class Y> operator auto_ptr_ref<Y>() throw();
    

    -?- Requires: X* can be implicitly converted to Y*.

    -3- Returns: An auto_ptr_ref<Y> that holds *this.

    -?- Notes: Because auto_ptr_ref is present for exposition only, the only way to invoke this function is by calling one of the auto_ptr conversions which take an auto_ptr_ref as an argument. Since all such conversions will call release() on *this (in the form of the auto_ptr that the auto_ptr_ref holds a reference to), an implementation of this function may cause instantiation of said release() function without changing the semantics of the program.

    template<class Y> operator auto_ptr<Y>() throw();
    

    -?- Requires: X* can be implicitly converted to Y*.

    -4- Effects: Calls release().

    -5- Returns: An auto_ptr<Y> that holds the pointer returned from release().

[2016-08 - Chicago]

Thurs AM: Moved to Tentatively Resolved

Proposed resolution:

Resolved by acceptance of N4190.


2529. Assigning to enable_shared_from_this::__weak_this twice

Section: 20.11.2.5 [util.smartptr.enab] Status: Tentatively Resolved Submitter: Jonathan Wakely Opened: 2015-08-26 Last modified: 2017-02-03

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.11.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:


2548. Missing vfscanf from <cstdio>

Section: 27.11 [c.files] Status: Tentatively Resolved Submitter: Richard Smith Opened: 2015-10-09 Last modified: 2017-02-03

Priority: 3

View all other issues in [c.files].

View all issues with Tentatively Resolved status.

Discussion:

C's vfscanf function is not present in C++'s <cstdio>, and presumably should be. It looks like this is the only missing member of C's [v]{f,s,sn}[w]{printf,scanf} family.

[2016-08 - Chicago]

Resolved by P0175R1

Thurs AM: Moved to Tentatively Resolved

Proposed resolution:

This wording is relative to N4527.

Modify Table 133 as follows:

ungetc
vfprintf
vfscanf
vprintf
vscanf


2663. Enable efficient retrieval of file size from directory_entry

Section: 27.10.15.14 [fs.op.file_size] Status: Tentatively Resolved Submitter: Gor Nishanov Opened: 2014-05-22 Last modified: 2017-02-03

Priority: 2

View all issues with Tentatively Resolved status.

Discussion:

On Windows, the FindFileData WIN32_FIND_DATA structure, which is the underlying data type for directory_entry, contains the file size as one of the fields. Thus efficient enumeration of files and getting their sizes is possible without doing a separate query for the file size.

[17 Jun 2014 Rapperswil LWG will investigate issue at a subsequent meeting.]

[23 Nov 2015 Editorally correct name of data structure mentioned in discussion.]

[Mar 2016 Jacksonville Beman to provide paper about this]

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

Previous resolution [SUPERSEDED]

In 27.10.12 [class.directory_entry] Class directory_entry add the following observer declarations:

      uintmax_t file_size();
      uintmax_t file_size(error_code& ec) noexcept;
    

In directory_entry observers 27.10.12.3 [directory_entry.obs] add the following:

      uintmax_t file_size();
      uintmax_t file_size(error_code& ec) noexcept;
    

Returns: if *this contains a cached file size, return it. Otherwise return file_size(path()) or file_size(path(), ec) respectively.

Throws: As specified in Error reporting (7).

[2016-08, Beman comments]

This will be resolved by P0317R1, Directory Entry Caching for Filesystem.

Fri AM: Moved to Tentatively Resolved

Proposed resolution:


2677. directory_entry::status is not allowed to be cached as a quality-of-implementation issue

Section: 27.10.12.3 [directory_entry.obs] Status: Tentatively Resolved Submitter: Billy O'Neal Opened: 2016-03-03 Last modified: 2017-02-03

Priority: 2

View all other issues in [directory_entry.obs].

View all issues with Tentatively Resolved status.

Discussion:

To fix multi-threading problems in directory_entry, caching behavior was removed from the type. This is bad for performance reasons, because the values can no longer be cached from the result of readdir on POSIX platforms, or from FindFirstFile/FindNextFile on Windows.

It appears that the intent was to allow implementers to fill in the values for directory_entry::status inside directory_iterator, but as currently specified:

Returns: status(path()[, ec]).

This is not allowed to be cached, because the target of the path can change. For example, consider the following program:

#include <stdio.h>
#include <stdlib.h>
#include <filesystem>
#include <fstream>

using namespace std;
namespace fs = ::std::filesystem;

void verify(const bool b, const char * const msg) {
    if (!b) {
        printf("fail: %s\n", msg);
        exit(1);
    }
}

void touch_file(const char * const filename) {
    ofstream f(filename);
    f << '\n' << endl;
    verify(f.good(), "File write failed");
}

int main() {
    fs::remove_all("subDir");
    fs::create_directory("subDir");
    fs::create_directory("subDir/child");
    touch_file("subDir/child/child");
    fs::current_path("./subDir");
    fs::directory_iterator dir(".");
    ++dir;
    fs::directory_entry entry = *dir;

    verify(entry == "./child",
      "unexpected subdirectory"); //enumerating "subDir" returned the directory "child"

    fs::file_status status = entry.status();
    verify(status.type() == fs::file_type::directory,
        "subDir/child was not a directory");
    fs::current_path("./child");
    status = entry.status(); // REQUIRED to re-stat() on POSIX,
                             // GetFileAttributes() on Windows
    verify(status.type() == fs::file_type::regular,
        "subDir/child/child was not a regular file");
    return 0;
}

directory_entry should be re-specified to allow implementers to cache the value of status(path) at the time irectory_iterator was incremented to avoid repeated stat() / GetFileAttributes calls. (This may mean additional constructors are necessary for directory_entry as well)

[2016-04, Issues Telecon]

Beman is working on a paper to address this.

[2016-08, Beman comments]

This will be resolved by P0317R1, Directory Entry Caching for Filesystem.

Fri AM: Moved to Tentatively Resolved

Proposed resolution:


2692. Overspecification of lvalueness of bitmask elements

Section: 17.4.2.1.4 [bitmask.types] Status: Tentatively NAD Submitter: Hubert Tong Opened: 2016-04-14 Last modified: 2017-02-03

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 Telecon]

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

Proposed resolution:


2717. scoped_allocator_adaptor uses forward to do move's job

Section: 20.13.4 [allocator.adaptor.members] Status: Tentatively NAD Submitter: Billy Robert O'Neal III Opened: 2016-05-24 Last modified: 2017-02-03

Priority: Not Prioritized

View other active issues in [allocator.adaptor.members].

View all other issues in [allocator.adaptor.members].

View all issues with Tentatively NAD status.

Discussion:

scoped_allocator_adaptor is specified to use forward when what it is really doing is moving elements. It should use move.

Previous resolution [SUPERSEDED]:

This wording is relative to N4582.

  1. Edit 20.13.4 [allocator.adaptor.members] p15 as indicated:

    template <class T1, class T2, class U, class V>
      void construct(pair<T1, T2>* p, pair<U, V>&& x);
    

    Effects: Equivalent to this->construct(p, piecewise_construct, forward_as_tuple(std::forwardmove<U>(x.first)), forward_as_tuple(std::forwardmove<V>(x.second))).

Proposed resolution:

Withdrawn by the submitter, since the prerequisites were incorrect.


2757. std::string{}.insert(3, "ABCDE", 0, 1) is ambiguous

Section: 21.3.1.6.4 [string.insert] Status: Tentatively Resolved Submitter: Marshall Clow Opened: 2016-07-30 Last modified: 2017-02-03

Priority: 1

View all other issues in [string.insert].

View all issues with Tentatively Resolved status.

Discussion:

Before C++17, we had the following signature to std::basic_string:

basic_string&
  insert(size_type pos1, const basic_string& str, size_type pos2, size_type n = npos);

Unlike most of the other member functions on std::basic_string, there were not corresponding versions that take a charT* or (charT *, size).

In p0254r2, we added:

basic_string&
  insert(size_type pos1, basic_string_view<charT, traits> sv, size_type pos2, size_type n = npos);

which made the code above ambiguous. There are two conversions from "const charT*", one to basic_string, and the other to basic_string_view, and they're both equally good (in the view of the compiler).

This ambiguity also occurs with the calls

assign(const basic_string& str,             size_type pos, size_type n = npos);
assign(basic_string_view<charT, traits> sv, size_type pos, size_type n = npos);

but I will file a separate issue (2758) for that.

A solution is to add even more overloads to insert, to make it match all the other member functions of basic_string, which come in fours (string, pointer, pointer + size, string_view).

[2016-08-03, Chicago, Robert Douglas provides wording]

Previous resolution [SUPERSEDED]:

This wording is relative to N4606.

  1. In 21.3.1 [basic.string] modify the synopsis for basic_string as follows:

    namespace std {
      template<class charT, class traits = char_traits<charT>,
        class Allocator = allocator<charT>>
      class basic_string {
      public:
        […]
        template<class T>
        basic_string& insert(size_type pos1, basic_string_view<charT, traits>T sv,
                             size_type pos2, size_type n = npos);
        […]
      };
    }
    
  2. In 21.3.1.6.4 [string.insert], modify basic_string_view overload as follows:

    template<class T>
    basic_string& insert(size_type pos1, basic_string_view<charT, traits>T sv,
                         size_type pos2, size_type n = npos);
    

    […]

    -?- Remarks: This function shall not participate in overload resolution unless is_same_v<T, basic_string_view<charT, traits>> is true.

[2016-08-04, Chicago, Robert Douglas comments]

For the sake of simplicity, the previous wording suggestion has been merged into the proposed wording of LWG 2758.

[08-2016, Chicago]

Fri PM: Move to Tentatively Ready (along with 2758).

[2016-09-09 Issues Resolution Telecon]

Since 2758 has been moved back to Open, move this one, too

[2016-10 Telecon]

Ville's wording for 2758 has been implemented in libstdc++ and libc++. Move 2758 to Tentatively Ready and this one to Tentatively Resolved

Proposed resolution:

This issue is resolved by the proposed wording for LWG 2758.


2768. any_cast and move semantics

Section: 20.8.4 [any.nonmembers] Status: Tentatively Ready Submitter: Casey Carter Opened: 2016-08-27 Last modified: 2017-02-03

Priority: 0

View other active issues in [any.nonmembers].

View all other issues in [any.nonmembers].

View all issues with Tentatively Ready status.

Discussion:

LWG 2509 made two changes to the specification of any in v2 of the library fundamentals TS:

  1. It altered the effects of the any_cast(any&&) overload to enable moving the value out of the any object and/or obtaining an rvalue reference to the contained value.
  2. It made changes to support pathological copyable-but-not-movable contained values, which is madness.

Change 1 has very desirable effects; I propose that we apply the sane part of LWG 2509 to any in the C++17 WP, for all of the reasons cited in the discussion of LWG 2509.

[2016-09-09 Issues Resolution Telecon]

P0; move to Tentatively Ready

Previous resolution [SUPERSEDED]:

This wording is relative to N4606.

  1. In 20.8.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, std::forward<ValueType>(*any_cast<remove_reference_t<ValueType>>(&operand)).

    […]

[Issues Telecon 16-Dec-2016]

Move to Tentatively Ready

Proposed resolution:

Resolved by the wording provided by LWG 2769.


2769. Redundant const in the return type of any_cast(const any&)

Section: 20.8.4 [any.nonmembers] Status: Tentatively Ready Submitter: Casey Carter Opened: 2016-09-02 Last modified: 2017-02-03

Priority: 0

View other active issues in [any.nonmembers].

View all other issues in [any.nonmembers].

View all issues with Tentatively Ready status.

Discussion:

The overload of any_cast that accepts a reference to constant any:

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

is specified to return *any_cast<add_const_t<remove_reference_t<ValueType>>>(&operand) in [any.nonmembers]/5. This calls the pointer-to-constant overload of any_cast:

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

which is specified as:

Returns: If operand != nullptr && operand->type() == typeid(ValueType), a pointer to the object contained by operand; otherwise, nullptr.

Since typeid(T) == typeid(const T) for all types T, any_cast<add_const_t<T>>(&operand) is equivalent to any_cast<T>(&operand) for all types T when operand is a constant lvalue any. The add_const_t in the return specification of the first overload above is therefore redundant.

[2016-09-09 Issues Resolution Telecon]

P0; move to Tentatively Ready

Casey will provide combined wording for this and 2768, since they modify the same paragraph.

Previous resolution [SUPERSEDED]:

This wording is relative to N4606.

  1. Modify 20.8.4 [any.nonmembers] as indicated:

    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).

    […]

[2016-09-09 Casey improves wording as determined by telecon]

The presented resolution is intended as the common wording for both LWG 2768 and LWG 2769.

Previous resolution [SUPERSEDED]:

This wording is relative to N4606.

  1. Modify 20.8.4 [any.nonmembers] as indicated:

    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 and second and third forms, *any_cast<remove_reference_t<ValueType>>(&operand). For the third form, std::forward<ValueType>(*any_cast<remove_reference_t<ValueType>>(&operand)).

    […]

[2016-10-05, Tomasz and Casey reopen and improve the wording]

The constraints placed on the non-pointer any_cast overloads are neither necessary nor sufficient to guarantee that the specified effects are well-formed. The current PR for LWG 2769 also makes it possible to retrieve a dangling lvalue reference to a temporary any with e.g. any_cast<int&>(any{42}), which should be forbidden.

[2016-10-16, Eric made some corrections to the wording]

Previous resolution [SUPERSEDED]:

This wording is relative to N4606.

  1. Modify 20.8.4 [any.nonmembers] as indicated:

    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.For the first overload, is_constructible_v<ValueType, const remove_cv_t<remove_reference_t<ValueType>>&> is true. For the second overload, is_constructible_v<ValueType, remove_cv_t<remove_reference_t<ValueType>>&> is true. For the third overload, is_constructible_v<ValueType, remove_cv_t<remove_reference_t<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 first and second overload, static_cast<ValueType>(*any_cast<remove_cv_t<remove_reference_t<ValueType>>>(&operand)). For the third overload, static_cast<ValueType>(std::move(*any_cast<remove_cv_t<remove_reference_t<ValueType>>>(&operand))).

    […]

[2016-11-10, LWG asks for simplification of the wording]

[Issues Telecon 16-Dec-2016]

Move to Tentatively Ready

Proposed resolution:

This wording is relative to N4606.

  1. Modify 20.8.4 [any.nonmembers] as indicated:

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

    -?- Let U be the type remove_cv_t<remove_reference_t<ValueType>>.

    -4- Requires: is_reference_v<ValueType> is true or is_copy_constructible_v<ValueType> is true.For the first overload, is_constructible_v<ValueType, const U&> is true. For the second overload, is_constructible_v<ValueType, U&> is true. For the third overload, is_constructible_v<ValueType, U> 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 first and second overload, static_cast<ValueType>(*any_cast<U>(&operand)). For the third overload, static_cast<ValueType>(std::move(*any_cast<U>(&operand))).

    […]


2789. Equivalence of contained objects

Section: 20.8.3 [any.class] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2016-11-09 Last modified: 2017-02-03

Priority: 0

View all issues with Tentatively Ready status.

Discussion:

Addresses US 29

What does it mean for (the contained) objects to be "equivalent"?

Suggested resolution:

Add definition (note that using operator==() involves complicated questions of overload resolution).

[2016-11-08, Jonathan comments and suggests wording]

We can rephrase the copy constructor in terms of equivalence to construction from the contained object. We need to use in-place construction to avoid recursion in the case where the contained object is itself an any.

For the move constructor we don't simply want to construct from the contrained object, because when the contained object is stored in dynamic memory we don't actually construct anything, we just transfer ownership of a pointer.

[Issues Telecon 16-Dec-2016]

Move to Tentatively Ready

Proposed resolution:

This wording is relative to N4606.

  1. Change [any.cons] p2:

    any(const any& other);
    

    Effects: Constructs an object of type any with an equivalent state as other.If other.has_value() is false, constructs an object that has no value. Otherwise, equivalent to any(in_place<T>, any_cast<const T&>(other)) where T is the type of the contained object.

  2. Change [any.cons] p4:

    any(any&& other);
    

    Effects: Constructs an object of type any with a state equivalent to the original state of other.If other.has_value() is false, constructs an object that has no value. Otherwise, constructs an object of type any that contains either the contained object of other, or contains an object of the same type constructed from the contained object of other considering that contained object as an rvalue.


2794. Missing requirements for allocator pointers

Section: 23.2.1 [container.requirements.general] Status: Tentatively Ready Submitter: Billy O'Neal III Opened: 2016-11-09 Last modified: 2017-02-03

Priority: 0

View other active issues in [container.requirements.general].

View all other issues in [container.requirements.general].

View all issues with Tentatively Ready status.

Discussion:

Addresses US 146

An allocator-aware contiguous container must require an allocator whose pointer type is a contiguous iterator. Otherwise, functions like data for basic_string and vector do not work correctly, along with many other expectations of the contiguous guarantee.

Suggested resolution:

Add a second sentence to 23.2.1 [container.requirements.general] p13:

An allocator-aware contiguous container requires allocator_traits<Allocator>::pointer is a contiguous iterator.

[2016-11-12, Issaquah]

Sat PM: Move to 'Tentatively Ready'

Proposed resolution:

This wording is relative to N4606.

  1. In 17.5.3.5 [allocator.requirements]/5, edit as follows:

    -5- An allocator type X shall satisfy the requirements of CopyConstructible (17.6.3.1). The X::pointer, X::const_pointer, X::void_pointer, and X::const_void_pointer types shall satisfy the requirements of NullablePointer (17.6.3.3). No constructor, comparison operator, copy operation, move operation, or swap operation on these pointer types shall exit via an exception. X::pointer and X::const_pointer shall also satisfy the requirements for a random access iterator (24.2 [iterator.requirements]24.2.7 [random.access.iterators]) and of a contiguous iterator (24.2.1 [iterator.requirements.general]).


2795. §[global.functions] provides incorrect example of ADL use

Section: 17.5.5.4 [global.functions] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2016-11-09 Last modified: 2017-02-03

Priority: Not Prioritized

View all other issues in [global.functions].

View all issues with Tentatively Ready status.

Discussion:

Addresses GB 39

The example is supposed to highlight the 'otherwise specified' aspect of invoking ADL, yet there is no such specification. It is unlikely that we intend to explicitly qualify calls to operator functions, so they probably should be exempted from this restriction.

Suggested resolution:

Fix example (and referenced clause) to specify use of ADL, or exempt operators from this clause, and find a better example, probably using swap.

[2016-11-09, Jonathan comments and provides wording]

The current wording was added by DR 225.

[2016-11-10, Tim Song comments]

The "non-operator" seems to have been added at the wrong spot. The problem at issue is permission to call operator functions found via ADL, not permission for operator functions in the standard library to ADL all over the place. The problem is not unique to operator functions in the standard library — a significant portion of <algorithm> and <numeric> uses some operator (==, <, +, *, etc.) that may be picked up via ADL.

There is also an existing problem in that the example makes no sense anyway: the constraint in this paragraph only applies to non-members, yet ostream_iterator::operator= is a member function.

[2016-11-10, Tim Song and Jonathan agree on new wording]

The new wording still doesn't quite get it right:

"calls to non-operator, non-member functions in the standard library do not use functions from another namespace which are found through argument-dependent name lookup" can be interpreted as saying that if a user writes "std::equal(a, b, c, d)", that call will not use ADL'd "operator==" because "std::equal(a, b, c, d)" is a "call" to a "non-operator, non-member function in the standard library".

The key point here is that "in the standard library" should be modifying "calls", not "function".

Previous resolution [SUPERSEDED]:

This wording is relative to N4606.

  1. Change 17.5.5.4 [global.functions] p4:

    Unless otherwise specified, non-operator, non-member functions in the standard library shall not use functions from another namespace which are found through argument-dependent name lookup (3.4.2). [Note: The phrase "unless otherwise specified" applies to cases such as the swappable with requirements (17.5.3.2 [swappable.requirements]). The exception for overloaded operators allowsis intended to allow argument-dependent lookup in cases like that of ostream_iterator::operator= (24.6.2.2):

    Effects:

    *out_stream << value;
    if (delim != 0)
      *out_stream << delim ;
    return *this;
    

    end note]

[Issues Telecon 16-Dec-2016]

Move to Tentatively Ready

Proposed resolution:

This wording is relative to N4606.

  1. Change 17.5.5.4 [global.functions] p4:

    Unless otherwise specified, calls made by functions in the standard library to non-operator, non-member functions in the standard library shalldo not use functions from another namespace which are found through argument-dependent name lookup (3.4.2). [Note: The phrase "unless otherwise specified" applies to cases such as the swappable with requirements (17.5.3.2 [swappable.requirements]). The exception for overloaded operators allowsis intended to allow argument-dependent lookup in cases like that of ostream_iterator::operator= (24.6.2.2):

    Effects:

    *out_stream << value;
    if (delim != 0)
      *out_stream << delim ;
    return *this;
    

    end note]


2804. Unconditional constexpr default constructor for istream_iterator

Section: 24.6.1.1 [istream.iterator.cons] Status: Tentatively Ready Submitter: Marshall Clow Opened: 2016-11-09 Last modified: 2017-02-03

Priority: 0

View other active issues in [istream.iterator.cons].

View all other issues in [istream.iterator.cons].

View all issues with Tentatively Ready status.

Discussion:

Addresses US 152

see below for the default constructor should simply be spelled constexpr. The current declaration looks like a member function, not a constructor, and the constexpr keyword implicitly does not apply unless the instantiation could make it so, under the guarantees al ready present in the Effects clause.

Proposed change:

Replace see below with constexpr in the declaration of the default constructor for istream_iterator in the class definition, and function specification.

[Issues Telecon 16-Dec-2016]

Jonathan provides wording, Move to Tentatively Ready

Proposed resolution:

In the class synopsis in 24.6.1 [istream.iterator] change the default constructor:

see belowconstexpr istream_iterator();
istream_iterator(istream_type& s);
istream_iterator(const istream_iterator& x) = default;
~istream_iterator() = default;

Change [istream.iterator.cons] before paragraph 1:

see belowconstexpr istream_iterator();

-1- Effects: ...

2812. Range access is available with <string_view>

Section: 24.7 [iterator.range], 21.4.1 [string.view.synop] Status: Tentatively Ready Submitter: Johel Ernesto Guerrero Peña Opened: 2016-10-29 Last modified: 2017-02-03

Priority: 0

View other active issues in [iterator.range].

View all other issues in [iterator.range].

View all issues with Tentatively Ready status.

Discussion:

21.4.1 [string.view.synop]/1 states

The function templates defined in 20.2.2 and 24.7 are available when <string_view> is included.

24.7 [iterator.range], in p1 is missing <string_view>.

[Issues Telecon 16-Dec-2016]

Move to Tentatively Ready

Proposed resolution:

This wording is relative to N4606.

  1. Edit 24.7 [iterator.range] p1 as indicated:

    -1- In addition to being available via inclusion of the <iterator> header, the function templates in 24.7 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>.


2824. list::sort should say that the order of elements is unspecified if an exception is thrown

Section: 23.3.10.5 [list.ops] Status: Tentatively Ready Submitter: Tim Song Opened: 2016-11-16 Last modified: 2017-02-05

Priority: 0

View all other issues in [list.ops].

View all issues with Tentatively Ready status.

Discussion:

Sometime between N1638 and N1804 the sentence "If an exception is thrown the order of the elements in the list is indeterminate." in the specification of list::sort went missing. This suspiciously coincided with the editorial change that "consolidated definitions of "Stable" in the library clauses" (N1805).

forward_list::sort says that "If an exception is thrown the order of the elements in *this is unspecified"; list::sort should do the same.

[2017-01-27 Telecon]

Priority 0

Proposed resolution:

This wording is relative to N4606.

  1. Edit 23.3.10.5 [list.ops] p29 as indicated:

    void sort();
    template <class Compare> void sort(Compare comp);
    

    -28- Requires: operator< (for the first version) or comp (for the second version) shall define a strict weak ordering (25.5 [alg.sorting]).

    -29- Effects: Sorts the list according to the operator< or a Compare function object. If an exception is thrown, the order of the elements in *this is unspecified. Does not affect the validity of iterators and references.

    […]


2826. string_view iterators use old wording

Section: 21.4.2.2 [string.view.iterators] Status: Tentatively Ready Submitter: Alisdair Meredith Opened: 2016-11-17 Last modified: 2017-02-03

Priority: 0

View all issues with Tentatively Ready status.

Discussion:

The wording for basic_string_view was written before the definition of a contiguous iterator was added to C++17 to avoid repeating redundant wording.

Suggested modification of 21.4.2.2 [string.view.iterators] p1 (stealing words from valarray begin/end):

-1- A constant random-access iterator type such that, for a const_iterator it, if &*(it + N) is valid, then &*(it + N) == (&*it) + NA type that meets the requirements of a constant random access iterator (24.2.7) and of a contiguous iterator (24.2.1) whose value_type is the template parameter charT.

[2017-01-27 Telecon]

Priority 0

Proposed resolution:

This wording is relative to N4606.

  1. Modify 21.4.2.2 [string.view.iterators] as indicated:

    using const_iterator = implementation-defined;
    

    -1- A constant random-access iterator type such that, for a const_iterator it, if &*(it + N) is valid, then &*(it + N) == (&*it) + Ntype that meets the requirements of a constant random access iterator (24.2.7 [random.access.iterators]) and of a contiguous iterator (24.2.1 [iterator.requirements.general]) whose value_type is the template parameter charT.

    -2- For a basic_string_view str, any operation that invalidates a pointer in the range [str.data(), str.data() + str.size()) invalidates pointers, iterators, and references returned from str's methods.

    -3- All requirements on container iterators (23.2 [container.requirements]) apply to basic_string_view::const_iterator as well.


2834. Resolution LWG 2223 is missing wording about end iterators

Section: 21.3.1.4 [string.capacity], 23.3.8.3 [deque.capacity], 23.3.11.3 [vector.capacity] Status: Tentatively Ready Submitter: Thomas Koeppe Opened: 2016-11-29 Last modified: 2017-02-03

Priority: 0

View all other issues in [string.capacity].

View all issues with Tentatively Ready status.

Discussion:

The resolution of LWG 2223 added the wording "Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence." to a number of shrink_to_fit operations.

This seems to be missing any mention of end iterators. Surely end iterators are invalidated, too?

Suggested resolution:

For string, deque, and vector each, append as follows:

Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence as well as the past-the-end iterator.

[2017-01-27 Telecon]

Priority 0

Proposed resolution:

This wording is relative to N4618.

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

    void shrink_to_fit();
    

    […]

    -15- Remarks: Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence as well as the past-the-end iterator. If no reallocation happens, they remain valid.

  2. Edit 23.3.8.3 [deque.capacity] as indicated:

    void shrink_to_fit();
    

    […]

    -8- Remarks: shrink_to_fit invalidates all the references, pointers, and iterators referring to the elements in the sequence as well as the past-the-end iterator.

  3. Edit 23.3.11.3 [vector.capacity] as indicated:

    void shrink_to_fit();
    

    […]

    -10- Remarks: Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence as well as the past-the-end iterator. If no reallocation happens, they remain valid.


2835. LWG 2536 seems to misspecify <tgmath.h>

Section: 26.9.6 [ctgmath.syn], D.4 [depr.c.headers] Status: Tentatively Ready Submitter: Thomas Koeppe Opened: 2016-11-29 Last modified: 2017-02-03

Priority: 0

View all issues with Tentatively Ready status.

Discussion:

The resolution of LWG 2536 touches on the specification of C headers (of the form foo.h), but while it fixes the specification of complex.h, it fails to address the specification of tgmath.h.

Just like complex.h, tgmath.h is not defined by C. Rather, our tgmath.h behaves like <ctgmath>, which is specified in [ctgmath.syn].

Suggested resolution:

Amend [depr.c.headers] p3 as follows:

3. The header <complex.h> behaves as if it simply includes the header <ccomplex>. The header <tgmath.h> behaves as if it simply includes the header <ctgmath>.

4. Every other C header […]

See also LWG 2828.

[2017-01-27 Telecon]

Priority 0

Proposed resolution:

This wording is relative to N4618.

  1. Edit D.4 [depr.c.headers] as indicated:

    […]

    -2- The use of any of the C++ headers […] is deprecated.

    -3- The header <complex.h> behaves as if it simply includes the header <ccomplex>. The header <tgmath.h> behaves as if it simply includes the header <ctgmath>.

    -4- Every other C header, […]


2837. gcd and lcm should support a wider range of input values

Section: 26.8.13 [numeric.ops.gcd], 26.8.14 [numeric.ops.lcm] Status: Tentatively Ready Submitter: Marshall Clow Opened: 2016-12-16 Last modified: 2017-02-03

Priority: 0

View all other issues in [numeric.ops.gcd].

View all issues with Tentatively Ready status.

Discussion:

This is a duplicate of 2792, which addressed LFTS 2.

By the current definition, gcd((int64_t)1234, (int32_t)-2147483648) is ill-formed (because 2147483648 is not representable as a value of int32_t.) We want to change this case to be well-formed. As long as both |m| and |n| are representable as values of the common type, absolute values can be calculate d without causing unspecified behavior, by converting m and n to the common type before taking the negation.

Suggested resolution:

|m| shall be representable as a value of type M and |n| shall be representable as a value of type N|m| and |n| shall be representable as a value of common_type_t<M, N>.

[2017-01-27 Telecon]

Priority 0

Proposed resolution:

This wording is relative to N4604.

  1. Edit 26.8.13 [numeric.ops.gcd] as indicated:

    template<class M, class N>
      constexpr common_type_t<M, N> gcd(M m, N n);
    

    -2- Requires: |m| shall be representable as a value of type M and |n| shall be representable as a value of type N|m| and |n| shall be representable as a value of common_type_t<M, N>. [Note: These requirements ensure, for example, that gcd(m, m) = |m| is representable as a value of type M. — end note]

  2. Edit 26.8.14 [numeric.ops.lcm] as indicated:

    template<class M, class N>
      constexpr common_type_t<M, N> lcm(M m, N n);
    

    -2- Requires: |m| shall be representable as a value of type M and |n| shall be representable as a value of type N|m| and |n| shall be representable as a value of common_type_t<M, N>. The least common multiple of |m| and |n| shall be representable as a value of type common_type_t<M, N>.


2838. is_literal_type specification needs a little cleanup

Section: D.11 [depr.meta.types] Status: Tentatively Ready Submitter: Tim Song Opened: 2016-12-09 Last modified: 2017-02-03

Priority: 0

View all issues with Tentatively Ready status.

Discussion:

D.11 [depr.meta.types]/3 currently reads:

Effects: is_literal_type has a base-characteristic of true_type if T is a literal type ([basic.types]), and a base-characteristic of false_type otherwise.

First, this doesn't seem like an Effects clause. Second, this wording fails to say that is_literal_type is an UnaryTypeTrait, and misspells BaseCharacteristic — which is only defined for UnaryTypeTraits and BinaryTypeTraits. Third, moving this to Annex D means that the general prohibition against specializing type traits in [meta.type.synop]/1 no longer applies, which is presumably unintended.

[2017-01-27 Telecon]

Priority 0

Proposed resolution:

This wording is relative to N4618.

  1. Edit D.11 [depr.meta.types] as indicated:

    The header <type_traits> has the following addition:

    namespace std {
      template <class T> struct is_literal_type;
      
      template <class T> constexpr bool is_literal_type_v = is_literal_type<T>::value;
    }
    

    -2- Requires: remove_all_extents_t<T> shall be a complete type or (possibly cv-qualified) void.

    -3- Effects: is_literal_type has a base-characteristic of true_type if T is a literal type (3.9), and a basecharacteristic of false_type otherwiseis_literal_type<T> is a UnaryTypeTrait (20.15.1 [meta.rqmts]) with a BaseCharacteristic of true_type if T is a literal type (3.9 [basic.types]), and false_type otherwise.

    -?- The behavior of a program that adds specializations for is_literal_type or is_literal_type_v is undefined.


2842. in_place_t check for optional::optional(U&&) should decay U

Section: 20.6.3.1 [optional.ctor] Status: Tentatively Ready Submitter: Tim Song Opened: 2016-12-13 Last modified: 2017-02-03

Priority: 0

View other active issues in [optional.ctor].

View all other issues in [optional.ctor].

View all issues with Tentatively Ready status.

Discussion:

As in_place_t is a normal tag type again, we need to decay U before doing the is_same_v check.

[2017-01-27 Telecon]

Priority 0

Proposed resolution:

This wording is relative to N4618.

  1. Edit 20.6.3.1 [optional.ctor] as indicated:

    template <class U = T>
      EXPLICIT constexpr optional(U&& v);
    

    […]

    -22- Remarks: If T's selected constructor is a constexpr constructor, this constructor shall be a constexpr constructor. This constructor shall not participate in overload resolution unless is_constructible_v<T, U&&> is true, is_same_v<decay_t<U>, in_place_t> is false, and is_same_v<optional<T>, decay_t<U>> is false. The constructor is explicit if and only if is_convertible_v<U&&, T> is false.


2850. std::function move constructor does unnecessary work

Section: 20.14.12.2.1 [func.wrap.func.con] Status: Tentatively Ready Submitter: Geoffrey Romer Opened: 2016-12-15 Last modified: 2017-02-03

Priority: 0

View other active issues in [func.wrap.func.con].

View all other issues in [func.wrap.func.con].

View all issues with Tentatively Ready status.

Discussion:

Consider [func.wrap.func.con]/p5:

function(function&& f);

Effects: If !f, *this has no target; otherwise, move constructs the target of f into the target of *this, leaving f in a valid state with an unspecified value.

By my reading, this wording requires the move constructor of std::function to construct an entirely new target object. This is silly: in cases where the target is held in separately allocated memory (i.e. where the target doesn't fit in std::function's internal buffer, if any), std::function's move constructor can be implemented by simply transferring ownership of the existing target object (which is a simple pointer assignment), so this requirement forces an unnecessary constructor invocation and probably an unnecessary allocation (the latter can be avoided with something like double-buffering, but ew). Fixing this would technically be a visible change, but I have a hard time imagining reasonable code that would be broken by it, especially since both libstdc++ and libc++ already do the sensible thing, constructing a new target only if the target is held in an internal buffer, and otherwise assigning pointers.

[2017-01-27 Telecon]

Priority 0

Proposed resolution:

This wording is relative to N4618.

  1. Edit 20.14.12.2.1 [func.wrap.func.con]/5 as indicated:

    Drafting note: The "equivalent to ... before the construction" wording is based on the wording for MoveConstructible.

    function(function&& f);
    

    -5- EffectsPostconditions: If !f, *this has no target; otherwise, move constructs the target of f into the target of *this, leaving fthe target of *this is equivalent to the target of f before the construction, and f is in a valid state with an unspecified value.


2853. Possible inconsistency in specification of erase in [vector.modifiers]

Section: 23.3.11.5 [vector.modifiers] Status: Tentatively Ready Submitter: Gerard Stone Opened: 2017-01-16 Last modified: 2017-02-03

Priority: 0

View other active issues in [vector.modifiers].

View all other issues in [vector.modifiers].

View all issues with Tentatively Ready status.

Discussion:

In Table 87 (Sequence container requirements) erase(q) and erase(q1, q2) functions have the following requirements:

For vector and deque, T shall be MoveAssignable.

On the other hand, section [vector.modifiers] has the following specification for erase functions (emphasis mine):

Throws: Nothing unless an exception is thrown by the copy constructor, move constructor, assignment operator, or move assignment operator of T.

Note that Table 87 requires T to be only MoveAssignable, it says nothing about T being copy- or move-constructible. It also says nothing about T being CopyInsertable and MoveInsertable, so why is this even there? The only reason might be so that vector could shrink, but in this case T should be required to be MoveInsertable or CopyInsertable into vector.

On the other hand, we expect that vector will neither allocate, nor deallocate any memory during this operation, because in Effects it is specified that iterators/references shall be invalidated at or after the point of the erase.

So to avoid any confusion, the proposed resolution is to remove mentions of T's copy/move constructors from [vector.modifiers] paragraph 5.

[2017-01-27 Telecon]

Priority 0

Proposed resolution:

This wording is relative to N4618.

  1. Edit 23.3.11.5 [vector.modifiers] p5 as indicated:

    iterator erase(const_iterator position);
    iterator erase(const_iterator first, const_iterator last);
    void pop_back();
    

    -3- Effects: Invalidates iterators and references at or after the point of the erase.

    -4- Complexity: The destructor of T is called the number of times equal to the number of the elements erased, but the assignment operator of T is called the number of times equal to the number of elements in the vector after the erased elements.

    -5- Throws: Nothing unless an exception is thrown by the copy constructor, move constructor, assignment operator, or move assignment operator of T.


2855. std::throw_with_nested("string_literal")

Section: 18.8.7 [except.nested] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2017-01-17 Last modified: 2017-02-03

Priority: 0

View other active issues in [except.nested].

View all other issues in [except.nested].

View all issues with Tentatively Ready status.

Discussion:

[except.nested] says:

template <class T> [[noreturn]] void throw_with_nested(T&& t);

Let U be remove_reference_t<T>.

Requires: U shall be CopyConstructible.

This forbids std::throw_with_nested("string literal") because T gets deduced as const char(&)[15] and so U is const char[15] which is not CopyConstructible.

A throw expression decays an array argument to a pointer (5.17 [expr.throw] p2) and so works fine with string literals. GCC's throw_with_nested also worked fine until I added a static_assert to enforce the CopyConstructible requirement.

The same problem exists when throwing a function type, which should also decay:

#include <exception>

void f() { }

int main() {
  std::throw_with_nested(f);
}

(Note: LWG 1370 added the remove_reference, which was a step in the right direction but not far enough.)

[2017-01-27 Telecon]

Priority 0

Proposed resolution:

This wording is relative to N4618.

  1. Edit 18.8.7 [except.nested] as indicated:

    template <class T> [[noreturn]] void throw_with_nested(T&& t);
    

    -6- Let U be remove_referencedecay_t<T>.

    -7- Requires: U shall be CopyConstructible.