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

## Unresolved Issues

### 423(i). Effects of negative `streamsize` in iostreams

Section: 29 [input.output] Status: Open Submitter: Martin Sebor Opened: 2003-09-18 Last modified: 2018-12-09

Priority: 3

View all other issues in [input.output].

View all issues with Open status.

Discussion:

A third party test suite tries to exercise `istream::ignore(N)` with a negative value of `N` and expects that the implementation will treat `N` as if it were `0`. Our implementation asserts that (`N >= 0`) holds and aborts the test.

I can't find anything in section 27 that prohibits such values but I don't see what the effects of such calls should be, either (this applies to a number of unformatted input functions as well as some member functions of the `basic_streambuf` template).

[ 2009-07 Frankfurt ]

> This is related to LWG 255.

> Move to NAD Future.

[LEWG Kona 2017]

Recommend Open: We agree that we should require `N >= 0` for the selected functions

[2018-12-04 Reflector prioritization]

Set Priority to 3

Proposed resolution:

I propose that we add to each function in clause 27 that takes an argument, say `N`, of type `streamsize` a Requires clause saying that "`N >= 0`." The intent is to allow negative streamsize values in calls to `precision()` and `width()` but disallow it in calls to `streambuf::sgetn()`, `istream::ignore()`, or `ostream::write()`.

[Kona: The LWG agreed that this is probably what we want. However, we need a review to find all places where functions in clause 27 take arguments of type `streamsize` that shouldn't be allowed to go negative. Martin will do that review.]

### 484(i). Convertible to `T`

Section: 23.3.5.3 [input.iterators] Status: Open Submitter: Chris Jefferson Opened: 2004-09-16 Last modified: 2018-01-27

Priority: 2

View other active issues in [input.iterators].

View all other issues in [input.iterators].

View all issues with Open status.

Discussion:

From comp.std.c++:

I note that given an input iterator a for type `T`, then `*a` only has to be "convertable to `T`", not actually of type `T`.

Firstly, I can't seem to find an exact definition of "convertable to `T`". While I assume it is the obvious definition (an implicit conversion), I can't find an exact definition. Is there one?

Slightly more worryingly, there doesn't seem to be any restriction on the this type, other than it is "convertable to `T`". Consider two input iterators `a` and `b`. I would personally assume that most people would expect `*a==*b` would perform `T(*a)==T(*b)`, however it doesn't seem that the standard requires that, and that whatever type `*a` is (call it `U`) could have == defined on it with totally different symantics and still be a valid inputer iterator.

Is this a correct reading? When using input iterators should I write `T(*a)` all over the place to be sure that the object I'm using is the class I expect?

This is especially a nuisance for operations that are defined to be "convertible to `bool`". (This is probably allowed so that implementations could return say an `int` and avoid an unnessary conversion. However all implementations I have seen simply return a `bool` anyway. Typical implemtations of STL algorithms just write things like `while(a!=b && *a!=0)`. But strictly speaking, there are lots of types that are convertible to `T` but that also overload the appropriate operators so this doesn't behave as expected.

If we want to make code like this legal (which most people seem to expect), then we'll need to tighten up what we mean by "convertible to `T`".

[Lillehammer: The first part is NAD, since "convertible" is well-defined in core. The second part is basically about pathological overloads. It's a minor problem but a real one. So leave open for now, hope we solve it as part of iterator redesign.]

[ 2009-07-28 Reopened by Alisdair. No longer solved by concepts. ]

[ 2009-10 Santa Cruz: ]

> Mark as NAD Future. We agree there's an issue, but there is no proposed solution at this time and this will be solved by concepts in the future.

[2017-02 in Kona, LEWG recommends NAD]

Has been clarified by 14. By design. Ranges might make it go away. Current wording for input iterators is more constrained.

[2017-06-02 Issues Telecon]

Move to Open. This is very similar to 2962, possibly a duplicate.

Marshall to research

[2017-07 Toronto Thurs Issue Prioritization]

Priority 2; same as 2962.

Proposed resolution:

Rationale:

[ San Francisco: ]

> Solved by N2758.

### 523(i). regex case-insensitive character ranges are unimplementable as specified

Section: 30 [re] Status: Open Submitter: Eric Niebler Opened: 2005-07-01 Last modified: 2020-07-17

Priority: 4

View other active issues in [re].

View all other issues in [re].

View all issues with Open status.

Discussion:

A problem with TR1 regex is currently being discussed on the Boost developers list. It involves the handling of case-insensitive matching of character ranges such as [Z-a]. The proper behavior (according to the ECMAScript standard) is unimplementable given the current specification of the TR1 `regex_traits<>` class template. John Maddock, the author of the TR1 regex proposal, agrees there is a problem. The full discussion can be found at http://lists.boost.org/boost/2005/06/28850.php (first message copied below). We don't have any recommendations as yet.

-- Begin original message --

The situation of interest is described in the ECMAScript specification (ECMA-262), section 15.10.2.15:

"Even if the pattern ignores case, the case of the two ends of a range is significant in determining which characters belong to the range. Thus, for example, the pattern /[E-F]/i matches only the letters E, F, e, and f, while the pattern /[E-f]/i matches all upper and lower-case ASCII letters as well as the symbols [, \, ], ^, _, and `."

A more interesting case is what should happen when doing a case-insensitive match on a range such as [Z-a]. It should match z, Z, a, A and the symbols [, \, ], ^, _, and `. This is not what happens with Boost.Regex (it throws an exception from the regex constructor).

The tough pill to swallow is that, given the specification in TR1, I don't think there is any effective way to handle this situation. According to the spec, case-insensitivity is handled with `regex_traits<>::translate_nocase(CharT)` — two characters are equivalent if they compare equal after both are sent through the `translate_nocase` function. But I don't see any way of using this translation function to make character ranges case-insensitive. Consider the difficulty of detecting whether "z" is in the range [Z-a]. Applying the transformation to "z" has no effect (it is essentially `std::tolower`). And we're not allowed to apply the transformation to the ends of the range, because as ECMA-262 says, "the case of the two ends of a range is significant."

So AFAICT, TR1 regex is just broken, as is Boost.Regex. One possible fix is to redefine translate_nocase to return a string_type containing all the characters that should compare equal to the specified character. But this function is hard to implement for Unicode, and it doesn't play nice with the existing ctype facet. What a mess!

-- End original message --

[ John Maddock adds: ]

One small correction, I have since found that ICU's regex package does implement this correctly, using a similar mechanism to the current TR1.Regex.

Given an expression [c1-c2] that is compiled as case insensitive it:

Enumerates every character in the range c1 to c2 and converts it to it's case folded equivalent. That case folded character is then used a key to a table of equivalence classes, and each member of the class is added to the list of possible matches supported by the character-class. This second step isn't possible with our current traits class design, but isn't necessary if the input text is also converted to a case-folded equivalent on the fly.

ICU applies similar brute force mechanisms to character classes such as [[:lower:]] and [[:word:]], however these are at least cached, so the impact is less noticeable in this case.

Quick and dirty performance comparisons show that expressions such as "[X-\\x{fff0}]+" are indeed very slow to compile with ICU (about 200 times slower than a "normal" expression). For an application that uses a lot of regexes this could have a noticeable performance impact. ICU also has an advantage in that it knows the range of valid characters codes: code points outside that range are assumed not to require enumeration, as they can not be part of any equivalence class. I presume that if we want the TR1.Regex to work with arbitrarily large character sets enumeration really does become impractical.

Finally note that Unicode has:

Three cases (upper, lower and title). One to many, and many to one case transformations. Character that have context sensitive case translations - for example an uppercase sigma has two different lowercase forms - the form chosen depends on context(is it end of a word or not), a caseless match for an upper case sigma should match either of the lower case forms, which is why case folding is often approximated by tolower(toupper(c)).

Probably we need some way to enumerate character equivalence classes, including digraphs (either as a result or an input), and some way to tell whether the next character pair is a valid digraph in the current locale.

Hoping this doesn't make this even more complex that it was already,

[ Portland: Alisdair: Detect as invalid, throw an exception. Pete: Possible general problem with case insensitive ranges. ]

[ 2009-07 Frankfurt ]

> We agree that this is a problem, but we do not know the answer.

> We are going to declare this NAD until existing practice leads us in some direction.

> No objection to NAD Future.

> Move to NAD Future.

[LEWG Kona 2017]

Recommend Open: Tim Shen proposes: forbid use of case-insensitive ranges with regex traits other than `std::regex_traits<{char, wchar_t, char16_t, char32_t}>` when regex_constants::collate is specified.

[2020-07-17; Priority set to 4 in telecon]

Proposed resolution:

### 532(i). Tuple comparison

Section: 20.5.8 [tuple.rel], 99 [tr.tuple.rel] Status: LEWG Submitter: David Abrahams Opened: 2005-11-29 Last modified: 2016-01-28

Priority: Not Prioritized

View other active issues in [tuple.rel].

View all other issues in [tuple.rel].

View all issues with LEWG status.

Duplicate of: 348

Discussion:

Where possible, `tuple` comparison operators <,<=,=>, and > ought to be defined in terms of `std::less` rather than `operator<`, in order to support comparison of tuples of pointers.

[ 2009-07-28 Reopened by Alisdair. No longer solved by concepts. ]

[ 2009-10 Santa Cruz: ]

> If we solve this for `tuple` we would have to solve it for `pair` algorithms, etc. It is too late to do that at this time. Move to NAD Future.

Proposed resolution:

change 6.1.3.5/5 from:

> Returns: The result of a lexicographical comparison between t and u. The result is defined as: (bool)(get<0>(t) < get<0>(u)) || (!(bool)(get<0>(u) < get<0>(t)) && ttail < utail), where rtail for some tuple r is a tuple containing all but the first element of r. For any two zero-length tuples e and f, e < f returns false.

to:

> Returns: The result of a lexicographical comparison between t and u. For any two zero-length tuples e and f, e < f returns false. Otherwise, the result is defined as: cmp( get<0>(t), get<0>(u)) || (!cmp(get<0>(u), get<0>(t)) && ttail < utail), where rtail for some tuple r is a tuple containing all but the first element of r, and cmp(x,y) is an unspecified function template defined as follows.

> Where T is the type of x and U is the type of y:

> if T and U are pointer types and T is convertible to U, returns less<U>()(x,y)

> otherwise, if T and U are pointer types, returns less<T>()(x,y)

> otherwise, returns (bool)(x < y)

[ Berlin: This issue is much bigger than just tuple (pair, containers, algorithms). Dietmar will survey and work up proposed wording. ]

Rationale:

Recommend NAD. This will be fixed with the next revision of concepts.

[ San Francisco: ]

> Solved by N2770.

### 936(i). Mutex type overspecified

Section: 32.5.4 [thread.mutex.requirements] Status: LEWG Submitter: Pete Becker Opened: 2008-12-05 Last modified: 2017-03-01

Priority: Not Prioritized

View other active issues in [thread.mutex.requirements].

View all other issues in [thread.mutex.requirements].

View all issues with LEWG status.

Duplicate of: 961

Discussion:

32.5.4 [thread.mutex.requirements] describes the requirements for a type to be a "Mutex type". A Mutex type can be used as the template argument for the `Lock` type that's passed to `condition_variable_any::wait` (although `Lock` seems like the wrong name here, since `Lock` is given a different formal meaning in 32.5.5 [thread.lock]) and, although the WD doesn't quite say so, as the template argument for `lock_guard` and `unique_lock`.

The requirements for a Mutex type include:

- `m.lock()` shall be well-formed and have [described] semantics, including a return type of `void`.
- `m.try_lock()` shall be well-formed and have [described] semantics, including a return type of `bool`.
- `m.unlock()` shall be well-formed and have [described] semantics, including a return type of `void`.

Also, a Mutex type "shall not be copyable nor movable".

The latter requirement seems completely irrelevant, and the three requirements on return types are tighter than they need to be. For example, there's no reason that `lock_guard` can't be instantiated with a type that's copyable. The rule is, in fact, that `lock_guard`, etc. won't try to copy objects of that type. That's a constraint on locks, not on mutexes. Similarly, the requirements for `void` return types are unnecessary; the rule is, in fact, that `lock_guard`, etc. won't use any returned value. And with the return type of `bool`, the requirement should be that the return type is convertible to `bool`.

[ Summit: ]

> Move to open. Related to conceptualization and should probably be tackled as part of that.

> - The intention is not only to place a constraint on what types such as `lock_guard` may do with mutex types, but on what any code, including user code, may do with mutex types. Thus the constraints as they are apply to the mutex types themselves, not the current users of mutex types in the standard.
> - This is a low priority issue; the wording as it is may be overly restrictive but this may not be a real issue.

[ Post Summit Anthony adds: ]

> Section 32.5.4 [thread.mutex.requirements] conflates the requirements on a generic Mutex type (including user-supplied mutexes) with the requirements placed on the standard-supplied mutex types in an attempt to group everything together and save space.

> When applying concepts to chapter 30, I suggest that the concepts `Lockable` and `TimedLockable` embody the requirements for *use* of a mutex type as required by `unique_lock/lock_guard/condition_variable_any`. These should be relaxed as Pete describes in the issue. The existing words in 32.5.4 [thread.mutex.requirements] are requirements on all of `std::mutex`, `std::timed_mutex`, `std::recursive_mutex` and `std::recursive_timed_mutex`, and should be rephrased as such.

[2017-03-01, Kona]

SG1: Agreement that we need a paper.

Proposed resolution:

### 961(i). Various threading bugs #11

Section: 32.5.4 [thread.mutex.requirements] Status: LEWG Submitter: Pete Becker Opened: 2009-01-07 Last modified: 2017-03-01

Priority: Not Prioritized

View other active issues in [thread.mutex.requirements].

View all other issues in [thread.mutex.requirements].

View all issues with LEWG status.

Duplicate of: 936

Discussion:

32.5.4 [thread.mutex.requirements] describes required member functions of mutex types, and requires that they throw exceptions under certain circumstances. This is overspecified. User-defined types can abort on such errors without affecting the operation of templates supplied by standard-library.

[ Summit: ]

> Move to open. Related to conceptualization and should probably be tackled as part of that.

[ 2009-10 Santa Cruz: ]

> Would be OK to leave it as is for time constraints, could loosen later.

> Mark as NAD Future.

[2017-03-01, Kona]

SG1: Agreement that we need a paper.

Proposed resolution:

### 1102(i). `std::vector`'s reallocation policy still unclear

Section: 22.3.11.3 [vector.capacity] Status: Open Submitter: Daniel Krügler Opened: 2009-04-20 Last modified: 2020-07-17

Priority: 3

View other active issues in [vector.capacity].

View all other issues in [vector.capacity].

View all issues with Open status.

Discussion:

I have the impression that even the wording of current draft N2857 does insufficiently express the intent of `vector`'s reallocation strategy. This has produced not too old library implementations which release memory in the `clear()` function and even modern articles about C++ programming cultivate the belief that `clear` is allowed to do exactly this. A typical example is something like this:

>     const int buf_size = ...;
>     std::vector<T> buf(buf_size);
>     for (int i = 0; i < some_condition; ++i) {
>       buf.resize(buf_size);
>       write_or_read_data(buf.data());
>       buf.clear(); // Ensure that the next round get's 'zeroed' elements
>     }

where still the myth is ubiquitous that `buf` might be allowed to reallocate it's memory inside the `for` loop.

IMO the problem is due to the fact, that

1. the actual memory-reallocation stability of `std::vector` is explained in 22.3.11.3 [vector.capacity]/3 and /6 which are describing just the effects of the `reserve` function, but in many examples (like above) there is no explicit call to `reserve` involved. Further-more 22.3.11.3 [vector.capacity]/6 does only mention insertions and never mentions the consequences of erasing elements.

2. the effects clause of `std::vector`'s `erase` overloads in 22.3.11.5 [vector.modifiers]/4 is silent about capacity changes. This easily causes a misunderstanding, because the counter parting insert functions described in 22.3.11.5 [vector.modifiers]/2 explicitly say, that

   > Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid.

   It requires a complex argumentation chain about four different places in the standard to provide the — possibly weak — proof that calling `clear()` also does never change the capacity of the `std::vector` container. Since `std::vector` is the de-facto replacement of C99's dynamic arrays this type is near to a built-in type and it's specification should be clear enough that usual programmers can trust their own reading.

[ Batavia (2009-05): ]

> Bill believes paragraph 1 of the proposed resolution is unnecessary because it is already implied (even if tortuously) by the current wording.

> Move to Review.

[ 2009-10 Santa Cruz: ]

> Mark as NAD. Rationale: there is no consensus to clarify the standard, general consensus that the standard is correct as written.

[2020-05-08; Reopen after reflector discussions]

"correct as written" has been disputed.

[2020-07-17; Priority set to 3 in telecon]

Proposed resolution:

[ This is a minimum version. I also suggest that the wording explaining the allocation strategy of `std::vector` in 22.3.11.3 [vector.capacity]/3 and /6 is moved into a separate sub paragraph of 22.3.11.3 [vector.capacity] before any of the prototype's are discussed, but I cannot provide reasonable wording changes now. ]

1. Change 22.3.11.3 [vector.capacity]/6 as follows:

   > It is guaranteed that no reallocation takes place during insertions or erasures that happen after a call to `reserve()` until the time when an insertion would make the size of the vector greater than the value of `capacity()`.

2. Change 22.3.11.5 [vector.modifiers]/4 as follows:

   > Effects: The capacity shall remain unchanged and no reallocation shall happen. Invalidates iterators and references at or after the point of the erase.

### 1175(i). `unordered` complexity

Section: 22.2.7 [unord.req] Status: Open Submitter: Pablo Halpern Opened: 2009-07-17 Last modified: 2020-09-06

Priority: 3

View other active issues in [unord.req].

View all other issues in [unord.req].

View all issues with Open status.

Discussion:

When I look at the `unordered_*` constructors, I think the complexity is poorly described and does not follow the style of the rest of the standard.

The complexity for the default constructor is specified as constant. Actually, it is proportional to `n`, but there are no invocations of `value_type` constructors or other `value_type` operations.

For the iterator-based constructor the complexity should be:

> Complexity: exactly `n` calls to construct `value_type` from `InputIterator::value_type` (where `n = distance(f,l)`). The number of calls to `key_equal::operator()` is proportional to `n` in the average case and `n*n` in the worst case.

[ 2010 Rapperswil: ]

> Concern that the current wording may require O(1) where that cannot be delivered. We need to look at both the clause 23 requirements tables and the constructor description of each unordered container to be sure.

> Howard suggests NAD Editorial as we updated the container requirement tables since this issue was written.

> Daniel offers to look deeper, and hopefully produce wording addressing any outstanding concerns at the next meeting.

> Move to Open.

[2011-02-26: Daniel provides wording]

I strongly suggest to clean-up the differences between requirement tables and individual specifications. In the usual way, the most specific specifications wins, which is in this case the wrong one. In regard to the concern expressed about missing `DefaultConstructible` requirements of the value type I disagree: The function argument `n` is no size-control parameter, but only some effective capacity parameter: No elements will be value-initialized by these constructors. The necessary requirement for the value type, `EmplaceConstructible` into `*this`, is already listed in Table 103 — Unordered associative container requirements. Another part of the proposed resolution is the fact that there is an inconsistency of the complexity counting when both a range and a bucket count is involved compared to constructions where only bucket counts are provided: E.g. the construction `X a(n);` has a complexity of `n` bucket allocations, but this part of the work is omitted for `X a(i, j, n);`, even though it is considerable larger (in the average case) for `n ≫ distance(i, j)`.

[2011-03-24 Madrid meeting]

Move to deferred

[ 2011 Bloomington ]

The proposed wording looks good. Move to Review.

[2012, Kona]

Fix up some presentation issues with the wording, combining the big-O expressions into single expressions rather than the sum of two separate big-Os.

Strike "constant or linear", prefer "linear in the number of buckets". This allows for number of buckets being larger than requested `n` as well.

Default `n` to "unspecified" rather than "implementation-defined". It seems an un-necessary burden asking vendors to document a quantity that is easily determined through the public API of these classes.

Replace `distance(f,l)` with "number of elements in the range `[f,l)`"

Retain in Review with the updated wording

[2012, Portland: Move to Open]

The wording still does not call out Pablo's original concern, that the element constructor is called no more than `N` times, and that the `N` squared term applies to moves during rehash.

Inconsistent use of O(n)+O(N) vs. O(n+N), with a preference for the former.

AJM to update wording with a reference to "no more than `N` element constructor calls".

Matt concerned that calling out the O(n) requirements is noise, and dangerous noise in suggesting a precision we do not mean. The cost of constructing a bucket is very different to constructing an element of user-supplied type.

AJM notes that if there are multiple rehashes, the 'n' complexity is probably not linear.

Matt suggests back to Open, Pablo suggests potentially NAD if we keep revisitting without achieving a resolution.

Matt suggests complexity we are concerned with is the number of operations, such as constructing elements, moving nodes, and comparing/hashing keys. We are less concerned with constructing buckets, which are generally noise in this bigger picture.

[2015-01-29 Telecon]

AM: essentially correct, but do we want to complicate the spec?

HH: Pablo has given us permission to NAD it

JM: when I look at the first change in the P/R I find it mildly disturbing that the existing wording says you have a constant time constructor with a single element even if your `n` is 10^6, so I think adding this change makes people aware there might be a large cost in initializing the hash table, even though it doesn't show up in user-visible constructions.

HH: one way to avoid that problem is make the default ctor `noexcept`. Then the container isn't allowed to create an arbitrarily large hash table

AM: but this is the constructor where the user provides `n`

MC: happy with the changes, except I agree with the editorial recommendation to keep the two 𝒪s separate.

JW: yes, the constant '`k`' is different in 𝒪(n) and 𝒪(N)

GR: do we want to talk about buckets at all

JM: yes, good to highlight that bucket construction might be a significant cost

HH: suggest we take the suggestion to split 𝒪(n+N) to 𝒪(n)+𝒪(N) and move to Tentatively Ready

GR: 23.2.1p2 says all complexity requirements are stated solely in terms of the number of operations on the contained object, so we shouldn't be stating complexity in terms of the hash table initialization

HH: channeling Pete, there's an implicit "unless otherwise specified" everywhere.

VV: seem to be requesting modifications that render this not Tentatively Ready

GR: I think it can't be T/R

AM: make the editorial recommendation, consider fixing 23.2.1/3 to give us permission to state complexity in terms of bucket initialization

HH: only set it to Review after we get new wording to review

[2015-02 Cologne]

Update wording, revisit later.

Previous resolution [SUPERSEDED]:

> 1. Modify the following rows in Table 103 — Unordered associative container requirements to add the explicit bucket allocation overhead of some constructions. As editorial recommendation it is suggested not to shorten the sum `𝒪(n) + 𝒪(N)` to `𝒪(n + N)`, because two different work units are involved.

>    > Table 103 — Unordered associative container requirements (in addition to container)
>    > Expression | Return type | Assertion/note pre-/post-condition | Complexity
>    > --- | --- | --- | ---
>    > …
>    > `X(i, j, n, hf, eq)` `X a(i, j, n, hf, eq)` | `X` | … Effects: Constructs an empty container with at least `n` buckets, using `hf` as the hash function and `eq` as the key equality predicate, and inserts elements from `[i, j)` into it. | Average case 𝒪(`n + N`) (`N` is `distance(i, j)`), worst case 𝒪(`n`) + 𝒪(`N2`)
>    > `X(i, j, n, hf)` `X a(i, j, n, hf)` | `X` | … Effects: Constructs an empty container with at least `n` buckets, using `hf` as the hash function and `key_equal()` as the key equality predicate, and inserts elements from `[i, j)` into it. | Average case 𝒪(`n + N`) (`N` is `distance(i, j)`), worst case 𝒪(`n + N2`)
>    > `X(i, j, n)` `X a(i, j, n)` | `X` | … Effects: Constructs an empty container with at least `n` buckets, using `hasher()` as the hash function and `key_equal()` as the key equality predicate, and inserts elements from `[i, j)` into it. | Average case 𝒪(`n + N`) (`N` is `distance(i, j)`), worst case 𝒪(`n + N2`)
>    > …

> 2. Modify 22.5.4.2 [unord.map.cnstr] p. 1-4 as indicated (The edits of p. 1 and p. 3 attempt to fix some editorial oversight.):

>    >     explicit unordered_map(size_type n = see below,
>    >                            const hasher& hf = hasher(),
>    >                            const key_equal& eql = key_equal(),
>    >                            const allocator_type& a = allocator_type());

>    > > 1 Effects: Constructs an empty `unordered_map` using the specified hash function, key equality function, and allocator, and using at least `n` buckets. If `n` is not provided, the number of buckets is unspecified impldefdefault number of buckets in `unordered_map`. `max_load_factor()` returns `1.0`.

>    > > 2 Complexity: Constant Linear in the number of buckets.

>    >     template <class InputIterator>
>    >     unordered_map(InputIterator f, InputIterator l,
>    >                   size_type n = see below,
>    >                   const hasher& hf = hasher(),
>    >                   const key_equal& eql = key_equal(),
>    >                   const allocator_type& a = allocator_type());

>    > > 3 Effects: Constructs an empty `unordered_map` using the specified hash function, key equality function, and allocator, and using at least `n` buckets. If `n` is not provided, the number of buckets is unspecified impldefdefault number of buckets in `unordered_map`. Then inserts elements from the range `[f, l)`. `max_load_factor()` returns `1.0`.

>    > > 4 Complexity: Average case linear, worst case quadratic Linear in the number of buckets. In the average case linear in `N` and in the worst case quadratic in `N` to insert the elements, where `N` is equal to number of elements in the range `[f,l)`.

> 3. Modify 22.5.5.2 [unord.multimap.cnstr] p. 1-4 as indicated (The edits of p. 1 and p. 3 attempt to fix some editorial oversight.):

>    >     explicit unordered_multimap(size_type n = see below,
>    >                                 const hasher& hf = hasher(),
>    >                                 const key_equal& eql = key_equal(),
>    >                                 const allocator_type& a = allocator_type());

>    > > 1 Effects: Constructs an empty `unordered_multimap` using the specified hash function, key equality function, and allocator, and using at least `n` buckets. If `n` is not provided, the number of buckets is unspecified impldefdefault number of buckets in `unordered_multimap`. `max_load_factor()` returns `1.0`.

>    > > 2 Complexity: Constant Linear in the number of buckets.

>    >     template <class InputIterator>
>    >     unordered_multimap(InputIterator f, InputIterator l,
>    >                        size_type n = see below,
>    >                        const hasher& hf = hasher(),
>    >                        const key_equal& eql = key_equal(),
>    >                        const allocator_type& a = allocator_type());

>    > > 3 Effects: Constructs an empty `unordered_multimap` using the specified hash function, key equality function, and allocator, and using at least `n` buckets. If `n` is not provided, the number of buckets is unspecified impldefdefault number of buckets in `unordered_multimap`. Then inserts elements from the range `[f, l)`. `max_load_factor()` returns `1.0`.

>    > > 4 Complexity: Average case linear, worst case quadratic Linear in the number of buckets. In the average case linear in `N` and in the worst case quadratic in `N` to insert the elements, where `N` is equal to number of elements in the range `[f,l)`.

> 4. Modify 22.5.6.2 [unord.set.cnstr] p. 1-4 as indicated (The edits of p. 1 and p. 3 attempt to fix some editorial oversight.):

>    >     explicit unordered_set(size_type n = see below,
>    >                            const hasher& hf = hasher(),
>    >                            const key_equal& eql = key_equal(),
>    >                            const allocator_type& a = allocator_type());

>    > > 1 Effects: Constructs an empty `unordered_set` using the specified hash function, key equality function, and allocator, and using at least `n` buckets. If `n` is not provided, the number of buckets is unspecified impldefdefault number of buckets in `unordered_set`. `max_load_factor()` returns `1.0`.

>    > > 2 Complexity: Constant Linear in the number of buckets.

>    >     template <class InputIterator>
>    >     unordered_set(InputIterator f, InputIterator l,
>    >                   size_type n = see below,
>    >                   const hasher& hf = hasher(),
>    >                   const key_equal& eql = key_equal(),
>    >                   const allocator_type& a = allocator_type());

>    > > 3 Effects: Constructs an empty `unordered_set` using the specified hash function, key equality function, and allocator, and using at least `n` buckets. If `n` is not provided, the number of buckets is unspecified impldefdefault number of buckets in `unordered_set`. Then inserts elements from the range `[f, l)`. `max_load_factor()` returns `1.0`.

>    > > 4 Complexity: Average case linear, worst case quadratic Linear in the number of buckets. In the average case linear in `N` and in the worst case quadratic in `N` to insert the elements, where `N` is equal to number of elements in the range `[f,l)`.

> 5. Modify 22.5.7.2 [unord.multiset.cnstr] p. 1-4 as indicated (The edits of p. 1 and p. 3 attempt to fix some editorial oversight.):

>    >     explicit unordered_multiset(size_type n = see below,
>    >                                 const hasher& hf = hasher(),
>    >                                 const key_equal& eql = key_equal(),
>    >                                 const allocator_type& a = allocator_type());

>    > > 1 Effects: Constructs an empty `unordered_multiset` using the specified hash function, key equality function, and allocator, and using at least `n` buckets. If `n` is not provided, the number of buckets is unspecified impldefdefault number of buckets in `unordered_multiset`. `max_load_factor()` returns `1.0`.

>    > > 2 Complexity: Constant Linear in the number of buckets.

>    >     template <class InputIterator>
>    >     unordered_multiset(InputIterator f, InputIterator l,
>    >                        size_type n = see below,
>    >                        const hasher& hf = hasher(),
>    >                        const key_equal& eql = key_equal(),
>    >                        const allocator_type& a = allocator_type());

>    > > 3 Effects: Constructs an empty `unordered_multiset` using the specified hash function, key equality function, and allocator, and using at least `n` buckets. If `n` is not provided, the number of buckets is unspecified impldefdefault number of buckets in `unordered_multiset`. Then inserts elements from the range `[f, l)`. `max_load_factor()` returns `1.0`.

>    > > 4 Complexity: Average case linear, worst case quadratic Linear in the number of buckets. In the average case linear in `N` and in the worst case quadratic in `N` to insert the elements, where `N` is equal to number of elements in the range `[f,l)`.

[2019-03-17; Daniel comments and provides revised wording]

The updated wording ensures that we can now specify complexity requirements for containers even when they are not expressed in terms of the number on the contained objects by an exception of the rule. This allows us to say that `𝒪(n)` describes the complexity in terms of bucket initialization instead.

Proposed resolution:

This wording is relative to N4810.

1. Modify 22.2.1 [container.requirements.general] as indicated:

   > -2- Unless otherwise specified,All of the complexity requirements in this Clause are stated solely in terms of the number of operations on the contained objects. [Example: The copy constructor of type `vector<vector<int>>` has linear complexity, even though the complexity of copying each contained `vector<int>` is itself linear. — end example]

2. Modify 22.2.7 [unord.req] as indicated:

   > -11- In Table 70:

   > 1. (11.1) — […]

   > 2. […]

   > 3. (11.23) — […]

   > 4. (11.?) — Notwithstanding the complexity requirements restrictions of 22.2.1 [container.requirements.general], the complexity form `𝒪(n)` describes the number of operations on buckets.

3. Modify the following rows in Table 70 — "Unordered associative container requirements" to add the explicit bucket allocation overhead of some constructions.

   > [Drafting note: It is kindly suggested to the Project Editor not to shorten the sum `𝒪(n) + 𝒪(N)` to `𝒪(n + N)`, because two different work units are involved. — end drafting note]

   > Table 70 — Unordered associative container requirements (in addition to container)
   > Expression | Return type | Assertion/note pre-/post-condition | Complexity
   > --- | --- | --- | ---
   > …
   > `X()` `X a;` | `X` | Expects: […] Effects: Constructs an empty container with an unspecified number `n` of buckets, using `hasher()` as the hash function and `key_equal()` as the key equality predicate. | constant 𝒪(`n`)
   > `X(i, j, n, hf, eq)` `X a(i, j, n, hf, eq)` | `X` | Expects: […] Effects: Constructs an empty container with at least `n` buckets, using `hf` as the hash function and `eq` as the key equality predicate, and inserts elements from `[i, j)` into it. | Average case 𝒪(`n`) + 𝒪(`N`) (`N` is `distance(i, j)`), worst case 𝒪(`n`) + 𝒪(`N2`)
   > `X(i, j, n, hf)` `X a(i, j, n, hf)` | `X` | Expects: […] Effects: Constructs an empty container with at least `n` buckets, using `hf` as the hash function and `key_equal()` as the key equality predicate, and inserts elements from `[i, j)` into it. | Average case 𝒪(`n`) + 𝒪(`N`) (`N` is `distance(i, j)`), worst case 𝒪(`n`) + 𝒪(`N2`)
   > `X(i, j, n)` `X a(i, j, n)` | `X` | Expects: […] Effects: Constructs an empty container with at least `n` buckets, using `hasher()` as the hash function and `key_equal()` as the key equality predicate, and inserts elements from `[i, j)` into it. | Average case 𝒪(`n`) + 𝒪(`N`) (`N` is `distance(i, j)`), worst case 𝒪(`n`) + 𝒪(`N2`)
   > `X(i, j)` `X a(i, j)` | `X` | Expects: […] Effects: Constructs an empty container with an unspecified number `n` of buckets, using `hasher()` as the hash function and `key_equal()` as the key equality predicate, and inserts elements from `[i, j)` into it. | Average case 𝒪(`n`) + 𝒪(`N`) (`N` is `distance(i, j)`), worst case 𝒪(`n`) + 𝒪(`N2`)
   > …

4. Modify 22.5.4.1 [unord.map.overview], class template `unordered_map`, as indicated:

   >     // 22.5.4.2 [unord.map.cnstr], construct/copy/destroy
   >     […]
   >     template <class InputIterator>
   >       unordered_map(InputIterator f, InputIterator l,
   >                     size_type n = see belowunspecified,
   >                     const hasher& hf = hasher(),
   >                     const key_equal& eql = key_equal(),
   >                     const allocator_type& a = allocator_type());
   >     […]
   >     unordered_map(initializer_list<value_type> il,
   >                   size_type n = see belowunspecified,
   >                   const hasher& hf = hasher(),
   >                   const key_equal& eql = key_equal(),
   >                   const allocator_type& a = allocator_type());
   >     […]

5. Modify 22.5.4.2 [unord.map.cnstr] as indicated:

   >     unordered_map() : unordered_map(size_type(see belowunspecified)) { }
   >     explicit unordered_map(size_type n,
   >                            const hasher& hf = hasher(),
   >                            const key_equal& eql = key_equal(),
   >                            const allocator_type& a = allocator_type());

   > > -1- Effects: Constructs an empty `unordered_map` using the specified hash function, key equality predicate, and allocator, and using at least `n` buckets. For the default constructor, the number of buckets is implementation-defined. `max_load_factor()` returns `1.0`.

   > > -?- Ensures: `max_load_factor() == 1.0`

   > > -2- Complexity: Constant Linear in the number of buckets.

   >     template <class InputIterator>
   >     unordered_map(InputIterator f, InputIterator l,
   >                   size_type n = see belowunspecified,
   >                   const hasher& hf = hasher(),
   >                   const key_equal& eql = key_equal(),
   >                   const allocator_type& a = allocator_type());
   >     unordered_map(initializer_list<value_type> il,
   >                   size_type n = see belowunspecified,
   >                   const hasher& hf = hasher(),
   >                   const key_equal& eql = key_equal(),
   >                   const allocator_type& a = allocator_type());

   > > -3- Effects: Constructs an empty `unordered_map` using the specified hash function, key equality predicate, and allocator, and using at least `n` buckets. If `n` is not provided, the number of buckets is implementation-defined. Then inserts elements from the range `[f, l)` for the first form, or from the range `[il.begin(), il.end())` for the second form. `max_load_factor()` returns `1.0`.

   > > -?- Ensures: `max_load_factor() == 1.0`

   > > -4- Complexity: Average case linear, worst case quadratic Linear in the number of buckets, plus 𝒪(`N`) (average case) or 𝒪(`N2`) (worst case) where `N` is the number of insertions.

6. Modify 22.5.5.1 [unord.multimap.overview], class template `unordered_multimap`, as indicated:

   >     // 22.5.5.2 [unord.multimap.cnstr], construct/copy/destroy
   >     […]
   >     template <class InputIterator>
   >       unordered_multimap(InputIterator f, InputIterator l,
   >                          size_type n = see belowunspecified,
   >                          const hasher& hf = hasher(),
   >                          const key_equal& eql = key_equal(),
   >                          const allocator_type& a = allocator_type());
   >     […]
   >     unordered_multimap(initializer_list<value_type> il,
   >                        size_type n = see belowunspecified,
   >                        const hasher& hf = hasher(),
   >                        const key_equal& eql = key_equal(),
   >                        const allocator_type& a = allocator_type());
   >     […]

7. Modify 22.5.5.2 [unord.multimap.cnstr] as indicated:

   >     unordered_multimap() : unordered_multimap(size_type(see belowunspecified)) { }
   >     explicit unordered_multimap(size_type n,
   >                                 const hasher& hf = hasher(),
   >                                 const key_equal& eql = key_equal(),
   >                                 const allocator_type& a = allocator_type());

   > > -1- Effects: Constructs an empty `unordered_multimap` using the specified hash function, key equality predicate, and allocator, and using at least `n` buckets. For the default constructor, the number of buckets is implementation-defined. `max_load_factor()` returns `1.0`.

   > > -?- Ensures: `max_load_factor() == 1.0`

   > > -2- Complexity: Constant Linear in the number of buckets.

   >     template <class InputIterator>
   >     unordered_multimap(InputIterator f, InputIterator l,
   >                        size_type n = see belowunspecified,
   >                        const hasher& hf = hasher(),
   >                        const key_equal& eql = key_equal(),
   >                        const allocator_type& a = allocator_type());
   >     unordered_multimap(initializer_list<value_type> il,
   >                        size_type n = see belowunspecified,
   >                        const hasher& hf = hasher(),
   >                        const key_equal& eql = key_equal(),
   >                        const allocator_type& a = allocator_type());

   > > -3- Effects: Constructs an empty `unordered_multimap` using the specified hash function, key equality predicate, and allocator, and using at least `n` buckets. If `n` is not provided, the number of buckets is implementation-defined. Then inserts elements from the range `[f, l)` for the first form, or from the range `[il.begin(), il.end())` for the second form. `max_load_factor()` returns `1.0`.

   > > -?- Ensures: `max_load_factor() == 1.0`

   > > -4- Complexity: Average case linear, worst case quadratic Linear in the number of buckets, plus 𝒪(`N`) (average case) or 𝒪(`N2`) (worst case) where `N` is the number of insertions.

8. Modify 22.5.6.1 [unord.set.overview], class template `unordered_set`, as indicated:

   >     // 22.5.6.2 [unord.set.cnstr], construct/copy/destroy
   >     […]
   >     template <class InputIterator>
   >       unordered_set(InputIterator f, InputIterator l,
   >                     size_type n = see belowunspecified,
   >                     const hasher& hf = hasher(),
   >                     const key_equal& eql = key_equal(),
   >                     const allocator_type& a = allocator_type());
   >     […]
   >     unordered_set(initializer_list<value_type> il,
   >                   size_type n = see belowunspecified,
   >                   const hasher& hf = hasher(),
   >                   const key_equal& eql = key_equal(),
   >                   const allocator_type& a = allocator_type());
   >     […]

9. Modify 22.5.6.2 [unord.set.cnstr] as indicated:

   >     unordered_set() : unordered_set(size_type(see belowunspecified)) { }
   >     explicit unordered_set(size_type n,
   >                            const hasher& hf = hasher(),
   >                            const key_equal& eql = key_equal(),
   >                            const allocator_type& a = allocator_type());

   > > -1- Effects: Constructs an empty `unordered_set` using the specified hash function, key equality predicate, and allocator, and using at least `n` buckets. For the default constructor, the number of buckets is implementation-defined. `max_load_factor()` returns `1.0`.

   > > -?- Ensures: `max_load_factor() == 1.0`

   > > -2- Complexity: Constant Linear in the number of buckets.

   >     template <class InputIterator>
   >     unordered_set(InputIterator f, InputIterator l,
   >                   size_type n = see belowunspecified,
   >                   const hasher& hf = hasher(),
   >                   const key_equal& eql = key_equal(),
   >                   const allocator_type& a = allocator_type());
   >     unordered_set(initializer_list<value_type> il,
   >                   size_type n = see belowunspecified,
   >                   const hasher& hf = hasher(),
   >                   const key_equal& eql = key_equal(),
   >                   const allocator_type& a = allocator_type());

   > > -3- Effects: Constructs an empty `unordered_set` using the specified hash function, key equality predicate, and allocator, and using at least `n` buckets. If `n` is not provided, the number of buckets is implementation-defined. Then inserts elements from the range `[f, l)` for the first form, or from the range `[il.begin(), il.end())` for the second form. `max_load_factor()` returns `1.0`.

   > > -?- Ensures: `max_load_factor() == 1.0`

   > > -4- Complexity: Average case linear, worst case quadratic Linear in the number of buckets, plus 𝒪(`N`) (average case) or 𝒪(`N2`) (worst case) where `N` is the number of insertions.

10. Modify 22.5.6.1 [unord.set.overview], class template `unordered_multiset`, as indicated:

    >     // 22.5.7.2 [unord.multiset.cnstr], construct/copy/destroy
    >     […]
    >     template <class InputIterator>
    >       unordered_multiset(InputIterator f, InputIterator l,
    >                          size_type n = see belowunspecified,
    >                          const hasher& hf = hasher(),
    >                          const key_equal& eql = key_equal(),
    >                          const allocator_type& a = allocator_type());
    >     […]
    >     unordered_multiset(initializer_list<value_type> il,
    >                        size_type n = see belowunspecified,
    >                        const hasher& hf = hasher(),
    >                        const key_equal& eql = key_equal(),
    >                        const allocator_type& a = allocator_type());
    >     […]

11. Modify 22.5.7.2 [unord.multiset.cnstr] as indicated:

    >     unordered_multiset() : unordered_multiset(size_type(see belowunspecified)) { }
    >     explicit unordered_multiset(size_type n,
    >                                 const hasher& hf = hasher(),
    >                                 const key_equal& eql = key_equal(),
    >                                 const allocator_type& a = allocator_type());

    > > -1- Effects: Constructs an empty `unordered_multiset` using the specified hash function, key equality predicate, and allocator, and using at least `n` buckets. For the default constructor, the number of buckets is implementation-defined. `max_load_factor()` returns `1.0`.

    > > -?- Ensures: `max_load_factor() == 1.0`

    > > -2- Complexity: Constant Linear in the number of buckets.

    >     template <class InputIterator>
    >     unordered_multiset(InputIterator f, InputIterator l,
    >                        size_type n = see belowunspecified,
    >                        const hasher& hf = hasher(),
    >                        const key_equal& eql = key_equal(),
    >                        const allocator_type& a = allocator_type());
    >     unordered_multiset(initializer_list<value_type> il,
    >                        size_type n = see belowunspecified,
    >                        const hasher& hf = hasher(),
    >                        const key_equal& eql = key_equal(),
    >                        const allocator_type& a = allocator_type());

    > > -3- Effects: Constructs an empty `unordered_multiset` using the specified hash function, key equality predicate, and allocator, and using at least `n` buckets. If `n` is not provided, the number of buckets is implementation-defined. Then inserts elements from the range `[f, l)` for the first form, or from the range `[il.begin(), il.end())` for the second form. `max_load_factor()` returns `1.0`.

    > > -?- Ensures: `max_load_factor() == 1.0`

    > > -4- Complexity: Average case linear, worst case quadratic Linear in the number of buckets, plus 𝒪(`N`) (average case) or 𝒪(`N2`) (worst case) where `N` is the number of insertions.

### 1213(i). Meaning of valid and singular iterator underspecified

Section: 23.3 [iterator.requirements] Status: Open Submitter: Daniel Krügler Opened: 2009-09-19 Last modified: 2016-01-28

Priority: 4

View all other issues in [iterator.requirements].

View all issues with Open status.

Discussion:

The terms valid iterator and singular aren't properly defined. The fuzziness of those terms became even worse after the resolution of 208 (including further updates by 278). In 23.3 [iterator.requirements] as of N2723 the standard says now:

> 5 - These values are called past-the-end values. Values of an iterator `i` for which the expression `*i` is defined are called dereferenceable. The library never assumes that past-the-end values are dereferenceable. Iterators can also have singular values that are not associated with any container. [...] Results of most expressions are undefined for singular values; the only exceptions are destroying an iterator that holds a singular value and the assignment of a non-singular value to an iterator that holds a singular value. [...] Dereferenceable values are always non-singular.

> 10 - An invalid iterator is an iterator that may be singular.

First, issue 208 intentionally removed the earlier constraint that past-the-end values are always non-singular. The reason for this was to support null pointers as past-the-end iterators of e.g. empty sequences. But there seem to exist different views on what a singular (iterator) value is. E.g. according to the SGI definition a null pointer is not a singular value:

> Dereferenceable iterators are always nonsingular, but the converse is not true. For example, a null pointer is nonsingular (there are well defined operations involving null pointers) even thought it is not dereferenceable.

and proceeds:

> An iterator is valid if it is dereferenceable or past-the-end.

Even if the standard prefers a different meaning of singular here, the change was incomplete, because by restricting feasible expressions of singular iterators to destruction and assignment isn't sufficient for a past-the-end iterator: Of-course it must still be equality-comparable and in general be a readable value.

Second, the standard doesn't clearly say whether a past-the-end value is a valid iterator or not. E.g. 25.11 [specialized.algorithms]/1 says:

> In all of the following algorithms, the formal template parameter `ForwardIterator` is required to satisfy the requirements of a forward iterator (24.1.3) [..], and is required to have the property that no exceptions are thrown from [..], or dereference of valid iterators.

The standard should make better clear what "singular pointer" and "valid iterator" means. The fact that the meaning of a valid value has a core language meaning doesn't imply that for an iterator concept the term "valid iterator" has the same meaning.

Let me add a final example: In 99 [allocator.concepts.members] of N2914 we find:

>     pointer X::allocate(size_type n);

> > 11 Returns: a pointer to the allocated memory. [Note: if `n == 0`, the return value is unspecified. —end note]

> [..]

>     void X::deallocate(pointer p, size_type n);

> > Preconditions: `p` shall be a non-singular pointer value obtained from a call to `allocate()` on this allocator or one that compares equal to it.

If singular pointer value would include null pointers this make the preconditions unclear if the pointer value is a result of `allocate(0)`: Since the return value is unspecified, it could be a null pointer. Does that mean that programmers need to check the pointer value for a null value before calling deallocate?

[ 2010-11-09 Daniel comments: ]

A later paper is in preparation.

[ 2010 Batavia: ]

Doesn't need to be resolved for Ox

[2014-02-20 Re-open Deferred issues as Priority 4]

Consider to await the paper.

Proposed resolution:

### 1238(i). Defining algorithms taking iterator for range

Section: 25 [algorithms] Status: Open Submitter: Alisdair Meredith Opened: 2009-10-15 Last modified: 2020-09-06

Priority: 3

View other active issues in [algorithms].

View all other issues in [algorithms].

View all issues with Open status.

Discussion:

The library has many algorithms that take a source range represented by a pair of iterators, and the start of some second sequence given by a single iterator. Internally, these algorithms will produce undefined behaviour if the second 'range' is not as large as the input range, but none of the algorithms spell this out in Requires clauses, and there is no catch-all wording to cover this in clause 17 or the front matter of 25.

There was an attempt to provide such wording in paper n2944 but this seems incidental to the focus of the paper, and getting the wording of this issue right seems substantially more difficult than the simple approach taken in that paper. Such wording will be removed from an updated paper, and hopefully tracked via the LWG issues list instead.

It seems there are several classes of problems here and finding wording to solve all in one paragraph could be too much. I suspect we need several overlapping requirements that should cover the desired range of behaviours.

Motivating examples:

A good initial example is the `swap_ranges` algorithm. Here there is a clear requirement that `first2` refers to the start of a valid range at least as long as the range `[first1, last1)`. n2944 tries to solve this by positing a hypothetical `last2` iterator that is implied by the signature, and requires `distance(first2,last2) < distance(first1,last1)`. This mostly works, although I am uncomfortable assuming that `last2` is clearly defined and well known without any description of how to obtain it (and I have no idea how to write that).

A second motivating example might be the `copy` algorithm. Specifically, let us image a call like:

>     copy(istream_iterator<int>(is),istream_iterator(),ostream_iterator<int>(os));

In this case, our input iterators are literally simple `InputIterators`, and the destination is a simple `OutputIterator`. In neither case am I happy referring to `std::distance`, in fact it is not possible for the `ostream_iterator` at all as it does not meet the requirements. However, any wording we provide must cover both cases. Perhaps we might deduce `last2 == ostream_iterator<int>{}`, but that might not always be valid for user-defined iterator types. I can well imagine an 'infinite range' that writes to `/dev/null` and has no meaningful `last2`.

The motivating example in n2944 is `std::equal`, and that seems to fall somewhere between the two.

Outlying examples might be `partition_copy` that takes two output iterators, and the `_n` algorithms where a range is specified by a specific number of iterations, rather than traditional iterator pair. We should also not accidentally apply inappropriate constraints to `std::rotate` which takes a third iterator that is not intended to be a separate range at all.

I suspect we want some wording similar to:

> For algorithms that operate on ranges where the end iterator of the second range is not specified, the second range shall contain at least as many elements as the first.

I don't think this quite captures the intent yet though. I am not sure if 'range' is the right term here rather than sequence. More awkwardly, I am not convinced we can describe an Output sequence such as produce by an `ostream_iterator` as "containing elements", at least not as a precondition to the call before they have been written.

Another idea was to describe require that the trailing iterator support at least distance(input range) applications of `operator++` and may be written through the same number of times if a mutable/output iterator.

We might also consider handling the case of an output range vs. an input range in separate paragraphs, if that simplifies how we describe some of these constraints.

[ 2009-11-03 Howard adds: ]

> Moved to Tentatively NAD Future after 5 positive votes on c++std-lib.

[LEWG Kona 2017]

Recommend Open: The design is clear here; we just need wording

[2019-01-20 Reflector prioritization]

Set Priority to 3

Rationale:

Does not have sufficient support at this time. May wish to reconsider for a future standard.

Proposed resolution:

### 1422(i). `vector<bool>` iterators are not random access

Section: 22.3.12 [vector.bool] Status: Open Submitter: BSI Opened: 2010-08-25 Last modified: 2020-09-06

Priority: 3

View other active issues in [vector.bool].

View all other issues in [vector.bool].

View all issues with Open status.

Discussion:

Addresses GB-118

`vector<bool>` iterators are not random access iterators because their reference type is a special class, and not `bool &`. All standard libary operations taking iterators should treat this iterator as if it was a random access iterator, rather than a simple input iterator.

[ Resolution proposed in ballot comment ]

Either revise the iterator requirements to support proxy iterators (restoring functionality that was lost when the Concept facility was removed) or add an extra paragraph to the `vector<bool>` specification requiring the library to treat `vector<bool>` iterators as-if they were random access iterators, despite having the wrong reference type.

[ Rapperswil Review ]

The consensus at Rapperswil is that it is too late for full support for proxy iterators, but requiring the library to respect `vector<bool>` iterators as-if they were random access would be preferable to flagging this container as deliberately incompatible with standard library algorithms.

Alisdair to write the note, which may become normative Remark depending on the preferences of the project editor.

[ Post-Rapperswil Alisdair provides wording ]

Initial wording is supplied, deliberately using Note in preference to Remark although the author notes his preference for Remark. The issue of whether `iterator_traits<vector<bool>>::iterator_category` is permitted to report `random_access_iterator_tag` or must report `input_iterator_tag` is not addressed.

[ Old Proposed Resolution: ]

> Insert a new paragraph into 22.3.12 [vector.bool] between p4 and p5:

> > [Note All functions in the library that take a pair of iterators to denote a range shall treat `vector<bool>` iterators as-if they were random access iterators, even though the `reference` type is not a true reference.-- end note]

[ 2010-11 Batavia: ]

> Closed as NAD Future, because the current iterator categories cannot correctly describe `vector<bool>::iterator`. But saying that they are Random Access Iterators is also incorrect, because it is not too hard to create a corresponding test that fails. We should deal with the more general proxy iterator problem in the future, and see no benefit to take a partial workaround specific to `vector<bool>` now.

[2017-02 in Kona, LEWG recommends NAD]

D0022 Proxy Iterators for the Ranges Extensions - as much a fix as we’re going to get for vector<bool>.

[2017-06-02 Issues Telecon]

P0022 is exploring a resolution. We consider this to be fairly important issue

Move to Open, set priority to 3

Proposed resolution:

Rationale:

No consensus to make this change at this time.

### 1459(i). Overlapping evaluations are allowed

Section: 31.4 [atomics.order] Status: LEWG Submitter: Canada Opened: 2010-08-25 Last modified: 2016-01-28

Priority: Not Prioritized

View other active issues in [atomics.order].

View all other issues in [atomics.order].

View all issues with LEWG status.

Duplicate of: 1458

Discussion:

Addresses CA-21, GB-131

31.5 [atomics.lockfree] p.8 states:

> An atomic store shall only store a value that has been computed from constants and program input values by a finite sequence of program evaluations, such that each evaluation observes the values of variables as computed by the last prior assignment in the sequence.

... but 6.9.1 [intro.execution] p.13 states:

> If A is not sequenced before B and B is not sequenced before A, then A and B are unsequenced. [ Note: The execution of unsequenced evaluations can overlap. — end note ]

Overlapping executions can make it impossible to construct the sequence described in 31.5 [atomics.lockfree] p.8. We are not sure of the intention here and do not offer a suggestion for change, but note that 31.5 [atomics.lockfree] p.8 is the condition that prevents out-of-thin-air reads.

For an example, suppose we have a function invocation f(e1,e2). The evaluations of e1 and e2 can overlap. Suppose that the evaluation of e1 writes y and reads x whereas the evaluation of e2 reads y and writes x, with reads-from edges as below (all this is within a single thread).

     e1           e2
    Wrlx y--   --Wrlx x
          rf\ /rf
             X
            / \
    Rrlx x<-   ->Rrlx y

This seems like it should be allowed, but there seems to be no way to produce a sequence of evaluations with the property above.

In more detail, here the two evaluations, e1 and e2, are being executed as the arguments of a function and are consequently not sequenced-before each other. In practice we'd expect that they could overlap (as allowed by 6.9.1 [intro.execution] p.13), with the two writes taking effect before the two reads. However, if we have to construct a linear order of evaluations, as in 31.5 [atomics.lockfree] p.8, then the execution above is not permited. Is that really intended?

[ Resolution proposed by ballot comment ]

Please clarify.

[2011-03-09 Hans comments:]

I'm not proud of 31.4 [atomics.order] p9 (formerly p8), and I agree with the comments that this isn't entirely satisfactory. 31.4 [atomics.order] p9 was designed to preclude out-of-thin-air results for races among `memory_order_relaxed` atomics, in spite of the fact that Java experience has shown we don't really know how to do that adequately. In the long run, we probably want to revisit this.

However, in the short term, I'm still inclined to declare this NAD, for two separate reasons:

1. 6.9.1 [intro.execution] p15 states: "If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined." I think the examples presented here have undefined behavior as a result. It's not completely clear to me whether examples can be constructed that exhibit this problem, and don't have undefined behavior.

2. This comment seems to be using a different meaning of "evaluation" from what is used elsewhere in the standard. The sequence of evaluations here doesn't have to consist of full expression evaluations. They can be evaluations of operations like lvalue to rvalue conversion, or individual assignments. In particular, the reads and writes executed by `e1` and `e2` in the example could be treated as separate evaluations for purposes of producing the sequence. The definition of "sequenced before" in 6.9.1 [intro.execution] makes little sense if the term "evaluation" is restricted to any notion of complete expression. Perhaps we should add yet another note to clarify this? 31.4 [atomics.order] p10 probably leads to the wrong impression here.

   An alternative resolution would be to simply delete our flakey attempt at preventing out-of-thin-air reads, by removing 31.4 [atomics.order] p9-11, possibly adding a note that explains that we technically allow, but strongly discourage them. If we were starting this from scratch now, that would probably be my preference. But it seems like too drastic a resolution at this stage.

[2011-03-24 Madrid]

Moved to NAD Future

Proposed resolution:

### 1484(i). Need a way to join a thread with a timeout

Section: 32.4.3 [thread.thread.class] Status: LEWG Submitter: INCITS Opened: 2010-08-25 Last modified: 2017-03-01

Priority: Not Prioritized

View all issues with LEWG status.

Discussion:

Addresses US-183

There is no way to join a thread with a timeout.

[ Resolution proposed by ballot comment: ]

> Add `join_for` and `join_until`. Or decide one should never join a thread with a timeout since `pthread_join` doesn't have a timeout version.

[ 2010 Batavia ]

The concurrency working group deemed this an extension beyond the scope of C++0x.

Rationale:

The LWG does not wish to make a change at this time.

[2017-03-01, Kona]

SG1 recommends: Close as NAD

There has not been much demand for it, and it would usually be difficult to deal with `thread_local` destructor races. It can be approximated with a condition variable wait followed by an unconditional `join`. Adding it would create implementation issues on Posix. As always, this may be revisited if we have a paper exploring the issues in detail.

Proposed resolution:

### 1488(i). Improve interoperability between the C++0x and C1x threads APIs

Section: 32.5 [thread.mutex] Status: LEWG Submitter: INCITS Opened: 2010-08-25 Last modified: 2017-03-01

Priority: Not Prioritized

View all other issues in [thread.mutex].

View all issues with LEWG status.

Discussion:

Addresses US-185

Cooperate with WG14 to improve interoperability between the `C++0x` and `C1x` threads APIs. In particular, `C1x` mutexes should be conveniently usable with a `C++0x` `lock_guard`. Performance overheads for this combination should be considered.

[ Resolution proposed by ballot comment: ]

> Remove `C++0x` `timed_mutex` and `timed_recursive_mutex` if that facilitates development of more compatible APIs.

[ 2010 Batavia ]

The concurrency sub-group reviewed the options, and decided that closer harmony should wait until both standards are published.

Rationale:

The LWG does not wish to make any change at this time.

[2017-03-01, Kona]

SG1 recommends: Close as NAD

Papers about C compatibility are welcome, but there may be more pressing issues. C threads are not consistently available at this point, so there seems to be little demand to fix this particular problem.

Proposed resolution:

### 1493(i). Add `mutex`, `recursive_mutex`, `is_locked` function

Section: 32.5.4 [thread.mutex.requirements] Status: LEWG Submitter: INCITS Opened: 2010-08-25 Last modified: 2017-03-01

Priority: Not Prioritized

View other active issues in [thread.mutex.requirements].

View all other issues in [thread.mutex.requirements].

View all issues with LEWG status.

Discussion:

Addresses US-189

`mutex` and `recursive_mutex` should have an `is_locked()` member function. `is_locked` allows a user to test a lock without acquiring it and can be used to implement a lightweight `try_try_lock`.

[ Resolution proposed by ballot comment: ]

> Add a member function:

>     bool is_locked() const;

> to `std::mutex` and `std::recursive_mutex`. These functions return true if the current thread would not be able to obtain a mutex. These functions do not synchronize with anything (and, thus, can avoid a memory fence).

[ 2010 Batavia ]

The Concurrency subgroup reviewed this issue and deemed it to be an extension to be handled after publishing C++0x.

Rationale:

The LWG does not wish to make a change at this time.

[2017-03-01, Kona]

SG1 recommends: Close as NAD

Several participants voiced strong objections, based on either memory model issues or lock elision. No support. It is already possible to write a wrapper that explicitly tracks ownership for testing in the owning thread, which may have been part of the intent here.

Proposed resolution:

### 1521(i). Requirements on internal pointer representations in containers

Section: 22.2.1 [container.requirements.general] Status: Open Submitter: Mike Spertus Opened: 2010-10-16 Last modified: 2019-01-20

Priority: 3

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

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

View all issues with Open status.

Discussion:

Addresses US-104, US-141

The standard doesn't say that containers should use abstract pointer types internally. Both Howard and Pablo agree that this is the intent. Further, it is necessary for containers to be stored, for example, in shared memory with an interprocess allocator (the type of scenario that allocators are intended to support).

In spite of the (possible) agreement on intent, it is necessary to make this explicit:

An implementations may like to store the result of dereferencing the pointer (which is a raw reference) as an optimization, but that prevents the data structure from being put in shared memory, etc. In fact, a container could store raw references to the allocator, which would be a little weird but conforming as long as it has one by-value copy. Furthermore, pointers to locales, ctypes, etc. may be there, which also prevents the data structure from being put in shared memory, so we should make explicit that a container does not store raw pointers or references at all.

[ Pre-batavia ]

This issue is being opened as part of the response to NB comments US-104/141. See paper N3171 in the pre-Batavia mailing.

[2011-03-23 Madrid meeting]

Deferred

[ 2011 Batavia ]

This may be an issue, but it is not clear. We want to gain a few years experience with the C++11 allocator model to see if this is already implied by the existing specification.

[LEWG Kona 2017]

Status to Open: Acknowledged, need wording: (N4618 numbering) 23.2.1 container.requirements.general p8 first sentence. Replace non-normative note with requirement.

See discussion on LEWG Wiki

[2019-01-20 Reflector prioritization]

Set Priority to 3

Proposed resolution:

Add to the end of 22.2.1 [container.requirements.general] p. 8:

> [..] In all container types defined in this Clause, the member `get_allocator()` returns a copy of the allocator used to construct the container or, if that allocator has been replaced, a copy of the most recent replacement. The container may not store internal objects whose types are of the form `T *` or `T &` except insofar as they are part of the item type or members.

### 2035(i). Output iterator requirements are broken

Section: 23.3.5.4 [output.iterators] Status: Open Submitter: Daniel Krügler Opened: 2011-02-27 Last modified: 2016-01-28

Priority: 3

View other active issues in [output.iterators].

View all other issues in [output.iterators].

View all issues with Open status.

Discussion:

During the Pittsburgh meeting the proposal N3066 became accepted because it fixed several severe issues related to the iterator specification. But the current working draft (N3225) does not reflect all these changes. Since I'm unaware whether every correction can be done editorial, this issue is submitted to take care of that. To give one example: All expressions of Table 108 — "Output iterator requirements" have a post-condition that the iterator is incrementable. This is impossible, because it would exclude any finite sequence that is accessed by an output iterator, such as a pointer to a C array. The N3066 wording changes did not have these effects.

[2011-03-01: Daniel comments:]

This issue has some overlap with the issue 2038 and I would prefer if we could solve both at one location. I suggest the following approach:

1. The terms `dereferencable` and `incrementable` could be defined in a more general way not restricted to iterators (similar to the concepts `HasDereference` and `HasPreincrement` from working draft N2914). But on the other hand, all current usages of `dereferencable` and `incrementable` are involved with types that satisfy iterator requirements. Thus, I believe that it is sufficient for C++0x to add corresponding definitions to 23.3.1 [iterator.requirements.general] and to let all previous usages of these terms refer to this sub-clause. Since the same problem occurs with the past-the-end iterator, this proposal suggest providing similar references to usages that precede its definition as well.

2. We also need to ensure that all iterator expressions get either an operational semantics in terms of others or we need to add missing pre- and post-conditions. E.g. we have the following ones without semantics:

   >     *r++ = o // output iterator
   >     *r--     // bidirectional iterator

   According to the SGI specification these correspond to

   >     { *r = o; ++r; }                         // output iterator
   >     { reference tmp = *r; --r; return tmp; } // bidirectional iterator

   respectively. Please note especially the latter expression for bidirectional iterator. It fixes a problem that we have for forward iterator as well: Both these iterator categories provide stronger guarantees than input iterator, because the result of the dereference operation is `reference`, and not only convertible to the value type (The exact form from the SGI documentation does not correctly refer to `reference`).

[2011-03-14: Daniel comments and updates the suggested wording]

In addition to the before mentioned necessary changes there is another one need, which became obvious due to issue 2042: `forward_list<>::before_begin()` returns an iterator value which is not dereferencable, but obviously the intention is that it should be incrementable. This leads to the conclusion that imposing dereferencable as a requirement for the expressions `++r` is wrong: We only need the iterator to be incrementable. A similar conclusion applies to the expression `--r` of bidirectional iterators.

[ 2011 Bloomington ]

Consensus this is the correct direction, but there are (potentially) missing incrementable preconditions on some table rows, and the Remarks on when an output iterator becomes dereferencable are probably better handled outside the table, in a manner similar to the way we word for input iterators.

There was some concern about redundant pre-conditions when the operational semantic is defined in terms of operations that have preconditions, and a similar level of concern over dropping such redundancies vs. applying a consistent level of redundant specification in all the iterator tables. Wording clean-up in either direction would be welcome.

[2011-08-18: Daniel adapts the proposed resolution to honor the Bloomington request]

There is only a small number of further changes suggested to get rid of superfluous requirements and essentially non-normative assertions. Operations should not have extra pre-conditions, if defined by "in-terms-of" semantics, see e.g. `a != b` or `a->m` for Table 107. Further, some remarks, that do not impose anything or say nothing new have been removed, because I could not find anything helpful they provide. E.g. consider the remarks for Table 108 for the operations dereference-assignment and preincrement: They don't provide additional information say nothing surprising. With the new pre-conditions and post-conditions it is implied what the remarks intend to say.

[ 2011-11-03: Some observations from Alexander Stepanov via c++std-lib-31405 ]

The following sentence is dropped from the standard section on OutputIterators:

"In particular, the following two conditions should hold: first, any iterator value should be assigned through before it is incremented (this is, for an output iterator `i, i++; i++;` is not a valid code sequence); second, any value of an output iterator may have at most one active copy at any given time (for example, `i = j; *++i = a; *j = b;` is not a valid code sequence)."

[ 2011-11-04: Daniel comments and improves the wording ]

In regard to the first part of the comment, the intention of the newly proposed wording was to make clear that for the expression

>     *r = o

we have the precondition dereferenceable and the post-condition incrementable. And for the expression

>     ++r

we have the precondition incrementable and the post-condition dereferenceable or past-the-end. This should not allow for a sequence like `i++; i++;` but I agree that it doesn't exactly say that.

In regard to the second point: To make this point clearer, I suggest to add a similar additional wording as we already have for input iterator to the "Assertion/note" column of the expression `++r`:

"Post: any copies of the previous value of `r` are no longer required to be dereferenceable or incrementable."

The proposed has been updated to honor the observations of Alexander Stepanov.

[2015-02 Cologne]

The matter is complicated, Daniel volunteers to write a paper.

Proposed resolution:

1. Add a reference to 23.3.1 [iterator.requirements.general] to the following parts of the library preceding Clause 24 Iterators library: (I stopped from 22.2.7 [unord.req] on, because the remaining references are the concrete containers)

   1. 16.4.4.3 [swappable.requirements] p5:

      > -5- A type `X` satisfying any of the iterator requirements (24.2) is `ValueSwappable` if, for any dereferenceable (23.3.1 [iterator.requirements.general]) object `x` of type `X`, `*x` is swappable.

   2. 16.4.4.6 [allocator.requirements], Table 27 — "Descriptive variable definitions", row with the expression `c`:

      > a dereferenceable (23.3.1 [iterator.requirements.general]) pointer of type `C*`

   3. 20.10.3.3 [pointer.traits.functions]:

      > Returns: The first template function returns a dereferenceable (23.3.1 [iterator.requirements.general]) pointer to `r` obtained by calling `Ptr::pointer_to(r)`; […]

   4. 21.3.3.4 [string.iterators] p. 2:

      > Returns: An iterator which is the past-the-end value (23.3.1 [iterator.requirements.general]).

   5. 28.4.6.2.3 [locale.time.get.virtuals] p. 11:

      >     iter_type do_get(iter_type s, iter_type end, ios_base& f,
      >       ios_base::iostate& err, tm *t, char format, char modifier) const;

      > > Requires: `t` shall be dereferenceable (23.3.1 [iterator.requirements.general]).

   6. 22.2.1 [container.requirements.general] p. 6:

      > […] `end()` returns an iterator which is the past-the-end (23.3.1 [iterator.requirements.general]) value for the container. […]

   7. 22.2.3 [sequence.reqmts] p. 3:

      > […] `q` denotes a valid dereferenceable (23.3.1 [iterator.requirements.general]) const iterator to `a`, […]

   8. 22.2.6 [associative.reqmts] p. 8 (I omit intentionally one further reference in the same sub-clause):

      > […] `q` denotes a valid dereferenceable (23.3.1 [iterator.requirements.general]) const iterator to `a`, […]

   9. 22.2.7 [unord.req] p. 10 (I omit intentionally one further reference in the same sub-clause):

      > […] `q` and `q1` are valid dereferenceable (23.3.1 [iterator.requirements.general]) const iterators to `a`, […]

2. Edit 23.3.1 [iterator.requirements.general] p. 5 as indicated (The intent is to properly define incrementable and to ensure some further library guarantee related to past-the-end iterator values):

   > -5- Just as a regular pointer to an array guarantees that there is a pointer value pointing past the last element of the array, so for any iterator type there is an iterator value that points past the last element of a corresponding sequence. These values are called past-the-end values. Values of an iterator `i` for which the expression `*i` is defined are called dereferenceable. Values of an iterator `i` for which the expression `++i` is defined are called incrementable. The library never assumes that past-the-end values are dereferenceable or incrementable. Iterators can also have singular values that are not associated with any sequence. […]

3. Modify the column contents of Table 106 — "Iterator requirements", 23.3.5.2 [iterator.iterators], as indicated:

   > Table 106 — Iterator requirements
   > Expression | Return type | Operational semantics | Assertion/note pre-/post-condition
   > --- | --- | --- | ---
   > `*r` | `reference` | `` | pre: `r` is dereferenceable.
   > `++r` | `X&` | `` | pre: `r` is incrementable.

4. Modify the column contents of Table 107 — "Input iterator requirements", 23.3.5.3 [input.iterators], as indicated [Rationale: The wording changes attempt to define a minimal "independent" set of operations, namely `*a` and `++r`, and to specify the semantics of the remaining ones. This approach seems to be in agreement with the original SGI specification — end rationale]:

   > Table 107 — Input iterator requirements (in addition to Iterator)
   > Expression | Return type | Operational semantics | Assertion/note pre-/post-condition
   > --- | --- | --- | ---
   > `a != b` | contextually convertible to `bool` | `!(a == b)` | pre: `(a, b)` is in the domain of `==`.
   > `*a` | convertible to `T` | `` | pre: `a` is dereferenceable. The expression `(void)*a, *a` is equivalent to `*a`. If `a == b` and `(a,b)` is in the domain of `==` then `*a` is equivalent to `*b`.
   > `a->m` | `` | `(*a).m` | pre: `a` is dereferenceable.
   > `++r` | `X&` | `` | pre: `r` is dereferenceable incrementable. post: `r` is dereferenceable or `r` is past-the-end. post: any copies of the previous value of `r` are no longer required either to be dereferenceable, incrementable, or to be in the domain of `==`.
   > `(void)r++` | `` | `(void)++r` | equivalent to `(void)++r`
   > `*r++` | convertible to `T` | `{ T tmp = *r; ++r; return tmp; }` | ``

5. Modify the column contents of Table 108 — "Output iterator requirements", 23.3.5.4 [output.iterators], as indicated [Rationale: The wording changes attempt to define a minimal "independent" set of operations, namely `*r = o` and `++r`, and to specify the semantics of the remaining ones. This approach seems to be in agreement with the original SGI specification — end rationale]:

   > Table 108 — Output iterator requirements (in addition to Iterator)
   > Expression | Return type | Operational semantics | Assertion/note pre-/post-condition
   > --- | --- | --- | ---
   > `*r = o` | result is not used | `` | pre: `r` is dereferenceable. Remark: After this operation `r` is not required to be dereferenceable and any copies of the previous value of `r` are no longer required to be dereferenceable or incrementable. post: `r` is incrementable.
   > `++r` | `X&` | `` | pre: `r` is incrementable. `&r == &++r`. Remark: After this operation `r` is not required to be dereferenceable. Remark: After this operation `r` is not required to be incrementable and any copies of the previous value of `r` are no longer required to be dereferenceable or incrementable. post: `r` is dereferenceable or `r` is past-the-end incrementable.
   > `r++` | convertible to `const X&` | `{ X tmp = r; ++r; return tmp; }` | Remark: After this operation `r` is not required to be dereferenceable. post: `r` is incrementable.
   > `*r++ = o` | result is not used | `{ *r = o; ++r; }` | Remark: After this operation `r` is not required to be dereferenceable. post: `r` is incrementable.

6. Modify the column contents of Table 109 — "Forward iterator requirements", 23.3.5.5 [forward.iterators], as indicated [Rationale: Since the return type of the expression `*r++` is now guaranteed to be type `reference`, the implied operational semantics from input iterator based on value copies is wrong — end rationale]

   > Table 109 — Forward iterator requirements (in addition to input iterator)
   > Expression | Return type | Operational semantics | Assertion/note pre-/post-condition
   > --- | --- | --- | ---
   > `r++` | convertible to `const X&` | `{ X tmp = r; ++r; return tmp; }` | ``
   > `*r++` | reference | `{ reference tmp = *r; ++r; return tmp; }` | ``

7. Modify the column contents of Table 110 — "Bidirectional iterator requirements", 23.3.5.6 [bidirectional.iterators], as indicated:

   > Table 110 — Bidirectional iterator requirements (in addition to forward iterator)
   > Expression | Return type | Operational semantics | Assertion/note pre-/post-condition
   > --- | --- | --- | ---
   > `--r` | `X&` | `` | pre: there exists `s` such that `r == ++s`. post: `r` is dereferenceable incrementable. `--(++r) == r`. `--r == --s` implies `r == s`. `&r == &--r`.
   > `r--` | convertible to `const X&` | `{ X tmp = r; --r; return tmp; }` | ``
   > `*r--` | reference | `{ reference tmp = *r; --r; return tmp; }` | ``

### 2038(i). Missing definition for `incrementable` iterator

Section: 23.3.5.4 [output.iterators] Status: Open Submitter: Pete Becker Opened: 2011-02-27 Last modified: 2016-01-28

Priority: 3

View other active issues in [output.iterators].

View all other issues in [output.iterators].

View all issues with Open status.

Discussion:

In comp.lang.c++, Vicente Botet raises the following questions:

> "In "24.2.4 Output iterators" there are 3 uses of incrementable. I've not found the definition. Could some one point me where it is defined?

> Something similar occurs with dereferenceable. While the definition is given in "24.2.1 In general" it is used several times before.

> Shouldn't these definitions be moved to some previous section?"

He's right: both terms are used without being properly defined.

There is no definition of "incrementable".

While there is a definition of "dereferenceable", it is, in fact, a definition of "dereferenceable iterator". "dereferenceable" is used throughout Clause 23 (Containers) before its definition in Clause 24. In almost all cases it's referring to iterators, but in 16.4.4.3 [swappable.requirements] there is a mention of "dereferenceable object"; in 16.4.4.6 [allocator.requirements] the table of Descriptive variable definitions refers to a "dereferenceable pointer"; 20.10.3.3 [pointer.traits.functions] refers to a "dereferenceable pointer"; in 28.4.6.2.3 [locale.time.get.virtuals]/11 (`do_get`) there is a requirement that a pointer "shall be dereferenceable". In those specific cases it is not defined.

[2011-03-02: Daniel comments:]

I believe that the currently proposed resolution of issue 2035 solves this issue as well.

[ 2011 Bloomington ]

Agree with Daniel, this will be handled by the resolution of 2035.

Proposed resolution:

### 2077(i). Further incomplete constraints for type traits

Section: 20.15.5.4 [meta.unary.prop] Status: Open Submitter: Daniel Krügler Opened: 2011-08-20 Last modified: 2016-01-28

Priority: 3

View other active issues in [meta.unary.prop].

View all other issues in [meta.unary.prop].

View all issues with Open status.

Discussion:

The currently agreed on proposed wording for 2015 using `remove_all_extents<T>::type` instead of the "an array of unknown bound" terminology in the precondition should be extended to some further entries especially in Table 49, notably the `is_*constructible`, `is_*assignable`, and `is_*destructible` entries. To prevent ODR violations, incomplete element types of arrays must be excluded for value-initialization and destruction for example. Construction and assignment has to be honored, when we have array-to-pointer conversions or pointer conversions of incomplete pointees in effect.

[2012, Kona]

The issue is that in three type traits, we are accidentally saying that in certain circumstances the type must give a specified answer when given an incomplete type. (Specifically: an array of unknown bound of incomplete type.) The issue asserts that there's an ODR violation, since the trait returns false in that case but might return a different version when the trait is completed.

Howard argues: no, there is no risk of an ODR violation. `is_constructible<A[]>` must return `false` regardless of whether `A` is complete, so there's no reason to forbid an array of unknown bound of incomplete types. Same argument applies to `is_assignable`. General agreement with Howard's reasoning.

There may be a real issue for `is_destructible`. None of us are sure what `is_destructible` is supposed to mean for an array of unknown bound (regardless of whether its type is complete), and the standard doesn't make it clear. The middle column doesn't say what it's supposed to do for incomplete types.

In at least one implementation, `is_destructible<A[]>` does return `true` if `A` is complete, which would result in ODR violation unless we forbid it for incomplete types.

Move to open. We believe there is no issue for `is_constructible` or `is_assignable`, but that there is a real issue for `is_destructible`.

Proposed resolution:

### 2088(i). `std::terminate` problem

Section: 17.9.5 [exception.terminate] Status: Open Submitter: Daniel Krügler Opened: 2011-09-25 Last modified: 2016-01-28

Priority: 3

View all issues with Open status.

Discussion:

Andrzej Krzemienski reported the following on comp.std.c++:

> In N3290, which is to become the official standard, in 17.9.5.4 [terminate], paragraph 1 reads

> > Remarks: Called by the implementation when exception handling must be abandoned for any of several reasons (15.5.1), in effect immediately after evaluating the throw-expression (18.8.3.1). May also be called directly by the program.

> It is not clear what is "in effect". It was clear in previous drafts where paragraphs 1 and 2 read:

> > Called by the implementation when exception handling must be abandoned for any of several reasons (15.5.1). May also be called directly by the program.

> > Effects: Calls the `terminate_handler` function in effect immediately after evaluating the throw-expression (18.8.3.1), if called by the implementation, or calls the current `terminate_handler` function, if called by the program.

> It was changed by N3189. The same applies to function unexpected (D. 11.4, paragraph 1).

> Assuming the previous wording is still intended, the wording can be read "unless `std::terminate` is called by the program, we will use the handler that was in effect immediately after evaluating the throw-expression".

> This assumes that there is some throw-expression connected to every situation that triggers the call to `std::terminate`. But this is not the case:
> - In case `std::thread` is assigned to or destroyed while being joinable there is no throw-expression involved.
> - In case `std::unexpected` is called by the program, `std::terminate` is triggered by the implementation - no throw-expression involved.
> - In case a destructor throws during stack unwinding we have two throw-expressions involved.

> Which one is referred to?

> In case `std::nested_exception::rethrow_nested` is called for an object that has captured no exception, there is no throw-expression involved directly (and may no throw be involved even indirectly).

> Next, 17.9.5.1 [terminate.handler], paragraph 2 says

> > Required behavior: A `terminate_handler` shall terminate execution of the program without returning to the caller.

> This seems to allow that the function may exit by throwing an exception (because word "return" implies a normal return).

> One could argue that words "terminate execution of the program" are sufficient, but then why "without returning to the caller" would be mentioned. In case such handler throws, noexcept specification in function `std::terminate` is violated, and `std::terminate` would be called recursively - should `std::abort` not be called in case of recursive `std::terminate` call? On the other hand some controlled recursion could be useful, like in the following technique.

The here mentioned wording changes by N3189 in regard to 17.9.5.4 [terminate] p1 were done for a better separation of effects (Effects element) and additional normative wording explanations (Remarks element), there was no meaning change intended. Further, there was already a defect existing in the previous wording, which was not updated when further situations where defined, when `std::terminate` where supposed to be called by the implementation.

The part

"in effect immediately after evaluating the throw-expression"

should be removed and the quoted reference to 17.9.5.1 [terminate.handler] need to be part of the effects element where it refers to the current `terminate_handler` function, so should be moved just after

"Effects: Calls the current `terminate_handler` function."

It seems ok to allow a termination handler to exit via an exception, but the suggested idiom should better be replaced by a more simpler one based on evaluating the current exception pointer in the terminate handler, e.g.

>     void our_terminate (void) {
>       std::exception_ptr p = std::current_exception();
>       if (p) {
>         ... // OK to rethrow and to determine it's nature
>       } else {
>         ... // Do something else
>       }
>     }

[2011-12-09: Daniel comments]

A related issue is 2111.

[2012, Kona]

Move to Open.

There is an interaction with Core issues in this area that Jens is already supplying wording for. Review this issue again once Jens wording is available.

Alisdair to review clause 15.5 (per Jens suggestion) and recommend any changes, then integrate Jens wording into this issue.

Proposed resolution:

### 2095(i). `promise` and `packaged_task` missing constructors needed for uses-allocator construction

Section: 32.9.6 [futures.promise], 32.9.10 [futures.task] Status: LEWG Submitter: Jonathan Wakely Opened: 2011-11-01 Last modified: 2019-06-03

Priority: 4

View other active issues in [futures.promise].

View all other issues in [futures.promise].

View all issues with LEWG status.

Discussion:

This example is ill-formed according to C++11 because `uses_allocator<promise<R>, A>::value` is true, but `is_constructible<promise<R>, A, promise<R>&&>::value` is false. Similarly for `packaged_task`.

>     #include <future>
>     #include <memory>
>     #include <tuple>

>     using namespace std;

>     typedef packaged_task<void()> task;
>     typedef promise<void> prom;
>     allocator<task> a;

>     tuple<task, prom> t1{ allocator_arg, a };
>     tuple<task, prom> t2{ allocator_arg, a, task{}, prom{} };

[2012, Portland]

This is an allocator issue, and should be dealt with directly by LWG.

[2013-03-06]

Jonathan suggests to make the new constructors non-explicit and makes some representational improvements.

[2013-09 Chicago]

Move to deferred.

This issue has much in common with similar problems with `std::function` that are being addressed by the polymorphic allocators proposal currently under evaluation in LEWG. Defer further discussion on this topic until the final outcome of that paper and its proposed resolution is known.

[2014-02-20 Re-open Deferred issues as Priority 4]

[2016-08 Chicago]

Fri PM: Send to LEWG - and this also applies to `function` in LFTS.

[2019-06-03 Jonathan Wakely provides updated wording]

Jonathan updates wording post-2976 and observes that this resolution conflicts with 3003.

Previous resolution [SUPERSEDED]:

> [This wording is relative to the FDIS.]

> 1. Add to 32.9.6 [futures.promise], class template `promise` synopsis, as indicated:

>    >     namespace std {
>    >       template <class R>
>    >       class promise {
>    >       public:
>    >         promise();
>    >         template <class Allocator>
>    >         promise(allocator_arg_t, const Allocator& a);
>    >         template <class Allocator>
>    >         promise(allocator_arg_t, const Allocator& a, promise&& rhs) noexcept;
>    >         promise(promise&& rhs) noexcept;
>    >         promise(const promise& rhs) = delete;
>    >         ~promise();
>    >         […]
>    >       };
>    >       […]
>    >     }

> 2. Change 32.9.6 [futures.promise] as indicated:

>    >     promise(promise&& rhs) noexcept;
>    >     template <class Allocator>
>    >     promise(allocator_arg_t, const Allocator& a, promise&& rhs) noexcept;

>    > > -5- Effects: constructs a new `promise` object and transfers ownership of the shared state of `rhs` (if any) to the newly-constructed object.

>    > > -6- Postcondition: `rhs` has no shared state.

>    > > -?- [Note: `a` is not used — end note]

> 3. Add to 32.9.10 [futures.task], class template `packaged_task` synopsis, as indicated:

>    >     namespace std {
>    >       template<class> class packaged_task; // undefined

>    >       template<class R, class... ArgTypes>
>    >       class packaged_task<R(ArgTypes...)> {
>    >       public:
>    >         // construction and destruction
>    >         packaged_task() noexcept;
>    >         template <class Allocator>
>    >           packaged_task(allocator_arg_t, const Allocator& a) noexcept;
>    >         template <class F>
>    >           explicit packaged_task(F&& f);
>    >         template <class F, class Allocator>
>    >           explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f);
>    >         ~packaged_task();

>    >         // no copy
>    >         packaged_task(const packaged_task&) = delete;
>    >         template<class Allocator>
>    >           packaged_task(allocator_arg_t, const Allocator& a, const packaged_task&) = delete;
>    >         packaged_task& operator=(const packaged_task&) = delete;

>    >         // move support
>    >         packaged_task(packaged_task&& rhs) noexcept;
>    >         template <class Allocator>
>    >           packaged_task(allocator_arg_t, const Allocator& a, packaged_task&& rhs) noexcept;
>    >         packaged_task& operator=(packaged_task&& rhs) noexcept;
>    >         void swap(packaged_task& other) noexcept;
>    >         […]
>    >       };
>    >       […]
>    >     }

> 4. Change 32.9.10.2 [futures.task.members] as indicated:

>    >     packaged_task() noexcept;
>    >     template <class Allocator>
>    >       packaged_task(allocator_arg_t, const Allocator& a) noexcept;

>    > > -1- Effects: constructs a `packaged_task` object with no shared state and no stored task.

>    > > -?- [Note: `a` is not used — end note]

>    […]

>    >     packaged_task(packaged_task&& rhs) noexcept;
>    >     template <class Allocator>
>    >       packaged_task(allocator_arg_t, const Allocator& a, packaged_task&& rhs) noexcept;

>    > > -5- Effects: constructs a new `packaged_task` object and transfers ownership of `rhs`'s shared state to `*this`, leaving `rhs` with no shared state. Moves the stored task from `rhs` to `*this`.

>    > > -6- Postcondition: `rhs` has no shared state.

>    > > -?- [Note: `a` is not used — end note]

Proposed resolution:

[This wording is relative to N4810.]

1. Add to 32.9.6 [futures.promise], class template `promise` synopsis, as indicated:

   >     namespace std {
   >       template <class R>
   >       class promise {
   >       public:
   >         promise();
   >         template <class Allocator>
   >           promise(allocator_arg_t, const Allocator& a);
   >         template <class Allocator>
   >           promise(allocator_arg_t, const Allocator& a, promise&& rhs) noexcept;
   >         promise(promise&& rhs) noexcept;
   >         promise(const promise& rhs) = delete;
   >         ~promise();
   >         […]
   >       };
   >       […]
   >     }

2. Change 32.9.6 [futures.promise] as indicated:

   >     promise(promise&& rhs) noexcept;
   >     template <class Allocator>
   >       promise(allocator_arg_t, const Allocator& a, promise&& rhs) noexcept;

   > > -5- Effects: constructs a new `promise` object and transfers ownership of the shared state of `rhs` (if any) to the newly-constructed object.

   > > -6- Postcondition: `rhs` has no shared state.

   > > -?- [Note: `a` is not used — end note]

### 2114(i). Incorrect "contextually convertible to `bool`" requirements

Section: 16.4.4.4 [nullablepointer.requirements], 23.3.5.3 [input.iterators], 23.3.5.7 [random.access.iterators], 25.1 [algorithms.general], 25.8 [alg.sorting], 32.2.1 [thread.req.paramname] Status: Open Submitter: Daniel Krügler Opened: 2011-12-09 Last modified: 2021-06-25

Priority: 3

View all issues with Open status.

Discussion:

As of 16.4.4.2 [utility.arg.requirements] Table 17/18, the return types of the expressions

>     a == b

or

>     a < b

for types satisfying the `EqualityComparable` or `LessThanComparable` types, respectively, are required to be "convertible to `bool`" which corresponds to a copy-initialization context. But several newer parts of the library that refer to such contexts have lowered the requirements taking advantage of the new terminology of "contextually convertible to `bool`" instead, which corresponds to a direct-initialization context (In addition to "normal" direct-initialization constructions, operands of logical operations as well as `if` or `switch` conditions also belong to this special context).

One example for these new requirements are input iterators which satisfy `EqualityComparable` but also specify that the expression

>     a != b

shall be just "contextually convertible to `bool`". The same discrepancy exists for requirement set `NullablePointer` in regard to several equality-related expressions.

For random access iterators we have

> `a < b` contextually convertible to `bool`

as well as for all derived comparison functions, so strictly speaking we could have a random access iterator that does not satisfy the `LessThanComparable` requirements, which looks like an artifact to me.

Even if we keep with the existing requirements based on `LessThanComparable` or `EqualityComparable` we still would have the problem that some current specifications are actually based on the assumption of implicit convertibility instead of "explicit convertibility", e.g. 20.11.1.6 [unique.ptr.special] p3:

>     template <class T1, class D1, class T2, class D2>
>     bool operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);

> > -3- Returns: `x.get() != y.get()`.

Similar examples exist in 20.11.1.3.3 [unique.ptr.single.dtor] p2, 20.11.1.3.4 [unique.ptr.single.asgn] p9, 20.11.1.3.5 [unique.ptr.single.observers] p1+3+8, etc.

In all these places the expressions involving comparison functions (but not those of the conversion of a `NullablePointer` to `bool`!) assume to be "convertible to `bool`". I think this is a very natural assumption and all delegations of the comparison functions of some type `X` to some other API type `Y` in third-party code does so assuming that copy-initialization semantics will just work.

The actual reason for using the newer terminology can be rooted back to LWG 556. My hypotheses is that the resolution of that issue also needs a slight correction. Why so?

The reason for opening that issue were worries based on the previous "convertible to `bool`" wording. An expressions like "`!pred(a, b)`" might not be well-formed in those situations, because `operator!` might not be accessible or might have an unusual semantics (and similarly for other logical operations). This can indeed happen with unusual proxy return types, so the idea was that the evaluation of `Predicate`, `BinaryPredicate` (25.1 [algorithms.general] p8+9), and `Compare` (25.8 [alg.sorting] p2) should be defined based on contextual conversion to `bool`. Unfortunately this alone is not sufficient: In addition, I think, we also want the predicates to be (implicitly) convertible to `bool`! Without this wording, several conditions are plain wrong, e.g. 25.6.5 [alg.find] p2, which talks about "`pred(*i) != false`" (`find_if`) and "`pred(*i) == false`" (`find_if_not`). These expressions are not within a boolean context!

While we could simply fix all these places by proper wording to be considered in a "contextual conversion to `bool`", I think that this is not the correct solution: Many third-party libraries already refer to the previous C++03 `Predicate` definition — it actually predates C++98 and is as old as the SGI specification. It seems to be a high price to pay to switch to direct initialization here instead of fixing a completely different specification problem.

A final observation is that we have another definition for a `Predicate` in 32.2.1 [thread.req.paramname] p2:

> If a parameter is `Predicate`, `operator()` applied to the actual template argument shall return a value that is convertible to `bool`.

The problem here is not that we have two different definitions of `Predicate` in the standard — this is confusing, but this fact alone is not a defect. The first (minor) problem is that this definition does not properly apply to function objects that are function pointers, because `operator()` is not defined in a strict sense. But the actually worse second problem is that this wording has the very `same` problem that has originally lead to LWG 556! We only need to look at 32.6.4 [thread.condition.condvar] p15 to recognice this:

>     while (!pred())
>       wait(lock);

The negation expression here looks very familiar to the example provided in LWG 556 and is sensitive to the same "unusual proxy" problem. Changing the 32.2.1 [thread.req.paramname] wording to a corresponding "contextual conversion to `bool`" wouldn't work either, because existing specifications rely on "convertible to `bool`", e.g. 32.6.4 [thread.condition.condvar] p32+33+42 or 32.6.5 [thread.condition.condvarany] p25+26+32+33.

To summarize: I believe that LWG 556 was not completely resolved. A pessimistic interpretation is, that even with the current wording based on "contextually convertible to `bool`" the actual problem of that issue has not been fixed. What actually needs to be required here is some normative wording that basically expresses something along the lines of:

> The semantics of any contextual conversion to `bool` shall be equivalent to the semantics of any implicit conversion to `bool`.

This is still not complete without having concepts, but it seems to be a better approximation. Another way of solving this issue would be to define a minimum requirements table with equivalent semantics. The proposed wording is a bit simpler but attempts to express the same thing.

[2012, Kona]

Agree with Daniel that we potentially broke some C++03 user code, accept the changes striking "contextually" from tables. Stefan to provide revised wording for section 25, and figure out changes to section 30.

Move to open, and then to Review when updated wording from Stefan is available.

[2012-10-12, STL comments]

1. The current proposed resolution still isn't completely satisfying. It would certainly be possible for the Standard to require these various expressions to be implicitly and contextually convertible to `bool`, but that would have a subtle consequence (which, I will argue, is undesirable - regardless of the fact that it dates all the way back to C++98/03). It would allow users to provide really wacky types to the Standard Library, with one of two effects:

   1. Standard Library implementations would have to go to great lengths to respect such wacky types, essentially using `static_cast<bool>` when invoking any predicates or comparators.

   2. Otherwise, such wacky types would be de facto nonportable, because they would make Standard Library implementations explode.

   Effect B is the status quo we're living with today. What Standard Library implementations want to do with `pred(args)` goes beyond "`if (pred(args))`" (C++03), contextually converting `pred(args)` to `bool` (C++11), or implicitly and contextually converting `pred(args)` to `bool` (the current proposed resolution). Implementations want to say things like:

   >     if (pred(args))
   >     if (!pred(args))
   >     if (cond && pred(args))
   >     if (cond && !pred(args))

   These are real examples taken from Dinkumware's implementation. There are others that would be realistic ("`pred(args) && cond`", "`cond || pred(args)`", etc.)

   Although negation was mentioned in this issue's Discussion section, and in LWG 556's, the current proposed resolution doesn't fix this problem. Requiring `pred(args)` to be implicitly and contextually convertible to `bool` doesn't prevent `operator!()` from being overloaded and returning `std::string` (as a wacky example). More ominously, it doesn't prevent `operator&&()` and `operator||()` from being overloaded and destroying short-circuiting.

2. I would like LWG input before working on Standardese for a new proposed resolution. Here's an outline of what I'd like to do:

   1. Introduce a new "concept" in 16.4.4 [utility.requirements], which I would call `BooleanTestable` in the absence of better ideas.

   2. Centralize things and reduce verbosity by having everything simply refer to `BooleanTestable` when necessary. I believe that the tables could say "Return type: `BooleanTestable`", while Predicate/BinaryPredicate/Compare would need the incantation "shall satisfy the requirements of BooleanTestable".

   3. Resolve the tug-of-war between users (who occasionally want to do weird things) and implementers (who don't want to have to contort their code) by requiring that:

      1. Given a `BooleanTestable x`, `x` is both implicitly and contextually convertible to `bool`.

      2. Given a `BooleanTestable x`, `!x` is `BooleanTestable`. (This is intentionally "recursive".)

      3. Given a `BooleanTestable x`, `bool t = x, t2(x), f = !x;` has the postcondition `t == t2 && t != f`.

      4. Given a `BooleanTestable x` and a `BooleanTestable y` of possibly different types, "`x && y`" and "`x || y`" invoke the built-in `operator&&()` and `operator||()`, triggering short-circuiting.

      5. `bool` is `BooleanTestable`.

   I believe that this simultaneously gives users great latitude to use types other than `bool`, while allowing implementers to write reasonable code in order to get their jobs done. (If I'm forgetting anything that implementers would want to say, please let me know.)

3. About requirement (I): As Daniel patiently explained to me, we need to talk about both implicit conversions and contextual conversions, because it's possible for a devious type to have both "`explicit operator bool()`" and "`operator int()`", which might behave differently (or be deleted, etc.).

4. About requirement (IV): This is kind of tricky. What we'd like to say is, "`BooleanTestable` can't ever trigger an overloaded logical operator". However, given a perfectly reasonable type `Nice` - perhaps even `bool` itself! - other code (perhaps a third-party library) could overload `operator&&(Nice, Evil)`. Therefore, I believe that the requirement should be "no first use" - the Standard Library will ask for various `BooleanTestable` types from users (for example, the result of "`first != last`" and the result of "`pred(args)`"), and as long as they don't trigger overloaded logical operators with each other, everything is awesome.

5. About requirement (V): This is possibly redundant, but it's trivial to specify, makes it easier for users to understand what they need to do ("oh, I can always achieve this with `bool`"), and provides a "base case" for requirement (IV) that may or may not be necessary. Since `bool` is `BooleanTestable`, overloading `operator&&(bool, Other)` (etc.) clearly makes the `Other` type non-`BooleanTestable`.

Previous resolution from Daniel [SUPERSEDED]:

> This wording is relative to the FDIS.

> 1. Change Table 25 — "`NullablePointer` requirements" in 16.4.4.4 [nullablepointer.requirements] as indicated:

>    Table 25 — `NullablePointer` requirements
>    Expression | Return type | Operational semantics
>    --- | --- | ---
>    `[…]`
>    `a != b` | contextually convertible to `bool` | `!(a == b)`
>    `a == np np == a` | contextually convertible to `bool` | `a == P()`
>    `a != np np != a` | contextually convertible to `bool` | `!(a == np)`

> 2. Change Table 107 — "Input iterator requirements" in 23.3.5.3 [input.iterators] as indicated:

>    Table 107 — Input iterator requirements (in addition to Iterator)
>    Expression | Return type | Operational semantics | Assertion/note pre-/post-condition
>    --- | --- | --- | ---
>    `a != b` | contextually convertible to `bool` | `!(a == b)` | pre: `(a, b)` is in the domain of `==`.
>    `[…]`

> 3. Change Table 111 — "Random access iterator requirements" in 23.3.5.7 [random.access.iterators] as indicated:

>    Table 111 — Random access iterator requirements (in addition to bidirectional iterator)
>    Expression | Return type | Operational semantics | Assertion/note pre-/post-condition
>    --- | --- | --- | ---
>    `[…]`
>    `a < b` | contextually convertible to `bool` | `b - a > 0` | `<` is a total ordering relation
>    `a > b` | contextually convertible to `bool` | `b < a` | `>` is a total ordering relation opposite to `<`.
>    `a >= b` | contextually convertible to `bool` | `!(a < b)` |
>    `a <= b` | contextually convertible to `bool` | `!(a > b)` |

> 4. Change 25.1 [algorithms.general] p8+9 as indicated:

>    > -8- The `Predicate` parameter is used whenever an algorithm expects a function object (20.14 [function.objects]) that, when applied to the result of dereferencing the corresponding iterator, returns a value testable as `true`. In other words, if an algorithm takes `Predicate pred` as its argument and first as its iterator argument, it should work correctly in the construct `pred(*first)` implicitly or contextually converted to `bool` (Clause 7.3 [conv]). The function object `pred` shall not apply any non-constant function through the dereferenced iterator.

>    > -9- The `BinaryPredicate` parameter is used whenever an algorithm expects a function object that when applied to the result of dereferencing two corresponding iterators or to dereferencing an iterator and type `T` when `T` is part of the signature returns a value testable as `true`. In other words, if an algorithm takes `BinaryPredicate binary_pred` as its argument and `first1` and `first2` as its iterator arguments, it should work correctly in the construct `binary_pred(*first1, *first2)` implicitly or contextually converted to `bool` (Clause 7.3 [conv]). `BinaryPredicate` always takes the first iterator's `value_type` as its first argument, that is, in those cases when `T` value is part of the signature, it should work correctly in the construct `binary_pred(*first1, value)` implicitly or contextually converted to `bool` (Clause 7.3 [conv]). `binary_pred` shall not apply any non-constant function through the dereferenced iterators.

> 5. Change 25.8 [alg.sorting] p2 as indicated:

>    > -2- `Compare` is a function object type (20.14 [function.objects]). The return value of the function call operation applied to an object of type `Compare`, when implicitly or contextually converted to `bool` (7.3 [conv]), yields `true` if the first argument of the call is less than the second, and `false` otherwise. `Compare comp` is used throughout for algorithms assuming an ordering relation. It is assumed that `comp` will not apply any non-constant function through the dereferenced iterator.

> 6. Change 32.2.1 [thread.req.paramname] p2 as indicated:

>    > -2- If a parameter is `Predicate`, operator() applied to the actual template argument shall return a value that is convertible to `bool` `Predicate` is a function object type (20.14 [function.objects]). The return value of the function call operation applied to an object of type `Predicate`, when implicitly or contextually converted to `bool` (7.3 [conv]), yields `true` if the corresponding test condition is satisfied, and `false` otherwise.

[2014-05-20, Daniel suggests concrete wording based on STL's proposal]

The presented wording follows relatively closely STL's outline with the following notable exceptions:

1. A reference to `BooleanTestable` in table "Return Type" specifications seemed very unusual to me and I found no "prior art" for this in the Standard. Instead I decided to follow the usual style to add a symbol with a specific meaning to a specific paragraph that specifies symbols and their meanings.

2. STL's requirement IV suggested to directly refer to built-in operators `&&` and `||`. In my opinion this concrete requirement isn't needed if we simply require that two `BooleanTestable` operands behave equivalently to two those operands after conversion to `bool` (each of them).

3. I couldn't find a good reason to require normatively that type `bool` meets the requirements of `BooleanTestable`: My assertion is that after having defined them, the result simply falls out of this. But to make this a bit clearer, I added also a non-normative note to these effects.

[2014-06-10, STL comments]

In the current wording I would like to see changed the suggested changes described by bullet #6:

1. In 22.2.1 [container.requirements.general] p4 undo the suggested change

2. Then change the 7 occurrences of "convertible to `bool`" in the denoted tables to "`bool`".

[2015-05-05 Lenexa]

STL: Alisdair wanted to do something here, but Daniel gave us updated wording.

[2015-07 Telecon]

Alisdair: Should specify we don't break short circuiting.
Ville: Looks already specified because that's the way it works for bool.
Geoffrey: Maybe add a note about the short circuiting.
B2/P2 is somewhat ambiguous. It implies that B has to be both implicitly convertible to bool and contextually convertible to bool.
We like this, just have nits.
Status stays Open.
Marshall to ping Daniel with feedback.

[2016-02-27, Daniel updates wording]

1. The revised wording has been updated from N3936 to N4567.

2. To satisfy the Kona 2015 committee comments, the wording in [booleantestable.requirements] has been improved to better separate the two different requirements of "can be contextually converted to `bool`" and "can be implicitly converted to `bool`. Both are necessary because it is possible to define a type that has the latter property but not the former, such as the following one:

   > 2016-08-07, Daniel: The below example has been corrected to reduce confusion about the performed conversions as indicated by the delta markers:

   >     using Bool = int;

   >     struct OddBoolean
   >     {
   >       explicit operator bool() const = delete;
   >       operator Bool() const;
   >       OddBoolean(bool) = delete;
   >       OddBoolean(Bool){}
   >     } ob;

   >     bool b2 = ob; // OK
   >     bool b1(ob);  // Error
   >     OddBoolean b2 = true; // OK
   >     OddBoolean b1(true);  // Error

3. In [booleantestable.requirements] a note has been added to ensure that an implementation is not allowed to break any short-circuiting semantics.

4. I decided to separate LWG 2587/2588 from this issue. Both these issues aren't exactly the same but depending on the committee's position, their resolution might benefit from the new vocabulary introduced here.

[2021-06-25; Daniel comments]

The paper P2167R1 is provided to resolve this issue.

Proposed resolution:

This wording is relative to N4567.

1. Change 16.4.4.2 [utility.arg.requirements] p1, Table 17 — "EqualityComparable requirements", and Table 18 — "LessThanComparable requirements" as indicated:

   > -1- […] In these tables, `T` is an object or reference type to be supplied by a C++ program instantiating a template; `a`, `b`, and `c` are values of type (possibly `const`) `T`; `s` and `t` are modifiable lvalues of type `T`; `u` denotes an identifier; `rv` is an rvalue of type `T`; and `v` is an lvalue of type (possibly `const`) `T` or an rvalue of type `const T`; and `BT` denotes a type that meets the `BooleanTestable` requirements ([booleantestable.requirements]).

   > […]

   > > Table 17 — `EqualityComparable` requirements [equalitycomparable]
   > > Expression | Return type | Requirement
   > > --- | --- | ---
   > > `a == b` | convertible to `bool` `BT` | `==` is an equivalence relation, that is, it has the following properties: […]

   > […]

   > > Table 18 — `LessThanComparable` requirements [lessthancomparable]
   > > Expression | Return type | Requirement
   > > --- | --- | ---
   > > `a < b` | convertible to `bool` `BT` | `<` is a strict weak ordering relation (25.8 [alg.sorting])

2. Between 16.4.4.3 [swappable.requirements] and 16.4.4.4 [nullablepointer.requirements] insert a new sub-clause as indicated:

   > ?.?.?.? `BooleanTestable` requirements [booleantestable.requirements]

   > > -?- A `BooleanTestable` type is a boolean-like type that also supports conversions to `bool`. A type `B` meets the `BooleanTestable` requirements if the expressions described in Table ?? are valid and have the indicated semantics, and if `B` also satisfies all the other requirements of this sub-clause [booleantestable.requirements].

   > > An object `b` of type `B` can be implicitly converted to `bool` and in addition can be contextually converted to `bool` (Clause 4). The result values of both kinds of conversions shall be equivalent.

   > > [Example: The types `bool`, `std::true_type`, and `std::bitset<>::reference` are `BooleanTestable` types. — end example]

   > > For the purpose of Table ??, let `B2` and `Bn` denote types (possibly both equal to `B` or to each other) that meet the `BooleanTestable` requirements, let `b1` denote a (possibly `const`) value of `B`, let `b2` denote a (possibly `const`) value of `B2`, and let `t1` denote a value of type `bool`.

   > > [Note: These rules ensure what an implementation can rely on but doesn't grant it license to break short-circuiting behavior of a `BooleanTestable` type. — end note]

3. Somewhere within the new sub-clause [booleantestable.requirements] insert the following new Table (?? denotes the assigned table number):

   > Table ?? — `BooleanTestable` requirements [booleantestable]
   > Expression | Return type | Operational semantics
   > --- | --- | ---
   > `bool(b1)` | `bool` | Remarks: `bool(b1) == t1` for every value `b1` implicitly converted to `t1`.
   > `!b1` | `Bn` | Remarks: `bool(b1) == !bool(!b1)` for every value `b1`.
   > `b1 && b2` | `bool` | `bool(b1) && bool(b2)`
   > `b1 || b2` | `bool` | `bool(b1) || bool(b2)`

4. Change 16.4.4.4 [nullablepointer.requirements] p5 and Table 25 — "NullablePointer requirements" as indicated:

   > […]

   > -5- In Table 25, `u` denotes an identifier, `t` denotes a non-`const` lvalue of type `P`, `a` and `b` denote values of type (possibly `const`) `P`, and `np` denotes a value of type (possibly `const`) `std::nullptr_t`, and `BT` denotes a type that meets the `BooleanTestable` requirements ([booleantestable.requirements]).

   > […]

   > > Table 25 — `NullablePointer` requirements [nullablepointer]
   > > Expression | Return type | Operational semantics
   > > --- | --- | ---
   > > `…`
   > > `a != b` | contextually convertible to `bool` `BT` | […]
   > > `a == np` `np == a` | contextually convertible to `bool` `BT` | […]
   > > `a != np` `np != a` | contextually convertible to `bool` `BT` | […]

5. Change 20.5.8 [tuple.rel] as indicated;

   >     template<class... TTypes, class... UTypes>
   >     constexpr bool operator==(const tuple<TTypes...>& t, const tuple<UTypes...>& u);

   > > -1- Requires: For all `i`, where `0 <= i` and `i < sizeof...(TTypes)`, `get<i>(t) == get<i>(u)` is a valid expression returning a type that is convertible to `bool` meets the `BooleanTestable` requirements ([booleantestable.requirements]). `sizeof...(TTypes) == sizeof...(UTypes)`.

   > > […]

   >     template<class... TTypes, class... UTypes>
   >     constexpr bool operator<(const tuple<TTypes...>& t, const tuple<UTypes...>& u);

   > > -4- Requires: For all `i`, where `0 <= i` and `i < sizeof...(TTypes)`, `get<i>(t) < get<i>(u)` and `get<i>(u) < get<i>(t)` are valid expressions returning types that are convertible to `bool` meet the `BooleanTestable` requirements ([booleantestable.requirements]). `sizeof...(TTypes) == sizeof...(UTypes)`.

   > > […]

6. Change 22.2.1 [container.requirements.general], Table 95 — "Container requirements", and Table 97 — "Optional container operations" as indicated:

   > -4- In Tables 95, 96, and 97 `X` denotes a container class containing objects of type `T`, `a` and `b` denote values of type `X`, `u` denotes an identifier, `r` denotes a non-`const` value of type `X`, and `rv` denotes a non-`const` rvalue of type `X`, and `BT` denotes a type that meets the `BooleanTestable` requirements ([booleantestable.requirements]).

   > > Table 95 — Container requirements
   > > Expression | Return type | […]
   > > --- | --- | ---
   > > `…`
   > > `a == b` | convertible to `bool` `BT` | […]
   > > `a != b` | convertible to `bool` `BT` | […]
   > > `…`
   > > `a.empty()` | convertible to `bool` `BT` | […]

   > […]

   > > Table 97 — Optional container requirements
   > > Expression | Return type | […]
   > > --- | --- | ---
   > > `…`
   > > `a < b` | convertible to `bool` `BT` | […]
   > > `a > b` | convertible to `bool` `BT` | […]
   > > `a <= b` | convertible to `bool` `BT` | […]
   > > `a >= b` | convertible to `bool` `BT` | […]

7. Change 23.3.1 [iterator.requirements.general], Table 106 — "Input iterator requirements", and Table 110 — "Random access iterator requirements" as indicated:

   > -12- In the following sections, `a` and `b` denote values of type `X` or `const X`, `difference_type` and `reference` refer to the types `iterator_traits<X>::difference_type` and `iterator_traits<X>::reference`, respectively, `n` denotes a value of `difference_type`, `u`, `tmp`, and `m` denote identifiers, `r` denotes a value of `X&`, `t` denotes a value of value type `T`, `o` denotes a value of some type that is writable to the output iterator, and `BT` denotes a type that meets the `BooleanTestable` requirements ([booleantestable.requirements]).

   > > Table 106 — Input iterator requirements
   > > Expression | Return type | […]
   > > --- | --- | ---
   > > `a != b` | contextually convertible to `bool` `BT` | […]

   > […]

   > > Table 110 — Random access iterator requirements
   > > Expression | Return type | […]
   > > --- | --- | ---
   > > `…`
   > > `a < b` | contextually convertible to `bool` `BT` | […]
   > > `a > b` | contextually convertible to `bool` `BT` | […]
   > > `a >= b` | contextually convertible to `bool` `BT` | […]
   > > `a <= b` | contextually convertible to `bool` `BT` | […]

8. Change 25.1 [algorithms.general] p8+p9 as indicated:

   > [Drafting note: The wording changes below also fix (a) unusual wording forms used ("should work") which are unclear in which sense they are imposing normative requirements and (b) the problem, that the current wording seems to allow that the predicate may mutate a call argument, if that is not a dereferenced iterator. Upon applying the new wording it became obvious that the both the previous and the new wording has the effect that currently algorithms such as `adjacent_find`, `search_n`, `unique`, and `unique_copy` are not correctly described (because they have no iterator argument named `first1`), which could give raise to a new library issue. — end drafting note]

   > -8- The `Predicate` parameter is used whenever an algorithm expects a function object (20.9) that, when applied to the result of dereferencing the corresponding iterator, returns a value testable as `true`. In other words, i If an algorithm takes `Predicate pred` as its argument and `first` as its iterator argument, it should work correctly in the construct `pred(*first)` contextually converted to `bool` (Clause 4)the expression `pred(*first)` shall have a type that meets the `BooleanTestable` requirements ( [booleantestable.requirements]). The function object `pred` shall not apply any non-constant function through the dereferenced iterator its argument.

   > -9- The `BinaryPredicate` parameter is used whenever an algorithm expects a function object that when applied to the result of dereferencing two corresponding iterators or to dereferencing an iterator and type `T` when `T` is part of the signature returns a value testable as `true`. In other words, i If an algorithm takes `BinaryPredicate binary_pred` as its argument and `first1` and `first2` as its iterator arguments, it should work correctly in the construct `binary_pred(*first1, *first2)` contextually converted to `bool` (Clause 4)the expression `binary_pred(*first1, *first2)` shall have a type that meets the `BooleanTestable` requirements ( [booleantestable.requirements]). `BinaryPredicate` always takes the first iterator's `value_type` as its first argument, that is, in those cases when `T` value is part of the signature, it should work correctly in the construct `binary_pred(*first1, value)` contextually converted to `bool` (Clause 4)the expression `binary_pred(*first1, value)` shall have a type that meets the `BooleanTestable` requirements ( [booleantestable.requirements]). `binary_pred` shall not apply any non-constant function through the dereferenced iterators any of its arguments.

9. Change 25.8 [alg.sorting] p2 as indicated:

   > […]

   > -2- `Compare` is a function object type (20.9). The return value of the function call operation applied to an object of type `Compare`, when contextually converted to `bool`(Clause 4), yields `true` if the first argument of the call is less than the second, and `false` otherwise. `Compare comp` is used throughout for algorithms assuming an ordering relation. Let `a` and `b` denote two argument values whose types depend on the corresponding algorithm. Then the expression `comp(a, b)` shall have a type that meets the `BooleanTestable` requirements ( [booleantestable.requirements]). The return value of `comp(a, b)`, converted to `bool`, yields `true` if the first argument `a` is less than the second argument `b`, and `false` otherwise. It is assumed that `comp` will not apply any non-constant function through the dereferenced iterator any of its arguments.

   > […]

10. Change 29.5.3.2 [fpos.operations] and Table 126 — "Position type requirements" as indicated:

    > -1- Operations specified in Table 126 are permitted. In that table,

    > - `P` refers to an instance of `fpos`,

    > - […]

    > - `o` refers to a value of type `streamoff`,

    > - `BT` refers to a type that meets the `BooleanTestable` requirements ([booleantestable.requirements]),

    > - […]

    > > Table 126 — Position type requirements
    > > Expression | Return type | […]
    > > --- | --- | ---
    > > `…`
    > > `p == q` | convertible to `bool` `BT` | […]
    > > `p != q` | convertible to `bool` `BT` | […]

11. Change 32.2.1 [thread.req.paramname] p1 as indicated:

    > -1- Throughout this Clause, the names of template parameters are used to express type requirements. If a template parameter is named `Predicate`, `operator()` applied to the template argument shall return a value that is convertible to `bool` `Predicate` is a function object type (20.14 [function.objects]). Let `pred` denote an lvalue of type `Predicate`. Then the expression `pred()` shall have a type that meets the `BooleanTestable` requirements ( [booleantestable.requirements]). The return value of `pred()`, converted to `bool`, yields `true` if the corresponding test condition is satisfied, and `false` otherwise.

### 2115(i). Undefined behaviour for `valarray` assignments with `mask_array` index?

Section: 26.7.8 [template.mask.array] Status: Open Submitter: Thomas Plum Opened: 2011-12-10 Last modified: 2016-01-28

Priority: 4

View all issues with Open status.

Discussion:

Recently I received a Service Request (SR) alleging that one of our testcases causes an undefined behavior. The complaint is that 26.7.8 [template.mask.array] in C++11 (and the corresponding subclause in C++03) are interpreted by some people to require that in an assignment "`a[mask] = b`", the subscript `mask` and the rhs `b` must have the same number of elements.

IMHO, if that is the intended requirement, it should be stated explicitly.

In any event, there is a tiny editorial cleanup that could be made:

In C++11, 26.7.8.1 [template.mask.array.overview] para 2 mentions

> "the expression `a[mask] = b;`"

but the semicolon cannot be part of an expression. The correction could omit the semicolon, or change the word "expression" to "assignment" or "statement".

Here is the text of the SR, slightly modified for publication:

> Subject: SR01174 LVS _26322Y31 has undefined behavior [open]

> [Client:]
> The test case t263.dir/_26322Y31.cpp seems to be illegal as it has an undefined behaviour. I searched into the SRs but found SRs were not related to the topic explained in this mail (SR00324, SR00595, SR00838).

> >     const char vl[] = {"abcdefghijklmnopqrstuvwxyz"};
> >     const char vu[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ"};
> >     const std::valarray<char> v0(vl, 27), vm5(vu, 5), vm6(vu, 6);
> >     std::valarray<char> x = v0;
> >     […]
> >     const bool vb[] = {false, false, true, true, false, true};
> >     const std::valarray<bool> vmask(vb, 6);
> >     x = v0;
> >     x[vmask] = vm5;      // ***** HERE....
> >     steq(&x[0], "abABeCghijklmnopqrstuvwxyz");
> >     x2 = x[vmask];       // ***** ....AND HERE
> >     […]

> This problem has already been discussed between [experts]: See thread http://gcc.gnu.org/ml/libstdc++/2009-11/threads.html#00051 Conclusion http://gcc.gnu.org/ml/libstdc++/2009-11/msg00099.html

> [Plum Hall:]
> Before I log this as an SR, I need to check one detail with you.

> I did read the email thread you mentioned, and I did find a citation (see INCITS ISO/IEC 14882-2003 Section 26.3.2.6 on valarray computed assignments):

> Quote: "If the array and the argument array do not have the same length, the behavior is undefined",

> But this applies to computed assignment (`*=`, `+=`, etc), not to simple assignment. Here is the C++03 citation re simple assignment:

> 26.3.2.2 valarray assignment [lib.valarray.assign]

> >     valarray<T>& operator=(const valarray<T>&);

> > > 1 Each element of the `*this` array is assigned the value of the corresponding element of the argument array. The resulting behavior is undefined if the length of the argument array is not equal to the length of the `*this` array.

> In the new C++11 (N3291), we find ...

> 26.6.2.3 valarray assignment [valarray.assign]

> >     valarray<T>& operator=(const valarray<T>& v);

> > > 1 Each element of the `*this` array is assigned the value of the corresponding element of the argument array. If the length of `v` is not equal to the length of `*this`, resizes `*this` to make the two arrays the same length, as if by calling `resize(v.size())`, before performing the assignment.

> So it looks like the testcase might be valid for C++11 but not for C++03; what do you think?

> [Client:]
> I quite agree with you but the two problems I mentioned:

> >     x[vmask] = vm5;      // ***** HERE....
> >     […]
> >     x2 = x[vmask];       // ***** ....AND HERE

> refer to `mask_array` assignment hence target the C++03 26.3.8 paragraph. Correct?

> [Plum Hall:]
> I mentioned the contrast between C++03 26.3.2.2 para 1 versus C++11 26.6.2.3 para 1.

> But in C++03 26.3.8, I don't find any corresponding restriction. Could you quote the specific requirement you're writing about?

> [Client:]
> I do notice the difference between c++03 26.3.2.2 and c++11 26.6.2.3 about assignments between different sized `valarray` and I perfectly agree with you.

> But, as already stated, this is not a simple `valarray` assignment but a `mask_array` assignment (c++03 26.3.8 / c++11 26.6.8). See c++11 quote below:

> 26.6.8 Class template mask_array
> 26.6.8.1 Class template mask_array overview
> [....]

> 1. This template is a helper template used by the mask subscript operator: `mask_array<T> valarray<T>::operator[](const valarray<bool>&)`.

> 2. It has reference semantics to a subset of an array specified by a boolean mask. Thus, the expression `a[mask] = b;` has the effect of assigning the elements of `b` to the masked elements in `a` (those for which the corresponding element in `mask` is true.)

> 26.6.8.2 mask_array assignment

> >     void operator=(const valarray<T>&) const;
> >     const mask_array& operator=(const mask_array&) const;

> > > 1 These assignment operators have reference semantics, assigning the values of the argument array elements to selected elements of the `valarray<T>` object to which it refers.

> In particular, [one of the WG21 experts] insisted on the piece "the elements of `b`".

> That is why I reported the test t263.dir/_26322Y31.cpp having an undefined behaviour.

> [Plum Hall:]
> OK, I can see that I will have to ask WG21; I will file an appropriate issue with the Library subgroup. In the meantime, I will mark this testcase as "DISPUTED" so that it is not required for conformance testing, until we get a definitive opinion.

[2012, Kona]

Moved to Open.

There appears to be a real need for clarification in the standard, and implementations differ in their current interpretation. This will need some research by implementers and a proposed resolution before further discussion is likely to be fruitful.

Proposed resolution:

### 2116(i). `is_nothrow_constructible` and destructors

Section: 20.15.5.4 [meta.unary.prop] Status: Open Submitter: Dave Abrahams Opened: 2011-12-09 Last modified: 2018-10-11

Priority: 3

View other active issues in [meta.unary.prop].

View all other issues in [meta.unary.prop].

View all issues with Open status.

Discussion:

IMO if we specified `is_[nothrow_]constructible` in terms of a variable declaration whose validity requires destructibility, it is clearly a bug in our specification and a failure to realize the actual original intent. The specification should have been in terms of placement-new.

Daniel:
At the time of the specification this was intended and the solution is not done by removing the destruction semantics of `is_constructible`.

The design of `is_constructible` was also impacted by the previous `Constructible` concept that explicitly contained destruction semantics, because during conceptification of the library it turned out to simplify the constraints in the library because you did not need to add `Destructible` all the time. It often was implied but never spoken out in C++03.

Pure construction semantics was considered as useful as well, so `HasConstructor` did also exist and would surely be useful as trait as well.

Another example that is often overlooked: This also affects wrapper types like `pair`, `tuple`, `array` that contain potentially more than one type: This is easy to understand if you think of `T1` having a deleted destructor and `T2` having a constructor that may throw: Obviously the compiler has potentially need to use the `destructor` of `T1` in the constructor of `std::pair<T1, T2>` to ensure that the core language requirements are satisfied (All previous fully constructed sub-objects must be destructed).

The core language also honors this fact in [class.copy] p11:

> A defaulted copy/move constructor for a class `X` is defined as deleted (9.5.3 [dcl.fct.def.delete]) if `X` has:
> […]
> — any direct or virtual base class or non-static data member of a type with a destructor that is deleted or inaccessible from the defaulted constructor,
> […]

Dave:
This is about `is_nothrow_constructible` in particular. The fact that it is foiled by not having a `noexcept` dtor is a defect.

[2012, Kona]

Move to Open.

`is_nothrow_constructible` is defined in terms of `is_constructible`, which is defined by looking at a hypothetical variable and asking whether the variable definition is known not to throw exceptions. The issue claims that this also examines the type's destructor, given the context, and thus will return `false` if the destructor can potentially throw. At least one implementation (Howard's) does return `false` if the constructor is `noexcept(true)` and the destructor is `noexcept(false)`. So that's not a strained interpretation. The issue is asking for this to be defined in terms of placement `new`, instead of in terms of a temporary object, to make it clearer that `is_nothrow_constructible` looks at the `noexcept` status of only the constructor, and not the destructor.

Sketch of what the wording would look like:

require `is_constructible`, and then also require that a placement `new` operation does not throw. (Remembering the title of this issue... What does this imply for `swap`?

If we accept this resolution, do we need any changes to `swap`?

STL argues: no, because you are already forbidden from passing anything with a throwing destructor to `swap`.

Dietmar argues: no, not true. Maybe statically the destructor can conceivably throw for some values, but maybe there are some values known not to throw. In that case, it's correct to pass those values to `swap`.

[2017-01-27 Telecon]

Gave the issue a better title

This issue interacts with 2827

Ville would like "an evolution group" to take a look at this issue.

Proposed resolution:

### 2117(i). `ios_base` manipulators should have `showgrouping/noshowgrouping`

Section: 28.4.3.3.3 [facet.num.put.virtuals], 99 [ios::fmtflags], 29.5.5.1 [fmtflags.manip] Status: Open Submitter: Benjamin Kosnik Opened: 2011-12-15 Last modified: 2016-04-16

Priority: 3

View other active issues in [facet.num.put.virtuals].

View all other issues in [facet.num.put.virtuals].

View all issues with Open status.

Discussion:

Iostreams should include a manipulator to toggle grouping on/off for locales that support grouped digits. This has come up repeatedly and been deferred. See LWG 826 for the previous attempt.

If one is using a locale that supports grouped digits, then output will always include the generated grouping characters. However, very plausible scenarios exist where one might want to output the number, un-grouped. This is similar to existing manipulators that toggle on/off the decimal point, numeric base, or positive sign.

See some user commentary here.

[21012, Kona]

Move to Open.

This is a feature request.

Walter is slightly uncomfortable with processing feature requests through the issues lists.

Alisdair says this is far from the first feature request that has come in from the issues list.

STL: The fact that you can turn off grouping on hex output is compelling.

Marshall: if we add this flag, we'll need to update tables 87-91 as well.

STL: If it has been implemented somewhere, and it works, we'd be glad to add it.

Howard: We need to say what the default is.

Alisdair sumarizes:

(1) We want clear wording that says what the effect is of turning the flag off;

(2) what the default values are, and

(3) how this fits into tables 87-90. (and 128)

[Issaquah 2014-02-10-12: Move to LEWG]

Since this issue was filed, we have grown a new working group that is better placed to handle feature requests.

We will track such issues with an LEWG status until we get feedback from the Library Evolution Working Group.

[Issaquah 2014-02-12: LEWG discussion]

Do we think this feature should exist?
SF | F | N | A | SA
2 | 4 | 1 | 0 | 0

Think about the ABI break for adding a flag. But this could be mitigated by putting the data into an iword instead of a flag.

This needs to change Stage 2 in [facet.num.put.virtuals].

Previous resolution, which needs the above corrections:

> This wording is relative to the FDIS.

> 1. Insert in 28.4.3.3.3 [facet.num.put.virtuals] paragraph 5:

>    > Stage 1: The first action of stage 1 is to determine a conversion specifier. The tables that describe this determination use the following local variables

>    >     fmtflags flags = str.flags() ;
>    >     fmtflags basefield = (flags & (ios_base::basefield));
>    >     fmtflags uppercase = (flags & (ios_base::uppercase));
>    >     fmtflags floatfield = (flags & (ios_base::floatfield));
>    >     fmtflags showpos = (flags & (ios_base::showpos));
>    >     fmtflags showbase = (flags & (ios_base::showbase));
>    >     fmtflags showgrouping = (flags & (ios_base::showgrouping));

> 2. Change header `<ios>` synopsis, [iostreams.base.overview] as indicated:

>    >     #include <iosfwd>

>    >     namespace std {
>    >       […]
>    >       // 27.5.6, manipulators:
>    >       […]
>    >       ios_base& showpoint     (ios_base& str);
>    >       ios_base& noshowpoint   (ios_base& str);
>    >       ios_base& showgrouping  (ios_base& str);
>    >       ios_base& noshowgrouping(ios_base& str);
>    >       ios_base& showpos       (ios_base& str);
>    >       ios_base& noshowpos     (ios_base& str);
>    >       […]
>    >     }

> 3. Change class `ios_base` synopsis, 29.5.2 [ios.base] as indicated:

>    >     namespace std {
>    >       class ios_base {
>    >       public:
>    >       class failure;
>    >         // 27.5.3.1.2 fmtflags
>    >         typedef T1 fmtflags;
>    >         […]
>    >         static constexpr fmtflags showpoint = unspecified ;
>    >         static constexpr fmtflags showgrouping = unspecified ;
>    >         static constexpr fmtflags showpos = unspecified ;
>    >         […]
>    >       };
>    >     }

> 4. Add a new entry to Table 122 — "`fmtflags` effects" as indicated:

>    Table 122 — `fmtflags` effects
>    Element | Effect(s) if set
>    --- | ---
>    `[…]`
>    `showpoint` | generates a decimal-point character unconditionally in generated floatingpoint output
>    `showgrouping` | generates grouping characters unconditionally in generated output
>    `[…]`

> 5. After 99 [ios::fmtflags] p12 insert the following:

>    >     ios_base& showgrouping(ios_base& str);

>    > > -?- Effects: Calls `str.setf(ios_base::showgrouping)`.

>    > > -?- Returns: `str`.

>    >     ios_base& noshowgrouping(ios_base& str);

>    > > -?- Effects: Calls `str.unsetf(ios_base::showgrouping)`.

>    > > -?- Returns: `str`.

Proposed resolution:

### 2136(i). Postconditions vs. exceptions

Section: 16.3.2 [structure] Status: Open Submitter: Jens Maurer Opened: 2012-03-08 Last modified: 2021-06-25

Priority: 3

View all issues with Open status.

Discussion:

The front matter in clause 17 should clarify that postconditions will not hold if a standard library function exits via an exception. Postconditions or guarantees that apply when an exception is thrown (beyond the basic guarantee) are described in an "Exception safety" section.

[ 2012-10 Portland: Move to Open ]

Consensus that we do not clearly say this, and that we probably should. A likely location to describe the guarantees of postconditions could well be a new sub-clause following 99 [res.on.required] which serves the same purpose for requires clauses. However, we need such wording before we can make progress.

Also, see 2137 for a suggestion that we want to see a paper resolving both issues together.

[2015-05-06 Lenexa: EirkWF to write paper addressing 2136 and 2137]

MC: Idea is to replace all such "If no exception" postconditions with "Exception safety" sections.

[2021-06-20; Daniel comments]

An informal editorial change suggestion has recently been made whose editorial implementation would promote the idea that the default assumption is that Postconditions: are only met if the function doesn't exit with an exception.

After analyzing all current existing Postconditions: elements the following seems to hold: Affected by this issue are only non-`noexcept` functions and mostly non-constructor functions (unless the Postconditions: element says something about the value of its arguments). Most existing Postconditions seem to be intended to apply only in non-exceptional cases. I found some where this is presumably not intended, namely those of the expressions `os << x` and `is >> v` in Tables [tab:rand.req.eng] and [tab:rand.req.dist], maybe also 27.11.2.4 [time.zone.db.remote] p4.

Nonetheless, the editorial change seems to be applicable even without having this issue resolved, because it doesn't actually change the normative state by itself.

Proposed resolution:

### 2137(i). Misleadingly constrained post-condition in the presence of exceptions

Section: 30.7.3 [re.regex.assign] Status: Open Submitter: Jonathan Wakely Opened: 2012-03-08 Last modified: 2021-06-20

Priority: 3

View all other issues in [re.regex.assign].

View all issues with Open status.

Discussion:

The post-conditions of `basic_regex<>::assign` 30.7.3 [re.regex.assign] p16 say:

> If no exception is thrown, `flags()` returns `f` and `mark_count()` returns the number of marked sub-expressions within the expression.

The default expectation in the library is that post-conditions only hold, if there is no failure (see also 2136), therefore the initial condition should be removed to prevent any misunderstanding.

[ 2012-10 Portland: Move to Open ]

A favorable resolution clearly depends on a favorable resolution to 2136. There is also a concern that this is just one example of where we would want to apply such a wording clean-up, and which is really needed to resolve both this issue and 2136 is a paper providing the clause 17 wording that gives the guarantee for postcondition paragraphs, and then reviews clauses 18-30 to apply that guarantee consistently. We do not want to pick up these issues piecemeal, as we risk opening many issues in an ongoing process.

[2015-05-06 Lenexa: EricWF to write paper addressing 2136 and 2137]

Proposed resolution:

This wording is relative to N3376.

>     template <class string_traits, class A>
>       basic_regex& assign(const basic_string<charT, string_traits, A>& s,
>         flag_type f = regex_constants::ECMAScript);

> > […]

> > -15- Effects: Assigns the regular expression contained in the string `s`, interpreted according the flags specified in `f`. If an exception is thrown, `*this` is unchanged.

> > -16- Postconditions: If no exception is thrown, `flags()` returns `f` and `mark_count()` returns the number of marked sub-expressions within the expression.

### 2146(i). Are reference types `Copy`/`Move-Constructible`/`Assignable` or `Destructible`?

Section: 16.4.4.2 [utility.arg.requirements] Status: Open Submitter: Nikolay Ivchenkov Opened: 2012-03-23 Last modified: 2020-10-02

Priority: 3

View all other issues in [utility.arg.requirements].

View all issues with Open status.

Discussion:

According to 16.4.4.2 [utility.arg.requirements] p1

> The template definitions in the C++ standard library refer to various named requirements whose details are set out in tables 17-24. In these tables, `T` is an object or reference type to be supplied by a C++ program instantiating a template; `a`, `b`, and `c` are values of type (possibly `const`) `T`; `s` and `t` are modifiable lvalues of type `T`; `u` denotes an identifier; `rv` is an rvalue of type `T`; and `v` is an lvalue of type (possibly `const`) `T` or an rvalue of type `const T`.

Is it really intended that `T` may be a reference type? If so, what should `a`, `b`, `c`, `s`, `t`, `u`, `rv`, and `v` mean? For example, are "`int &`" and "`int &&`" `MoveConstructible`?

As far as I understand, we can explicitly specify template arguments for `std::swap` and `std::for_each`. Can we use reference types there?

1. >     #include <iostream>
   >     #include <utility>

   >     int main()
   >     {
   >       int x = 1;
   >       int y = 2;
   >       std::swap<int &&>(x, y); // undefined?
   >       std::cout << x << " " << y << std::endl;
   >     }

2. >     #include <algorithm>
   >     #include <iostream>
   >     #include <iterator>
   >     #include <utility>

   >     struct F
   >     {
   >       void operator()(int n)
   >       {
   >         std::cout << n << std::endl;
   >         ++count;
   >       }
   >       int count;
   >     } f;

   >     int main()
   >     {
   >       int arr[] = { 1, 2, 3 };
   >       auto&& result = std::for_each<int *, F &&>( // undefined?
   >         std::begin(arr),
   >         std::end(arr),
   >         std::move(f));
   >       std::cout << "count: " << result.count << std::endl;
   >     }

Are these forms of usage well-defined?

Let's also consider the following constructor of `std::thread`:

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

> > Requires: `F` and each `Ti` in `Args` shall satisfy the `MoveConstructible` requirements.

When the first argument of this constructor is an lvalue (e.g. a name of a global function), template argument for `F` is deduced to be lvalue reference type. What should "`MoveConstructible`" mean with regard to an lvalue reference type? Maybe the wording should say that `std::decay<F>::type` and each `std::decay<Ti>::type` (where `Ti` is an arbitrary item in `Args`) shall satisfy the `MoveConstructible` requirements?

[2013-03-15 Issues Teleconference]

Moved to Open.

The questions raised by the issue are real, and should have a clear answer.

[2015-10, Kona Saturday afternoon]

STL: std::thread needs to be fixed, and anything behaving like it needs to be fixed, rather than reference types. std::bind gets this right. We need to survey this. GR: That doesn't sound small to me. STL: Seach for CopyConstructible etc. It may be a long change, but not a hard one.

MC: It seems that we don't have a PR. Does anyone have one? Is anyone interested in doing a survey?

[2016-03, Jacksonville]

Casey volunteers to make a survey

[2016-06, Oulu]

During an independent survey performed by Daniel as part of the analysis of LWG 2716, some overlap was found between these two issues. Daniel suggested to take responsibility for surveying LWG 2146 and opined that the P/R of LWG 2716 should restrict to forwarding references, where the deduction to lvalue references can happen without providing an explicit template argument just by providing an lvalue function argument.

[2018-06, Rapperwsil]

Jonathan says that this will be covered by his Omnibus requirements paper.

[2019 Cologne Wednesday night]

Daniel will start working on this again; Marshall to provide rationale why some of the examples are not well-formed.

[2020-10-02; Issue processing telecon: change from P2 to P3]

For the examples given in the original report, the `for_each` case is now banned, because 25.2 [algorithms.requirements] p15 forbids explicit template argument lists. `std::thread`'s constructor has also been fixed to describe the requirements on `decay_t<T>` instead of `T`.

We believe we're more careful these days about using `remove_cvref` or `decay` as needed, but there are still places where we incorrectly state requirements in terms of types that might be references. The `swap` case still needs solving. Still need a survey.

Proposed resolution:

### 2152(i). Instances of standard container types are not swappable

Section: 16.4.4.3 [swappable.requirements], 22.2.1 [container.requirements.general] Status: LEWG Submitter: Robert Shearer Opened: 2012-04-13 Last modified: 2020-09-06

Priority: 3

View all other issues in [swappable.requirements].

View all issues with LEWG status.

Discussion:

Sub-clause 16.4.4.3 [swappable.requirements] defines two notions of swappability: a binary version defining when two objects are swappable with one another, and a unary notion defining whether an object is swappable (without qualification), with the latter definition requiring that the object satisfy the former with respect to all values of the same type.

Let `T` be a container type based on a non-propagating allocator whose instances do not necessarily compare equal. Then sub-clause 22.2.1 [container.requirements.general] p7 implies that no object `t` of type `T` is swappable (by the unary definition).

Throughout the standard it is the unary definition of "swappable" that is listed as a requirement (with the exceptions of 20.2.2 [utility.swap] p4, 20.4.2 [pairs.pair] p31, 20.5.3.3 [tuple.swap] p2, 25.7.3 [alg.swap] p2, and 25.7.3 [alg.swap] p6, which use the binary definition). This renders many of the mutating sequence algorithms of sub-clause 25.7 [alg.modifying.operations], for example, inapplicable to sequences of standard container types, even where every element of the sequence is swappable with every other.

Note that this concern extends beyond standard containers to all future allocator-based types.

Resolution proposal:

I see two distinct straightforward solutions:

1. Modify the requirements of algorithms from sub-clause 25.7 [alg.modifying.operations], and all other places that reference the unary "swappable" definition, to instead use the binary "swappable with" definition (over a domain appropriate to the context). The unary definition of "swappable" could then be removed from the standard.
2. Modify sub-clause 22.2.1 [container.requirements.general] such that objects of standard container types are "swappable" by the unary definition.

I favor the latter solution, for reasons detailed in the following issue.

[ 2012-10 Portland: Move to Open ]

The issue is broader than containers with stateful allocotors, although they are the most obvious example contained within the standard itself. The basic problem is that once you have a stateful allocator, that does not `propagate_on_swap`, then whether two objects of this type can be swapped with well defined behavior is a run-time property (the allocators compare equal) rather than a simple compile-time property that can be deduced from the type. Strictly speaking, any type where the nature of swap is a runtime property does not meet the `swappable` requirements of C++11, although typical sequences of such types are going to have elements that are all `swappable with` any other element in the sequence (using our other term of art for specifying requirements) as the common case is a container of elements who all share the same allocator.

The heart of the problem is that the `swappable` requirments demand that any two objects of the same type be `swappable with` each other, so if any two such objects would not be `swappable with` each other, then the whole type is never `swappable`. Many algorithms in clause 25 are specified in terms of `swappable` which is essentially an overspecification as all they actually need is that any element in the sequence is `swappable with` any other element in the sequence.

At this point Howard joins the discussion and points out that the intent of introducing the two swap-related terms was to support `vector<bool>::reference` types, and we are reading something into the wording that was never intended. Consuses is that regardless of the intent, that is what the words today say.

There is some support to see a paper reviewing the whole of clause 25 for this issue, and other select clauses as may be necessary.

There was some consideration to introducing a note into the front of clause 25 to indicate `swappable` requirements in the clause should be interpreted to allow such awkward types, but ultimately no real enthusiasm for introducing a `swappable for clause 25` requirement term, especially if it confusingly had the same name as a term used with a subtly different meaning through the rest of the standard.

There was no enthusiasm for the alternate resolution of requiring containers with unequal allocators that do not propagate provide a well-defined swap behavior, as it is not believed to be possible without giving `swap` linear complexity for such values, and even then would require adding the constraint that the container element types are CopyConstructible.

Final conclusion: move to open pending a paper from a party with a strong interest in stateful allocators.

[2016-03 Jacksonville]

Alisdair says that his paper P0178 addresses this.

[2016-06 Oulu]

P0178 reviewed, and sent back to LEWG for confirmation.

Thursday Morning: A joint LWG/LEWG meeting declined to adopt P0178.

[2017-02 in Kona, LEWG responds]

Note in the issue that this is tracked here

[2017-06-02 Issues Telecon]

Leave as LEWG; priority 3

Proposed resolution:

Apply P0178.

### 2153(i). Narrowing of the non-member `swap` contract

Section: 20.2.2 [utility.swap], 16.4.4.3 [swappable.requirements], 22.2.1 [container.requirements.general] Status: LEWG Submitter: Robert Shearer Opened: 2012-04-13 Last modified: 2020-10-02

Priority: 2

View all other issues in [utility.swap].

View all issues with LEWG status.

Discussion:

Sub-clause 20.2.2 [utility.swap] defines a non-member 'swap' function with defined behavior for all `MoveConstructible` and `MoveAssignable` types. It does not guarantee constant-time complexity or `noexcept` in general, however this definition does render all objects of `MoveConstructible` and `MoveAssignable` type swappable (by the unary definition of sub-clause 16.4.4.3 [swappable.requirements]) in the absence of specializations or overloads.

The overload of the non-member `swap` function defined in Table 96, however, defines semantics incompatible with the generic non-member `swap` function, since it is defined to call a member `swap` function whose semantics are undefined for some values of `MoveConstructible` and `MoveAssignable` types.

The obvious (perhaps naive) interpretation of sub-clause 16.4.4.3 [swappable.requirements] is as a guide to the "right" semantics to provide for a non-member `swap` function (called in the context defined by 16.4.4.3 [swappable.requirements] p3) in order to provide interoperable user-defined types for generic programming. The standard container types don't follow these guidelines.

More generally, the design in the standard represents a classic example of "contract narrowing". It is entirely reasonable for the contract of a particular `swap` overload to provide more guarantees, such as constant-time execution and `noexcept`, than are provided by the `swap` that is provided for any `MoveConstructible` and `MoveAssignable` types, but it is not reasonable for such an overload to fail to live up to the guarantees it provides for general types when it is applied to more specific types. Such an overload or specialization in generic programming is akin to an override of an inherited virtual function in OO programming: violating a superclass contract in a subclass may be legal from the point of view of the language, but it is poor design and can easily lead to errors. While we cannot prevent user code from providing overloads that violate the more general `swap` contract, we can avoid doing so within the library itself.

My proposed resolution is to draw a sharp distinction between member `swap` functions, which provide optimal performance but idiosyncratic contracts, and non-member `swap` functions, which should always fulfill at least the contract of 20.2.2 [utility.swap] and thus render objects swappable. The member `swap` for containers with non-propagating allocators, for example, would offer constant-time guarantees and `noexcept` but would only offer defined behavior for values with allocators that compare equal; non-member `swap` would test allocator equality and then dispatch to either member `swap` or `std::swap` depending on the result, providing defined behavior for all values (and rendering the type "swappable"), but offering neither the constant-time nor the `noexcept` guarantees.

[2013-03-15 Issues Teleconference]

Moved to Open.

This topic deserves more attention than can be given in the telecon, and there is no proposed resolution.

[2016-03 Jacksonville]

Alisdair says that his paper P0178 addresses this.

[2016-08 Chicago]

Send to LEWG

[2016-06 Oulu]

P0178 reviewed, and sent back to LEWG for confirmation.

Thursday Morning: A joint LWG/LEWG meeting declined to adopt P0178.

[2020-10-02; remove P0178 as Proposed Resolution]

Proposed resolution:

### 2157(i). How does `std::array<T,0>` initialization work when `T` is not default-constructible?

Section: 22.3.7.5 [array.zero] Status: Open Submitter: Daryle Walker Opened: 2012-05-08 Last modified: 2021-03-14

Priority: 3

View all other issues in [array.zero].

View all issues with Open status.

Discussion:

Objects of `std::array<T, N>` are supposed to be initialized with aggregate initialization (when not the destination of a copy or move). This clearly works when `N` is positive. What happens when `N` is zero? To continue using an (inner) set of braces for initialization, a `std::array<T, 0>` implementation must have an array member of at least one element, and let default initialization take care of those secret elements. This cannot work when `T` has a set of constructors and the default constructor is deleted from that set. Solution: Add a new paragraph in 22.3.7.5 [array.zero]:

> The unspecified internal structure of array for this case shall allow initializations like:

> >     array<T, 0> a = { };

> and said initializations must be valid even when `T` is not default-constructible.

[2012, Portland: Move to Open]

Some discussion to understand the issue, which is that implementations currently have freedom to implement an empty `array` by holding a dummy element, and so might not support value initialization, which is surprising when trying to construct an empty container. However, this is not mandated, it is an unspecified implementation detail.

Jeffrey points out that the implication of 22.3.7.1 [array.overview] is that this initialization syntax must be supported by empty `array` objects already. This is a surprising inference that was not obvious to the room, but consensus is that the reading is accurate, so the proposed resolution is not necessary, although the increased clarity may be useful.

Further observation is that the same clause effectively implies that `T` must always be DefaultConstructible, regardless of `N` for the same reasons - as an initializer-list may not supply enough values, and the remaining elements must all be value initialized.

Concern that we are dancing angels on the head of pin, and that relying on such subtle implications in wording is not helpful. We need a clarification of the text in this area, and await wording.

[2015-02 Cologne]

DK: What was the outcome of Portland? AM: Initially we thought we already had the intended behaviour. We concluded that `T` must always be `DefaultConstructible`, but I'm not sure why. GR: It's p2 in `std::array`, "up to `N`". AM: That wording already implies that "`{}`" has to work when `N` is zero. But the wording of p2 needs to be fixed to make clear that it does not imply that `T` must be `DefaultConstructible`.

Conclusion: Update wording, revisit later.

[2015-10, Kona Saturday afternoon]

MC: How important is this? Can you not just use default construction for empty arrays?

TK: It needs to degenerate properly from a pack. STL agrees.

JW: Yes, this is important, and we have to make it work.

MC: I hate the words "initialization like".

JW: I'll reword this.

WEB: Can I ask that once JW has reworded this we move it to Review rather than Open?

MC: We'll try to review it in a telecon and hopefully get it to tentatively ready.

STL: Double braces must also work: `array<T, 0> a = {{}};`.

Jonathan to reword.

[2018-03-14 Wednesday evening issues processing]

Jens suggested that we remove the requirement that `begin() == end() ==` unique-value, specifically the unique value part.

Previous resolution [SUPERSEDED]:

> This wording is relative to N3376.

> Add the following new paragraph between the current 22.3.7.5 [array.zero] p1 and p2:

> > -1- `array` shall provide support for the special case `N == 0`.

> > -?- The unspecified internal structure of `array` for this case shall allow initializations like:

> > >     array<T, 0> a = { };

> > and said initializations must be valid even when `T` is not default-constructible.

> > -2- In the case that `N == 0`, `begin() == end() ==` unique value. The return value of `data()` is unspecified.

> > -3- The effect of calling `front()` or `back()` for a zero-sized array is undefined.

> > -4- Member function `swap()` shall have a noexcept-specification which is equivalent to `noexcept(true)`.

[2018-06-14, Jonathan Wakely comments and provides revised wording]

The new wording does not address the 2018-03-14 suggestion from Jens to remove the unique value. It wasn't clear to me that there was consensus to make that change, and it would be a change in behaviour not just a clarification of the existing wording.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4750.

> Modify 22.3.7.5 [array.zero] as indicated:

> > -1- `array` shall provides support for the special case of a zero-sized `array` that is always empty, i.e. `N == 0`, with the properties described in this subclause.

> > -?- A zero-sized `array` type is an aggregate that meets the `DefaultConstructible` (Table 22) and `CopyConstructible` (Table 24) requirements. There is a single element of the aggregate, of an unspecified `DefaultConstructible` type. [Note: This allows initialization of the form `array<T, 0> a = {{}};`. There is no requirement for `T` to be `DefaultConstructible`. — end note]

> > -2- In the case that `N == 0`, `begin() == end() ==` unique value `begin()` and `end()` return non-dereferenceable iterators such that `begin() == end()` and `a.begin() != b.begin()` where `a` and `b` are distinct objects of the same zero-sized `array` type. The return value of `data()` is unspecified.

> > -3- The effect of calling `front()` or `back()` for a zero-sized array is undefined.

> > -4- Member function `swap()` shall have has constant complexity and a non-throwing exception specification.

[2018-08-30, Jonathan revises wording following feedback from Daniel Kruegler and Tim Song.]

Daniel noted that it's undefined to compare iterators from different containers, so `a.begin() != b.begin()` can't be used. That means whether the iterators from different containers are unique is unobservable anyway. We can say they don't share the same underlying sequence, which tells users they can't compare them and tells implementors they can't return value-initialized iterators.
Tim noted that it's not sufficient to say the unspecified type in a zero-sized array is DefaultConstructible, it also needs to be constructible from `= {}`. Also, a zero-sized array should be CopyAssignable.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4762.

> Modify 22.3.7.5 [array.zero] as indicated:

> > -1- `array` shall provides support for the special case of a zero-sized `array` that is always empty, i.e. `N == 0`, with the properties described in this subclause.

> > -?- A zero-sized `array` type is an aggregate that meets the Cpp17DefaultConstructible (Table 24) and Cpp17CopyConstructible (Table 26) and Cpp17CopyAssignable (Table 28) requirements. There is a single element of the aggregate, of an unspecified Cpp17DefaultConstructible type that is copy-list-initializable from an empty list. [Note: This allows initialization of the form `array<T, 0> a = {{}};`. There is no requirement for `T` to be Cpp17DefaultConstructible. — end note]

> > -2- In the case that `N == 0`, `begin() == end() ==` unique value `begin()` and `end()` return non-dereferenceable iterators such that `begin() == end()`. When `a` and `b` are distinct objects of the same zero-sized `array` type, `a.begin()` and `b.begin()` are not iterators over the same underlying sequence. [Note: Therefore `begin()` does not return a value-initialized iterator — end note]. The return value of `data()` is unspecified.

> > -3- The effect of calling `front()` or `back()` for a zero-sized array is undefined.

> > -4- Member function `swap()` shall have has constant complexity and a non-throwing exception specification.

[2021-03-14; Johel Ernesto Guerrero Peña comments and provides improved wording]

The currently proposed wording specifies:

> There is a single element of the aggregate, of an unspecified Cpp17DefaultConstructible type that is copy-list-initializable from an empty list.

This doesn't specify which expressions involving zero-sized array specializations are constant expressions. 22.3.7.1 [array.overview] p4 specifies `array<T, 0>` to be a structural type when `T` is a structural type. This requires that its single element, let's call it single-element, be a structural type. But that says nothing about which of the special member functions of single-element are constant expressions. By being a structural type, single-element is permitted to be implemented as a literal class type. To meet this requirement, single-element can be implemented to have one constexpr constructor that is not a copy or move constructor (6.8.1 [basic.types.general] p10), so its default constructor needn't be constexpr. This is unlike non-zero-sized array specializations, which inherit these properties from `T`. Furthermore, this permits an implementation of single-element whose default constructor stores the result of `std::source_location::current()` in a data member (as exemplified in the specification for `current`). Cpp17DefaultConstructible doesn't require the default constructor to produce equal values. The simplest way to solve these issues and any other that might arise from future changes and oversights would be to specify single-element as an empty aggregate type. Then the wording from 22.3.7.2 [array.cons] p1 makes it clear that all the special member functions are constant expressions. It would also mean that the default constructor produces template-argument-equivalent values.

Proposed resolution:

This wording is relative to N4878.

Modify 22.3.7.5 [array.zero] as indicated:

1. > -1- `array` shall provides support for the special case of a zero-sized `array` that is always empty, i.e. `N == 0`, with the properties described in this subclause.

   > -?- A zero-sized `array` type is an aggregate that meets the Cpp17DefaultConstructible (Table 29 [tab:cpp17.defaultconstructible]) and Cpp17CopyConstructible (Table 31 [tab:cpp17.copyconstructible]) and Cpp17CopyAssignable (Table 33 [tab:cpp17.copyassignable]) requirements. There is a single element of the aggregate, of an unspecified empty aggregate type. [Note: This allows initialization of the form `array<T, 0> a = {{}};`. There is no requirement for `T` to be Cpp17DefaultConstructible. — end note]

   > -2- In the case that `N == 0`, `begin() == end() ==` unique value `begin()` and `end()` return non-dereferenceable iterators such that `begin() == end()`. When `a` and `b` are distinct objects of the same zero-sized `array` type, `a.begin()` and `b.begin()` are not iterators over the same underlying sequence. [Note: Therefore `begin()` does not return a value-initialized iterator — end note].. The return value of `data()` is unspecified.

   > -3- The effect of calling `front()` or `back()` for a zero-sized array is undefined.

   > -4- Member function `swap()` shall have has constant complexity and a non-throwing exception specification.

### 2158(i). Conditional copy/move in `std::vector`

Section: 22.3.11.3 [vector.capacity] Status: Open Submitter: Nikolay Ivchenkov Opened: 2012-05-08 Last modified: 2020-09-06

Priority: 3

View other active issues in [vector.capacity].

View all other issues in [vector.capacity].

View all issues with Open status.

Discussion:

There are various operations on `std::vector` that can cause elements of the vector to be moved from one location to another. A move operation can use either rvalue or const lvalue as argument; the choice depends on the value of `!is_nothrow_move_constructible<T>::value && is_copy_constructible<T>::value`, where `T` is the element type. Thus, some operations on `std::vector` (e.g. 'resize' with single parameter, 'reserve', 'emplace_back') should have conditional requirements. For example, let's consider the requirement for 'reserve' in N3376 – 22.3.11.3 [vector.capacity]/2:

> Requires: `T` shall be `MoveInsertable` into `*this`.

This requirement is not sufficient if an implementation is free to select copy constructor when `!is_nothrow_move_constructible<T>::value && is_copy_constructible<T>::value` evaluates to true. Unfortunately, `is_copy_constructible` cannot reliably determine whether `T` is really copy-constructible. A class may contain public non-deleted copy constructor whose definition does not exist or cannot be instantiated successfully (e.g., `std::vector<std::unique_ptr<int>>` has copy constructor, but this type is not copy-constructible). Thus, the actual requirements should be:

- if `!is_nothrow_move_constructible<T>::value && is_copy_constructible<T>::value` then `T` shall be `CopyInsertable` into `*this`;

- otherwise `T` shall be `MoveInsertable` into `*this`.

Maybe it would be useful to introduce a new name for such conditional requirement (in addition to "`CopyInsertable`" and "`MoveInsertable`").

[2016-08 Chicago]

The problem does not appear to be as severe as described. The `MoveInsertable` requirements are consistently correct, but an issue may arise on the exception-safety guarantees when we check for `is_copy_constructible_v<T>`. The problem, as described, is typically for templates that appear to have a copy constructor, but one that fails to compile once instantiated, and so gives a misleading result for the trait.

In general, users should not provide such types, and the standard would not serve users well by trying to address support for such types. However, the standard should not be providing such types either, such as `vector<unique_ptr<T>>`. A possible resolution would be to tighten the constraints in Table 80 — Container Requirements, so that if the Requirements for the copy constructor/assingment operator of a container are not satisfied, that operation shall be deleted.

A futher problem highlighted by this approach is that there are no constraints on the copy-assignment operator, so that `vector<unique_ptr<T>>` should be `CopyAssignable`! However, we can lift the equivalent constraints from the Allocator-aware container requirements.

[08-2016, Chicago]

Fri PM: Move to Open

[2017-11 Albuquerque Saturday issues processing]

There's a bunch of uses of "shall" here that are incorrect. Also, CopyInsertable contains some semantic requirements, which can't be checked at compile time, so 'ill-formed' is not possible for detecting that.

[2018-06 Rapperswil Wednesday issues processing]

Daniel to provide updated wording.

[2018-06-12, Daniel provides revised wording]

Previous resolution [SUPERSEDED]:

> This wording is relative to N4606.

> 22.2.1 [container.requirements.general] Table 80 — Container requirements
> Expression | Return type | Operational semantics | Assertion/note/pre-/post-condition | Complexity
> `X(a)` |  |  | Requires: `T` is `CopyInsertable` into `X` (see below)., otherwise this expression shall be ill-formed. post: `a == X(a)`. | linear
> `X u(a)` `X u = a;` |  |  | Requires: `T` is `CopyInsertable` into `X` (see below)., otherwise this expression shall be ill-formed. post: `u == a`. | linear
> ... | ... | ... | ... | ...
> `r = a` | `X&` |  | Requires: `T` is `CopyInsertable` into `X` and `CopyAssignable`, otherwise this expression shall be ill-formed. post: `r == a`. | linear

> 22.2.1 [container.requirements.general] Table 83 — Allocator-aware container requirements
> Expression | Return type | Operational semantics | Assertion/note/pre-/post-condition | Complexity
> `a = t` | `X&` |  | Requires: `T` is `CopyInsertable` into `X` and `CopyAssignable`., otherwise this expression shall be ill-formed post: `r == a`. | linear

[2018-08-23 Batavia Issues processing. Priority to 3]

Changed `CopyInsertable` -> `Cpp17CopyInsertable` in the resolution.

Tim says that the wording is not quite right - it imposes additional requirements.

Proposed resolution:

This wording is relative to N4750.

> The revised wording below uses the new Mandates: element introduced by adopting P0788R3 at the Rapperswil meeting 2018 and which will become a new term of art with Jonathan's omnibus paper throughout the Standard Library.

22.2.1 [container.requirements.general] Table 77 — Container requirements
Expression | Return type | Operational semantics | Assertion/note/pre-/post-condition | Complexity
`X(a)` |  |  | Mandates: Syntactic requirements of `T` is `Cpp17CopyInsertable` into `X` (see below). Requires: `T` is `Cpp17CopyInsertable` into `X` (see below). post: `a == X(a)`. | linear
`X u(a)` `X u = a;` |  |  | Mandates: Syntactic requirements of `T` is `Cpp17CopyInsertable` into `X` (see below). Requires: `T` is `Cpp17CopyInsertable` into `X` (see below). post: `u == a`. | linear
... | ... | ... | ... | ...
`r = a` | `X&` |  | Mandates: Syntactic requirements of `T` is `Cpp17CopyInsertable` into `X` (see below) and `CopyAssignable`. Requires: `T` is `Cpp17CopyInsertable` into `X` and `CopyAssignable`. post: `r == a`. | linear

22.2.1 [container.requirements.general] Table 80 — Allocator-aware container requirements
Expression | Return type | Operational semantics | Assertion/note/pre-/post-condition | Complexity
`a = t` | `X&` |  | Mandates: Syntactic requirements of `T` is `Cpp17CopyInsertable` into `X` and `CopyAssignable`. Requires: `T` is `Cpp17CopyInsertable` into `X` and `CopyAssignable`. post: `r == a`. | linear

### 2173(i). The meaning of `operator +` in the description of the algorithms

Section: 25 [algorithms] Status: Open Submitter: Nikolay Ivchenkov Opened: 2012-08-01 Last modified: 2018-06-12

Priority: 4

View other active issues in [algorithms].

View all other issues in [algorithms].

View all issues with Open status.

Discussion:

According to 25.1 [algorithms.general]/12,

> In the description of the algorithms operators `+` and `-` are used for some of the iterator categories for which they do not have to be defined. In these cases the semantics of `a+n` is the same as that of

> >     X tmp = a;
> >     advance(tmp, n);
> >     return tmp;

There are several places where such operator `+` is applied to an output iterator — for example, see the description of `std::copy`:

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

> > -1- Effects: Copies elements in the range `[first,last)` into the range `[result,result + (last - first))` starting from `first` and proceeding to `last`. For each non-negative integer `n < (last - first)`, performs `*(result + n) = *(first + n)`.

`std::advance` is not supposed to be applicable to output iterators, so we need a different method of description.

See also message c++std-lib-32908.

[2014-06-07 Daniel comments and provides wording]

The specification for output iterators is somewhat tricky, because here a sequence of increments is required to be combined with intervening assignments to the dereferenced iterator. I tried to respect this fact by using a conceptual assignment operation as part of the specification.

Another problem in the provided as-if-code is the question which requirements are imposed on `n`. Unfortunately, the corresponding function `advance` is completely underspecified in this regard, so I couldn't borrow wording from it. We cannot even assume here that `n` is the difference type of the iterator, because for output iterators there is no requirements for this associated type to be defined. The presented wording attempts to minimize assumptions, but still can be considered as controversial.

[2018-06 Rapperswil Wednesday issues processing]

Status to Open

Proposed resolution:

This wording is relative to N4606.

1. Change 25.1 [algorithms.general] around p12 as indicated:

   > -12- In the description of the algorithms operators `+` and `-` are used for some of the iterator categories for which they do not have to be defined. In these cases the semantics of `a+n` is the same as that of

   > >     X tmp = a;
   > >     advance(tmp, n);
   > >     return tmp;

   > when `X` meets the input iterator requirements (23.3.5.3 [input.iterators]), otherwise it is the same as that of

   > >     X tmp = a;
   > >     for (auto i = n; i; ++tmp, (void) --i)
   > >       *tmp = Expr(i);
   > >     return tmp;

   > where `Expr(i)` denotes the `(n-i)`th expression that is assigned to for the corresponding algorithm; and that of `b-a` is the same as of

   > >     return distance(a, b);

### 2189(i). Throwing `swap` breaks unordered containers' state

Section: 22.2.7.2 [unord.req.except] Status: Open Submitter: Alisdair Meredith Opened: 2012-09-23 Last modified: 2019-07-22

Priority: 3

View all issues with Open status.

Discussion:

The hash functor and key-comparison functor of unordered containers are allowed to throw on `swap`.

22.2.7.2 [unord.req.except]p3 "For unordered associative containers, no `swap` function throws an exception unless that exception is thrown by the swap of the container's Hash or Pred object (if any)."

In such a case we must offer the basic exception safety guarantee, where both objects are left in valid but unspecified states, and no resources are leaked. This yields a corrupt, un-usable container if the first `swap` succeeds, but the second fails by throwing, as the functors form a matched pair.

So our basic scenario is first, swap the allocators if the allocators propagate on swap, according to `allocator_traits`. Next we swap the pointers to our internal hash table data structures, so that they match the allocators that allocated them. (Typically, this operation cannot throw). Now our containers are back in a safely destructible state if an exception follows.

Next, let's say we swap the hash functor, and that throws. We have a corrupt data structure, in that the buckets are not correctly indexed by the correct functors, lookups will give unpredicatable results etc. We can safely restore a usable state by forcibly clearing each container - which does not leak resources and leaves us with two (empty but) usable containers.

Now let us assume that the hasher swap succeeds. Next we swap the equality comparator functor, and this too could throw. The important point to bear in mind is that these two functors form an important pairing - two objects that compare equal by the equality functor must also hash to the same value. If we swap one without the other, we most likely leave the container in an unusable state, even if we clear out all elements.

1. A colleague pointed out that the solution for this is to dynamically allocate the two functors, and then we need only swap pointers, which is not a throwing operation. And if we don't want to allocate on default construction (a common QoI request), we might consider moving to a dynamically allocated functors whenever `swap` is called, or on first insertion. Of course, allocating memory in `swap` is a whole new can of worms, but this does not really sound like the design we had intended.

2. The simplest option is to say that we do not support hasher or equality functors that throw on ADL `swap`. Note that the requirement is simply to not throw, rather than to be explicitly marked as `noexcept`. Throwing functors are allowed, so long as we never use values that would actually manifest a throw when used in an unordered container.

Pablo went on to give me several more options, to be sure we have a full set to consider:

3. Disallow one or the other functor from throwing. In that case, the possibly-throwing functor must be swapped first, then the other functor, the allocator, and the data pointer(s) afterwards (in any order -- there was a TC that allocator assignment and swap may not throw if the corresponding propagation trait is true.). Of course, the question becomes: which functor is allowed to throw and which one is not?

4. Require that any successful functor `swap` be reliably reversible. This is very inventive. I know of no other place in the standard where such a requirement is stated, though I have occasionally wanted such a guarantee.

5. Allow a failed swap to leave the containers in a state where future insertions may fail for reasons other than is currently allowed. Specifically, if the hash and equality functors are out of sync, all insertions will fail. Presumably some "incompletely swapped" exception would be thrown. This is "slightly" inventive, although people have been discussing "radioactive" states for a while.

[2013-03-15 Issues Teleconference]

Moved to Open.

[2019 Cologne Wednesday night]

Billy to write resolution for option #2. This may require a paper.

Proposed resolution:

### 2195(i). Missing constructors for `match_results`

Section: 30.9 [re.results] Status: Open Submitter: Daniel Krügler Opened: 2012-10-06 Last modified: 2020-09-06

Priority: 3

View all other issues in [re.results].

View all issues with Open status.

Discussion:

The requirement expressed in 30.9 [re.results] p2

> The class template `match_results` shall satisfy the requirements of an allocator-aware container and of a sequence container, as specified in 22.2.3 [sequence.reqmts], except that only operations defined for const-qualified sequence containers are supported.

can be read to require the existence of the described constructors from as well, but they do not exist in the synopsis.

The missing sequence constructors are:

>     match_results(initializer_list<value_type>);
>     match_results(size_type, const value_type&);
>     template<class InputIterator> match_results(InputIterator, InputIterator);

The missing allocator-aware container constructors are:

>     match_results(const match_results&, const Allocator&);
>     match_results(match_results&&, const Allocator&);

It should be clarified, whether (a) constructors are an exception of above mentioned operations or (b) whether at least some of them (like those accepting a `match_results` value and an allocator) should be added.

As visible in several places of the standard (including the core language), constructors seem usually to be considered as "operations" and they certainly can be invoked for const-qualified objects.

The below given proposed resolution applies only the minimum necessary fix, i.e. it excludes constructors from above requirement.

[2013-04-20, Bristol]

Check current implementations to see what they do and, possibly, write a paper.

[2013-09 Chicago]

Ask Daniel to update the proposed wording to include the allocator copy and move constructors.

[2014-01-18 Daniel changes proposed resolution]

Previous resolution from Daniel [SUPERSEDED]:

> 1. Change 30.9 [re.results] p2 as indicated:

>    > The class template `match_results` shall satisfy the requirements of an allocator-aware container and of a sequence container, as specified in 22.2.3 [sequence.reqmts], except that only operations defined for const-qualified sequence containers that are not constructors are supported.

[2015-05-06 Lenexa]

MC passes important knowledge to EF.

VV, RP: Looks good.

TK: Second form should be conditionally noexcept

JY: Sequence constructors are not here, but mentioned in the issue writeup. Why?

TK: That would have been fixed by the superseded wording.

JW: How does this interact with Mike Spertus' allocator-aware regexes? [...] Perhaps it doesn't.

JW: Can't create match_results, want both old and new resolution.

JY: It's problematic that users can't create these, but not this issue.

VV: Why conditional noexcept?

MC: Allocator move might throw.

JW: Update superseded wording to "only non-constructor operations that are"?

MC: Only keep superseded, but append "and the means of constructing match_results are limited to [...]"?

JY: Bullet 4 paragraph 2 needs to address the allocator constructor.

Assigned to JW for drafting.

[2015-10, Kona Saturday afternoon]

STL: I want Mike Spertus to be aware of this issue.

Previous resolution from Daniel [SUPERSEDED]:

> This wording is relative to N3936.

> 1. Change 30.9 [re.results] p4, class template `match_results` synopsis, as indicated:

>    >     […]
>    >     // 28.10.1, construct/copy/destroy:
>    >     explicit match_results(const Allocator& a = Allocator());
>    >     match_results(const match_results& m);
>    >     match_results(const match_results& m, const Allocator& a);
>    >     match_results(match_results&& m) noexcept;
>    >     match_results(match_results&& m, const Allocator& a) noexcept;
>    >     […]

> 2. Change 30.9.2 [re.results.const] as indicated: [Drafting note: Paragraph 6 as currently written, makes not much sense, because the `noexcept` does not allow any exception to propagate. Further-on, the allocator requirements do not allow for throwing move constructors. Deleting it seems to be near to editorial — end drafting note]

>    >     match_results(const match_results& m);
>    >     match_results(const match_results& m, const Allocator& a);

>    > > -4- Effects: Constructs an object of class `match_results`, as a copy of `m`.

>    >     match_results(match_results&& m) noexcept;
>    >     match_results(match_results&& m, const Allocator& a) noexcept;

>    > > -5- Effects: Move-constructs an object of class `match_results` from `m` satisfying the same postconditions as Table 142. Additionally For the first form, the stored `Allocator` value is move constructed from `m.get_allocator()`.

>    > > -6- Throws: Nothing if the allocator's move constructor throws nothing.

[2019-03-27 Jonathan updates proposed resolution]

Proposed resolution:

This wording is relative to N4810.

These edits overlap with the proposed resolution of 2191 but it should be obvious how to resolve the conflicts. Both resolutions remove the word "Additionally" from p4. Issue 2191 removes the entire Throws: element in p5 but this issue replaces it with different text that applies to the new constructor only.

1. Change 30.9 [re.results] p4, class template `match_results` synopsis, as indicated:

   >     […]
   >     // 30.10.1, construct/copy/destroy:
   >     explicit match_results(const Allocator& a = Allocator());
   >     match_results(const match_results& m);
   >     match_results(const match_results& m, const Allocator& a);
   >     match_results(match_results&& m) noexcept;
   >     match_results(match_results&& m, const Allocator& a);
   >     […]

2. Change 30.9.2 [re.results.const] as indicated:

   >     match_results(const match_results& m);
   >     match_results(const match_results& m, const Allocator& a);

   > > -3- Effects: Constructs an object of class `match_results`, as a copy of `m`. For the second form, the stored `Allocator` value is constructed from `a`.

   >     match_results(match_results&& m) noexcept;
   >     match_results(match_results&& m, const Allocator& a);

   > > -4- Effects: Move-constructs an object of class `match_results` from `m` satisfying the same postconditions as Table 128. Additionally For the first form, the stored `Allocator` value is move constructed from `m.get_allocator()`. For the second form, the stored `Allocator` value is constructed from `a`.

   > > -6- Throws: Nothing. The second form throws nothing if `a == m.get_allocator()`.

### 2198(i). `max_load_factor(z)` makes no strong guarantees, but bans useful behavior

Section: 22.2.7 [unord.req] Status: Open Submitter: Alisdair Meredith Opened: 2012-10-09 Last modified: 2016-12-10

Priority: 3

View other active issues in [unord.req].

View all other issues in [unord.req].

View all issues with Open status.

Discussion:

The user cannot specify a `max_load_factor` for their unordered container at construction, it must be supplied after the event, when the container is potentially not empty. The contract for this method is deliberately vague, not guaranteeing to use the value supplied by the user, and any value actually used will be used as a ceiling that the container will attempt to respect.

The only guarantee we have is that, if user requests a `max_load_factor` that is less than the current `load_factor`, then the operation will take constant time, thus outlawing an implementation that chooses to rehash and so preserve as a class invariant that `load_factor < max_load_factor`.

Reasonable options conforming to the standard include ignoring the user's request if the requested value is too low, or deferring the rehash to the next `insert` operation and allowing the container to have a strange state (wrt `max_load_factor`) until then - and there is still the question of rehashing if the next `insert` is for a duplicate key in a unique container.

Given the deliberate vagueness of the current wording, to support a range of reasonable (but not perfect) behaviors, it is not clear why the equally reasonable rehash to restore the constraint should be outlawed. It is not thought that this is a performance critical operation, where users will be repeatedly setting low load factors on populated containers, in a tight or (less unlikely) an instant response scenario.

[2013-03-15 Issues Teleconference]

Moved to Open.

Alisdair to provide wording.

[2016-11-12, Issaquah]

Sat PM: Howard to provide wording

[2016-11-17 Howard provided wording.]

> The provided wording is consistent with LWG discussion in Issaquah. An implementation of the proposed wording would be setting `max_load_factor()` to `max(z, load_factor())`. This preserves the container invariant:

> >     load_factor() <= max_load_factor()

> And it preserves the existing behavior that no rehash is done by this operation.

> If it is desired to change the `max_load_factor()` to something smaller than the current `load_factor()` that can be done by first reducing the current `load_factor()` by either increasing `bucket_count()` (via `rehash` or `reserve`), or decreasing `size()` (e.g. `erase`), and then changing `max_load_factor()`.

> This resolution reaffirms that `load_factor() <= max_load_factor()` is a container invariant which can never be violated.

[2016-11-27, Nico comments]

Current implementations behave differently.

In regard to the sentence

> "The only guarantee we have is that, if user requests a `max_load_factor` that is less than the current `load_factor`, then the operation will take constant time, thus outlawing an implementation that chooses to rehash and so preserve as a class invariant that `load_factor < max_load_factor`."

Note that the current spec says that there is constant complexity without any precondition. So, rehashing to keep the invariant would violate the spec (which is probably not be the intention).

This issue is related to LWG 2199.

Proposed resolution:

Modify Table 87 as follows:

Table 87 — Unordered associative container requirements
Expression | Return type | Assertion/note pre-/post-condition | Complexity
--- | --- | --- | ---
`a.max_load_factor(z)` | `void` | Pre: `z` shall be positive. May change the container's maximum load factor, uing `z` as a hint. Post: `a.load_factor() <= a.max_load_factor()` Note: `a.load_factor()` is not modified by this operation. | Constant

### 2202(i). Missing allocator support by `async`

Section: 32.9.9 [futures.async] Status: Deferred Submitter: Detlef Vollmann Opened: 2012-10-19 Last modified: 2016-01-28

Priority: 4

View other active issues in [futures.async].

View all other issues in [futures.async].

Discussion:

`promise`, `packaged_task`, and `async` are the only places where a shared state is actually supposed to be allocated. Accordingly, `promise` and `packaged_task` are "allocator-aware". But function template `async` provides no way to provide an allocator.

[2013-09 Chicago]

Matt: deprecate async

Nico: read my paper

Alisdair: defer issues to wait for polymorphic allocators

Alisdair: defer, active topic of research Deferred

[2014-02-20 Re-open Deferred issues as Priority 4]

[2015-05 Lenexa, SG1 response]

We want whatever status approximates: "will not fix; we're working on a replacement facility and don't want to add features to a broken one"

Proposed resolution:

### 2206(i). Inaccuracy in `initializer_list` constructor requirements

Section: 22.2.3 [sequence.reqmts], 22.2.6 [associative.reqmts], 22.2.7 [unord.req], 26.6.3.2 [rand.req.seedseq] Status: Open Submitter: Jeffrey Yasskin Opened: 2012-10-21 Last modified: 2020-09-06

Priority: 3

View other active issues in [sequence.reqmts].

View all other issues in [sequence.reqmts].

View all issues with Open status.

Discussion:

In 22.2.3 [sequence.reqmts] p3, we have "`il` designates an object of type `initializer_list<value_type>`", and then several functions that take '`il`' as an argument. However, an expression like `{1, 2, 'a'}` is not an object of type `initializer_list<int>` unless it's used to initialize an explicitly-typed variable of that type. I believe we want:

>     std::vector<int> v;
>     v = {1, 2, 'a'};

to compile portably, so we should say something different when defining '`il`'. The same phrasing happens in 22.2.6 [associative.reqmts], 22.2.7 [unord.req], and 26.6.3.2 [rand.req.seedseq].

This may just be an editorial issue because the actual class synopses declare the functions to take `initializer_list<exact_type>`.

[2013-03-15 Issues Teleconference]

Moved to Open.

This is definitely not NAD

Should copy the suggested wording as the proposed resolution.

[2019-03-26; Daniel comments and provides wording]

The 2013-03-15 comment is confusing, since it recommends to "copy the suggested wording as the proposed resolution". I couldn't find such wording in the issue nor in the associated wiki, so I provided that wording out of myself. The tricky part is to define which kind of braced-init-list we want to allow. As Tim Song pointed out, we still need the existing support for `std::initializer_list<value_type>` as well, because otherwise existing semantics based on expressions such as `li.begin()` won't work anymore. The below suggested wording restricts supported braced-init-lists to every initializer list that can be used to copy-list-initialize an object of type `std::initializer_list<value_type>` by saying:

> "`bil` designates any braced-init-list suitable to copy-list-initialize an object of type `initializer_list<value_type>` (9.4.5 [dcl.init.list])"

As a drive-by fix, the provided wording adds another initialization "expression" that makes the construction of the form

>     std::vector<int> v = {1, 2, 'a'};

valid (We just miss a copy-initialization case).

Proposed resolution:

This wording is relative to N4810.

> [Drafting note: We need to special-case the "expression" `X u = bil;` below, because for empty braced-init-list the effects are those of calling the default constructor. — end drafting note]

1. Modify 22.2.3 [sequence.reqmts] as indicated:

   > -3- In Tables 66 and 67, […] `il` designates an object value of type `initializer_list<value_type>`, `bil` designates any braced-init-list suitable to copy-list-initialize an object of type `initializer_list<value_type>` (9.4.5 [dcl.init.list]), […]

2. Modify Table 66 — "Sequence container requirements (in addition to container)" as indicated:

   > Table 66 — Sequence container requirements (in addition to container)
   > Expression | Return type | Assertion/note pre-/post-condition
   > --- | --- | ---
   > `[…]`
   > `X(il)` `X u = il;` | `` | Equivalent to `X(il.begin(), il.end())` or `X u(il.begin(), il.end());`, respectively
   > `X(bil)` | `` | Equivalent to `X(initializer_list<value_type>(bil))`
   > `X u = bil;` | `` | If `bil` is empty, equivalent to `X u;`, otherwise equivalent to `X u = initializer_list<value_type>(bil);`
   > `a = il` | `X&` | […]
   > `a = bil` | `X&` | Equivalent to `a = initializer_list<value_type>(bil)`
   > `[…]`
   > `a.insert(p, il)` | `iterator` | […]
   > `a.insert(p, bil)` | `iterator` | Equivalent to `a.insert(p, initializer_list<value_type>(bil))`
   > `[…]`
   > `a.assign(il)` | `void` | […]
   > `a.assign(bil)` | `void` | Equivalent to `a.assign(initializer_list<value_type>(bil))`
   > `[…]`

3. Modify 22.2.6 [associative.reqmts] as indicated:

   > -8- In Table 69, […] `il` designates an object value of type `initializer_list<value_type>`, `bil` designates any braced-init-list suitable to copy-list-initialize an object of type `initializer_list<value_type>` (9.4.5 [dcl.init.list]), […]

4. Modify Table 69 — "Associative container requirements (in addition to container)" as indicated:

   > Table 69 — Associative container requirements (in addition to container)
   > Expression | Return type | Assertion/note pre-/post-condition | Complexity
   > --- | --- | --- | ---
   > `[…]`
   > `X(il)` `X u = il;` | `` | same as `X(il.begin(), il.end())` or `X u(il.begin(), il.end());`, respectively | same as `X(il.begin(), il.end())` or `X u(il.begin(), il.end());`, respectively
   > `X(bil)` | `` | Equivalent to `X(initializer_list<value_type>(bil))` |
   > `X u = bil;` | `` | If `bil` is empty, equivalent to `X u;`, otherwise equivalent to `X u = initializer_list<value_type>(bil);` |
   > `X(il,c)` | `` | same as `X(il.begin(), il.end(), c)` | same as `X(il.begin(), il.end(), c)`
   > `X(bil, c)` | `` | Equivalent to `X(initializer_list<value_type>(bil), c)` |
   > `a = il` | `X&` | […] | […]
   > `a = bil` | `X&` | Equivalent to `a = initializer_list<value_type>(bil)` |
   > `[…]`
   > `a.insert(il)` | `void` | equivalent to `a.insert(il.begin(), il.end())` |
   > `a.insert(bil)` | `void` | Equivalent to `a.insert(initializer_list<value_type>(bil))` |
   > `[…]`
   > `a.assign(il)` | `void` | […]
   > `a.assign(bil)` | `void` | Equivalent to `a.assign(initializer_list<value_type>(bil))`
   > `[…]`

5. Modify 22.2.7 [unord.req] p11's bullet list as indicated:

   > -11- In Table 70:

   > 1. (11.1) — […]

   > 2. […]

   > 3. (11.14) — `il` denotes a value of type `initializer_list<value_type>`,

   > 4. (11.?) — `bil` denotes any braced-init-list suitable to copy-list-initialize an object of type `initializer_list<value_type>` (9.4.5 [dcl.init.list]),

   > 5. […]

6. Modify Table 70 — "Unordered associative container requirements (in addition to container)" as indicated:

   > [Drafting note: There is a preexisting issue with Table 70, that there is no symbol `u` specified ("`u` denotes the name of a variable being declared"), so existing initialization forms with a named variable are currently always written as "`X a[…]`" where `a` is defined as "`a` denotes a value of type `X`", the wording below follows this existing practice but the author of this wording would like to kindly ask the Project Editor to introduce said symbol `u` and apply it to all existing and new such named initialization forms instead. — end drafting note]

   > Table 70 — Unordered associative container requirements (in addition to container)
   > Expression | Return type | Assertion/note pre-/post-condition | Complexity
   > --- | --- | --- | ---
   > `[…]`
   > `X(il)` `X a = il;` | `X` | Same as `X(il.begin(), il.end())` or `X a(il.begin(), il.end());`, respectively | Same as `X(il.begin(), il.end())` or `X a(il.begin(), il.end());`, respectively
   > `X(bil)` | `X` | Equivalent to `X(initializer_list<value_type>(bil))` |
   > `X a = bil;` | `X` | If `bil` is empty, equivalent to `X a;`, otherwise equivalent to `X a = initializer_list<value_type>(bil);` |
   > `X(il, n)` | `X` | Same as `X(il.begin(), il.end(), n)` | Same as `X(il.begin(), il.end(), n)`
   > `X(bil, n)` | `X` | Equivalent to `X(initializer_list<value_type>(bil), n)` |
   > `X(il, n, hf)` | `X` | Same as `X(il.begin(), il.end(), n, hf)` | Same as `X(il.begin(), il.end(), n, hf)`
   > `X(bil, n, hf)` | `X` | Equivalent to `X(initializer_list<value_type>(bil), n, hf)` |
   > `X(il, n, hf, eq)` | `X` | Same as `X(il.begin(), il.end(), n, hf, eq)` | Same as `X(il.begin(), il.end(), n, hf, eq)`
   > `X(bil, n, hf, eq)` | `X` | Equivalent to `X(initializer_list<value_type>(bil), n, hf, eq)` |
   > `[…]`
   > `a = il` | `X&` | […] | […]
   > `a = bil` | `X&` | Equivalent to `a = initializer_list<value_type>(bil)` |
   > `[…]`
   > `a.insert(il)` | `void` | Same as `a.insert(il.begin(), il.end())`. | Same as `a.insert(il.begin(), il.end())`.
   > `a.insert(bil)` | `void` | Equivalent to `a.insert(initializer_list<value_type>(bil))` |
   > `[…]`

7. Modify 26.6.3.2 [rand.req.seedseq] p2's bullet list as indicated:

   > -2- A class `S` satisfies the requirements of a seed sequence if the expressions shown in Table 82 are valid and have the indicated semantics, and […] In that Table and throughout this subclause:

   > 1. (2.1) — […]

   > 2. (2.?) — `u` denotes the name of a variable being declared,

   > 3. […]

   > 4. (2.6) — `il` is a value of `initializer_list<T>`.;

   > 5. (2.?) — `bil` denotes any braced-init-list suitable to copy-list-initialize an object of type `initializer_list<T>` (9.4.5 [dcl.init.list]).

8. Modify Table 82 — "Seed sequence requirements" as indicated:

   > Table 82 — Seed sequence requirements
   > Expression | Return type | Pre/post-condition | Complexity
   > --- | --- | --- | ---
   > `[…]`
   > `S(il)` `S u = il;` |  | Same as `S(il.begin(), il.end())` or `S u(il.begin(), il.end());`, respectively | same as `S(il.begin(), il.end())` or `S u(il.begin(), il.end());`, respectively
   > `S(bil)` |  | Equivalent to `S(initializer_list<T>(bil))` |
   > `S u = bil;` |  | If `bil` is empty, equivalent to `S u;`, otherwise equivalent to `S u = initializer_list<T>(bil);` |
   > `[…]`

### 2214(i). Clarify `basic_ios::init` call restrictions

Section: 29.5.4.2 [basic.ios.cons] Status: Open Submitter: Andrey Semashev Opened: 2012-11-09 Last modified: 2021-07-31

Priority: 4

View all other issues in [basic.ios.cons].

View all issues with Open status.

Discussion:

There is an ambiguity in how `std::basic_ios::init` method (29.5.4.2 [basic.ios.cons]) can be used in the derived class. The Standard only specify the state of the `basic_ios` object after the call completes. However, in `basic_ios` default constructor description (29.5.4.2 [basic.ios.cons]) there is this sentence:

> Effects: Constructs an object of class `basic_ios` (29.5.2.8 [ios.base.cons]) leaving its member objects uninitialized. The object shall be initialized by calling `basic_ios::init` before its first use or before it is destroyed, whichever comes first; otherwise the behavior is undefined.

This restriction hints that `basic_ios::init` should be called exactly once before the object can be used or destroyed, because `basic_ios::init` may not know whether it was called before or not (i.e. whether its members are actually uninitialized or are initialized by the previous call to `basic_ios::init`). There is no such restriction in the `basic_ios::init` preconditions so it is not clear whether it is allowed to call `basic_ios::init` multiple times or not.

This problem has already affected publicly available implementations. For example, Microsoft Visual C++ STL introduces a memory leak if `basic_ios::init` is called multiple times, while GCC 4.7 and STLPort reinitialize the `basic_ios` object correctly without memory leak or any other undesired effects. There was a discussion of this issue on Boost developers mailing list, and there is a test case that reproduces the problem. The test case is actually a bug report for my Boost.Log library, which attempts to cache `basic_ostream`-derived objects internally to avoid expensive construction and destruction. My stream objects allowed resetting the stream buffer pointers the stream is attached to, without requiring to destroy and construct the stream.

My personal view of the problem and proposed resolution follows.

While apparently the intent of `basic_ios::init` is to provide a way to initialize `basic_ios` after default construction, I see no reason to forbid it from being called multiple times to reinitialize the stream. Furthermore, it is possible to implement a conforming `basic_ios` that does not have this restriction.

The quoted above section of the Standard that describes the effects of the default constructor is misleading. The Standard does not mandate any data members of `basic_ios` or `ios_base` (29.5.2 [ios.base]), which it derives from. This means that the implementation is allowed to use non-POD data members with default constructors that initialize the members with particular default values. For example, in the case of Microsoft Visual C++ STL the leaked memory is an `std::locale` instance that is dynamically allocated during `basic_ios::init`, a raw pointer to which is stored within ios_base. It is possible to store e.g. an `unique_ptr` instead of a raw pointer as a member of `ios_base`, the smart pointer will default initialize the underlying raw pointer on default construction and automatically destroy the allocated object upon being reset or destroyed, which would eliminate the leak and allow `basic_ios::init` to be called multiple times. This leads to conclusion that the default constructor of `basic_ios` cannot leave "its member objects uninitialized" but instead performs default initialization of the member objects, which would mean the same thing in case of POD types.

However, I feel that restricting `ios_base` and `basic_ios` members to non-POD types is not acceptable. Since multiple calls to `basic_ios::init` are not forbidden by the Standard, I propose to correct the `basic_ios` default constructor description so that it is allowed to destroy `basic_ios` object without calling `basic_ios::init`. This would imply that any raw members of `basic_ios` and `ios_base` should be initialized to values suitable for destruction (essentially, this means only initializing raw pointers to NULL). The new wording could look like this:

> Effects: Constructs an object of class `basic_ios` (29.5.2.8 [ios.base.cons]) initializing its member objects to unspecified state, only suitable for `basic_ios` destruction. The object shall be initialized by calling `basic_ios::init` before its first use; otherwise the behavior is undefined.

This would remove the hint that `basic_ios::init` must be called exactly once. Also, this would remove the requirement for `basic_ios::init` to be called at all before the destruction. This is also an important issue because the derived stream constructor may throw an exception before it manages to call `basic_ios::init` (for example, if the streambuf constructor throws), and in this case the `basic_ios` destructor has undefined behavior.

To my mind, the described modification is sufficient to resolve the issue. But to emphasize the possibility to call `basic_ios::init` multiple times, a remark or a footnote for `basic_ios::init` postconditions could be added to explicitly state the semantics of calling it multiple times. The note could read as follows:

> The function can be called multiple times during the object lifetime. Each subsequent call reinitializes the object to the described in postconditions initial state.

[2013-04-20, Bristol]

Alisdair: The current wording is unclear but the proposed resolution is wrong

Solution: Clarify that `init` must be called once and only once. Move then to review.

[2021-07-29 Tim comments]

The requirement that "`init` must be called once and only once" conflicts with the disposition of LWG 135.

Proposed resolution:

This wording is relative to N3485.

1. Edit 29.5.4.2 [basic.ios.cons] as indicated:

   >     basic_ios();

   > > -2- Effects: Constructs an object of class `basic_ios` (29.5.2.8 [ios.base.cons]) leaving its member objects uninitialized initializing its member objects to unspecified state, only suitable for `basic_ios` destruction. The object shall be initialized by calling `basic_ios::init` before its first use or before it is destroyed, whichever comes first; otherwise the behavior is undefined.

   >     void init(basic_streambuf<charT,traits>* sb);

   > > Postconditions: The postconditions of this function are indicated in Table 128.

   > > -?- Remarks: The function can be called multiple times during the object lifetime. Each subsequent call reinitializes the object to the described in postconditions initial state.

### 2215(i). (unordered) associative container functors should be `CopyConstructible`

Section: 22.2.6 [associative.reqmts], 22.2.7 [unord.req] Status: Open Submitter: Alisdair Meredith Opened: 2012-11-14 Last modified: 2015-10-22

Priority: 3

View other active issues in [associative.reqmts].

View all other issues in [associative.reqmts].

View all issues with Open status.

Discussion:

The requirements on the functors used to arrange elements in the various associative and unordered containers are given by a set of expressions in tables 102 — Associative container requirements, and 103 — Unordered associative container requirements. In keeping with Library convention these expressions make the minimal requirements necessary on their types. For example, we have the following 3 row extracts for the unordered containers:

Expression | Assertion/note pre-/post-condition
    X(n, hf, eq)
    X a(n, hf, eq)
| Requires: `hasher` and `key_equal` are `CopyConstructible`.
    X(n, hf)
    X a(n, hf)
| Requires: `hasher` is `CopyConstructible` and `key_equal` is `DefaultConstructible`.
    X(n)
    X a(n)
| Requires: `hasher` and `key_equal` are `DefaultConstructible`.

However, the signature for each class template requires that the functors must effectively be `CopyConstructible` for each of these expressions:

>     template <class Key,
>               class T,
>               class Hash  = hash<Key>,
>               class Pred  = std::equal_to<Key>,
>               class Allocator = std::allocator<std::pair<const Key, T> > >
>     class unordered_map
>     {
>       ...

>       // construct/destroy/copy
>       explicit unordered_map(size_type n = see below,
>                              const hasher& hf = hasher(),
>                              const key_equal& eql = key_equal(),
>                              const allocator_type& a = allocator_type());

>       ...
>     }

The letter of the standard can be honored as long as implementors recognize their freedom to split this one signature into multiple overloads, so that the documented default arguments (requiring a `CopyConstructible` functor) are not actually passed as default arguments.

As we look into the requirements for the copy constructor and copy-assignment operator, the requirements are even more vague, as the explicit requirements on the functors are not called out, other than saying that the functors are copied.

Must the functors be `CopyAssignable`? Or is `CopyConstructible` sufficient in this case? Do we require that the functors be `Swappable` so that the copy-swap idiom can be deployed here? Note that a type that is both `CopyConstructible` and `CopyAssignable` is still not guaranteed to be `Swappable` as the user may delete the `swap` function for their type in their own namespace, which would be found via ADL.

Some clean-up of the requirements table looks necessary, to at least document the assignment behavior. In addition, we should have clear guidance on whether these functors should always be `CopyConstructible`, as suggested by the class template definitions, or if the requirement tables are correct and we should explicitly split up the constructors in the (unordered) associative containers to no longer use default (function) arguments to obtain their defaulted functors.

I recommend the simplest solution would be to always require that the functors for (unordered) associative containers be `CopyConstructible`, above the requirements tables themselves, so that the issue need not be addressed within the tables. I suggest that the assignment operators for these containers add the requirement that the functors be `Swappable`, rather than forwarding the corresponding `Assignable` requirement.

[2013-03-15 Issues Teleconference]

Moved to Open.

Alisdair to propose wording.

[2014-06-08, Daniel comments]

The area of this issue partially overlaps what LWG 2227 addresses.

[2015-10-20, Daniel comments]

The revised resolution of LWG 2227 should resolve this issue as well. It follows the recommendations of the submitter to require `CopyConstructible` requirements for the function objects owned by containers, but it does not impose any further fundamental requirements.

Proposed resolution:

See the resolution of LWG 2227.

### 2216(i). `regex_replace(basic_string)` allocator handling

Section: 30.10.4 [re.alg.replace] Status: New Submitter: Jeffrey Yasskin Opened: 2012-11-26 Last modified: 2016-01-28

Priority: 3

View all other issues in [re.alg.replace].

View all issues with New status.

Discussion:

>     template <class traits, class charT, class ST, class SA>
>       basic_string<charT, ST, SA>
>       regex_replace(const basic_string<charT, ST, SA>& s,
>           const basic_regex<charT, traits>& e,
>           const charT* fmt,
>           regex_constants::match_flag_type flags =
>     	    regex_constants::match_default);

and friends are documented as

> Constructs an empty string result of type `basic_string<charT, ST, SA>` and calls `regex_replace(back_inserter(result), s.begin(), s.end(), e, fmt, flags)`.

This appears to require the result to have a default-constructed allocator, which isn't even possible for all allocator types. I suspect the allocator should be copied from 's' instead. Possibly there should be an additional defaulted argument to override the allocator of the result.

Proposed resolution:

### 2220(i). Under-specification of `operator==` for `regex_token_iterator`

Section: 30.11.2.3 [re.tokiter.comp] Status: Open Submitter: Pete Becker Opened: 2012-11-21 Last modified: 2018-08-23

Priority: 3

View all issues with Open status.

Discussion:

Consider the following example:

>     std::string str0("x");
>     std::regex rg0("a");
>     std::regex_token_iterator it0(str0.begin(), str0.end(), rg0, -1); // points at "x" in str0
>     std::string str1("x");
>     std::regex rg1("b");
>     std::regex_token_iterator it1(str1.begin(), str1.end(), rg1, -1); // points at "x" in str1

30.11.2.3 [re.tokiter.comp] p1 says that `it0.operator==(it1)` returns true "if `*this` and `right` are both suffix iterators and `suffix == right.suffix`"; both conditions are satisfied in this example. It does not say that they must both be iterators into the same sequence, nor does it say (as general iterator requirements do) that they must both be in the domain of `==` in order for the comparison to be meaningful. It's a simple statement: they're equal if the strings they point at compare equal. Given this being a valid comparison, the obtained result of "true" looks odd.

The problem is that for iterator values prior to the suffix iterator, equality means the same regular expression and the same matched sequence (both uses of "same" refer to identity, not equality); for the suffix iterator, equality means that the matched sequences compare equal.

[2014-02-10]

Priority set to 2

[2018-08-20 Casey adds a proposed resolution]

Priority changed to 3.

Marshall notes that iterator comparisons typically require the iterators to denote elements of the same sequence.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4762.

> - Modify 30.11.2.3 [re.tokiter.comp] as follows:

>   >     bool operator==(const regex_token_iterator& right) const;

>   > -?- Expects: `*this` and `right` are both end-of-sequence iterators or both have the same underlying sequence.

>   > -1- Returns: `true` if `*this` and `right` are both end-of-sequence iterators, or if […]

>   >     bool operator!=(const regex_token_iterator& right) const;

>   > -?- Expects: `*this` and `right` are both end-of-sequence iterators or both have the same underlying sequence.

>   > -2- Returns: `!(*this == right)`.

[2018-08-23 Casey revises the P/R in response to LWG feedback]

Proposed resolution:

This wording is relative to N4762.

- Modify 30.11.2.3 [re.tokiter.comp] as follows:

  >     bool operator==(const regex_token_iterator& right) const;

  > -?- Expects: At least one of `*this` and `right` is an end-of-sequence iterator, or both `*this` and `right` have the same underlying sequence.

  > -1- Returns: `true` if `*this` and `right` are both end-of-sequence iterators, or if […]

  >     bool operator!=(const regex_token_iterator& right) const;

  > -?- Expects: At least one of `*this` and `right` is an end-of-sequence iterator, or both `*this` and `right` have the same underlying sequence.

  > -2- Returns: `!(*this == right)`.

### 2227(i). Stateful comparison objects in associative containers

Section: 22.2.6 [associative.reqmts] Status: Open Submitter: Juan Soulie Opened: 2012-12-19 Last modified: 2019-04-23

Priority: 3

View other active issues in [associative.reqmts].

View all other issues in [associative.reqmts].

View all issues with Open status.

Discussion:

Table 102 in 22.2.6 [associative.reqmts]/8 states on expression `a.key_comp()` that it "returns the comparison object out of which a was constructed". At the same time, 22.2.1 [container.requirements.general]/8 states (starting in the third line) that "...Any `Compare`, `Pred`, or `Hash` objects belonging to `a` and `b` shall be swappable and shall be exchanged by unqualified calls to non-member swap...". This is problematic for any compliant implementation, since once swapped the container cannot return the comparison object out of which it was constructed unless incurring in storing an otherwise needless object.

The simple solution is to correct that statement in Table 102, but I believe this is part of a larger problem of underspecified behavior: The new standard has made an effort in regards to allocators and now fully specifies what happens to stateful allocator objects. It has even specified what happens to stateful `hasher` and `key_equal` members of unordered containers (they propagate), but it says nothing about stateful comparison objects of (ordered) associative containers, except for the statement in 22.2.1 [container.requirements.general]/8 referred above and only related to `swap`.

For example, it is unclear to me what is specified to happen on an assignment: should the comparison object be copied/moved along with the elements, or should the left-hand side object keep its own? Maybe this has been intentionally left unspecified with the purpose of compatibility with C++98, which I understand it specified that comparison objects were kept for the entire life of the container (like allocators) — an unfortunate choice. But anyway, the segment of 22.2.1 [container.requirements.general] quoted above seems to break any possible backwards compatibility with C++98 in this regard.

Therefore, taking into consideration consistency with how this is dealed with for unordered associative containers, I propose that Table 102 is modified as follows:

- The row for expression `a.key_comp()` is changed so that its "assertion/note pre-/post-condition" reads "Returns `a`'s comparison object."

- A new row is added at the appropriate location (which I believe would be after "X(il)" row), with:

  > Table 102 — Associative container requirements (in addition to container)
  > Expression | Return type | Assertion/note pre-/post-condition | Complexity
  > --- | --- | --- | ---
  > `X(b) X a(b)` | `X` | Copy constructor. In addition to the requirements of Table 96, copies the comparison object. | Linear in `b.size()`
  > `a = b` | `X&` | Copy assignment operator. In addition to the requirements of Table 96, copies the comparison object. | Linear in `a.size()` and `b.size()`

[2013-03-15 Issues Teleconference]

Moved to Review.

[2013-04-18, Bristol]

STL: can't believe we don't specify this already. this is totally necessary

Alisdair: how does it do this? copy construction? assignment?

Also need it for move.

STL: we already specify this for constructing from a comparator, not during copy construction though.

Jonathan: don't like wording, should say "`key_compare` is `CopyConstructible`. Uses `b.key_comp()` as a comparison object."

STL: we get it right for unordered!

Jonathan: can't wordsmith this now, but I think implementations do the right thing.

Alisdair: not sure what right thing is for moves. Also we say nothing about propagating allocators to functors.

Moved to Open.

[2015-02 Cologne]

TK: There's no need for fine-grained propagate/not-propagate control. If you don't want to propagate the predicate, you can simply construct or insert from an iterator range.

VV: libstdc++ already implements the resolution of this issue.

GR: There are a couple of other problems. We don't specify move constructor and move assignment for maps. Those are just general.

TK: General container requirements already describe the semantics for {copy,move}-{construction,assignment}, so it doesn't seem that there's room for choice in `std::map` assignments. `unordered_map` is different, though.

[Note: Check what general container requirements say about container equality.]

DK will draft wording. The decision is to unambiguously make all {copy,move}-{construction,assignment} operations endow the LHS with the exact state of the RHS, including all predicates and hash function states.

Conclusion: Update wording, revisit later.

[2015-05-06 Lenexa: Waiting for updated wording]

Previous resolution [SUPERSEDED]:

> This wording is relative to N3485.

> 1. Change Table 102 as indicated:

>    > Table 102 — Associative container requirements (in addition to container)
>    > Expression | Return type | Assertion/note pre-/post-condition | Complexity
>    > --- | --- | --- | ---
>    > `…`
>    > `X(il)` | `` | Same as `X(il.begin(), il.end())`. | same as `X(il.begin(), il.end())`.
>    > `X(b) X a(b)` | `` | Copy constructor. In addition to the requirements of Table 96, copies the comparison object. | Linear in `b.size()`
>    > `a = b` | `X&` | Copy assignment operator. In addition to the requirements of Table 96, copies the comparison object. | Linear in `a.size()` and `b.size()`
>    > `…`
>    > `a.key_comp()` | `X::key_compare` | r Returns the `a`'s comparison object out of which a was constructed. | constant

[2015-10-19 Daniel comments and provides alternative wording]

The current standard is especially unclear in regard to what effects move operations of unordered/associative containers should have. We have one example that is standardized exactly in this way by looking at 22.6.5.3 [priqueue.cons.alloc] p7:

>     template <class Alloc> priority_queue(priority_queue&& q, const Alloc& a);

> > -7- Effects: Initializes `c` with `std::move(q.c)` as the first argument and `a` as the second argument, and initializes `comp` with `std::move(q.comp)`

A similarly comparable example are the move-operations of `std::unique_ptr` in regard to the deleter (when this is no a reference), which also respect move-capabilities of that function object.

We have wording from C++98 for associative containers (but not for unordered containers!) that was never adjusted to C++11 move-semantics in 22.2.6 [associative.reqmts] p12:

> When an associative container is constructed by passing a comparison object the container shall not store a pointer or reference to the passed object, even if that object is passed by reference. When an associative container is copied, either through a copy constructor or an assignment operator, the target container shall then use the comparison object from the container being copied, as if that comparison object had been passed to the target container in its constructor.

The second sentence of this wording is problematic for several reasons:

1. It only talks about copy operations, not about move operations, except that the term "assignment" without leading "copy" is a bit ambigious (albeit it seems clear in the complete context).

2. It is not really clear how to interpret "as if that comparison object had been passed to the target container in its constructor" for an assignment operation. A possible but not conclusive interpretation could be that this is wording supporting a "copy-via-swap" idiom.

3. There does not exist similar wording for unordered containers, except that Table 102 provides entries for copy construction and copy assignment of the containers whose wording just talks of "copies" in either case.

Existing implementations differ already:

1. Visual Studio 2015 uses copy construction and copy assignment for the two copy operations but uses swap operations for the move operations.

2. GCC's libstdc++ performs copy construction and copy assignment for the two copy operations and for the two move operations, respectively

3. clang++'s libc++ performs copy/move construction and copy/move assignment for the corresponding four copy/move operations

The alternative wording provided below attempts to clarify that container copy/move operations perform the corresponding copy/move operations on the owned function objects.

In addition the wording also resolves LWG 2215: I believe that the current wording should require that container function objects should meet the `CopyConstructible` requirements. Adding this general requirement also fixes the underspecified requirements of the accessor functions `key_comp()` and `value_comp()`.

I don't think that a general requirement for `Swappable` is needed, only the member `swap` function currently requires this. Nonetheless the wording below does support stateful functors that are also moveable or move-assignable, therefore the specified semantics in terms of move operations.

I should add the following warning, though: If this proposed wording would be accepted, there is a little chance of code breakage, because the current wording can be read that in general there is no requirement that the container functors are `CopyConstructible`. The following code example is accepted by gcc + libstd++:

>     #include <map>
>     #include <utility>
>     #include <iostream>

>     struct Cmp {
>       Cmp() = default;
>       Cmp(const Cmp&) = delete;
>       Cmp(Cmp&&) = delete;
>       Cmp& operator=(const Cmp&) = delete;
>       Cmp& operator=(Cmp&&) = delete;
>       template<class T>
>       bool operator()(const T& x, const T& y) const
>       {
>         return x < y;
>       }
>     };

>     typedef std::map<int, int, Cmp> MyMap;

>     int main() {
>       MyMap m;
>       std::cout << (m.find(12) == m.end()) << std::endl;
>     }

Previous resolution [SUPERSEDED]:

> This wording is relative to N4527.

> 1. Change 22.2.6 [associative.reqmts] p8 as indicated:

>    > -8- In Table 101, `X` denotes an associative container class, `a` denotes a value of type `X`, `b` denotes a possibly `const` value of type `X`, `rv` denotes a non-`const` rvalue of type `X`, `u` denotes the name of a variable being declared, […]

> 2. Change Table 101 as indicated:

>    > Table 101 — Associative container requirements (in addition to container)
>    > Expression | Return type | Assertion/note pre-/post-condition | Complexity
>    > --- | --- | --- | ---
>    > `…`
>    > `X::key_compare` | `Compare` | Requires: `Compare` is `CopyConstructible`. defaults to `less<key_type>` | compile time
>    > `X(c) X u(c);` | `` | Requires: `key_compare` is `CopyConstructible`. Effects: Constructs an empty container. Uses a copy of `c` as a comparison object. | […]
>    > `…`
>    > `X(i,j,c) X u(i,j,c);` | `` | Requires: `key_compare` is `CopyConstructible`. `value_type` is `EmplaceConstructible` into `X` from `*i`. Effects: Constructs an empty container and inserts elements from the range `[i, j)` into it; uses `c` as a comparison object. | […]
>    > `…`
>    > `X(il)` | `` | Same as `X(il.begin(), il.end())`. | same as `X(il.begin(), il.end())`.
>    > `X(b) X a(b)` | `` | (In addition to the requirements of Table 95) Effects: Copy constructs the comparison object of `a` from the comparison object of `b`. | Linear in `b.size()`
>    > `X(rv) X a(rv)` | `` | (In addition to the requirements of Table 95 and Table 98) Effects: Move constructs the comparison object of `a` from the comparison object of `rv`. | constant
>    > `a = b` | `X&` | (In addition to the requirements of Table 95 and Table 98) Requires: `key_compare` is `CopyAssignable`. Effects: Copy assigns the comparison object of `b` to the comparison object of `a`. | Linear in `a.size()` and `b.size()`
>    > `a = rv` | `X&` | (In addition to the requirements of Table 95 and Table 98) Requires: `key_compare` is `MoveAssignable`. Effects: Move assigns from the comparison object of `rv` to the comparison object of `a`. | Linear
>    > `…`
>    > `a.key_comp()` | `X::key_compare` | r Returns the `a`'s comparison object out of which a was constructed. | constant

> 3. Change 22.2.6 [associative.reqmts] p12 as indicated:

>    > -12- When an associative container is constructed by passing a comparison object the container shall not store a pointer or reference to the passed object, even if that object is passed by reference. When an associative container is copied, either through a copy constructor or an assignment operator, the target container shall then use the comparison object from the container being copied, as if that comparison object had been passed to the target container in its constructor.

> 4. Change 22.2.7 [unord.req] p11 as indicated:

>    > -11- In Table 102: `X` denotes an unordered associative container class, `a` denotes a value of type `X`, `b` denotes a possibly `const` value of type `X`, `rv` denotes a non-`const` rvalue of type `X`, […]

> 5. Change Table 102 as indicated:

>    > Table 102 — Unordered associative container requirements (in addition to container)
>    > Expression | Return type | Assertion/note pre-/post-condition | Complexity
>    > --- | --- | --- | ---
>    > `…`
>    > `X::hasher` | `Hash` | Requires: `Hash` is `CopyConstructible`. `Hash` shall be a unary function object type such that the expression `hf(k)` has type `std::size_t`. | compile time
>    > `X::key_equal` | `Pred` | Requires: `Pred` is `CopyConstructible`. `Pred` shall be a binary predicate that takes two arguments of type `Key`. `Pred` is an equivalence relation. | compile time
>    > `…`
>    > `X(n, hf, eq) X a(n, hf, eq)` | `X` | Requires: `hasher` and `key_equal` are `CopyConstructible`. Effects: […] | […]
>    > `X(n, hf) X a(n, hf)` | `X` | Requires: `hasher` is `CopyConstructible` and `key_equal` is `DefaultConstructible`. Effects: […] | […]
>    > `…`
>    > `X(i, j, n, hf, eq) X a(i, j, n, hf, eq)` | `X` | Requires: `hasher` and `key_equal` are `CopyConstructible`. `value_type` is `EmplaceConstructible` into `X` from `*i`. Effects: […] | […]
>    > `X(i, j, n, hf) X a(i, j, n, hf)` | `X` | Requires: `hasher` is `CopyConstructible` and `key_equal` is `DefaultConstructible`. `value_type` is `EmplaceConstructible` into `X` from `*i`. Effects: […] | […]
>    > `…`
>    > `X(b) X a(b)` | `X` | Copy constructor. In addition to the requirements of Table 95, copies the hash function, predicate, and maximum load factor. (In addition to the requirements of Table 95) Effects: Copy constructs the hash function, predicate, and maximum load factor of `a` from the corresponding objects of `b`. | Average case linear in `b.size()`, worst case quadratic.
>    > `X(rv) X a(rv)` | `X` | (In addition to the requirements of Table 95 and Table 98) Effects: Move constructs the hash function, predicate, and maximum load factor of `a` from the corresponding objects of `rv`. | constant
>    > `a = b` | `X&` | Copy assignment operator. In addition to the requirements of Table 95, copies the hash function, predicate, and maximum load factor. (In addition to the requirements of Table 95 and Table 98) Requires: `hasher` and `key_equal` are `CopyAssignable`. Effects: Copy assigns the hash function, predicate, and maximum load factor of `b` to the corresponding objects of `a`. | Average case linear in `b.size()`, worst case quadratic.
>    > `a = rv` | `X&` | (In addition to the requirements of Table 95 and Table 98) Requires: `hasher` and `key_equal` are `MoveAssignable`. Effects: Move assigns the hash function, predicate, and maximum load factor from `rv` to the corresponding objects of `a`. | Linear
>    > `…`

[2016-08-07]

Daniel removes the previously proposed wording to work on revised wording.

[2019-04-22, Billy comments]

In addition to the Cpp17CopyConstructible discussion going on there, I think we need to require that calling the comparison function when `Compare` itself is `const` needs to produce the same answer as if `Compare` is non-`const`.

Proposed resolution:

### 2236(i). `kill_dependency` unconditionally noexcept

Section: 31.2 [atomics.syn], 31.4 [atomics.order] Status: SG1 Submitter: Daniel Krügler Opened: 2013-01-19 Last modified: 2016-01-28

Priority: Not Prioritized

View other active issues in [atomics.syn].

View all other issues in [atomics.syn].

View all issues with SG1 status.

Discussion:

The "magic" `kill_dependency` function is a function without any constraints on the template parameter `T` and is specified as

>     template <class T>
>     T kill_dependency(T y) noexcept;

> > -14- Effects: The argument does not carry a dependency to the return value (1.10).

> > -15- Returns: `y`.

I wonder whether the unconditional `noexcept` is really intended here: Assume we have some type `U` that has a potentially throwing move constructor (or it has a potentially throwing copy constructor and no move constructor), for any "normal" function template with the same signature and the same effects (modulo the dependency magic) this would mean that it cannot safely be declared `noexcept` because of the return statement being part of the complete function call affected by `noexcept` (The by-value function argument is irrelevant in this context). In other words it seems that a function call such as

>     struct S {
>       ...
>       S(const S& r) { if(some condition) throw Something(); }
>       ...
>     };

>     int main() {
>       S s1 = ...;
>       S s2 = std::kill_dependency(s1);
>     }

would be required to call `std::terminate` if the copy constructor of `S` throws during the return of `std::kill_dependency`.

To require copy elision for this already magic function would look like a low-hanging fruit to solve this problem, but this case is not covered by current copy elision rules see 12.8 p31 b1:

"— in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function's return value".

Some options come into my mind:

1. Make the exception-specification a constrained one in regard via `std::is_nothrow_move_constructible`:

   >     template <class T>
   >     T kill_dependency(T y) noexcept(see below);

   This is similar to the approach taken for function templates such as `std::swap`.

2. Use perfect forwarding (This needs further wording to correct the effects):

   >     template <class T>
   >     T&& kill_dependency(T&& y) noexcept;

3. Impose constraints on the template arguments in regard to throwing exceptions while copying/moving.

4. Keep the state as it is but possibly add a note about a call of `std::terminate` in above scenario.

A second problem is that the current wording is not clear whether it is well-defined to call the function with types that are reference types, such as in the following example:

>     #include <atomic>

>     int main()
>     {
>       int a = 12;
>       int& b = std::kill_dependency<int&>(a);
>     }

It is unclear what kind of dependency is killed here. This is presumably a core language problem, but could affect the possible resolutions of the problem.

[2014-11 Urbana]

Recommend using a revised example:

>     int lookup(class D* p)
>     {
>       class E* q = p->a.load(memory_order_consume);
>       int y = std::kill_dependency(q->y);
>     }

[2015-02 Cologne]

Handed over to SG1.

Proposed resolution:

### 2237(i). `<cuchar>` macros

Section: 21.5 [c.strings] Status: New Submitter: Jason Merrill Opened: 2013-01-29 Last modified: 2016-01-28

Priority: 4

View other active issues in [c.strings].

View all other issues in [c.strings].

View all issues with New status.

Discussion:

Apparently C1X changes `__STDC_UTF_16__` and `__STDC_UTF_32__` from macros defined in `uchar.h` (and reflected in C++ by Table 79) to be predefined by the compiler. Do we want to do the same?

Proposed resolution:

### 2238(i). Problematic iterator-pair constructor of containers

Section: 21.5 [c.strings] Status: Open Submitter: Johannes Schaub Opened: 2013-02-02 Last modified: 2016-08-09

Priority: 3

View other active issues in [c.strings].

View all other issues in [c.strings].

View all issues with Open status.

Discussion:

The non-explicit nature of the iterator-pair constructor of containers, such a

>     template <class InputIterator>
>     vector(InputIterator first, InputIterator last, const Allocator& = Allocator());

can be selected in unexpected situations, leading to a hard runtime error, as demonstrated by the following example:

>     #include <vector>

>     void f(std::vector<char> v){ /* ... */}

>     int main() {
>       f({"A", "B"});
>     }

The actually intended initializer-list constructor isn't feasible here, so the best match is the constructor template

>     template <class InputIterator>
>     vector(InputIterator first, InputIterator last, const Allocator& = Allocator());

This compiles, but will result in code running amok. The potential trap (that cannot be easily detected by the library implementation) could be reduced by making this constructor explicit. It would still have the effect to be selected here, but the code would be ill-formed, so the programmer gets a clear message here.

[2014-06 Rapperswil]

JW: can't fix this, don't want to touch this, Do The Right Thing clause has been a source of tricky issues. only really happens with string literals, that's the only way to create an array that isn't obviously an array

GR: want to see paper

AM: is it only string literals, or also UDLs?

STL: maybe, but we don't need to deal with that. This is only a problem in a very specific case

Leave as Open.

Proposed resolution:

### 2248(i). `numeric_limits::is_iec559` misnamed

Section: 17.3.5 [numeric.limits] Status: New Submitter: Pete Becker Opened: 2013-03-08 Last modified: 2018-11-08

Priority: 4

View other active issues in [numeric.limits].

View all other issues in [numeric.limits].

View all issues with New status.

Discussion:

This member should probably be named "is_ieee754". Or at least the standard should explain that IEC-559 no longer exists, and that it's been superseded by IEEE-754.

[2016-06, Oulu]

The ISO version of the standard is ISO/IEC/IEEE 60559:2011, which C11 Annex F refers to as IEC 60559 (although C still refers to it as IEC 559 in the `__STDC_IEC_559__` macro).

Proposed resolution:

### 2262(i). Requirement for `unique_ptr<T>::get_deleter()(p)` to be able to destroy the `unique_ptr`

Section: 20.11.1.3 [unique.ptr.single] Status: Open Submitter: Rob Desbois Opened: 2013-05-15 Last modified: 2017-03-21

Priority: 3

View other active issues in [unique.ptr.single].

View all other issues in [unique.ptr.single].

View all issues with Open status.

Discussion:

N3337 20.11.1.3.6 [unique.ptr.single.modifiers] contains 2 non-normative notes stating:

> [para 4]: "The order of these operations is significant because the call to `get_deleter()` may destroy `*this`."

> [para 5]: "The postcondition does not hold if the call to `get_deleter()` destroys `*this` since `this->get()` is no longer a valid expression."

It seems this wording was created to resolve 998 due to the possibility that a `unique_ptr` may be destroyed through deletion of its stored pointer where that directly or indirectly refers to the same `unique_ptr`. If `unique_ptr` is required to support circular references then it seems this must be normative text: an implementation is currently allowed to operate on `*this` after the assignment and deletion specified in para 4, since this is only 'disallowed' by the non-normative note.

I propose the following draft rewording:

[para 4]: Effects: assigns `p` to the stored pointer, and then if the old value of the stored pointer, `old_p`, was not equal to `nullptr`, calls `get_deleter()(old_p)`. No operation shall be performed after the call to `get_deleter()(old_p)` that requires `*this` to be valid, because the deletion may destroy `*this` if it is referred to directly or indirectly by the stored pointer. [Note: The order of these operations is significant because the call to `get_deleter()` may destroy `*this`. — end note]

[para 5]: Postconditions: If the call `get_deleter()(old_p)` destroyed `*this`, none. Otherwise, `get() == p`. [Note: The postcondition does not hold if the call to `get_deleter()` destroys `*this` since `this->get()` is no longer a valid expression. — end note]

I expect it will also be necessary to amend the requirements for a deleter, so in addition:

20.11.1.3 [unique.ptr.single] [para 1]: The default type for the template parameter `D` is `default_delete`. A client-supplied template argument `D` shall be a function object type (20.10), lvalue-reference to function, or lvalue-reference to function object type for which, given a value `d` of type `D` and a value `ptr` of type `unique_ptr<T, D>::pointer`, the expression `d(ptr)` is valid and has the effect of disposing of the pointer as appropriate for that deleter. Where `D` is not an lvalue reference type, `d(ptr)` shall be valid if `ptr` refers directly or indirectly to the invoking `unique_ptr` object.

[2013-10-05, Stephan T. Lavavej comments and provides alternative wording]

In Chicago, we determined that the original proposed change to 20.11.1.3 [unique.ptr.single]/1 was insufficient, because `d` might be a reference to a deleter functor that's destroyed during self-destruction.

We believed that 20.11.1.3.6 [unique.ptr.single.modifiers]/4 was already sufficiently clear. The Standard occasionally prevents implementations of `X` from doing various things, through the principle of "nothing allows `X` to fail in that situation". For example, `v.push_back(v[0])` is required to work for non-empty vectors because nothing allows that to fail. In this case, the intent to allow self-destruction is already clear.

Additionally, we did not believe that 20.11.1.3.6 [unique.ptr.single.modifiers]/5 had to be changed. The current note is slightly squirrely but it does not lead to confusion for implementers or users.

Previous resolution from Rob Desbois:

> 1. Edit 20.11.1.3 [unique.ptr.single] p1 as indicated:

>    > The default type for the template parameter `D` is `default_delete`. A client-supplied template argument `D` shall be a function object type (20.10), lvalue-reference to function, or lvalue-reference to function object type for which, given a value `d` of type `D` and a value `ptr` of type `unique_ptr<T, D>::pointer`, the expression `d(ptr)` is valid and has the effect of disposing of the pointer as appropriate for that deleter. Where `D` is not an lvalue reference type, `d(ptr)` shall be valid if `ptr` refers directly or indirectly to the invoking `unique_ptr` object.

> 2. Edit 20.11.1.3.6 [unique.ptr.single.modifiers] p4+5 as indicated:

>    >     void reset(pointer p = pointer()) noexcept;

>    > > -3- Requires: The expression `get_deleter()(get())` shall be well formed, shall have well-defined behavior, and shall not throw exceptions.

>    > > -4- Effects: assigns `p` to the stored pointer, and then if the old value of the stored pointer, `old_p`, was not equal to `nullptr`, calls `get_deleter()(old_p)`. No operation shall be performed after the call to `get_deleter()(old_p)` that requires `*this` to be valid, because the deletion may destroy `*this` if it is referred to directly or indirectly by the stored pointer. [Note: The order of these operations is significant because the call to `get_deleter()` may destroy `*this`. — end note]

>    > > -5- Postconditions: If the call `get_deleter()(old_p)` destroyed `*this`, none. Otherwise, `get() == p`. [Note: The postcondition does not hold if the call to `get_deleter()` destroys `*this` since `this->get()` is no longer a valid expression. — end note]

Previous resolution [SUPERSEDED]:

> This wording is relative to N3691.

> 1. Edit 20.11.1.3 [unique.ptr.single] p1 as indicated:

>    > The default type for the template parameter `D` is `default_delete`. A client-supplied template argument `D` shall be a function object type (20.10), lvalue-reference to function, or lvalue-reference to function object type for which, given a value `d` of type `D` and a value `ptr` of type `unique_ptr<T, D>::pointer`, the expression `d(ptr)` is valid and has the effect of disposing of the pointer as appropriate for that deleter. `d(ptr)` shall be valid even if it triggers the destruction of `d` or (if `D` is an lvalue reference to function object type) the function object that `d` refers to.

[2015-05, Lenexa]

After some discussion in Lenexa there was some wavering on if the added sentence is necessary. Here is example code that demonstrates why the extra sentence is necessary. In this example the call to `d(ptr)` is valid, however the deleter references `*this` after destructing its element:

>     #include <cassert>
>     #include <memory>
>     #include <iostream>

>     class Deleter
>     {
>         int state_ = 0;

>         enum
>         {
>             destructed            = -4,
>             self_move_assigned    = -3,
>             move_assigned_from    = -2,
>             move_constructed_from = -1
>         };
>     public:
>         ~Deleter() {state_ = destructed;}

>         Deleter() = default;
>         Deleter(Deleter const&) = default;
>         Deleter& operator=(Deleter const&) = default;

>         Deleter(Deleter&& a) noexcept
>             : state_(a.state_)
>         {a.state_ = move_constructed_from;}

>         Deleter& operator=(Deleter&& a) noexcept
>         {
>             if (this == &a)
>                 state_ = self_move_assigned;
>             else
>             {
>                 state_ = a.state_;
>                 a.state_ = move_assigned_from;
>             }
>             return *this;
>         }

>         Deleter(int state)
>             : state_(state)
>         {
>             assert(state >= 0);
>         }

>         template <class T>
>         void
>         operator()(T* t) const
>         {
>             std::cout << "Deleter beginning operator()(T*)\n";
>             std::cout << "The deleter = " << *this << '\n';
>             std::cout << "Deleter about to destruct the X.\n";
>             delete t;
>             std::cout << "Deleter has destructed the X.\n";
>             std::cout << "The deleter = " << *this << '\n';
>             std::cout << "Deleter ending operator()(T*)\n";
>         }

>         friend
>         std::ostream&
>         operator<<(std::ostream& os, const Deleter& a)
>         {
>             switch (a.state_)
>             {
>             case destructed:
>                 os << "**destructed**";
>                 break;
>             case self_move_assigned:
>                 os << "self_move_assigned";
>                 break;
>             case move_assigned_from:
>                 os << "move_assigned_from";
>                 break;
>             case move_constructed_from:
>                 os << "move_constructed_from";
>                 break;
>             default:
>                 os << a.state_;
>                 break;
>             }
>             return os;
>         }
>     };

>     struct X
>     {
>         Deleter deleter_{1};
>     };

>     int main()
>     {
>         auto xp = new X;
>         {
>             std::unique_ptr<X, Deleter&> p(xp, xp->deleter_);
>             std::cout << "unique_ptr is constructed.\n";
>             std::cout << "The deleter = " << p.get_deleter() << '\n';
>             std::cout << "Destructing unique_ptr...\n";
>         }
>         std::cout << "unique_ptr is destructed.\n";
>     }

Which outputs:

>     unique_ptr is constructed.
>     The deleter = 1
>     Destructing unique_ptr...
>     Deleter beginning operator()(T*)
>     The deleter = 1
>     Deleter about to destruct the X.
>     Deleter has destructed the X.
>     The deleter = **destructed**
>     Deleter ending operator()(T*)
>     unique_ptr is destructed.

The line "`The deleter = **destructed**`" represents the deleter referencing itself after it has been destructed by the `d(ptr)` expression, but prior to that call returning.

Suggested alternative to the current proposed wording:

> The expression `d(ptr)` shall not refer to the object `d` after it executes `ptr->~T()`.

[2015-07, Telecon]

Geoffrey: Deleter may or may not execute ~T().
Alisdair: After the destructor after the element has run. Say it in words instead of code.
Howard will provide updated wording. Perhaps need both normative and non-normative wording.

[2015-08-03, Howard updates P/R per telecon discussion.]

[2017-03-04, Kona]

This is related to 2751, which has been suggested NAD.

STL wants "Effects equivalent to" here - say it in code. Marshall to research.

Proposed resolution:

This wording is relative to N4431.

1. Edit 20.11.1.3 [unique.ptr.single] p1 as indicated:

   > The default type for the template parameter `D` is `default_delete`. A client-supplied template argument `D` shall be a function object type (20.9), lvalue-reference to function, or lvalue-reference to function object type for which, given a value `d` of type `D` and a value `ptr` of type `unique_ptr<T, D>::pointer`, the expression `d(ptr)` is valid and has the effect of disposing of the pointer as appropriate for that deleter. The expression `d(ptr)`, if it destructs the object referred to by `ptr`, shall not refer to the object `d` after it destructs `*ptr`. [Note: The object being destructed may control the lifetime of `d`. — end note]

### 2265(i). 29.3p9 appears to rule out some acceptable executions

Section: 31.4 [atomics.order] Status: Open Submitter: Brian Demsky Opened: 2013-06-17 Last modified: 2016-01-28

Priority: 4

View other active issues in [atomics.order].

View all other issues in [atomics.order].

View all issues with Open status.

Discussion:

I believe that the following variation on IRIW should admit executions in which `c1 = d1 = 5` and `c2 = d2 = 0`. If this is allowed, then what is sequence of program evaluations for 31.4 [atomics.order] p9 that justifies the store to `z`? It seems that 31.4 [atomics.order] p9 should not allow this execution because one of the stores to `x` or `y` has to appear earlier in the sequence, each of the `fetch_adds` reads the previous load in the thread (and thus must appear later in the sequence), and 31.4 [atomics.order] p9 states that each load must read from the last prior assignment in the sequence.

>     atomic_int x;
>     atomic_int y;
>     atomic_int z;
>     int c1, c2, d1, d2;

>     static void a(void* obj)
>     {
>       atomic_store_explicit(&x, 5, memory_order_relaxed);
>     }

>     static void b(void* obj)
>     {
>       atomic_store_explicit(&y, 5, memory_order_relaxed);
>     }

>     static void c(void* obj)
>     {
>       c1 = atomic_load_explicit(&x, memory_order_relaxed);
>       // this could also be an atomic load if the address depends on c1:
>       c2 = atomic_fetch_add_explicit(&y, c1, memory_order_relaxed);
>     }

>     static void d(void* obj)
>     {
>       d1 = atomic_load_explicit(&y, memory_order_relaxed);
>       d2 = atomic_fetch_add_explicit(&x, d1, memory_order_relaxed);
>     }

>     int user_main(int argc, char** argv)
>     {
>       thrd_t t1, t2, t3, t4;

>       atomic_init(&x, 0);
>       atomic_init(&y, 0);

>       printf("Main thread: creating 4 threads\n");
>       thrd_create(&t1, (thrd_start_t)&a, NULL);
>       thrd_create(&t2, (thrd_start_t)&b, NULL);
>       thrd_create(&t3, (thrd_start_t)&c, NULL);
>       thrd_create(&t4, (thrd_start_t)&d, NULL);

>       thrd_join(t1);
>       thrd_join(t2);
>       thrd_join(t3);
>       thrd_join(t4);
>       printf("c1=%d c2=%d\n",c1,c2);
>       printf("d1=%d d2=%d\n",d1,d2);

>       // Can this store write 1000 (i.e., c1=d1=5, c2=d2=0)?
>       atomic_store(&z, (c1+d1)*100+c2+d2);

>       printf("Main thread is finished\n");

>       return 0;
>     }

It seems that the easiest fix is to allow a load in 31.4 [atomics.order] p9 to read from any prior store in the evaluation order.

That said, I would personally advocate the following: It seems to me that C/C++ atomics are in a bit of different situation than Java because:

1. People are expected to use relaxed C++ atomics in potentially racy situations, so it isn't clear that semantics as complicated as the JMM's causality would be sane.

2. People who use C/C++ atomics are likely to be experts and use them in a very controlled fashion. I would be really surprised if compilers would find any real wins by optimizing the use of atomics.

Why not do something like:

There is satisfaction DAG of all program evaluations. Each evaluation observes the values of variables as computed by some prior assignment in the DAG.

There is an edge `x->y` between two evaluations `x` and `y` if:

1. the evaluation `y` observes a value computed by the evaluation `x` or

2. the evaluation `y` is an atomic store, the evaluation `x` is an atomic load, and there is a condition branch c that may depend (intrathread dependence) on `x` and `x-sb->c` and `c-sb->y`.

This seems to allow reordering of relaxed atomics that processors do without extra fence instructions, allows most reorderings by the compiler, and gets rid of satisfaction cycles.

[2015-02 Cologne]

Handed over to SG1.

[2015-05 Lenexa, SG1 response]

This was partially addressed (weasel-worded) in C++14 (See N3786). The remainder is an open research problem. N3710 outlines a "solution" that doesn't have a consensus behind it because it costs performance. We have no better solution at the moment.

Proposed resolution:

### 2267(i). `partial_sort_copy` underspecified for ranges of two different types

Section: 25.8.2.4 [partial.sort.copy] Status: New Submitter: Matt Austern Opened: 2013-06-26 Last modified: 2016-01-28

Priority: 3

View all issues with New status.

Discussion:

The signature of this function is:

>     template<class InputIterator, class RandomAccessIterator>
>     RandomAccessIterator
>     partial_sort_copy(InputIterator first, InputIterator last,
>                       RandomAccessIterator result_first,
>                       RandomAccessIterator result_last);

(and the usual overload for an explicitly provided comparison function). The standard says nothing about requirements in the case where the input type (`iterator_traits<InputIterator>::value_type`) and the output type (`iterator_traits<RandomAccessIterator>::value_type`) are different.

Presumably the input type must be convertible to the output type. What's less clear is what the requirements are on the comparison operator. Does the algorithm only perform comparisons on two values of the output type, or does it also perform comparisons on values of the input type, or might it even perform heterogeneous comparisons?

Proposed resolution:

### 2269(i). Container iterators and argument-dependent lookup

Section: 22.2.1 [container.requirements.general] Status: New Submitter: Matt Austern Opened: 2013-06-26 Last modified: 2016-01-28

Priority: 4

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

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

View all issues with New status.

Discussion:

Consider the following code snippet:

>     #include <vector>
>     #include <algorithm>

>     int main() {
>       std::vector<int> v1(100, 3);
>       std::vector<int> v2(100);
>       copy(v1.begin(), v1.end(), v2.begin());
>     }

It compiles without error on my desktop. Is it required to? I can't find evidence from the standard that it is. In my test `std::copy` was found by argument-dependent lookup because the implementation I used made `std::vector<int>::iterator` a user-defined type defined in namespace `std`. But the standard only requires `std::vector<int>::iterator` to be an implementation specified random access iterator type. I can't find anything requiring it to be a user-defined type at all (and in fact there are reasonable implementation where it isn't), let alone a user defined type defined in a specific namespace.

Since the defining namespace of container iterators is visible to users, should the standard say anything about what that namespace is?

Proposed resolution:

### 2286(i). `stringbuf::underflow()` underspecified

Section: 29.8.2.5 [stringbuf.virtuals] Status: Open Submitter: Sergey Zubkov Opened: 2013-08-29 Last modified: 2018-06-12

Priority: 4

View other active issues in [stringbuf.virtuals].

View all other issues in [stringbuf.virtuals].

View all issues with Open status.

Discussion:

In 29.8.2.5 [stringbuf.virtuals]/1, `basic_stringbuf::underflow()` is specified to unconditionally return `traits::eof()` when a read position is not available.

The semantics of `basic_stringbuf` require, and existing libraries implement it so that this function makes a read position available if possible to do so, e.g. if some characters were inserted into the stream since the last call to `overflow()`, resulting in `pptr() > egptr()`. Compare to the conceptually similar D.12.2.4 [depr.strstreambuf.virtuals]/15.

[2018-06-06, Billy argues for NAD]

The existing "Any character in the underlying buffer which has been initialized is considered to be part of the input sequence." sentence already describes what the `stringbuf` is supposed to do to the get area. The specific mechanism that the `stringbuf` uses to alter the get area is unspecified because the mechanism by which the `stringbuf` remembers the "high water mark" is unspecified.

Consider the following:

>     stringstream s;
>     s << "Hello";
>     s.seekp(0);
>     string x;
>     s >> x;

Before this P/R, this will store `Hello` in `x`, because the characters `Hello` are initialized. After this P/R, the "written put area" is empty, so it will store the empty string in `x`.

Saying that the initialized part of the string is used already describes what needs to happen here.

[2018-06 Rapperswil Wednesday issues processing]

Billy to provide rationale for closing as NAD.

Proposed resolution:

This wording is relative to N3691.

1. Change 29.8.2.5 [stringbuf.virtuals] as indicated:

   >     int_type underflow();

   > > -1- Returns: If the input sequence has a read position available or the function makes a read position available (as described below), returns `traits::to_int_type(*gptr())`. Otherwise, returns `traits::eof()`. Any character in the underlying buffer which has been initialized is considered to be part of the input sequence.

   > > -?- The function can make a read position available only if `(mode & ios_base::in) != 0` and if the write next pointer `pptr()` is not null and is greater than the current read end pointer `egptr()`. To make a read position available, the function alters the read end pointer `egptr()` to equal `pptr()`.

### 2289(i). `constexpr` guarantees of defaulted functions still insufficient

Section: 20.4.2 [pairs.pair], 20.5.3.1 [tuple.cnstr], 27.5 [time.duration] Status: Open Submitter: Daniel Krügler Opened: 2013-09-09 Last modified: 2020-06-13

Priority: 3

View other active issues in [pairs.pair].

View all other issues in [pairs.pair].

View all issues with Open status.

Discussion:

During the acceptance of N3471 and some similar `constexpr` papers, specific wording was added to `pair`, `tuple`, and other templates that were intended to impose implementation constraints that ensure that the observable `constexpr` "character" of a defaulted function template is solely determined by the required expressions of the user-provided types when instantiated, for example:

> The defaulted move and copy constructor, respectively, of pair shall be a `constexpr` function if and only if all required element-wise initializations for copy and move, respectively, would satisfy the requirements for a `constexpr` function.

This wording doesn't require enough, especially since the core language via CWG 1358 does now support `constexpr` function template instantiations, even if such function cannot appear in a constant expression (as specified in 7.7 [expr.const]) or as a constant initializer of that object (as specified in [basic.start.init]). The wording should be improved and should require valid uses in constant expressions and as constant initializers instead.

[Lenexa 2015-05-05]

STL : notice order of move/copy and copy/move with "respectively".

General word-smithing; ask for updated wording

Are we happy with this with changes we are suggesting?

unanimous

[2016-12-14, Daniel comments]

LWG 2833 overlaps considerably and both should be resolved together.

Previous resolution from Daniel [SUPERSEDED]:

> This wording is relative to N3691.

> 1. Change 20.4.2 [pairs.pair] p2 as indicated:

>    > -2- The defaulted move and copy constructor, respectively, of pair shall be a `constexpr` function if and only if all required element-wise initializations for copy and move, respectively, would satisfy the requirements for a `constexpr` function An invocation of the move or copy constructor of `pair` shall be a constant expression (7.7 [expr.const]) if all required element-wise initializations would be constant expressions. An invocation of the move or copy constructor of `pair` shall be a constant initializer for that `pair` object ( [basic.start.init]) if all required element-wise initializations would be constant initializers for the respective subobjects.

> 2. Change 20.5.3.1 [tuple.cnstr] p2 as indicated:

>    > -2- The defaulted move and copy constructor, respectively, of `tuple` shall be a `constexpr` function if and only if all required element-wise initializations for copy and move, respectively, would satisfy the requirements for a `constexpr` function. The defaulted move and copy constructor of `tuple<>` shall be `constexpr` functions An invocation of the move or copy constructor of `tuple` shall be a constant expression (7.7 [expr.const]) if all required element-wise initializations would be constant expressions. An invocation of the move or copy constructor of `tuple` shall be a constant initializer for that `tuple` object ( [basic.start.init]) if all required element-wise initializations would be constant initializers for the respective subobjects. An invocation of the move or copy constructor of `tuple<>` shall be a constant expression, or a constant initializer for that `tuple<>` object, respectively, if the function argument would be constant expression.

> 3. Change 27.5 [time.duration] p7 as indicated:

>    > -7- Remarks: The defaulted copy constructor of duration shall be a `constexpr` function if and only if the required initialization of the member `rep_` for copy and move, respectively, would satisfy the requirements for a `constexpr` function.An invocation of the copy constructor of `duration` shall be a constant expression (7.7 [expr.const]) if the required initialization of the member `rep_` would be a constant expression. An invocation of the copy constructor of `duration` shall be a constant initializer for that `duration` object ( [basic.start.init]) if the required initialization of the member `rep_` would be constant initializers for this subobject.

[2020-06-08 Nina Dinka Ranns comments]

The revised wording provided by LWG 2833 should resolve this issue as well.

Proposed resolution:

### 2290(i). Top-level "SFINAE"-based constraints should get a separate definition in Clause 17

Section: 20.15 [meta] Status: Open Submitter: Daniel Krügler Opened: 2013-09-02 Last modified: 2016-01-28

Priority: 3

View other active issues in [meta].

View all other issues in [meta].

View all issues with Open status.

Discussion:

The current library specification uses at several places wording that is intended to refer to core language template deduction failure at the top-level of expressions (aka "SFINAE"), for example:

> The expression `declval<T>() = declval<U>()` is well-formed when treated as an unevaluated operand (Clause 5). Access checking is performed as if in a context unrelated to `T` and `U`. Only the validity of the immediate context of the assignment expression is considered. [Note: The compilation of the expression can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note]

Similar wording can be found in the specification of `result_of`, `is_constructible`, and `is_convertible`, being added to resolve an NB comment by LWG 1390 and 1391 through N3142.

This wording is necessary to limit speculative compilations needed to implement these traits, but it is also lengthy and repetitive.

[2014-05-19, Daniel suggests a descriptive term]

constrictedly well-formed expression:

An expression e depending on a set of types `A1`, ..., `An` which is well-formed when treated as an unevaluated operand (Clause 5). Access checking is performed as if in a context unrelated to `A1`, ..., `An`. Only the validity of the immediate context of e is considered. [Note: The compilation of the expression can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note]

[2014-05-20, Richard and Jonathan suggest better terms]

Richard suggested "locally well-formed"

Jonathan suggested "contextually well-formed" and then "The expression ... is valid in a contrived argument deduction context"

[2014-06-07, Daniel comments and improves wording]

The 2014-05-19 suggestion did only apply to expressions, but there are two important examples that are not expressions, but instead are involving an object definition (`std::is_constructible`) and a function definition (`std::is_convertible`), respectively, instead. Therefore I suggest to rephrase the usage of "expression" into "program construct" in the definition of Jonathan's suggestion of "valid in a contrived argument deduction context".

I would like to point out that given the new definition of "valid in a contrived argument deduction context", there are several other places of the Library specification that could take advantage of this wording to improve the existing specification, such as 20.14.17.3 [func.wrap.func] p2, most functions in 20.10.8.3 [allocator.traits.members], and the `**Insertable`, `EmplaceConstructible`, and `Erasable` definitions in 22.2.1 [container.requirements.general], but given that these are not fully described in terms of the aforementioned wording yet, I would recommend to fix them by a separate issue once the committee has agreed on following the suggestion presented by this issue.

[2015-05-05 Lenexa: Move to Open]

...

MC: I think we like the direction but it isn't quite right: it needs some work

JW: I'm prepared to volunteer to move that further, hopefully with the help of Daniel

Roger Orr: should this be Core wording because it doesn't really have anything to do with libraries - the term could then just be used here

AM: Core has nothing to deal with that, though

HT: it seems there is nothing to imply that allows dropping out with an error - maybe that's a separate issue

MC: I'm not getting what you are getting at: could you write an issue? - any objection to move to Open?

...

Proposed resolution:

This wording is relative to N3936.

1. Add the following new definition to [definitions] as indicated:

   valid in a contrived argument deduction context [defns.valid.contr.context]

   A program construct c depending on a set of types `A1`, ..., `An`, and treated as an unevaluated operand (Clause 5) when c is an expression, which is well-formed. Access checking is performed as if in a context unrelated to `A1`, ..., `An`. Only the validity of the immediate context (13.10.3 [temp.deduct]) of c is considered. [Note: The compilation of c can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note].

2. Change Table 49 ("Type property predicates") as indicated:

   > Table 49 — Type property predicates
   > Template | Condition | Preconditions
   > --- | --- | ---
   > `…`
   > `template <class T, class U> struct is_assignable;` | The expression `declval<T>() = declval<U>()` is valid in a contrived argument deduction context ([defns.valid.contr.context]) for types `T` and `U`. well-formed when treated as an unevaluated operand (Clause 5). Access checking is performed as if in a context unrelated to `T` and `U`. Only the validity of the immediate context of the assignment expression is considered. [Note: The compilation of the expression can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note] | […]
   > `…`

3. Change 20.15.5.4 [meta.unary.prop] p7 as indicated:

   > -7- Given the following function prototype:

   > >     template <class T>
   > >       add_rvalue_reference_t<T> create() noexcept;

   > the predicate condition for a template specialization `is_constructible<T, Args...>` shall be satisfied if and only if the following variable definition would be well-formed for some invented variable `t` would be valid in a contrived argument deduction context ([defns.valid.contr.context]) for types `T` and `Args...`:

   > >     T t(create<Args>()...);

   > [Note: These tokens are never interpreted as a function declaration. — end note] Access checking is performed as if in a context unrelated to `T` and any of the `Args`. Only the validity of the immediate context of the variable initialization is considered. [Note: The evaluation of the initialization can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note]

4. Change Table 57 ("Other transformations") as indicated:

   > Table 57 — Other transformations
   > Template | Condition | Comments
   > --- | --- | ---
   > `…`
   > `template <class Fn, class... ArgTypes> struct result_of<Fn(ArgTypes...)>;` | […] | If the expression `INVOKE(declval<Fn>(), declval<ArgTypes>()...)` is valid in a contrived argument deduction context ([defns.valid.contr.context]) for types `Fn` and `ArgTypes...` well formed when treated as an unevaluated operand (Clause 5), the member typedef type shall name the type `decltype(INVOKE(declval<Fn>(), declval<ArgTypes>()...))`; otherwise, there shall be no member type. Access checking is performed as if in a context unrelated to `Fn` and `ArgTypes`. Only the validity of the immediate context of the expression is considered. [Note: The compilation of the expression can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note]
   > `…`

5. Change 20.15.7 [meta.rel] p4 as indicated:

   > -4- Given the following function prototype:

   > >     template <class T>
   > >       add_rvalue_reference_t<T> create() noexcept;

   > the predicate condition for a template specialization `is_convertible<From, To>` shall be satisfied if and only if the return expression in the following code would be well-formed valid in a contrived argument deduction context ([defns.valid.contr.context]) for types `To` and `From`, including any implicit conversions to the return type of the function:

   > >     To test() {
   > >       return create<From>();
   > >     }

   > [Note: This requirement gives well defined results for reference types, `void` types, array types, and function types. — end note] Access checking is performed as if in a context unrelated to `To` and `From`. Only the validity of the immediate context of the expression of the return-statement (including conversions to the return type) is considered. [Note: The evaluation of the conversion can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note]

### 2295(i). Locale name when the provided `Facet` is a `nullptr`

Section: 28.3.1.3 [locale.cons] Status: New Submitter: Juan Soulie Opened: 2013-09-04 Last modified: 2022-02-14

Priority: 3

View other active issues in [locale.cons].

View all other issues in [locale.cons].

View all issues with New status.

Discussion:

28.3.1.3 [locale.cons] p14 ends with:

> "[…] If `f` is null, the resulting object is a copy of `other`."

but the next line p15 says:

> "Remarks: The resulting locale has no name."

But both can't be true when `other` has a name and `f` is null.

I've tried it on two implementations (MSVC,GCC) and they are inconsistent with each other on this.

Daniel Krügler:

As currently written, the Remarks element applies unconditionally for all cases and thus should "win". The question arises whether the introduction of this element by LWG 424 had actually intended to change the previous Note to a Remarks element. In either case the wording should be improved to clarify this special case.

[2022-02-14; Daniel comments]

This issue seems to have some overlap with LWG 3676 so both should presumably be resolved in a harmonized way.

Proposed resolution:

### 2303(i). Explicit instantiation of `std::vector<UserType>` broken?

Section: 17.6.3.4 [new.delete.placement] Status: New Submitter: Daniel Krügler Opened: 2013-09-18 Last modified: 2016-01-28

Priority: 3

View all other issues in [new.delete.placement].

View all issues with New status.

Discussion:

The library gives explicit permission in 16.4.5.2.1 [namespace.std] p2 that user code may explicitly instantiate a library template provided that the instantiations depend on at least one user-defined type:

> A program may explicitly instantiate a template defined in the standard library only if the declaration depends on the name of a user-defined type and the instantiation meets the standard library requirements for the original template.

But it seems that the C++11 library is not specified in a way that guarantees such an instantiation to be well-formed if the minimum requirements of the library is not satisfied.

For example, in general, the first template parameter of `std::vector` is not required to be `DefaultConstructible` in general, but due to the split of the single C++03 member function with default argument

>     void resize(size_type sz, T c = T());

into

>     void resize(size_type sz);
>     void resize(size_type sz, const T& c);

the effect is now that for a type `ND` that is not `DefaultConstructible`, such as

>     struct NP {
>       NP(int);
>     };

the explicit instantiation of `std::vector<ND>` is no longer well-formed, because the attempt to instantiate the single-argument overload of `resize` cannot not succeed, because this function imposes the `DefaultInsertable` requirements and given the default allocator this effectively requires `DefaultConstructible`.

But `DefaultConstructible` is not the only point, what about `CopyConstructible` versus `MoveConstructible` alone? It turns out that currently the second `resize` overload would fail during an explicit instantiation for a type like

>     struct MO {
>       MO() = default;
>       MO(MO&&) = default;
>     };

because it imposes `CopyInsertable` requirements that end up being equivalent to the `CopyConstructible` requirements for the default allocator.

Technically a library can solve these issues: For special member functions by defining them in some base class, for others by transforming them effectively into a function template due to the great feature of default template arguments for function templates (At the very moment the validity of the latter approach depends on a resolution of core language issue CWG 1635, though). E.g. the here mentioned `resize` functions of `std::vector` could be prevented from instantiation by defining them like this with an implementation:

>     template<class = void>
>     void resize(size_type sz) { […] }
>     template<class = void>
>     void resize(size_type sz, const T& c) { […] }

In this case, these functions could also be defined in a base class, but the latter approach won't work in all cases.

Basically such an implementation is required to constrain all member functions that are not covered by the general requirements imposed on the actual library template parameters. I tested three different C++11 library implementations and but none could instantiate for example `std::list`, `std::vector`, or `std::deque` with value types that are not `DefaultConstructible` or only `MoveConstructible`.

This issue is raised to clarify the current situation in regard to the actual requirements imposed on user-provided types that are used to explicitly instantiate Library-provided templates. For example, the current Container requirements impose very little requirements on the actual value type and it is unclear to which extend library implementations have to respect that.

The minimum solution of this issue should be to at least realize that there is no fundamental requirement on `DefaultConstructible` for value types of library containers, because we have since C++03 the general statement of 16.4.4.2 [utility.arg.requirements] ("In general, a default constructor is not required."). It is unclear whether `CopyConstructible` should be required for an explicit instantiation request, but given the careful introduction of move operations in the library it would seem astonishing that a `MoveConstructible` type wouldn't suffice for value types of the container types.

In any case I can envision at least two approaches to solve this issue:

1. As indicated in LWG 2292, those function could get an explicit "Template Constraints:" element, albeit this promises more than needed to solve this issue.

2. The library could introduce a completely new element form, such as "Instantiation Constraints:" that would handle this situation for explicit instantiation situations. This would allow for simpler techniques to solve the issue when explicit instantiation is required compared to the first bullet, because it would not (necessarily) guarantee SFINAE-friendly expression-wellformedness, such as inspecting the expression `std::declval<std::vector<ND>&>.resize(0)` in an unevaluated context.

It should be noted that the 2013-08-27 comment to LWG 2193 could be resolved by a similar solution as indicated in this issue here.

Proposed resolution:

### 2307(i). Should the Standard Library use `explicit` only when necessary?

Section: 22 [containers] Status: LEWG Submitter: Zhihao Yuan Opened: 2013-09-26 Last modified: 2018-11-12

Priority: 2

View other active issues in [containers].

View all other issues in [containers].

View all issues with LEWG status.

Discussion:

LWG 2193 yields `explicit` for default ctors to allow `{}`, but not for all cases of uniform initialization. For example:

>     explicit vector(size_type count, const Allocator& alloc = Allocator());

This prevents `{n, alloc()}`. Although this use is relatively rare, but the behavior is inconsistent with that of

>     vector(size_type count, const T& value, const Allocator& alloc = Allocator());

[Urbana 2014-11-07: Move to Open]

[2018-08 Batavia Monday issue discussion]

This really needs a paper; splitting a lot of constructors. Nevin to write paper.

[2018-11 San Diego Thursday night issue processing]

LEWG has rejected Nevin's paper, so they need to formulate a policy.

Proposed resolution:

### 2321(i). Moving containers should (usually) be required to preserve iterators

Section: 22.2.1 [container.requirements.general] Status: Open Submitter: Stephan T. Lavavej Opened: 2013-09-21 Last modified: 2018-08-24

Priority: 3

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

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

View all issues with Open status.

Discussion:

22.2.1 [container.requirements.general]/10 says that unless otherwise specified, "no `swap()` function invalidates any references, pointers, or iterators referring to the elements of the containers being swapped. [Note: The `end()` iterator does not refer to any element, so it may be invalidated. — end note]". However, move constructors and move assignment operators aren't given similar invalidation guarantees. The guarantees need several exceptions, so I do not believe that blanket language like /11 "Unless otherwise specified (either explicitly or by defining a function in terms of other functions), invoking a container member function or passing a container as an argument to a library function shall not invalidate iterators to, or change the values of, objects within that container." is applicable.

[2014-02-13 Issaquah]

General agreeement on intent, several wording nits and additional paragraphs to hit.

STL to provide updated wording. Move to Open.

[2015-02 Cologne]

AM: in the proposed wording, I'd like to mention that the iterators now refer to elements of a different container. I think we're saying something like this somewhere. JY: There's some wording like that for swap I think. TK: It's also in `list::splice()`. DK to JY: 23.2.1p9.

VV: The issue says that STL was going to propose new wording. Has he done that? AM: I believe we're looking at that. GR: The request touches on multiple paragraphs, and this PR has only one new paragraph, so this looks like it's not up-to-date. MC: This was last updated a year ago in Issaquah.

Conclusion: Skip, not up to date.

[2015-06, Telecon]

Still waiting for updated wording

[2015-08 Chicago]

Still waiting for updated wording

[2018-08-23 Batavia Issues processing]

Priority to 3

Proposed resolution:

This wording is relative to N3691.

1. In 22.2.1 [container.requirements.general]/10 change as indicated:

   > -10- Unless otherwise specified (see 23.2.4.1, 23.2.5.1, 23.3.3.4, and 23.3.7.5) all container types defined in this Clause meet the following additional requirements:

   > - […]

   > - no copy constructor or assignment operator of a returned iterator throws an exception.

   > - no move constructor (or move assignment operator when `allocator_traits<allocator_type>::propagate_on_container_move_assignment::value` is true) of a container (except for `array`) invalidates any references, pointers, or iterators referring to the elements of the source container. [Note: The `end()` iterator does not refer to any element, so it may be invalidated. — end note]

   > - no `swap()` function throws an exception.

   > - no `swap()` function invalidates any references, pointers, or iterators referring to the elements of the containers being swapped. [Note: The `end()` iterator does not refer to any element, so it may be invalidated. — end note]

### 2331(i). `regex_constants::collate`'s effects are inaccurately summarized

Section: 30.4.2 [re.synopt] Status: Open Submitter: Stephan T. Lavavej Opened: 2013-09-21 Last modified: 2016-01-28

Priority: 3

View all other issues in [re.synopt].

View all issues with Open status.

Discussion:

The table in 30.4.2 [re.synopt]/1 says that `regex_constants::collate` "Specifies that character ranges of the form "`[a-b]`" shall be locale sensitive.", but 30.12 [re.grammar]/14 says that it affects individual character comparisons too.

[2012-02-12 Issaquah : recategorize as P3]

Marshall Clow: 28.13/14 only applies to ECMAScript

All: we're unsure

Jonathan Wakely: we should ask John Maddock

Move to P3

[2014-5-14, John Maddock response]

The original intention was the original wording: namely that `collate` only made character ranges locale sensitive. To be frank it's a feature that's probably hardly ever used (though I have no real hard data on that), and is a leftover from early POSIX standards which required locale sensitive collation for character ranges, and then later changed to implementation defined if I remember correctly (basically nobody implemented locale-dependent collation).

So I guess the question is do we gain anything by requiring all character-comparisons to go through the locale when this bit is set? Certainly it adds a great deal to the implementation effort (it's not what Boost.Regex has ever done). I guess the question is are differing code-points that collate identically an important use case? I guess there might be a few Unicode code points that do that, but I don't know how to go about verifying that.

STL:

If this was unintentional, then 30.4.2 [re.synopt]/1's table should be left alone, while 30.12 [re.grammar]/14 should be changed instead.

Jeffrey Yasskin:

This page mentions that [V] in Swedish should match "W" in a perfect world.

However, the most recent version of TR18 retracts both language-specific loose matches and language-specific ranges because "for most full-featured regular expression engines, it is quite difficult to match under code point equivalences that are not 1:1" and "tailored ranges can be quite difficult to implement properly, and can have very unexpected results in practice. For example, languages may also vary whether they consider lowercase below uppercase or the reverse. This can have some surprising results: [a-Z] may not match anything if `Z < a` in that locale."

ECMAScript doesn't include collation at all.

IMO, +1 to changing 28.13 instead of 28.5.1. It seems like we'd be on fairly solid ground if we wanted to remove `regex_constants::collate` entirely, in favor of named character classes, but of course that's not for this issue.

Proposed resolution:

This wording is relative to N3691.

1. In 30.4.2 [re.synopt]/1, Table 138 — "`syntax_option_type` effects", change as indicated:

   > Table 138 — `syntax_option_type` effects
   > Element | Effect(s) if set
   > --- | ---
   > `…`
   > `collate` | Specifies that character ranges of the form "`[a-b]`"comparisons and character range comparisons shall be locale sensitive.
   > `…`

### 2338(i). §[re.traits]/7 expects of locale facets something not guaranteed by [locale.facet]/4

Section: 30.6 [re.traits], 28.3.1.2.2 [locale.facet] Status: Open Submitter: Sergey Zubkov Opened: 2013-10-15 Last modified: 2016-02-01

Priority: 3

View all other issues in [re.traits].

View all issues with Open status.

Discussion:

30.6 [re.traits]/7, begins with "if `typeid(use_facet<collate<charT> >) == typeid(collate_byname<charT>)`", which appears to be pseudocode with the intention to convey that the collate facet has not been replaced by the user. Cf. the wording in N1429 "there is no portable way to implement `transform_primary` in terms of `std::locale`, since even if the sort key format returned by `std::collate_byname<>::transform` is known and can be converted into a primary sort key, the user can still install their own custom `std::collate` implementation into the locale object used, and that can use any sort key format they see fit.".

Taken literally, 30.6 [re.traits]/7 appears to imply that named locales are required to hold their collate facets with dynamic type `std::collate_byname<charT>`, which is in fact true in some implementations (e.g libc++), but not others (e.g. libstdc++). This does not follow from the description of `_byname` in 28.3.1.2.2 [locale.facet]/4, which is only required to provide equivalent semantics, to the named locale's facet, not to actually be one.

[2015-05-06 Lenexa: Move to Open]

MC, RP: Consequence of failing to follow the rule is UB.

MC: Tightening of requirements.

RP: It should be this way, we just didn't impose it before.

MC: Second change is a bug fix, original code didn't work.

TK: Doesn't seem to make things worse.

Bring up in larger group tomorrow.

JW arrives.

JW: libstdc++ violates this due to two std::string ABIs.

JW: This prevents installing a type derived from Facet_byname, constrains the implementor from using a smarter derived class version.

JW: Can't look at facet id to detect replacement, because replacements have the same id.

RP: Can you give it multiple ids through multiple inheritance?

JW: No, the facet mechanism wouldn't like that.

JW: We should also ask Martin Sebor, he's implemented this stuff recently.

MC: Sounds like this resolution doesn't work, need a better solution.

JW: Write in words "if the facet has not been replaced by the user", the implementation knows how to detect that, but not like this.

RP: User RE traits need to detect this too.

JW: =(

Move to Open, JW will invite Martin Sebor to join LWG for discussion.

Later ...

JW: This is not needed for user specializations after all.

MC: Agree, [re.traits]/7 only applies to the stdlib traits.

NM: Effects: doesn't make sense.

JW, NM, Martin Sebor to come up with new wording.

Proposed resolution:

This wording is relative to N3691.

1. Modify 28.3.1.2.2 [locale.facet]/4 as indicated:

   > For some standard facets a standard "...`_byname`" class, derived from it, implements the virtual function semantics equivalent to provided by that facet of the locale constructed by `locale(const char*)` with the same name. Each such facet provides a constructor that takes a `const char*` argument, which names the locale, and a `refs` argument, which is passed to the base class constructor. Each such facet also provides a constructor that takes a string argument `str` and a `refs` argument, which has the same effect as calling the first constructor with the two arguments `str.c_str()` and `refs`. If there is no "...`_byname`" version of a facet, the base class implements named locale semantics itself by reference to other facets. For any locale `loc` constructed by `locale(const char*)` and facet `Facet` that has a corresponding standard `Facet_byname` class, `typeid(use_facet<Facet>(loc)) == typeid(Facet_byname)`.

2. Modify 30.6 [re.traits]/7 as indicated:

   >     template <class ForwardIterator>
   >       string_type transform_primary(ForwardIterator first, ForwardIterator last) const;

   > > -7- Effects: if `typeid(use_facet<collate<charT> >(getloc())) == typeid(collate_byname<charT>)` and the form of the sort key returned by `collate_byname<charT>::transform(first, last)` is known and can be converted into a primary sort key then returns that key, otherwise returns an empty string.

### 2342(i). User conversion to `wchar_t const*` or to `wchar_t` not invoked for `operator<<`

Section: 29.7.5.2 [ostream] Status: New Submitter: Alf P. Steinbach Opened: 2013-10-29 Last modified: 2016-01-28

Priority: 4

View all other issues in [ostream].

View all issues with New status.

Discussion:

For wide streams argument types `wchar_t const*` and `wchar_t` are supported only as template parameters. User defined conversions are not considered for template parameter matching. Hence inappropriate overloads of `operator<<` are selected when an implicit conversion is required for the argument, which is inconsistent with the behavior for `char const*` and `char`, is unexpected, and is a useless result.

Demonstration:

>     #include <iostream>

>     struct Byte_string
>     {
>       operator char const*() const { return "Hurray, it works!"; }
>     };

>     struct Wide_string
>     {
>       operator wchar_t const*() const { return L"Hurray, it works!"; }
>     };

>     struct Byte_ch
>     {
>       operator char() const { return 'X'; }
>     };

>     struct Wide_ch
>     {
>       operator wchar_t() const { return L'X'; }
>     };

>     auto main() -> int
>     {
>       using namespace std;
>       wcout << "'X' as char value   : " << Byte_ch() << endl;
>       wcout << "'X' as wchar_t value: " << Wide_ch() << endl;
>       wcout << "Byte string pointer : " << Byte_string() << endl;
>       wcout << "Wide string pointer : " << Wide_string() << endl;
>     }

Example output:

>     'X' as char value   : X
>     'X' as wchar_t value: 88
>     Byte string pointer : Hurray, it works!
>     Wide string pointer : 000803C8

Proposed resolution:

This wording is relative to N3797.

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

   >     namespace std {
   >     […]

   >     // 27.7.3.6.4 character inserters
   >     template<class charT, class traits>
   >       basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&,
   >                                               charT);
   >     template<class charT, class traits>
   >       basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&,
   >                                               char);
   >     template<class traits>
   >       basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&,
   >                                              char);
   >     template<class traits>
   >       basic_ostream<wchar_t,traits>& operator<<(basic_ostream<wchar_t,traits>&,
   >                                                 wchar_t);
   >     […]

   >     template<class charT, class traits>
   >       basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&,
   >                                               const charT*);
   >     template<class charT, class traits>
   >       basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&,
   >                                               const char*);
   >     template<class traits>
   >       basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&,
   >                                              const char*);
   >     template<class traits>
   >       basic_ostream<wchar_t,traits>& operator<<(basic_ostream<wchar_t,traits>&,
   >                                                 const wchar_t*);
   >     […]
   >     }

2. Modify 29.7.5.3.4 [ostream.inserters.character] as indicated: [Drafting note: The replacement of `os` by `out` in p1 and the insertion of "`out.`" in p4 just fix two obvious typos — end drafting note]

   >     template<class charT, class traits>
   >       basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out,
   >                                               charT c);
   >     template<class charT, class traits>
   >       basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out,
   >                                               char c);
   >     // specialization
   >     template<class traits>
   >       basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out,
   >                                              char c);
   >     template<class traits>
   >       basic_ostream<wchar_t,traits>& operator<<(basic_ostream<wchar_t,traits>& out,
   >                                                 wchar_t c);

   >     // signed and unsigned
   >     template<class traits>
   >       basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out,
   >                                               signed char c);
   >     template<class traits>
   >       basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out,
   >                                               unsigned char c);

   > > -1- Effects: Behaves as a formatted output function (29.7.5.3.1 [ostream.formatted.reqmts]) of `out`. Constructs a character sequence `seq`. If `c` has type `char` and the character type of the stream is not `char`, then `seq` consists of `out.widen(c)`; otherwise `seq` consists of `c`. Determines padding for `seq` as described in 29.7.5.3.1 [ostream.formatted.reqmts]. Inserts `seq` into `out`. Calls `osout.width(0)`.

   > > -2- Returns: `out`.

   >     template<class charT, class traits>
   >       basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out,
   >                                               const charT* s);
   >     template<class charT, class traits>
   >       basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out,
   >                                               const char* s);
   >     template<class traits>
   >       basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out,
   >                                              const char* s);
   >     template<class traits>
   >       basic_ostream<wchar_t,traits>& operator<<(basic_ostream<wchar_t,traits>& out,
   >                                                 const wchar_t* s);

   >     template<class traits>
   >       basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out,
   >                                              const signed char* s);
   >     template<class traits>
   >       basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out,
   >                                              const unsigned char* s);

   > > -3- Requires: `s` shall not be a null pointer.

   > > -4- Effects: Behaves like a formatted inserter (as described in 29.7.5.3.1 [ostream.formatted.reqmts]) of `out`. Creates a character sequence `seq` of `n` characters starting at `s`, each widened using `out.widen()` (27.5.5.3), where `n` is the number that would be computed as if by:

   > > - `traits::length(s)` for the following overloads:

   > >   - where the first argument is of type `basic_ostream<charT, traits>&` and the second is of type `const charT*`,

   > >   - and also for the overload where the first argument is of type `basic_ostream<char, traits>&` and the second is of type `const char*`,

   > >   - where the first argument is of type `basic_ostream<wchar_t, traits>&` and the second is of type `const wchar_t*`,

   > > - `std::char_traits<char>::length(s)` for the overload where the first argument is of type `basic_ostream<charT, traits>&` and the second is of type `const char*`,

   > > - `traits::length(reinterpret_cast<const char*>(s))` for the other two overloads.

   > > Determines padding for `seq` as described in 29.7.5.3.1 [ostream.formatted.reqmts]. Inserts `seq` into `out`. Calls `out.width(0)`.

   > > -5- Returns: `out`.

### 2348(i). `charT('1')` is not the wide equivalent of `'1'`

Section: 20.9.2 [template.bitset], 29.7.8 [quoted.manip] Status: Open Submitter: Zhihao Yuan Opened: 2013-12-02 Last modified: 2016-01-28

Priority: 3

View all other issues in [template.bitset].

View all issues with Open status.

Discussion:

Example: `char16_t('1') != u'1'` is possible.

The numeric value of `char16_t` is defined to be Unicode code point, which is same to the ASCII value and UTF-8 for 7-bit chars. However, `char` is not guaranteed to have an encoding which is compatible with ASCII. For example, `'1'` in EBCDIC is 241.

I found three places in the standard casting narrow char literals: `bitset::bitset`, `bitset::to_string` and `quoted`.

PJ confirmed this issue and says he has a solution used in their `<filesystem>` implementation, and he may want to propose it to the standard.

The solution in my mind, for now, is to make those default arguments magical, where the "magic" can be implemented with a C11 `_Generic` selection (works in clang):

>     #define _G(T, literal) _Generic(T{}, \
>           char: literal, \
>           wchar_t: L ## literal, \
>           char16_t: u ## literal, \
>           char32_t: U ## literal)

>       _G(char16_t, '1') == u'1'

[Lenexa 2015-05-05: Move to Open]

Ask for complete PR (need quoted, to string, et al.)

Will then take it up again

Expectation is that this is correct way to fix this

Proposed resolution:

This wording is relative to N3797.

[Drafting note: This is a sample wording fixing only one case; I'm just too lazy to copy-paste it before we discussed whether the solution is worth and sufficient (for example, should the other `charT`s like `unsigned char` just don't compile without supplying those arguments? I hope so). — end drafting note]

1. Modify 20.9.2 [template.bitset] p1, class template `bitset` synopsis, as indicated:

   >     namespace std {
   >       template <size_t N> class bitset {
   >       public:
   >         […]
   >         template<class charT, class traits, class Allocator>
   >           explicit bitset(
   >             const basic_string<charT,traits,Allocator>& str,
   >             typename basic_string<charT,traits,Allocator>::size_type pos = 0,
   >             typename basic_string<charT,traits,Allocator>::size_type n =
   >               basic_string<charT,traits,Allocator>::npos,
   >               charT zero = charT('0')see below, charT one = charT('1')see below);
   >          […]
   >       };
   >       […]
   >     }

2. Modify 20.9.2.2 [bitset.cons] as indicated:

   >     template<class charT, class traits, class Allocator>
   >     explicit
   >     bitset(const basic_string<charT, traits, Allocator>& str,
   >            typename basic_string<charT, traits, Allocator>::size_type pos = 0,
   >            typename basic_string<charT, traits, Allocator>::size_type n =
   >              basic_string<charT, traits, Allocator>::npos,
   >              charT zero = charT('0')see below, charT one = charT('1')see below);

   > > -?- The default values of `zero` and `one` compare equal to the character literals `0` and `1` of type `charT`, respectively.

   > > -3- Requires:: `pos <= str.size()`.

   > > […]

### 2349(i). Clarify input/output function rethrow behavior

Section: 29.7.4.3.1 [istream.formatted.reqmts] Status: Open Submitter: Zhihao Yuan Opened: 2013-12-06 Last modified: 2016-01-28

Priority: 3

View all other issues in [istream.formatted.reqmts].

View all issues with Open status.

Discussion:

The formatted input function requirement says in 29.7.4.3.1 [istream.formatted.reqmts]:

> "If an exception is thrown during input then `ios::badbit` is turned on in `*this`'s error state. If `(exceptions()&badbit) != 0` then the exception is rethrown."

while some formatted function may throw an exception from `basic_ios::clear`, for example in 20.9.4 [bitset.operators] p6:

> "If no characters are stored in `str`, calls `is.setstate(ios_base::failbit)` (which may throw `ios_base::failure`)"

So should this exception be considered as "an exception [...] thrown during input"? And here is an implementation divergence (or you can read the following as "a bug libc++ only has" :)

>     cin.exceptions(ios_base::failbit);
>     bitset<N> b;
>     try {
>       cin >> b;  // type 'a' and return
>     } catch (...)
>     {}

Now `cin.rdstate()` is just `failbit` in libstdc++ (and Dinkumware, by PJ), but `failbit & badbit` libc++. Similar difference found in other places, like `eofbit & badbid` after `std::getline`.

PJ and Matt both agree that the intention (of `badbit` + rethrow) is "to signify an exception arising in user code, not the iostreams package".

In addition, I found the following words in unformatted input function's requirements (29.7.4.4 [istream.unformatted]):

> If an exception is thrown during input then `ios::badbit` is turned on in `*this`'s error state. (Exceptions thrown from `basic_ios<>::clear()` are not caught or rethrown.) If `(exceptions()&badbit) != 0` then the exception is rethrown.

The content within the parenthesis is added by LWG defect 61, and does fix the ambiguity. However, it only fixed the 1 of 4 requirements, and it lost some context (the word "rethrown" is not seen before this sentence within this section).

[Lenexa 2015-05-07: Marshall to research and report]

Proposed resolution:

This wording is relative to N3797.

[Drafting note: The editor is kindly asked to introduce additional spaces at the following marked occurrences of `operator&` — end drafting note]

1. Modify 29.7.4.3.1 [istream.formatted.reqmts] p1 as indicated:

   > -1- Each formatted input function begins execution by constructing an object of class `sentry` with the `noskipws` (second) argument false. If the `sentry` object returns true, when converted to a value of type `bool`, the function endeavors to obtain the requested input. If an exception, other than the ones thrown from `clear()`, if any, is thrown during input then `ios::badbit` is turned on[Footnote 314] in `*this`'s error state. If `(exceptions() & badbit) != 0` then the exception is rethrown. In any case, the formatted input function destroys the `sentry` object. If no exception has been thrown, it returns `*this`.

2. Modify 29.7.5.3.1 [ostream.formatted.reqmts] p1 as indicated:

   > -1- Each formatted output function begins execution by constructing an object of class `sentry`. If this object returns true when converted to a value of type `bool`, the function endeavors to generate the requested output. If the generation fails, then the formatted output function does `setstate(ios_base::failbit)`, which might throw an exception. If an exception, other than the ones thrown from `clear()`, if any, is thrown during output, then `ios::badbit` is turned on[Footnote 327] in `*this`'s error state. If `(exceptions() & badbit) != 0` then the exception is rethrown. Whether or not an exception is thrown, the `sentry` object is destroyed before leaving the formatted output function. If no exception is thrown, the result of the formatted output function is `*this`.

3. Modify 29.7.5.4 [ostream.unformatted] p1 as indicated:

   > -1- Each unformatted output function begins execution by constructing an object of class `sentry`. If this object returns true, while converting to a value of type `bool`, the function endeavors to generate the requested output. If an exception, other than the ones thrown from `clear()`, if any, is thrown during output, then ios::badbit is turned on[Footnote 330] in `*this`'s error state. If `(exceptions() & badbit) != 0` then the exception is rethrown. In any case, the unformatted output function ends by destroying the `sentry` object, then, if no exception was thrown, returning the value specified for the unformatted output function.

4. Modify 29.7.4.4 [istream.unformatted] p1 as indicated:

   > -1- Each unformatted input function begins execution by constructing an object of class `sentry` with the default argument `noskipws` (second) argument true. If the `sentry` object returns true, when converted to a value of type `bool`, the function endeavors to obtain the requested input. Otherwise, if the `sentry` constructor exits by throwing an exception or if the sentry object returns false, when converted to a value of type `bool`, the function returns without attempting to obtain any input. In either case the number of extracted characters is set to `0`; unformatted input functions taking a character array of non-zero size as an argument shall also store a null character (using `charT()`) in the first location of the array. If an exception, other than the ones thrown from `clear()`, if any, is thrown during input then `ios::badbit` is turned on[Footnote 317] in `*this`'s error state. (Exceptions thrown from `basic_ios<>::clear()` are not caught or rethrown.) If `(exceptions() & badbit) != 0` then the exception is rethrown. It also counts the number of characters extracted. If no exception has been thrown it ends by storing the count in a member object and returning the value specified. In any event the `sentry` object is destroyed before leaving the unformatted input function.

### 2352(i). Is a default-constructed `std::seed_seq` intended to produce a predictable `.generate()`?

Section: 26.6.8.1 [rand.util.seedseq] Status: New Submitter: Thomas Plum Opened: 2013-12-02 Last modified: 2018-01-22

Priority: 2

View all other issues in [rand.util.seedseq].

View all issues with New status.

Discussion:

With respect to class `seed_seq` 26.6.8.1 [rand.util.seedseq], is a default-constructed `std::seed_seq` intended to produce a predictable `.generate()` sequence?

Implementations differ.

[2014-02-10]

Priority set to 2

Proposed resolution:

### 2358(i). Apparently-bogus definition of `is_empty` type trait

Section: 20.15.5.4 [meta.unary.prop] Status: Open Submitter: Richard Smith Opened: 2014-02-01 Last modified: 2017-02-02

Priority: 3

View other active issues in [meta.unary.prop].

View all other issues in [meta.unary.prop].

View all issues with Open status.

Discussion:

The 'Condition' for `std::is_empty` is listed as:

> "`T` is a class type, but not a union type, with no non-static data members other than bit-fields of length 0, no virtual member functions, no virtual base classes, and no base class `B` for which `is_empty<B>::value` is false."

This is incorrect: there is no such thing as a non-static data member that is a bit-field of length 0, since bit-fields of length 0 must be unnamed, and unnamed bit-fields are not members (see 11.4.10 [class.bit] p2).

It also means that classes such as:

>     struct S {
>      int : 3;
>     };

are empty (because they have no non-static data members). There's implementation divergence on the value of `is_empty<S>::value`.

I'm not sure what the purpose of `is_empty` is (or how it could be useful), but if it's desirable for the above type to not be treated as empty, something like this could work:

> "`T` is a class type, but not a union type, with no non-static data members other than, no unnamed bit-fields of non-zero length 0, no virtual member functions, no virtual base classes, and no base class `B` for which `is_empty<B>::value` is false."

and if the above type should be treated as empty, then this might be appropriate:

> "`T` is a class type, but not a union type, with no (named) non-static data members other than bit-fields of length 0, no virtual member functions, no virtual base classes, and no base class `B` for which `is_empty<B>::value` is false."

[2016-08 Chicago]

Walter says: We want `is_empty_v<S>` to produce false as a result. Therefore, we recommend adoption of the first of the issue's suggestions.

Tuesday AM: Moved to Tentatively Ready

Previous resolution [SUPERSEDED]:

[2016-10 by Marshall - this PR incorrectly highlighted changed portions]

> Modify Table 38 — Type property predicates for `is_empty` as follows:

> > `T` is a non-union class type with no non-static data members other than, no unnamed bit-fields of non-zero length 0, no virtual member functions, no virtual base classes, and no base class `B` for which `is_empty_v<B>` is false.

[2016-10 Telecon]

Should probably point at section 1.8 for some of this. Status back to 'Open'

Proposed resolution:

Modify Table 38 — Type property predicates for `is_empty` as follows:

> `T` is a class type, but not a union type,is a non-union class type with no non-static data members other than, no unnamed bit-fields of non-zero length 0, no virtual member functions, no virtual base classes, and no base class `B` for which `is_empty_v<B>` is false.

### 2362(i). unique, associative `emplace()` should not move/copy the `mapped_type` constructor arguments when no insertion happens

Section: 22.2.6 [associative.reqmts], 22.2.7 [unord.req] Status: New Submitter: Jeffrey Yasskin Opened: 2014-02-15 Last modified: 2015-09-23

Priority: 3

View other active issues in [associative.reqmts].

View all other issues in [associative.reqmts].

View all issues with New status.

Discussion:

`a_uniq.emplace(args)` is specified as:

> Effects: Inserts a value_type object `t` constructed with
> `std::forward<Args>(args)...` if and only if there is no element in the
> container with key equivalent to the key of `t`. The `bool` component of
> the returned pair is true if and only if the insertion takes place,
> and the iterator component of the pair points to the element with key
> equivalent to the key of `t`.

However, we occasionally find code of the form:

>     std::unique_ptr<Foo> p(new Foo);
>     auto res = m.emplace("foo", std::move(p));

where we'd like to avoid destroying the `Foo` if the insertion doesn't take place (if the container already had an element with the specified key).

N3873 includes a partial solution to this in the form of a new `emplace_stable` member function, but LEWG's discussion strongly agreed that we'd rather have `emplace()` Just Work:

Should `map::emplace()` be guaranteed not to move/copy its arguments if the insertion doesn't happen?

SF: 8 F: 3 N: 0 A: 0 SA: 0

This poll was marred by the fact that we didn't notice or call out that `emplace()` must construct the key before doing the lookup, and it must not then move the key after it determines whether an insert is going to happen, and the `mapped_type` instance must live next to the key.

The very similar issue 2006 was previously marked NAD, with N3178 as discussion. However, given LEWG's interest in the alternate behavior, we should reopen the question in this issue.

We will need a paper that describes how to implement this before we can make more progress.

Proposed resolution:

### 2366(i). `istreambuf_iterator` end-of-stream equality

Section: 23.6.4 [istreambuf.iterator] Status: New Submitter: Hyman Rosen Opened: 2014-02-19 Last modified: 2014-06-17

Priority: 3

View other active issues in [istreambuf.iterator].

View all other issues in [istreambuf.iterator].

View all issues with New status.

Discussion:

Given the following code,

>     #include <sstream>

>     std::stringbuf buf;
>     std::istreambuf_iterator<char> begin(&buf);
>     std::istreambuf_iterator<char> end;

it is not clear from the wording of the Standard whether `begin.equal(end)` must be true. In at least one implementation it is not (CC: Sun C++ 5.10 SunOS_sparc Patch 128228-25 2013/02/20) and in at least one implementation it is (gcc version 4.3.2 x86_64-unknown-linux-gnu).

23.6.4 [istreambuf.iterator] says that `end` is an end-of-stream iterator since it was default constructed. It also says that an iterator becomes equal to an end-of-stream iterator when end of stream is reached by `sgetc()` having returned `eof()`. 99 [istreambuf.iterator::equal] says that `equal()` returns true iff both iterators are end of stream or not end of stream. But there seems to be no requirement that `equal` check for end-of-stream by calling `sgetc()`.

Jiahan Zi at BloombergLP discovered this issue through his code failing to work correctly. Dietmar Kühl has opined in a private communication that the iterators should compare equal.

Proposed resolution:

### 2383(i). Overflow cannot be ill-formed for chrono::duration integer literals

Section: 27.5.9 [time.duration.literals] Status: Open Submitter: Jonathan Wakely Opened: 2014-05-16 Last modified: 2014-11-08

Priority: 3

View all issues with Open status.

Discussion:

27.5.9 [time.duration.literals] p3 says:

> If any of these suffixes are applied to an integer literal and the resulting `chrono::duration` value cannot be represented in the result type because of overflow, the program is ill-formed.

Ill-formed requires a diagnostic at compile-time, but there is no way to detect the overflow from `unsigned long long` to the `signed duration<>::rep` type.

Overflow could be detected if the duration integer literals were literal operator templates, otherwise overflow can either be undefined or a run-time error, not ill-formed.

[Urbana 2014-11-07: Move to Open]

Proposed resolution:

### 2392(i). "character type" is used but not defined

Section: 3.36 [defns.ntcts], 28.3.1.2.1 [locale.category], 29.2.3 [iostreams.limits.pos], 29.7.5.3.1 [ostream.formatted.reqmts], 29.7.5.3.4 [ostream.inserters.character] Status: New Submitter: Jeffrey Yasskin Opened: 2014-06-01 Last modified: 2017-04-22

Priority: 3

View all issues with New status.

Discussion:

The term "character type" is used in 3.36 [defns.ntcts], 28.3.1.2.1 [locale.category], 29.2.3 [iostreams.limits.pos], 29.7.5.3.1 [ostream.formatted.reqmts], and 29.7.5.3.4 [ostream.inserters.character], but the core language only defines "narrow character types" (6.8.2 [basic.fundamental]).

"wide-character type" is used in D.22 [depr.locale.stdcvt], but the core language only defines a "wide-character set" and "wide-character literal".

Proposed resolution:

### 2398(i). `type_info`'s destructor shouldn't be required to be virtual

Section: 17.7.3 [type.info] Status: Open Submitter: Stephan T. Lavavej Opened: 2014-06-14 Last modified: 2016-08-06

Priority: 3

View all other issues in [type.info].

View all issues with Open status.

Discussion:

`type_info`'s destructor is depicted as being `virtual`, which is nearly unobservable to users (since they can't construct or copy this class, they can't usefully derive from it). However, it's technically observable (via `is_polymorphic` and `has_virtual_destructor`). It also imposes real costs on implementations, requiring them to store one vptr per `type_info` object, when RTTI space consumption is a significant concern.

Making this implementation-defined wouldn't affect users (who can observe this only if they're specifically looking for it) and wouldn't affect implementations who need `virtual` here, but it would allow other implementations to drop `virtual` and improve their RTTI space consumption.

Richard Smith:

It's observable in a few other ways.

>     std::map<void*, something> m;
>     m[dynamic_cast<void*>(&typeid(blah))] = stuff;

... is broken by this change, because you can't `dynamic_cast` a non-polymorphic class type to `void*`.

>     type_info& f();
>     typeid(f());

... evaluates `f()` at runtime without this change, and might not do so with this change.

These are probably rare things, but I can imagine at least some forms of the latter being used in SFINAE tricks.

[Lenexa 2015-05-05: Move to Open]

Marshall to poll LEWG for their opinion

[2016-06]

On the reflector, STL wrote:

> We'll prototype this change and report back with data in the future.

[2016-08 Chicago]

No update from STL. Set priority to P3

Proposed resolution:

This wording is relative to N3936.

1. Change 17.7.3 [type.info] as indicated:

   >     namespace std {
   >       class type_info {
   >       public:
   >         virtualsee below ~type_info();
   >         […]
   >       };
   >     }

   > -1- The class `type_info` describes type information generated by the implementation. Objects of this class effectively store a pointer to a name for the type, and an encoded value suitable for comparing two types for equality or collating order. The names, encoding rule, and collating sequence for types are all unspecified and may differ between programs. Whether `~type_info()` is `virtual` is implementation-defined.

### 2413(i). `assert` macro is overconstrained

Section: 19.3 [assertions] Status: New Submitter: David Krauss Opened: 2014-06-25 Last modified: 2014-11-03

Priority: 4

View other active issues in [assertions].

View all other issues in [assertions].

View all issues with New status.

Discussion:

When `NDEBUG` is defined, `assert` must expand exactly to the token sequence `((void)0)`, with no whitespace (C99 §7.2/1 and also C11 §7.2/1). This is a lost opportunity to pass the condition along to the optimizer.

The user may observe the token sequence using the stringize operator or discriminate it by making a matching `#define` directive. There is little chance of practical code doing such things. It's reasonable to allow any expansion that is a `void` expression with no side effects or semantic requirements, for example, an extension keyword or an attribute-specifier finagled into the context.

Conforming optimizations would still be limited to treating the condition as hint, not a requirement. Nonconformance on this point is quite reasonable though, given user preferences. Anyway, it shouldn't depend on preprocessor quirks.

As for current practice, Darwin OS `<assert.h>` provides a GCC-style compiler hint `__builtin_expect` but only in debug mode. Shouldn't release mode preserve hints?

Daniel:

The corresponding resolution should take care not to conflict with the intention behind LWG 2234.

Proposed resolution:

### 2414(i). Member function reentrancy should be implementation-defined

Section: 16.4.6.9 [reentrancy] Status: Open Submitter: Stephan T. Lavavej Opened: 2014-07-01 Last modified: 2021-07-31

Priority: 3

View all other issues in [reentrancy].

View all issues with Open status.

Discussion:

N3936 16.4.6.9 [reentrancy]/1 talks about "functions", but that doesn't address the scenario of calling different member functions of a single object. Member functions often have to violate and then re-establish invariants. For example, vectors often have "holes" during insertion, and element constructors/destructors/etc. shouldn't be allowed to observe the vector while it's in this invariant-violating state. The [reentrancy] Standardese should be extended to cover member functions, so that implementers can either say that member function reentrancy is universally prohibited, or selectively allowed for very specific scenarios.

(For clarity, this issue has been split off from LWG 2382.)

[2014-11-03 Urbana]

AJM confirmed with SG1 that they had no special concerns with this issue, and LWG should retain ownership.

AM: this is too overly broad as it also covers calling the exact same member function on a different object
STL: so you insert into a map, and copying the value triggers another insertion into a different map of the same type
GR: reentrancy seems to imply the single-threaded case, but needs to consider the multi-threaded case

Needs more wording.

Move to Open

[2015-07 Telecon Urbana]

Marshall to ping STL for updated wording.

[2016-05 email from STL]

I don't have any better suggestions than my original PR at the moment.

Previous resolution [SUPERSEDED]:

> This wording is relative to N3936.

> 1. Change 16.4.6.9 [reentrancy] p1 as indicated:

>    > -1- Except where explicitly specified in this standard, it is implementation-defined which functions (including different member functions called on a single object) in the Standard C++ library may be recursively reentered.

[2021-07-29 Tim suggests new wording]

The "`this` pointer" restriction is modeled on 11.9.5 [class.cdtor] p2. It allows us to continue to specify a member function `f` as calling some other member function `g`, since any such call would use something obtained from the first member function's `this` pointer.

In all other cases, this wording disallows such "recursion on object" unless both member functions are `const` (or are treated as such for the purposes of data race avoidance). Using "access" means that we also cover direct access to the object representation, such as the following pathological example from Arthur O'Dwyer, which is now undefined:

>     std::string s = "hello world";
>     char *first = (char*)&s;
>     char *last = (char*)(&s + 1);
>     s.append(first, last);

Proposed resolution:

This wording is relative to N4892.

1. Add the following paragraph to 16.4.6.9 [reentrancy]:

   > -?- During the execution of a standard library non-static member function F on an object, if that object is accessed through a glvalue that is not obtained, directly or indirectly, from the `this` pointer of F, in a manner that can conflict (6.9.2.2 [intro.races]) with any access that F is permitted to perform (16.4.6.10 [res.on.data.races]), the behavior is undefined unless otherwise specified.

### 2421(i). Non-specification of handling zero size in `std::align` [ptr.align]

Section: 20.10.5 [ptr.align] Status: New Submitter: Melissa Mears Opened: 2014-08-06 Last modified: 2014-11-03

Priority: 3

View all other issues in [ptr.align].

View all issues with New status.

Discussion:

The specification of `std::align` does not appear to specify what happens when the value of the `size` parameter is 0. (The question of what happens when `alignment` is 0 is mentioned in another Defect Report, 2377; it would change the behavior to be undefined rather than potentially implementation-defined.)

The case of `size` being 0 is interesting because the result is ambiguous. Consider the following code's output:

>     #include <cstdio>
>     #include <memory>

>     int main()
>     {
>       alignas(8) char buffer[8];
>       void *ptr = &buffer[1];
>       std::size_t space = sizeof(buffer) - sizeof(char[1]);

>       void *result = std::align(8, 0, ptr, space);

>       std::printf("%d %td\n", !!result, result ? (static_cast<char*>(result) - buffer) : std::ptrdiff_t(-1));
>     }

There are four straightforward answers as to what the behavior of `std::align` with size 0 should be:

1. The behavior is undefined because the size is invalid.

2. The behavior is implementation-defined. This seems to be the status quo, with current implementations using #3.

3. Act the same as `size == 1`, except that if `size == 1` would fail but would be defined and succeed if space were exactly 1 larger, the result is a pointer to the byte past the end of the `ptr` buffer. That is, the "aligned" version of a 0-byte object can be one past the end of an allocation. Such pointers are, of course, valid when not dereferenced (and a "0-byte object" shouldn't be), but whether that is desired is not specified in the Standard's definition of `std::align`, it appears. The output of the code sample is "`1 8`" in this case.

4. Act the same as `size == 1`; this means that returning "one past the end" is not a possible result. In this case, the code sample's output is "`0 -1`".

The two compilers I could get working with `std::align`, Visual Studio 2013 and Clang 3.4, implement #3. (Change `%td` to `%Id` on Visual Studio 2013 and earlier. 2014 and later will have `%td`.)

Proposed resolution:

### 2423(i). Missing specification `slice_array`, `gslice_array`, `mask_array`, `indirect_array` copy constructor

Section: 26.7.5 [template.slice.array], 26.7.7 [template.gslice.array], 26.7.8 [template.mask.array], 26.7.9 [template.indirect.array] Status: New Submitter: Akira Takahashi Opened: 2014-08-12 Last modified: 2014-11-03

Priority: 4

View all other issues in [template.slice.array].

View all issues with New status.

Discussion:

I found a missing specification of the copy constructor of the following class templates:

- `slice_array` (26.7.5 [template.slice.array])

- `gslice_array` (26.7.7 [template.gslice.array])

- `mask_array` (26.7.8 [template.mask.array])

- `indirect_array` (26.7.9 [template.indirect.array])

Proposed resolution:

1. Before 26.7.5.2 [slice.arr.assign] insert a new sub-clause as indicated:

   -?- `slice_array` constructors [slice.arr.cons]

   >     slice_array(const slice_array&);

   > -?- Effects: The constructed slice refers to the same `valarray<T>` object to which the argument slice refers.

2. Before 26.7.7.2 [gslice.array.assign] insert a new sub-clause as indicated:

   -?- `gslice_array` constructors [gslice.array.cons]

   >     gslice_array(const gslice_array&);

   > -?- Effects: The constructed slice refers to the same `valarray<T>` object to which the argument slice refers.

3. Before 26.7.8.2 [mask.array.assign] insert a new sub-clause as indicated:

   -?- `mask_array` constructors [mask.array.cons]

   >     mask_array(const mask_array&);

   > -?- Effects: The constructed slice refers to the same `valarray<T>` object to which the argument slice refers.

4. Before 26.7.9.2 [indirect.array.assign] insert a new sub-clause as indicated:

   -?- `indirect_array` constructors [indirect.array.cons]

   >     indirect_array(const indirect_array&);

   > -?- Effects: The constructed slice refers to the same `valarray<T>` object to which the argument slice refers.

### 2431(i). Missing regular expression traits requirements

Section: 30.2 [re.req] Status: New Submitter: Jonathan Wakely Opened: 2014-09-30 Last modified: 2020-04-16

Priority: 3

View other active issues in [re.req].

View all other issues in [re.req].

View all issues with New status.

Discussion:

The requirements on the traits class in 30.2 [re.req] do not say whether a regular expression traits class is required to be `DefaultConstructible`, `CopyConstructible`, `CopyAssignable` etc.

The `std::regex_traits` class appears to be all of the above, but can `basic_regex` assume that for user-defined traits classes?

Should the following statements all leave `u` in equivalent states?

>     X u{v};
>     X u; u = v;
>     X u; u.imbue(v.getloc();

Whether they are equivalent has implications for `basic_regex` copy construction and assignment.

[2020-04-16, Jonathan adds that 30.7.5 [re.regex.locale] requires the traits type to be default-initialized, despite no guarantee that the traits type is default constructible. ]

Proposed resolution:

### 2432(i). `initializer_list` assignability

Section: 17.10 [support.initlist] Status: EWG Submitter: David Krauss Opened: 2014-09-30 Last modified: 2015-05-22

Priority: 2

View other active issues in [support.initlist].

View all other issues in [support.initlist].

View all issues with EWG status.

Discussion:

`std::initializer_list::operator=` 17.10 [support.initlist] is horribly broken and it needs deprecation:

>     std::initializer_list<foo> a = {{1}, {2}, {3}};
>     a = {{4}, {5}, {6}};
>     // New sequence is already destroyed.

Assignability of `initializer_list` isn't explicitly specified, but most implementations supply a default assignment operator. I'm not sure what 16.3 [description] says, but it probably doesn't matter.

[Lenexa 2015-05-05: Send to EWG as discussed in Telecon]

Proposed resolution:

1. Edit 17.10 [support.initlist] p1, class template `initializer_list` synopsis, as indicated:

   >     namespace std {
   >       template<class E> class initializer_list {
   >       public:
   >         […]
   >         constexpr initializer_list() noexcept;

   >         initializer_list(const initializer_list&) = default;
   >         initializer_list(initializer_list&&) = default;
   >         initializer_list& operator=(const initializer_list&) = delete;
   >         initializer_list& operator=(initializer_list&&) = delete;

   >         constexpr size_t size() const noexcept;
   >         […]
   >       };
   >       […]
   >     }

### 2452(i). `is_constructible`, etc. and default arguments

Section: 20.15 [meta] Status: Core Submitter: Hubert Tong Opened: 2014-11-04 Last modified: 2015-10-21

Priority: 3

View other active issues in [meta].

View all other issues in [meta].

Discussion:

The `BaseCharacteristic` for `is_constructible` is defined in terms of the well-formedness of a declaration for an invented variable. The well-formedness of the described declaration itself may change for the same set of arguments because of the introduction of default arguments.

In the following program, there appears to be conflicting definitions of a specialization of `std::is_constructible`; however, it seems that this situation is caused without a user violation of the library requirements or the ODR. There is a similar issue with `is_convertible`, `result_of` and others.

a.cc:

>     #include <type_traits>
>     struct A { A(int, int); };
>     const std::false_type& x1 = std::is_constructible<A, int>();

>     int main() { }

b.cc:

>     #include <type_traits>
>     struct A { A(int, int); };

>     inline A::A(int, int = 0) { }

>     const std::true_type& x2 = std::is_constructible<A, int>();

Presumably this program should invoke undefined behaviour, but the Library specification doesn't say that.

[2015-02 Cologne]

Core wording should say "this kind of thing is ill-formed, no diagnostic required"

Proposed resolution:

### 2453(i). §[iterator.range] and now [iterator.container] aren't available via `<initializer_list>`

Section: 17.10 [support.initlist], 23.7 [iterator.range] Status: New Submitter: Richard Smith Opened: 2014-11-11 Last modified: 2021-06-06

Priority: 3

View other active issues in [support.initlist].

View all other issues in [support.initlist].

View all issues with New status.

Discussion:

These sections define helper functions, some of which apply to `initializer_list<T>`. And they're available if you include one of a long list of header files, many of which include `<initializer_list>`. But they are not available if you include `<initializer_list>`. This seems very odd.

>     #include <initializer_list>
>     auto x = {1, 2, 3};
>     const int *p = data(x); // error, undeclared
>     #include <vector>
>     const int *q = data(x); // ok

Proposed resolution:

### 2457(i). `std::begin()` and `std::end()` do not support multi-dimensional arrays correctly

Section: 23.7 [iterator.range] Status: New Submitter: Janez Žemva Opened: 2014-11-16 Last modified: 2015-02-23

Priority: 3

View other active issues in [iterator.range].

View all other issues in [iterator.range].

View all issues with New status.

Discussion:

The following code:

>     #include <algorithm>
>     #include <iterator>
>     #include <iostream>
>     #include <cassert>

>     int main()
>     {
>       int a[2][3][4] = { { { 1,  2,  3,  4}, { 5,  6,  7,  8}, { 9, 10, 11, 12} },
>                          { {13, 14, 15, 16}, {17, 18, 19, 20}, {21, 22, 23, 24} } };
>       int b[2][3][4];

>       assert(std::distance(std::begin(a), std::end(a)) == 2 * 3 * 4);
>       std::copy(std::begin(a), std::end(a), std::begin(b));
>       std::copy(std::begin(b), std::end(b), std::ostream_iterator<int>(std::cout, ","));
>     }

does not compile.

A possible way to remedy this would be to add the following overloads of `begin`, `end`, `rbegin`, and `rend` to 23.7 [iterator.range], relying on recursive evaluation:

>     namespace std {

>       template <typename T, size_t M, size_t N>
>       constexpr remove_all_extents_t<T>*
>       begin(T (&array)[M][N])
>       {
>         return begin(*array);
>       }

>       template <typename T, size_t M, size_t N>
>       constexpr remove_all_extents_t<T>*
>       end(T (&array)[M][N])
>       {
>         return end(array[M - 1]);
>       }

>       template <typename T, size_t M, size_t N>
>       reverse_iterator<remove_all_extents_t<T>*>
>       rbegin(T (&array)[M][N])
>       {
>         return decltype(rbegin(array))(end(array[M - 1]));
>       }

>       template <typename T, size_t M, size_t N>
>       reverse_iterator<remove_all_extents_t<T>*>
>       rend(T (&array)[M][N])
>       {
>         return decltype(rend(array))(begin(*array));
>       }

>     }

Proposed resolution:

### 2461(i). Interaction between allocators and container exception safety guarantees

Section: 16.4.4.6 [allocator.requirements], 22.3.11.3 [vector.capacity], 22.3.11.5 [vector.modifiers] Status: New Submitter: dyp Opened: 2014-12-06 Last modified: 2015-06-10

Priority: 3

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with New status.

Discussion:

When resizing a `vector`, the accessibility and exception specification of the value type's constructors determines whether the elements are copied or moved to the new buffer. However, the copy/move is performed via the allocator's `construct` member function, which is assumed, but not required, to call the copy/move constructor and propagate only exceptions from the value type's copy/move constructor. The issue might also affect other classes.

The current wording in N4296 relevant here is from Table 28 — "Allocator requirements" in 16.4.4.6 [allocator.requirements]:

> Table 28 — Allocator requirements
> Expression | Return type | Assertion/note pre-/post-condition | Default
> --- | --- | --- | ---
> `…`
> `a.construct(c, args)` | (not used) | Effect: Constructs an object of type `C` at `c` | `::new ((void*)c) C(forward<Args>(args)...)`
> `…`

and from 16.4.4.6 [allocator.requirements] p9:

> An allocator may constrain the types on which it can be instantiated and the arguments for which its `construct` member may be called. If a type cannot be used with a particular allocator, the allocator class or the call to `construct` may fail to instantiate.

I conclude the following from the wording:

1. The allocator is not required to call the copy constructor if the arguments (args) is a single (potentially const) lvalue of the value type. Similarly for a non-const rvalue + move constructor. See also 22.2.1 [container.requirements.general] p15 which seems to try to require this, but is not sufficient: That paragraph specifies the semantics of the allocator's operations, but not which constructors of the value type are used, if any.

2. The allocator may throw exceptions in addition to the exceptions propagated by the constructors of the value type; it can also propagate exceptions from constructors other than a copy/move constructor.

This leads to an issue with the wording of the exception safety guarantees for vector modifiers in 22.3.11.5 [vector.modifiers] p1:

> […]

>     void push_back(const T& x);
>     void push_back(T&& x);

> > Remarks: Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid. If an exception is thrown other than by the copy constructor, move constructor, assignment operator, or move assignment operator of `T` or by any InputIterator operation there are no effects. If an exception is thrown while inserting a single element at the end and `T` is `CopyInsertable` or `is_nothrow_move_constructible<T>::value` is true, there are no effects. Otherwise, if an exception is thrown by the move constructor of a non-`CopyInsertable` `T`, the effects are unspecified.

The wording leads to the following problem: Copy and move assignment are invoked directly from `vector`. For intermediary objects (see 2164), `vector` also directly invokes the copy and move constructor of the value type. However, construction of the actual element within the buffer is invoked via the allocator abstraction. As discussed above, the allocator currently is not required to call a copy/move constructor. If `is_nothrow_move_constructible<T>::value` is `true` for some value type `T`, but the allocator uses modifying operations for `MoveInsertion` that do throw, the implementation is required to ensure that "there are no effects", even if the source buffer has been modified.

Similarly, the `vector` capacity functions specify exception safety guarantees referring to the move constructor of the value type. For example, `vector::resize` in 22.3.11.3 [vector.capacity] p14:

> Remarks: If an exception is thrown other than by the move constructor of a non-`CopyInsertable` `T` there are no effects.

The wording leads to the same issue as described above.

Code example:

>     template<class T>
>     class allocator;

>     class pot_reg_type // a type which creates
>                        // potentially registered instances
>     {
>     private:
>       friend class allocator<pot_reg_type>;
>       struct register_t {};

>       static std::set<pot_reg_type*>& get_registry()
>       {
>         static std::set<pot_reg_type*> registry;
>         return registry;
>       }
>       void enregister() noexcept(false)
>       {
>         get_registry().insert(this);
>       }
>       void deregister()
>       {
>         get_registry().erase(this);
>       }

>     public:
>       pot_reg_type(void               ) noexcept(true) {}
>       pot_reg_type(pot_reg_type const&) noexcept(true) {}
>       pot_reg_type(pot_reg_type&&     ) noexcept(true) {}

>     private:
>       pot_reg_type(register_t                     ) noexcept(false)
>       { enregister(); }
>       pot_reg_type(register_t, pot_reg_type const&) noexcept(false)
>       { enregister(); }
>       pot_reg_type(register_t, pot_reg_type&&     ) noexcept(false)
>       { enregister(); }
>     };

>     template<class T>
>     class allocator
>     {
>     public:
>       using value_type = T;

>       value_type* allocate(std::size_t p)
>       { return (value_type*) ::operator new(p); }

>       void deallocate(value_type* p, std::size_t)
>       { ::operator delete(p); }

>       void construct(pot_reg_type* pos)
>       {
>         new((void*)pos) pot_reg_type((pot_reg_type::register_t()));
>       }
>       void construct(pot_reg_type* pos, pot_reg_type const& source)
>       {
>         new((void*)pos) pot_reg_type(pot_reg_type::register_t(), source);
>       }

>       template<class... Args>
>       void construct(T* p, Args&&... args)
>       {
>         new((void*)p) T(std::forward<Args>(args)...);
>       }
>     };

The `construct` member function template is only required for rebinding, which can be required e.g. to store additional debug information in the allocated memory (e.g. VS2013).

Even though the value type has an accessible and `noexcept(true)` move constructor, this allocator won't call that constructor for rvalue arguments. In any case, it does not call a constructor for which vector has formulated its requirements. An exception thrown by a constructor called by this allocator is not covered by the specification in 22.3.11.5 [vector.modifiers] and therefore is guaranteed not to have any effect on the vector object when resizing.

For an example how this might invalidate the exception safety guarantees, see this post on the std-discussion mailing list.

Another problem arises for value types whose constructors are private, but may be called by the allocator e.g. via friendship. Those value types are not `MoveConstructible` (`is_move_constructible` is false), yet they can be `MoveInsertable`. It is not possible for `vector` to create intermediary objects (see 2164) of such a type by directly using the move constructor. Current implementations of the single-element forms of `vector::insert` and `vector::emplace` do create intermediary objects by directly calling one of the value type's constructors, probably to allow inserting objects from references that alias other elements of the container. As far as I can see, Table 100 — "Sequence container requirements" in 22.2.3 [sequence.reqmts] does not require that the creation of such intermediare objects can be performed by containers using the value type's constructor directly. It is unclear to me if the allocator's construct function could be used to create those intermediary objects, given that they have not been allocated by the allocator.

Two possible solutions:

1. Add the following requirement to the `allocator_traits::construct` function: If the parameter pack `args` consists of a single parameter of the type `value_type&&`, the function may only propagate exceptions if `is_nothrow_move_constructible<value_type>::value` is `false`.

   Requiring `alloctor_traits::construct` to call a true copy/move constructor of the value type breaks `std::scoped_allocator_adapter`, as pointed out by Casey Carter in a post on the std-discussion mailing list.

2. Change vector's criterion whether to move or copy when resizing:

   Instead of testing the value type's constructors via `is_move_constructible`, check the value of `noexcept( allocator_traits<Allocator>::construct(alloc, ptr, rval) )` where `alloc` is an lvalue of type `Allocator`, `ptr` is an expression of type `allocator_traits<Allocator>::pointer` and `rval` is a non-const rvalue of type `value_type`.

A short discussion of the two solutions:

Solution 1 allows keeping `is_nothrow_move_constructible<value_type>` as the criterion for `vector` to decide between copying and moving when resizing. It restricts what can be done inside the `construct` member function of allocators, and requires implementers of allocators to pay attention to the value types used. One could conceive allocators checking the following with a `static_assert`: If the value type `is_nothrow_move_constructible`, then the constructor actually called for `MoveInsertion` within the `construct` member function is also declared as noexcept.

Solution 2 requires changing both the implementation of the default allocator (add a conditional `noexcept`) and `vector` (replace `is_move_constructible` with an allocator-targeted check). It does not impose additional restrictions on the allocator (other than 22.2.1 [container.requirements.general] p15), and works nicely even if the move constructor of a `MoveInsertable` type is private or deleted (the allocator might be a friend of the value type).

In both cases, an addition might be required to provide the basic exception safety guarantee. A short discussion on this topic can be found in the std-discussion mailing list. Essentially, if `allocator_traits<Allocator>::construct` throws an exception, the object may or may not have been constructed. Two solutions are mentioned in that discussion:

1. `allocator_traits<Allocator>::construct` needs to tell its caller whether or not the construction was successful, in case of an exception.

2. If `allocator_traits<Allocator>::construct` propagates an exception, it shall either not have constructed an object at the specified location, or that object shall have been destroyed (or it shall ensure otherwise that no resources are leaked).

[2015-05-23, Tomasz Kamiński comments]

Solution 1 discussed in this issue also breaks support for the `polymorphic_allocator` proposed in the part of the Library Fundamentals TS v1, in addition to already mentioned `std::scoped_allocator_adapter`. Furthermore there is unknown impact on the other user-defined state-full allocators code written in the C++11.

In addition the library resolution proposed in the LWG issues 2089 and N4462, will break the relation between the `std::allocator_trait::construct` method and copy/move constructor even for the standard `std::allocator`. As example please consider following class:

>     struct NonCopyable
>     {
>       NonCopyable() = default;
>       NonCopyable(NonCopyable const&) = delete;
>       NonCopyable(NonCopyable&&) = delete;
>     };

>     struct InitListConstructor : NonCopyable
>     {
>       InitListConstructor() = default;
>       InitListConstructor(std::initializer_list<int>);
>       operator int() const;
>     };

For the above declarations following expression are ill-formed:

>     InitListConstructor copy(std::declval<InitListConstructor const&>());
>     InitListConstructor move(std::declval<InitListConstructor&&>());

So the class is not `CopyConstructible` nor `MoveConstructible`. However the following are well formed:

>     InitListConstructor copy{std::declval<InitListConstructor const&>()};
>     InitListConstructor move{std::declval<InitListConstructor&&>()};

And will be used by `std::allocator<InitListConstructor>::construct` in case of move-insertion and copy-insertion, after appliance of the resolution proposed in mentioned papers:

> The gist of the proposed library fix is simple:

> - if `is_constructible_v<TargetType, Args...>`, use direct-nonlist-initialization

> - otherwise, use brace-initialization.

As consequence the requirement proposed in the Solution 1:

> If the parameter pack `args` consists of a single parameter of the type `value_type&&`, the function may only propagate exceptions if `is_nothrow_move_constructible<value_type>::value` is false.

Will no longer hold for the `std::allocator`.

Proposed resolution:

### 2471(i). `copy_n`'s number of `InputIterator` increments unspecified

Section: 25.7.1 [alg.copy] Status: Open Submitter: Jonathan Wakely Opened: 2015-01-28 Last modified: 2018-06-22

Priority: 3

View other active issues in [alg.copy].

View all other issues in [alg.copy].

View all issues with Open status.

Discussion:

It's unspecified how many times `copy_n` increments the `InputIterator`. `uninitialized_copy_n` is specified to increment it exactly `n` times, which means if an `istream_iterator` is used then the next character after those copied is read from the stream and then discarded, losing data.

I believe all three of Dinkumware, libc++ and libstdc++ implement `copy_n` with `n - 1` increments of the `InputIterator`, which avoids reading and discarding a character when used with `istream_iterator`, but is inconsistent with `uninitialized_copy_n` and causes surprising behaviour with `istreambuf_iterator` instead, because `copy_n(in, 2, copy_n(in, 2, out))` is not equivalent to `copy_n(in, 4, out)`

[2016-08 Chicago]

Tues PM: refer to LEWG

[LEWG Kona 2017]

This is a mess. Append to Effects: If the InputIterator is not a forward iterator, increments n-1 times. Otherwise the number of increments is not more than n. (ncm) The preceding proposition is unsatisfactory, because it is wrong for istreambuf_iterator, which is much more useful than istream_iterator. Proposing instead: Append to Effects: If InputIterator is istream_iterator for some T, increments n-1 times. Otherwise, increments n times. Want a paper exploring what the implementations actually do, and what non-uniformity is "right".

Status to Open

Proposed resolution:

### 2472(i). Heterogeneous comparisons in the standard library can result in ambiguities

Section: 20.5.8 [tuple.rel], 20.10.9.3 [allocator.globals], 20.11.1.6 [unique.ptr.special], 20.11.3.8 [util.smartptr.shared.cmp], 27.5.7 [time.duration.comparisons], 27.6.7 [time.point.comparisons], 20.13.5 [scoped.adaptor.operators], 23.5.1.8 [reverse.iter.cmp], 23.5.3.8 [move.iter.op.comp] Status: New Submitter: Richard Smith Opened: 2015-02-07 Last modified: 2021-06-06

Priority: 3

View other active issues in [tuple.rel].

View all other issues in [tuple.rel].

View all issues with New status.

Discussion:

The standard library specifies a lot of heterogeneous comparison operators. For instance:

>     template<class... TTypes, class... UTypes>
>     constexpr bool operator!=(const tuple<TTypes...>&, const tuple<UTypes...>&);

This has an unfortunate consequence:

>     #include <tuple>
>     #include <utility>

>     using namespace std::rel_ops;
>     std::tuple<int> a(0);
>     bool b = a != a;

The last line here is ill-formed due to ambiguity: it might be `rel_ops::operator!=`, and it might be the heterogeneous tuple `operator!=`. These are not partially ordered, because they have different constraints: `rel_ops` requires the types to match, whereas the tuple comparison requires both types to be tuples (but not to match). The same thing happens for user code that defines its own unconstrained '`template<typename T> operator!=(const T&, const T&)`' rather than using `rel_ops`.

One straightforward fix would be to add a homogeneous overload for each heterogeneous comparison:

>     template<class... TTypes>
>     constexpr bool operator!=(const tuple<TTypes...>&, const tuple<TTypes...>&);

> This is then unambiguously chosen over the other options in the preceding case. FWIW, libstdc++ already does this in some cases.

Proposed resolution:

### 2478(i). Unclear how `wstring_convert` uses `cvtstate`

Section: D.23.2 [depr.conversions.string] Status: New Submitter: Jonathan Wakely Opened: 2015-03-04 Last modified: 2017-04-22

Priority: 4

View other active issues in [depr.conversions.string].

View all other issues in [depr.conversions.string].

View all issues with New status.

Discussion:

How do `wstring_convert::from_bytes` and `wstring_convert::to_bytes` use the `cvtstate` member?

Is it passed to the `codecvt` member functions? Is a copy of it passed to the member functions? "Otherwise it shall be left unchanged" implies a copy is used, but if that's really what's intended there are simpler ways to say so.

Proposed resolution:

### 2479(i). Unclear how `wbuffer_convert` uses `cvtstate`

Section: D.23.3 [depr.conversions.buffer] Status: New Submitter: Jonathan Wakely Opened: 2015-03-04 Last modified: 2017-04-22

Priority: 4

View other active issues in [depr.conversions.buffer].

View all other issues in [depr.conversions.buffer].

View all issues with New status.

Discussion:

How does `wbuffer_convert` use the `cvtstate` member?

Is the same conversion state object used for converting both the get and put areas? That means a read which runs out of bytes halfway through a multibyte character will leave some shift state in cvtstate, which would then be used by a following write, even though the shift state of the get area is unrelated to the put area.

Proposed resolution:

### 2480(i). Error handling of `wbuffer_convert` unclear

Section: D.23.3 [depr.conversions.buffer] Status: New Submitter: Jonathan Wakely Opened: 2015-03-04 Last modified: 2017-04-22

Priority: 4

View other active issues in [depr.conversions.buffer].

View all other issues in [depr.conversions.buffer].

View all issues with New status.

Discussion:

If a `codecvt` conversion returns `codecvt_base::error` should that be treated as `EOF`? An exception? Should all the successfully converted characters before a conversion error be available to the users of the `wbuffer_convert` and/or the internal `streambuf`, or does a conversion error lose information?

Proposed resolution:

### 2481(i). `wstring_convert` should be more precise regarding "byte-error string" etc.

Section: D.23.2 [depr.conversions.string] Status: New Submitter: Jonathan Wakely Opened: 2015-03-04 Last modified: 2017-04-22

Priority: 4

View other active issues in [depr.conversions.string].

View all other issues in [depr.conversions.string].

View all issues with New status.

Discussion:

Paragraph 4 of D.23.2 [depr.conversions.string] introduces `byte_err_string` as "a byte string to display on errors". What does display mean? The string is returned on error, it's not displayed anywhere.

Paragraph 14 says "Otherwise, if the object was constructed with a byte-error string, the member function shall return the byte-error string." The term byte-error string is not used anywhere else.

Paragraph 17 talks about storing "default values in `byte_err_string`". What default value? Is "Hello, world!" allowed? If it means default-construction it should say so. If paragraph 14 says it won't be used what does it matter how it's initialized? The end of the paragraph refers to storing "`byte_err` in `byte_err_string`". This should be more clearly related to the wording in paragraph 14.

It might help if the constructor (and destructor) was specified before the other member functions, so it can more formally define the difference between being "constructed with a byte-error string" and not.

All the same issues apply to the `wide_err_string` member.

Proposed resolution:

### 2490(i). `<regex>` needs lots of `noexcept`

Section: 30 [re] Status: New Submitter: Stephan T. Lavavej Opened: 2015-03-27 Last modified: 2015-05-05

Priority: 3

View other active issues in [re].

View all other issues in [re].

View all issues with New status.

Discussion:

Only 4 functions are marked `noexcept` in all of Clause 28. Many more need to be marked — for example, `regex_error::code()`, `basic_regex::swap()`, and `sub_match::length()`.

Proposed resolution:

### 2491(i). `std::less<T*>` in constant expression

Section: 20.14.8 [comparisons] Status: New Submitter: Agustín K-ballo Bergé Opened: 2015-04-01 Last modified: 2021-04-10

Priority: 3

View other active issues in [comparisons].

View all other issues in [comparisons].

View all issues with New status.

Discussion:

It is not entirely clear if and when the specializations of `std::less` (and friends) for pointer types can be used in a constant expression. Consider the following code:

>     #include <functional>

>     struct foo {};
>     foo x, y;
>     constexpr bool b = std::less<foo*>{}(&x, &y); // [1]

>     foo z[] = {{}, {}};
>     constexpr bool ba = std::less<foo*>{}(&z[0], &z[1]); // [2]

Comparing the address of unrelated objects is not a constant expression since the result is unspecified, so it could be expected for [1] to fail and [2] to succeed. However, `std::less` specialization for pointer types is well-defined and yields a total order, so it could just as well be expected for [1] to succeed. Finally, since the implementation of such specializations is not mandated, [2] could fail as well (This could happen, if an implementation would provide such a specialization and if that would use built-in functions that would not be allowed in constant expressions, for example). In any case, the standard should be clear so as to avoid implementation-defined `constexpr`-ness.

[2017-01-22, Jens provides rationale and proposed wording]

`std::less<T*>` is required to deliver a total order on pointers. However, the layout of global objects is typically determined by the linker, not the compiler, so requiring `std::less<T*>` to provide an ordering at compile-time that is consistent with run-time would need results from linking to feed back to the compiler, something that C++ has traditionally not required.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4618.

> 1. Add at the end of 20.14.8 [comparisons]:

>    > -2- For templates `less`, `greater`, `less_equal`, and `greater_equal`, […], if the call operator calls a built-in operator comparing pointers, the call operator yields a strict total order that is consistent among those specializations and is also consistent with the partial order imposed by those built-in operators. Relational comparisons of pointer values are not required to be usable as constant expressions.

[2021-04-05; Jiang An comments and provides alternative wording]

The libc++ and MSVC STL implementations only support flat address spaces, and always use comparison operators. The libstdc++ implementation casts pointer values to `uintptr_t` if the direct comparison result is unusable in constant evaluation.

So, I think that we can specify that the implementation-defined strict total order (3.27 [defns.order.ptr]) generates a core constant expression if and only if the corresponding underlying comparison expression comparing pointer values is a core constant expression. No any other case should be a core constant expression, otherwise we should also make the underlying comparison expression a core constant expression.

IMO the proposed resolution is already implemented in libc++, libstdc++, and MSVC STL, and implementable on compilers that either support flat address spaces only or have implemented intrinsics needed for transparent comparison operators and `std::is_constant_evaluated`.

Proposed resolution:

This wording is relative to N4885.

1. Add at the end of 20.14.8 [comparisons] p2:

   > -2- For templates `less`, `greater`, `less_equal`, and `greater_equal`, the specializations for any pointer type yield a result consistent with the implementation-defined strict total order over pointers (3.27 [defns.order.ptr]). [Note 1: If `a < b` is well-defined for pointers `a` and `b` of type `P`, then `(a < b) == less<P>()(a, b)`, `(a > b) == greater<P>()(a, b)`, and so forth. — end note] For template specializations `less<void>`, `greater<void>`, `less_equal<void>`, and `greater_equal<void>`, if the call operator calls a built-in operator comparing pointers, the call operator yields a result consistent with the implementation-defined strict total order over pointers. A comparison result of pointer values is a core constant expression if and only if the corresponding built-in comparison expression is a core constant expression.

2. Add at the end of 20.14.9 [range.cmp] (3.1):

   > -3- Effects:

   > 1. (3.1) — If the expression `std::forward<T>(t) == std::forward<U>(u)` results in a call to a built-in operator `==` comparing pointers: returns `false` if either (the converted value of) `t` precedes `u` or `u` precedes `t` in the implementation-defined strict total order over pointers (3.27 [defns.order.ptr]) and otherwise `true`. The result is a core constant expression if and only if `std::forward<T>(t) == std::forward<U>(u)` is a core constant expression.

   > 2. (3.2) — Otherwise, equivalent to: `return std::forward<T>(t) == std::forward<U>(u);`

3. Add at the end of 20.14.9 [range.cmp] (7.1):

   > -7- Effects:

   > 1. (7.1) — If the expression `std::forward<T>(t) < std::forward<U>(u)` results in a call to a built-in operator `<` comparing pointers: returns `true` if (the converted value of) `t` precedes `u` in the implementation-defined strict total order over pointers (3.27 [defns.order.ptr]) and otherwise `false`. The result is a core constant expression if and only if `std::forward<T>(t) < std::forward<U>(u)` is a core constant expression.

   > 2. (7.2) — Otherwise, equivalent to: `return std::forward<T>(t) < std::forward<U>(u);`

4. Add at the end of 20.14.8.8 [comparisons.three.way] (3.1):

   > -3- Effects:

   > 1. (3.1) — If the expression `std::forward<T>(t) <=> std::forward<U>(u)` results in a call to a built-in operator `<=>` comparing pointers: returns `strong_ordering::less` if (the converted value of) `t` precedes `u` in the implementation-defined strict total order over pointers (3.27 [defns.order.ptr]), `strong_ordering::greater` if `u` precedes `t`, and otherwise `strong_ordering::equal`. The result is a core constant expression if and only if `std::forward<T>(t) <=> std::forward<U>(u)` is a core constant expression.

   > 2. (3.2) — Otherwise, equivalent to: `return std::forward<T>(t) <=> std::forward<U>(u);`

### 2493(i). `initializer_list` supports incomplete classes

Section: 17.10 [support.initlist] Status: New Submitter: David Krauss Opened: 2015-04-27 Last modified: 2015-05-05

Priority: 4

View other active issues in [support.initlist].

View all other issues in [support.initlist].

View all issues with New status.

Discussion:

The typical use-case of `std::initializer_list<T>` is for a pass-by-value parameter of `T`'s constructor. However, this contravenes 16.4.5.8 [res.on.functions]/2.5 because `initializer_list` doesn't specifically allow incomplete types (as do for example `std::unique_ptr` (20.11.1 [unique.ptr]/5) and `std::enable_shared_from_this` (20.11.6 [util.smartptr.enab]/2)).

A resolution would be to copy-paste the relevant text from such a paragraph.

Proposed resolution:

### 2496(i). Certain hard-to-avoid errors not in the immediate context are not allowed to be triggered by the evaluation of type traits

Section: 20.15.5.4 [meta.unary.prop] Status: New Submitter: Hubert Tong Opened: 2015-05-07 Last modified: 2015-08-03

Priority: 3

View other active issues in [meta.unary.prop].

View all other issues in [meta.unary.prop].

View all issues with New status.

Discussion:

I do not believe that the wording in 20.15.5.4 [meta.unary.prop] paragraph 3 allows for the following program to be ill-formed:

>     #include <type_traits>

>     template <typename T> struct B : T { };
>     template <typename T> struct A { A& operator=(const B<T>&); };

>     std::is_assignable<A<int>, int> q;

In particular, I do not see where the wording allows for the "compilation of the expression" `declval<T>() = declval<U>()` to occur as a consequence of instantiating `std::is_assignable<T, U>` (where `T` and `U` are, respectively, `A<int>` and `int` in the example code).

Instantiating `A<int>` as a result of requiring it to be a complete type does not trigger the instantiation of `B<int>`; however, the "compilation of the expression" in question does.

Proposed resolution:

### 2497(i). Use of `uncaught_exception()`

Section: 29.7.5.2.4 [ostream.sentry] Status: New Submitter: Roger Orr Opened: 2015-05-08 Last modified: 2020-09-06

Priority: 3

View all other issues in [ostream.sentry].

View all issues with New status.

Discussion:

In the current 29.7.5.2.4 [ostream.sentry], p4 refers to the now deprecated `std::uncaught_exception()`: D.9 [depr.uncaught].

> If `((os.flags() & ios_base::unitbuf) && !uncaught_exception() && os.good())` is true, calls `os.rdbuf()->pubsync()`.

This needs to be changed, for example to use `std::uncaught_exceptions()` and to capture the value on entry and compare with the saved value on exit.

[2015-06, Telecon]

JW: I already added an 's' here to make it use the new function, but that doesn't resolve Roger's suggestion to capture the value on entry and check it.

[2019-03-21; Daniel comments and provides wording]

The wording below implements Roger's suggestion.

Proposed resolution:

This wording is relative to N4810.

1. Modify 29.7.5.2.4 [ostream.sentry], class `basic_ostream::sentry` synopsis, as indicated:

   >     namespace std {
   >       template<class charT, class traits = char_traits<charT>>
   >       class basic_ostream<charT, traits>::sentry {
   >         bool ok_; // exposition only
   >         int uncaught_ = uncaught_exceptions(); // exposition only
   >       public:
   >         explicit sentry(basic_ostream<charT, traits>& os);
   >         ~sentry();
   >         explicit operator bool() const { return ok_; }
   >         sentry(const sentry&) = delete;
   >         sentry& operator=(const sentry&) = delete;
   >       };
   >     }

   > […]

   >     ~sentry();

   > > -4- If `(os.flags() & ios_base::unitbuf) && !uncaught_exceptions() <= uncaught_ && os.good()` is `true`, calls `os.rdbuf()->pubsync()`. If that function returns `-1`, sets `badbit` in `os.rdstate()` without propagating an exception.

### 2504(i). `basic_streambuf` is not an abstract class

Section: 29.6.3 [streambuf] Status: New Submitter: Jonathan Wakely Opened: 2015-05-28 Last modified: 2015-08-03

Priority: 3

View all other issues in [streambuf].

View all issues with New status.

Discussion:

29.6.3 [streambuf] p1 says:

> The class template `basic_streambuf<charT, traits>` serves as an abstract base class for deriving various stream buffers whose objects each control two character sequences: […]

The term "abstract base class" is not defined in the standard, but "abstract class" is (11.7.4 [class.abstract]).

According to the synopsis `basic_streambuf` has no pure virtual functions so is not an abstract class and none of libstdc++, libc++, or dinkumware implement it as an abstract class. I don't believe the wording was ever intended to require it to be an abstract class, but it could be read that way.

I suggest the wording be changed to "polymorphic base class" or something else that can't be seen to imply a normative requirement to make it an abstract class.

Proposed resolution:

### 2506(i). Underspecification of atomics

Section: 6.9.2 [intro.multithread], 31.8 [atomics.types.generic], 17.13 [support.runtime] Status: SG1 Submitter: Geoffrey Romer Opened: 2015-05-29 Last modified: 2018-03-15

Priority: 3

View all other issues in [intro.multithread].

View all issues with SG1 status.

Discussion:

The concurrency libraries specified in clauses 29 and 30 do not adequately specify how they relate to the concurrency model specified in 6.9.2 [intro.multithread]. In particular:

6.9.2 [intro.multithread] specifies "atomic objects" as having certain properties. I can only assume that instances of the classes defined in Clause 29 are intended to be "atomic objects" in this sense, but I can't find any wording to specify that, and it's genuinely unclear whether Clause 30 objects are atomic objects. In fact, on a literal reading the C++ Standard doesn't appear to provide any portable way to create an atomic object, or even determine whether an object is an atomic object.

(It's not clear if the term "atomic object" is actually needed, given that atomic objects can have non-atomic operations, and non-atomic objects can have atomic operations. But even if the term itself goes away, there still needs to be some indication that Clause 29 objects have the properties currently attributed to atomic objects).

Similarly, 6.9.2 [intro.multithread] uses "atomic operation" as a term of art, but the standard never unambiguously identifies any operation as an "atomic operation" (although in one case it unambiguously identifies an operation that is not atomic). It does come close in a few cases, but not close enough:

- 6.9.2 [intro.multithread]/p7 could be read to imply that "synchronization operations" in Clauses 29 and 30 are also atomic operations. However, that's vague and indirect, and somewhat belied by 32.5.4.2 [thread.mutex.requirements.mutex]/p5, which specifies that mutex lock and unlock operations "behave as atomic operations", but only "for purposes of determining the existence of a data race". Furthermore, not a single operation in Clause 29 explicitly identifies itself as a "synchronization operation".

- 31.8 [atomics.types.generic]/p4 states in part that "There shall be a specialization `atomic<bool>` which provides the general atomic operations as specified in 29.6.1", but read in context, "general atomic operations" appears to be a loose synonym for "general operations on atomic types" as defined in [atomics.types.operations.general], rather than a use of "atomic object" as Words of Power. Incidentally, "atomic type" is never satisfactorily defined either (although the `<atomic>` synopsis comes close).

- 17.13 [support.runtime]/p10 specifies exactly which operations are "plain lock-free atomic operations", but in a standard where an "integral constant expression" isn't necessarily a "constant expression", I do not feel safe assuming that a "plain lock-free atomic operation" is an "atomic operation".

- Hans Boehm tells me the operations with "atomically" in the Effects element are intended to be atomic operations, but since "atomic operation" is a term of art (e.g. in 6.9.2 [intro.multithread]/p27.4), I think this needs to be spelled out rather than assumed. Furthermore, this does not help with 31.11 [atomics.fences], or anything in Clause 30.

[2018-03 JAX; Geoffrey comments in behalf of SG1]

SG1 consensus is that operations outside clause 32 are not "atomic operations", and objects of types defined outside clause 32 are not "atomic objects". "Synchronization operations" are operations which act as endpoints of primitive edges of partial orders other than sequenced-before, but it may make more sense to just drop that term and inline the definition, so to speak.

We would welcome a paper to make those definitions more explicit, and revise the wording as needed to be consistent with those definitions.

Proposed resolution:

### 2507(i). `codecvt_mode` should be a bitmask type

Section: D.22 [depr.locale.stdcvt] Status: New Submitter: Jonathan Wakely Opened: 2015-06-08 Last modified: 2017-04-22

Priority: 3

View all other issues in [depr.locale.stdcvt].

View all issues with New status.

Discussion:

The enumeration type `codecvt_mode` is effectively a bitmask type (16.3.3.3.4 [bitmask.types]) with three elements, but isn't defined as such.

This harms usability because bitmask types are required to work well with bitwise operators, but `codecvt_mode` doesn't have overloaded operators, making it very inconvenient to combine values:

>     std::codecvt_utf16<char32_t, 0x10FFFF,
>       static_cast<std::codecvt_mode>(std::little_endian|std::generate_header)>
>     cvt;

The `static_cast` harms readability and should not be necessary.

I suggest that either `codecvt_mode` is specified to be a bitmask type, or as a minimal fix we provide an overloaded `operator|` that returns the right type.

Proposed resolution:

### 2508(i). §[new.delete.dataraces] wording needs to be updated

Section: 17.6.3.5 [new.delete.dataraces] Status: New Submitter: Hans Boehm Opened: 2015-06-09 Last modified: 2016-02-01

Priority: 3

View all other issues in [new.delete.dataraces].

View all issues with New status.

Discussion:

17.6.3.5 [new.delete.dataraces] uses obsolete wording.

It should introduce a "synchronizes with" relationship. "Happens before" is too weak, since that may not composes with sequenced before.

The "shall not introduce a data race" wording is probably not technically correct either. These may race with other (non-allocation/deallocation) concurrent accesses to the object being allocated or deallocated.

Proposed resolution:

### 2512(i). Y2K bites; what is an "unambiguous year identifier"?

Section: 28.4.6.2.3 [locale.time.get.virtuals] Status: Open Submitter: Hubert Tong Opened: 2015-06-19 Last modified: 2017-09-07

Priority: 4

View other active issues in [locale.time.get.virtuals].

View all other issues in [locale.time.get.virtuals].

View all issues with Open status.

Discussion:

I recently encountered a failure related to questionable use of `do_get_year`. The platform where the code happened to work had an implementation which handled certain three-digit "year identifiers" as the number of years since 1900 (this article describes such an implementation).

28.4.6.2.3 [locale.time.get.virtuals] makes it implementation defined whether two-digit years are accepted, etc., but does not say anything specifically about three-digit years.

The implementation freedom to not report errors in 28.4.6.2 [locale.time.get] paragraph 1 also seems to be too broad.

See also the discussion following c++std-lib-38042.

[2016-08 Chicago]

Wed PM: This has been this way since C++98. Don't think it's a P2.

Change to P4, and move to Open.

Proposed resolution:

### 2513(i). Missing requirements for `basic_string::value_type`

Section: 21.1 [strings.general] Status: New Submitter: Jonathan Wakely Opened: 2015-06-26 Last modified: 2020-09-06

Priority: 4

View all other issues in [strings.general].

View all issues with New status.

Discussion:

The allocator-aware container requirements in Table 98 impose no `MoveAssignable` requirements on the `value_type` when `propagate_on_container_move_assignment` is true, because typically the container's storage would be moved by just exchanging some pointers.

However for a `basic_string` using the small string optimization move assignment may need to assign individual characters into the small string buffer, even when the allocator propagates.

The only requirement on the char-like objects stored in a `basic_string` are that they are non-array POD types and `Destructible`, which means that a POD type with a deleted move assignment operator should be usable in a `basic_string`, despite it being impossible to move assign:

>     #include <string>

>     struct odd_pod
>     {
>       odd_pod() = default;
>       odd_pod& operator=(odd_pod&&) = delete;
>     };

>     static_assert(std::is_pod<odd_pod>::value, "POD");

>     int main()
>     {
>       using S = std::basic_string<odd_pod>;
>       S s;
>       s = S{};       // fails
>     }

Using libstdc++ `basic_string<odd_pod>` cannot even be default-constructed because the constructor attempts to assign the null terminator to the first element of the small string buffer.

Similar problems exist with POD types with a deleted default constructor.

I believe that `basic_string` should require its `value_type` to be at least `DefaultConstructible` and `MoveAssignable`.

[2016-06, Oulu]

This should be resolved by P0178

Note: P0178 was sent back to LEWG in Oulu.

Proposed resolution:

### 2524(i). `generate_canonical` can occasionally return 1.0

Section: 26.6.9.4.2 [rand.dist.pois.exp] Status: Open Submitter: Michael Prähofer Opened: 2015-08-20 Last modified: 2018-08-22

Priority: 2

View all issues with Open status.

Discussion:

Original title was: `exponential_distribution<float>` sometimes returns inf.

The random number distribution class template `exponential_distribution<float>` may return "inf" as can be seen from the following example program:

>     // compiled with
>     // g++ -std=c++11 Error_exp_distr.cpp

>     #include <iostream>
>     #include <random>
>     #include <bitset>

>     int main(){
>       unsigned long long h;
>       std::mt19937_64 mt1(1);
>       std::mt19937_64 mt2(1);
>       mt1.discard(517517);
>       mt2.discard(517517);
>       std::exponential_distribution<float> dis(1.0);
>       h = mt2();
>       std::cout << std::bitset<64>(h) << " " << (float) -log(1 - h/pow(2, 64)) << " "
>                 << -log(1 - (float) h/pow(2, 64)) << " " << dis(mt1) << std::endl;
>       h = mt2();
>       std::cout << std::bitset<64>(h) << " " << (float) -log(1 - h/pow(2, 64)) << " "
>                 << -log(1 - (float) h/pow(2, 64)) << " " << dis(mt1) << std::endl;
>     }

output:

>     0110010110001001010011000111000101001100111110100001110011100001 0.505218 0.505218 0.505218
>     1111111111111111111111111101010011000110011110011000110101100110 18.4143 inf inf

The reason seems to be that converting a `double x` in the range `[0, 1)` to `float` may result in `1.0f` if `x` is close enough to `1`. I see two possibilities to fix that:

1. use internally `double` (or `long double`?) and then convert the result at the very end to `float`.

2. take only 24 random bits and convert them to a `float x` in the range `[0, 1)` and then return `-log(1 - x)`.

I have not checked if `std::exponential_distribution<double>` has the same problem: For `float` on the average 1 out of 224 (~107) draws returns "inf", which is easily confirmed. For `double` on the average 1 out of 253 (~1016) draws might return "inf", which I have not tested.

Marshall:
I don't think the problem is in `std::exponential_distribution`; but rather in `generate_canonical`.

Consider:

>     std::mt19937_64 mt2(1);
>     mt2.discard(517517);
>     std::cout << std::hexfloat << std::generate_canonical<float, std::numeric_limits<float>::digits>(mt2) << std::endl;
>     std::cout << std::hexfloat << std::generate_canonical<float, std::numeric_limits<float>::digits>(mt2) << std::endl;
>     std::cout << std::hexfloat << std::generate_canonical<float, std::numeric_limits<float>::digits>(mt2) << std::endl;

which outputs:

>     0x1.962532p-2
>     0x1p+0
>     0x1.20d0cap-3

but `generate_canonical` is defined to return a result in the range [0, 1).

[2015-10, Kona Saturday afternoon]

Options:

- 1) NAD, make it work. E.g. nudge slightly, making the hightest result return the highest allowable value (next_after). This might change the distribution slightly.
- 2) Re-run the algorithm when you get a 1. This changes the specification in that it makes extra calls to the random engine.
- 3) Something else

WEB: The one thing we cannot tolerate is any output range other than [0, 1).

WEB: I believe there may be a documented algorithm for the generator, and perhaps it's possible to discover en-route that the algorithm produces the wrong result and fix it.

MC: No. I analyzed this once, and here it is: the algorithm is in [rand.util.canonical], and it's all fine until p5. The expression `S/R^k` is mathematically less than one, but it may round to one.

GR: Could we change the rounding mode for the computation?

HH: No, because the rounding mode is global, not thread-local.

AM: SG1 wants to get rid of the floating point environment.

STL: The problem is that the standard specifies the implementation, and the implementation doesn't work.

MC: I'm not sure if nudging it down will introduce a subtle bias.

EF: I worry about how the user's choice of floating point environment affects the behaviour.

MS offers to run the topic past colleagues.

MC: Will set the status to open. STL wants to rename the issue. WEB wants to be able to find the issue by its original name still.

Mike Spertus to run the options past his mathematical colleagues, and report back.

[2017-11 Albuquerque Wednesday issue processing]

Choice: Rerun the algorithm if it gets 1.0.

Thomas K to provide wording; Marshall and STL to review.

[2018-08 Batavia Monday issue discussion]

Davis has a paper P0952 which resolves this.

Proposed resolution:

### 2528(i). Order of `std::tuple` construction unspecified

Section: 20.5.3.1 [tuple.cnstr] Status: New Submitter: Brian Rodriguez Opened: 2015-08-25 Last modified: 2017-02-19

Priority: 3

View other active issues in [tuple.cnstr].

View all other issues in [tuple.cnstr].

View all issues with New status.

Discussion:

The `std::tuple` order of element construction is unspecified. It is either in the same order of the type list or in reverse.

Consider the following program:

>     #include <iostream>
>     #include <tuple>

>     struct X
>     {
>       X(int) { std::cout << "X constructor\n"; }
>     };

>     struct Y
>     {
>       Y(int) { std::cout << "Y constructor\n"; }
>     };

>     int main()
>     {
>       std::tuple<X, Y> t(1, 2);
>     }

Here is a link to two sample compilations. The first uses libstdc++ and constructs in reverse order, and the second uses libc++ and constructs in in-order.

A `std::tuple` mimics both a struct and type-generic container and should thus follow their standards. Construction is fundamentally different from a function call, and it has been historically important for a specific order to be guaranteed; namely: whichever the developer may decide. Mandating construction order will allow developers to reference younger elements later on in the chain as well, much like a struct allows you to do with its members.

There are implementation issues as well. Reversed lists will require unnecessary overhead for braced-initializer-list initialization. Since lists are evaluated from left to right, the initializers must be placed onto the stack to respect the construction order. This issue could be significant for large tuples, deeply nested tuples, or tuples with elements that require many constructor arguments.

I propose that the `std::tuple<A, B, ..., Y, Z>`'s constructor implementation be standardized, and made to construct in the same order as its type list e.g. `A{}, B{}, ..., Y{}, Z{}`.

Daniel:

When N3140 became accepted, wording had been added that gives at least an indication of requiring element initialization in the order of the declaration of the template parameters. This argumentation can be based on 20.5.3.1 [tuple.cnstr] p3 (emphasize mine):

> -3- In the constructor descriptions that follow, let `i` be in the range `[0,sizeof...(Types))` in order, `Ti` be the `ith` type in `Types`, and `Ui` be the `ith` type in a template parameter pack named `UTypes`, where indexing is zero-based.

But the current wording needs to be improved to make that intention clearer and an issue like this one is necessary to be sure that the committee is agreeing (or disagreeing) with that intention, especially because N3140 didn't really point out the relevance of the element construction order in the discussion, and because not all constructors explicitly refer to the ordered sequence of numbers generated by the variable `i` (The move constructor does it right, but most other don't do that).

[2017-02-12, Alisdair comments]

Note that this issue should not be extended to cover the assignment operators, as implementations may want the freedom to re-order member-wise assignment so that, for example, all potentially-throwing assignments are performed before non-throwing assignments (as indicated by the `noexcept` operator).

Proposed resolution:

### 2530(i). Clarify observable side effects of releasing a shared state

Section: 32.9.5 [futures.state] Status: Open Submitter: Agustín K-ballo Bergé Opened: 2015-09-03 Last modified: 2016-08-06

Priority: 3

View all other issues in [futures.state].

View all issues with Open status.

Discussion:

When a shared-state is released, it may be necessary to execute user defined code for the destructor of a stored value or exception. It is unclear whether the execution of said destructor constitutes an observable side effect.

While discussing N4445 in Lenexa, Nat Goodspeed pointed out that 32.9.5 [futures.state]/5.1 does not explicitly mention the destruction of the result, so implementations should be allowed to release (or reuse) a shared state ahead of time under the "as-if" rule.

The standard should clarify whether the execution of destructors is a visible side effect of releasing a shared state.

[2016-08-03 Chicago]

This is related to 2532

Fri AM: Moved to Open

Proposed resolution:

### 2532(i). Satisfying a `promise` at thread exit

Section: 32.9.6 [futures.promise] Status: Open Submitter: Agustín K-ballo Bergé Opened: 2015-09-03 Last modified: 2016-08-06

Priority: 3

View other active issues in [futures.promise].

View all other issues in [futures.promise].

View all issues with Open status.

Discussion:

`promise::set_value_at_thread_exit` and `promise::set_exception_at_thread_exit` operate on a shared state at thread exit, without making the thread participate in the ownership of such shared state.

Consider the following snippet:

>     std::promise<int>{}.set_value_at_thread_exit(42);

Arguably, since the `promise` abandons its shared state without actually making it ready, a `broken_promise` error condition should be stored in the shared state. Implementations diverge, they either crash at thread exit by dereferencing an invalid pointer, or keep the shared state around until thread exit.

[2016-08-03 Chicago]

This is related to 2530

[2016-08-03, Billy O'Neal suggests concrete wording]

Fri AM: Moved to Open

Proposed resolution:

This wording is relative to N4606.

1. Change 32.9.5 [futures.state] p7 as indicated:

   > -7- When an asynchronous provider is said to abandon its shared state, it means:

   > 1. (7.1) — first, if that state is not ready or scheduled to be made ready at thread exit, the provider

   >    1. (7.1.1) — stores an exception object of type `future_error` with an error condition of `broken_promise` within its shared state; and then

   >    2. (7.1.2) — makes its shared state ready;

2. Change 32.9.5 [futures.state] p10 as indicated:

   > -10- Some functions (e.g., `promise::set_value_at_thread_exit`) delay making the shared state ready until schedule the shared state to be made ready when the calling thread exits. This associates a reference to the shared state with the calling thread. The destruction of each of that thread's objects with thread storage duration (6.7.5.3 [basic.stc.thread]) is sequenced before making that shared state ready. When the calling thread makes the shared state ready, if the thread holds the last reference to the shared state, the shared state is destroyed. [Note: This means that the shared state may not become ready until after the asynchronous provider has been destroyed. — end note]

### 2533(i). [concurr.ts] Constrain threads where `future::then` can run a continuation

Section: 99 [concurr.ts::futures.unique.future] Status: SG1 Submitter: Agustín K-ballo Bergé Opened: 2015-09-03 Last modified: 2021-06-06

Priority: Not Prioritized

View all issues with SG1 status.

Discussion:

Addresses: concurr.ts

In N4538, the continuation given to `future::then` can be run "on an unspecified thread of execution". This is too broad, as it allows the continuation to be run on the main thread, a UI thread, or any other thread. In comparison, functions given to `async` run "as if in a new thread of execution", while the Parallelism TS gives less guarantees by running "in either the invoking thread or in a thread implicitly created by the library to support parallel algorithm execution". The threads on which the continuation given to `future::then` can run should be similarly constrained.

[2017-03-01, Kona, SG1]

Agreement that this is a problem. Suggested addition to the issue is below. We have no immediate delivery vehicle for a fix at the moment, but we would like to make the intended direction clear.

There is SG1 consensus that `.then` continuations should, by default, and in the absence of executors, be run only in the following ways:

1. If the future is not ready when `.then()` is called, the `.then` argument may be run on the execution agent that fulfills the promise.

2. In all cases, the `.then` argument may be run on an implementation-provided thread, i.e. a thread that is neither the main thread nor explicitly created by the user.

In the absence of an executor argument (which currently cannot be supplied), running of the `.then()` continuation will not block the thread calling `.then()`, even if the future is ready at the time.

Straw polls:

SF | F | N | A | SA

For the default behaviour:

"1. Run on completed task or new execution agent"

0 | 7 | 5 | 1 | 0

"2. Run on completed task or `.then` caller"

0 | 0 | 5 | 5 | 3

"3. Leave as implementation defined"

1 | 2 | 4 | 3 | 3

"4. Always new execution agent"

2 | 3 | 6 | 2 | 0

The actual conclusion was to allow either (1) or (4) for now, since they are quite close, but present a very different programming mode from (2).

Proposed resolution:

### 2546(i). Implementability of locale-sensitive UnicodeEscapeSequence matching

Section: 30.12 [re.grammar] Status: New Submitter: Hubert Tong Opened: 2015-10-08 Last modified: 2015-10-21

Priority: 4

View other active issues in [re.grammar].

View all other issues in [re.grammar].

View all issues with New status.

Discussion:

In 30.12 [re.grammar] paragraph 2:

> `basic_regex` member functions shall not call any locale dependent C or C++ API, including the formatted string input functions. Instead they shall call the appropriate traits member function to achieve the required effect.

Yet, the required interface for a regular expression traits class (30.2 [re.req]) does not appear to have any reliable method for determining whether a character as encoded for the locale associated with the traits instance is the same as a character represented by a UnicodeEscapeSequence, e.g., assuming a sane `ru_RU.koi8r` locale:

>     #include <stdio.h>
>     #include <stdlib.h>
>     #include <regex>

>     const char data[] = "\xB3";
>     const char matchCyrillicCaptialLetterYo[] = R"(\u0401)";

>     int main(void)
>     {
>       try {
>         std::regex myRegex;
>         myRegex.imbue(std::locale("ru_RU.koi8r"));

>         myRegex.assign(matchCyrillicCaptialLetterYo, std::regex_constants::ECMAScript);
>         printf("(%s)\n", std::regex_replace(std::string(data), myRegex, std::string("E")).c_str());

>         myRegex.assign("[[:alpha:]]", std::regex_constants::ECMAScript);
>         printf("(%s)\n", std::regex_replace(std::string(data), myRegex, std::string("E")).c_str());
>       } catch (std::regex_error& e) {
>         abort();
>       }
>       return 0;
>     }

The implementation I tried prints:

>     (Ё)
>     (E)

Which means that the character class matching worked, but not the matching to the UnicodeEscapeSequence.

Proposed resolution:

### 2547(i). Container requirements (and other library text) should say "strict total order", not just "total order"

Section: 20.14.8 [comparisons], 22.2.1 [container.requirements.general], 32.4.3.2 [thread.thread.id] Status: New Submitter: Matt Austern Opened: 2015-10-08 Last modified: 2015-10-21

Priority: 3

View other active issues in [comparisons].

View all other issues in [comparisons].

View all issues with New status.

Discussion:

A number of places in the library, including 20.14.8 [comparisons]/14, the Optional container requirements in 22.2.1 [container.requirements.general], and 32.4.3.2 [thread.thread.id]/8, use the phrase "total order". Unfortunately, that phrase is ambiguous. In mathematics, the most common definition is that a relation `≤` is a total order if it's total, transitive, and antisymmetric in the sense that `x≤y ∧ y≤x ⇒ x=y`. What we really want is a strict total order: a relation `<` is a strict total order if it's total, transitive, and antisymmetric in the sense that exactly one of `x<y`, `y<x`, and `x=y` holds.

The non-normative note in 25.8 [alg.sorting]/4 correctly uses the phrase "strict total ordering" rather than simply "total ordering".

We could address this issue by replacing "total order" with "strict total order" everywhere it appears, since I think there are no cases where we actually want a non-strict total order, or we could add something in Clause 17 saying that we always mean strict total order whenever we say total order.

Proposed resolution:

### 2561(i). [fund.ts.v2] Incorrect exception specifications for 'swap' in C++ Extensions for Library Fundamentals

Section: 5.3.4 [fund.ts.v2::optional.object.swap], 3.7.8 [fund.ts.v2::propagate_const.modifiers] Status: New Submitter: Daniel Krügler Opened: 2015-11-14 Last modified: 2020-03-30

Priority: 3

View all issues with New status.

Discussion:

Addresses: fund.ts.v2

As pointed out in N4511, the Library fundamentals are affected by a similar problem as described in LWG 2456. First, it is caused by `optional`'s member `swap` (5.3.4 [fund.ts.v2::optional.object.swap]):

>     void swap(optional<T>& rhs) noexcept(see below);

with

> The expression inside `noexcept` is equivalent to:

> >     is_nothrow_move_constructible_v<T> && noexcept(swap(declval<T&>(), declval<T&>()))

Again, the unqualified lookup for `swap` finds the member `swap` instead of the result of a normal argument-depending lookup, making this ill-formed.

A second example of such a problem recently entered the arena with the addition of the `propagate_const` template with another member `swap` (3.7.8 [fund.ts.v2::propagate_const.modifiers]):

>     constexpr void swap(propagate_const& pt) noexcept(see below);

> > -2- The constant-expression in the exception-specification is `noexcept(swap(t_, pt.t_))`.

A working approach is presented in N4511. By adding a new trait to the standard library and referencing this by the library fundamentals (A similar approach had been applied in the file system specification where the `quoted` manipulator from C++14 had been referred to, albeit the file system specification is generally based on the C++11 standard), `optional`'s member `swap` exception specification could be rephrased as follows:

> The expression inside `noexcept` is equivalent to:

> >     is_nothrow_move_constructible_v<T> && is_nothrow_swappable_v<T>noexcept(swap(declval<T&>(), declval<T&>()))

and `propagate_const`'s member `swap` exception specification could be rephrased as follows:

>     constexpr void swap(propagate_const& pt) noexcept(see below);

> > -2- The constant-expression in the exception-specification is `is_nothrow_swappable_v<T>noexcept(swap(t_, pt.t_))`.

[2016-02-20, Ville comments]

Feedback from an implementation:

libstdc++ already applies the proposed resolution for `propagate_const`, but not for `optional`.

[2016-02-20, Daniel comments]

A recent paper update has been provided: P0185R0.

[2016-03, Jacksonville]

Add a link to 2456

[2016-11-08, Issaquah]

Not adopted during NB comment resolution

[2020-03-30; Daniel comments]

This has strong overlap with LWG 3413, which describes a sub-set of the problem here. Rebasing of the library fundamentals on C++20 has removed the mentioned problem for `optional`s free `swap`, so there are now no longer any further free `swap` function templates with conditionally `noexcept` specifications except for `propagate_const` (but now handled by LWG 3413).

Proposed resolution:

### 2564(i). [fund.ts.v2] `std::experimental::function` constructors taking allocator arguments may throw exceptions

Section: 4.2 [fund.ts.v2::func.wrap.func] Status: New Submitter: Tim Song Opened: 2015-12-05 Last modified: 2016-11-20

Priority: 3

View all other issues in [fund.ts.v2::func.wrap.func].

View all issues with New status.

Discussion:

Addresses: fund.ts.v2

[This is essentially LWG 2370, but deals with the fundamentals TS version rather than the one in the standard]

In 4.2 [fund.ts.v2::func.wrap.func] of library fundamentals TS, the constructors

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

must type-erase and store the provided allocator, since the `operator=` specification requires using the "allocator specified in the construction of" the `std::experimental::function` object. This may require a dynamic allocation and so cannot be noexcept. Similarly, the following constructors

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

cannot satisfy the C++14 requirement that they "shall not throw exceptions if [the `function` object to be stored] is a callable object passed via `reference_wrapper` or a function pointer" if they need to type-erase and store the allocator.

[2016-11-08, Issaquah]

Not adopted during NB comment resolution

Proposed resolution:

This wording is relative to N4562.

1. Edit 4.2 [fund.ts.v2::func.wrap.func], class template `function` synopsis, as follows:

   >     namespace std {
   >       namespace experimental {
   >       inline namespace fundamentals_v2 {

   >         […]

   >         template<class R, class... ArgTypes>
   >         class function<R(ArgTypes...)> {
   >         public:
   >           […]
   >           template<class A> function(allocator_arg_t, const A&) noexcept;
   >           template<class A> function(allocator_arg_t, const A&,
   >             nullptr_t) noexcept;
   >           […]
   >         };

   >         […]

   >       } // namespace fundamentals_v2
   >       } // namespace experimental

   >       […]

   >     } // namespace std

2. Insert the following paragraphs after 4.2.1 [fund.ts.v2::func.wrap.func.con]/1:

   > [Drafting note: This just reproduces the wording from C++14 with the "shall not throw exceptions for `reference_wrapper`/function pointer" provision deleted. — end drafting note]

   > -1- When a `function` constructor that takes a first argument of type `allocator_arg_t` is invoked, the second argument is treated as a type-erased allocator (8.3). If the constructor moves or makes a copy of a function object (C++14 §20.9), including an instance of the `experimental::function` class template, then that move or copy is performed by using-allocator construction with allocator `get_memory_resource()`.

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

   > > > -?- Postconditions: `!*this`.

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

   > > > -?- Throws: 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, 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.

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

   > > > -?- Requires: `F` shall be `CopyConstructible`.

   > > > -?- Remarks: This constructor shall not participate in overload resolution unless `f` is Callable (C++14 §20.9.11.2) for argument types `ArgTypes...` and return type `R`.

   > > > -?- 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`.

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

   > > > -?- Throws: May throw `bad_alloc` or any exception thrown by `F`'s copy or move constructor.

   > -2- In the following descriptions, let `ALLOCATOR_OF(f)` be the allocator specified in the construction of `function f`, or `allocator<char>()` if no allocator was specified.

   > […]

### 2592(i). Require that `chrono::duration_cast`s from smaller durations to larger durations do not overflow

Section: 27.2 [time.syn] Status: New Submitter: Andy Giese Opened: 2016-02-05 Last modified: 2016-05-08

Priority: 4

View all other issues in [time.syn].

View all issues with New status.

Discussion:

Currently 27.2 [time.syn] states

>     // convenience typedefs
>     typedef duration<signed integer type of at least 64 bits,        nano> nanoseconds;
>     typedef duration<signed integer type of at least 55 bits,       micro> microseconds;
>     typedef duration<signed integer type of at least 45 bits,       milli> milliseconds;
>     typedef duration<signed integer type of at least 35 bits             > seconds;
>     typedef duration<signed integer type of at least 29 bits, ratio<  60>> minutes;
>     typedef duration<signed integer type of at least 23 bits, ratio<3600>> hours;

However, a `duration_cast<minutes>(seconds::max())` would cause overflow if the underlying signed integers only met the minimums specified.

The standard should specify that implementations guarantee that a `duration_cast` from any smaller duration in these "convenience typedefs" will not overflow any larger duration. That is, `hours` should be able to hold the maximum of `minutes`, which should be able to hold the maximum of `seconds` and so on.

More formally, if the ratio `typedef A` and `typedef B` is `1:Y` where `Y > 1` (e.g., 1 : 60 in case of `minutes` : `seconds`), then `#bitsA-1` must be at least `ceil(log2(2#bitsB-1)/Y))`.

In the case of `minutes` : `seconds`, `X = 1`, `Y = 60`. Let `#bitsseconds = 32`. Therefore:

- `2(#bitsseconds - 1) = 231 = 2147483648`

- `ceil(log2(231 / 60) = 26`

- `#bitsminutes - 1 = 26`

- `#bitsminutes = 27`

Therefore, a minimum of 27 bits would be needed to store `minutes` if 32 were used to store `seconds`.

I propose to change the definitions of the convenience typedefs as follows:

>     // convenience typedefs
>     typedef duration<signed integer type of at least 64 bits,        nano> nanoseconds;
>     typedef duration<signed integer type of at least 55 bits,       micro> microseconds;
>     typedef duration<signed integer type of at least 46 bits,       milli> milliseconds;
>     typedef duration<signed integer type of at least 37 bits             > seconds;
>     typedef duration<signed integer type of at least 32 bits, ratio<  60>> minutes;
>     typedef duration<signed integer type of at least 27 bits, ratio<3600>> hours;

These bits were chosen to satisfy the above formula. Note that minimums only increased, so larger ranges could be held. A nice outcome of this choice is that `minutes` does not go above 32 bits.

[2016-04-23, Tim Song comments]

The P/R of LWG 2592 doesn't fix the issue it wants to solve, because the actual underlying type will likely have more bits than the specified minimum.

Consider `seconds`, which the P/R requires to have at least 37 bits. On a typical system this implies using a 64-bit integer. To ensure that casting from `seconds::max()` to `minutes` doesn't overflow in such a system, it is necessary for the latter to have at least 59 bits (which means, in practice, 64 bits too), not just 32 bits. Thus, just changing the minimum number of bits will not be able to provide the desired guarantee that casting from a smaller unit to a larger one never overflow.

If such a guarantee is to be provided, it needs to be spelled out directly. Note that the difference here is 9 bits (for the 1000-fold case) and 5 bits (for the 60-fold case), which is less than the size difference between integer types on common systems, so such a requirement would effectively require those convenience typedefs to use the same underlying integer type.

Proposed resolution:

This wording is relative to N4567.

1. Change 27.2 [time.syn], header `<chrono>` synopsis, as indicated

   >     […]

   >     // convenience typedefs
   >     typedef duration<signed integer type of at least 64 bits,        nano> nanoseconds;
   >     typedef duration<signed integer type of at least 55 bits,       micro> microseconds;
   >     typedef duration<signed integer type of at least 4645 bits,       milli> milliseconds;
   >     typedef duration<signed integer type of at least 3735 bits             > seconds;
   >     typedef duration<signed integer type of at least 3229 bits, ratio<  60>> minutes;
   >     typedef duration<signed integer type of at least 2723 bits, ratio<3600>> hours;

   >     […]

### 2594(i). Contradicting definition of empty `shared_ptr` on `shared_ptr(nullptr, d)`

Section: 20.11.3 [util.smartptr.shared] Status: New Submitter: Kazutoshi Satoda Opened: 2016-02-20 Last modified: 2016-06-20

Priority: 3

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

View all issues with New status.

Discussion:

Latest draft (N4567) 20.11.3 [util.smartptr.shared] p1 says:

> A `shared_ptr` object is empty if it does not own a pointer.

Please note that it says "own a pointer". This definition was added as the resolution for LWG defect 813.

20.11.3.2 [util.smartptr.shared.const] p8 says about the effect of `shared_ptr(nullptr_t p, D d)`:

> Effects: Constructs a `shared_ptr` object that owns the object `p` and the deleter `d`.

Please note that it says "owns the object". This was intentionally changed from "the pointer" as a part of resolution for LWG defect 758, to cover `nullptr_t` case.

Since `shared_ptr(nullptr, d)` owns an object of type `nullptr_t`, but does not own a pointer, it is said as "empty" by a strict reading of the above mentioned definition in 20.11.3 [util.smartptr.shared] p1.

These cause a contradiction:

20.11.3.2 [util.smartptr.shared.const] p9 sets a postcondition `use_count() == 1` on `shared_ptr(nullptr, d)`. But 20.11.3.6 [util.smartptr.shared.obs] p7 says that the return value of `use_count()` is "`0` when `*this` is empty".

Proposed wording changes:

Replace the last 2 words in 20.11.3 [util.smartptr.shared] p1 from

> […] empty if it does not own a pointer.

to

> […] empty if it does not own an object.

Note that `shared_ptr(nullptr_t)` is defined to be empty in synopsis in 20.11.3 [util.smartptr.shared].

>     constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() { }

It could be less confusing if `shared_ptr(nullptr, d)` could be defined to be empty. But it seems too late to change that (which means changing whether the deleter is called or not, see this Stackoverflow article). Then I'm proposing just fix the contradiction.

Proposed resolution:

This wording is relative to N4594.

1. Change 20.11.3 [util.smartptr.shared] p1 as indicated:

   > -1- The `shared_ptr` class template stores a pointer, usually obtained via `new`. `shared_ptr` implements semantics of shared ownership; the last remaining owner of the pointer is responsible for destroying the object, or otherwise releasing the resources associated with the stored pointer. A `shared_ptr` object is empty if it does not own an object a pointer.

### 2595(i). `reverse_iterator::operator[]`'s return type revisited

Section: 23.5.1.2 [reverse.iterator], 23.5.1.6 [reverse.iter.elem] Status: New Submitter: Robert Haberlach Opened: 2016-02-28 Last modified: 2021-06-06

Priority: 3

View all other issues in [reverse.iterator].

View all issues with New status.

Discussion:

Issue 386 changed the return type of `reverse_iterator::operator[]` to unspecified. However, as of N3066, the return type of a random access iterator's `operator[]` shall be convertible to `reference`; thus the return type of `reverse_iterator::operator[]` should be `reference` (and it is in all common implementations).

Suggested resolution: Adjust 23.5.1.2 [reverse.iterator]'s synopsis and 23.5.1.6 [reverse.iter.elem] to use `reference` instead of `unspecified`.

[2021-06-06 Tim syncs wording to current working draft]

Proposed resolution:

This wording is relative to N4885.

1. Edit 23.5.1.2 [reverse.iterator], class template `` synopsis, as indicated:

   >     namespace std {
   >       template <class Iterator>
   >       class reverse_iterator {
   >       public:
   >         […]
   >         using reference         = iter_reference_t<Iterator>;
   >         […]
   >         constexpr referenceunspecified operator[](difference_type n) const;
   >         […]
   >       };
   >     }

2. Change 23.5.1.6 [reverse.iter.elem] before p3 as indicated:

   >     constexpr referenceunspecified operator[](difference_type n) const;

### 2599(i). Library incomplete type permission phrase is unclear

Section: 20.2.6 [declval], 20.11.1 [unique.ptr], 20.11.1.2.1 [unique.ptr.dltr.general], 20.11.3 [util.smartptr.shared], 20.11.4 [util.smartptr.weak], 20.11.6 [util.smartptr.enab] Status: New Submitter: Zhihao Yuan Opened: 2016-03-08 Last modified: 2016-04-16

Priority: 3

View all issues with New status.

Discussion:

Currently the phrase to grant this permission is:

> The template parameter `T` of `LibraryTemplate` may be an incomplete type.

Two problems:

1. The timing is unclear. We always allow specializations like `LibraryTemplate<Incomp>* p;`

2. To the users of a template, the correct terminology should be "argument" rather than "parameter".

Suggested resolution:

> In an instantiation of `LibraryTemplate`, an incomplete type may be used as the template argument for the template parameter `T`.

as shown here.

Or, to copy N4510's wording:

> An incomplete type `T` may be used when instantiating `LibraryTemplate`.

Proposed resolution:

### 2675(i). `register_callback` can fail

Section: 29.5.2.7 [ios.base.callback] Status: New Submitter: David Krauss Opened: 2016-03-14 Last modified: 2019-06-15

Priority: 3

View all issues with New status.

Discussion:

`register_callback` allocates memory and so it can fail, but the case is unspecified. libc++ sets `badbit`, which is consistent with `iword` and `pword`. libstdc++ throws `std::bad_alloc`.

[2019-06-13; Billy comments]

Just as an additional data point: MSVC++ agrees with libstdc++ and also throws `std::bad_alloc`.

Proposed resolution:

### 2691(i). `money_base::space` and `do_put`: U+0020 versus `fill`

Section: 28.4.7.4 [locale.moneypunct] Status: New Submitter: Hubert Tong Opened: 2016-04-12 Last modified: 2016-05-22

Priority: 3

View all other issues in [locale.moneypunct].

View all issues with New status.

Discussion:

The description of `money_base::space` is that "at least one space is required at that position." (N4582 subclause 22.4.6.3 [locale.moneypunct] paragraph 2)

When formatting for output (28.4.7.3.2 [locale.money.put.virtuals]), it is not clear that

1. "the number of characters generated for the specified format" (excluding fill padding) includes exactly one character for `money_base::space` (if present), and

2. all characters corresponding to `money_base::space` (excluding fill padding) are copies of `fill`.

In particular, there is implementation divergence over point (b) as to whether U+0020 or `fill` should be used. Further, should a character other than `fill` be used, it is unclear when "the fill characters are placed where `none` or `space` appears in the formatting pattern", whether the fill characters are placed at the beginning or the end of the "space field".

I believe that a strict interpretation of the current wording supports U+0020; however, `fill` is more likely to be the pragmatic choice.

Proposed resolution:

This wording is relative to N4582.

1. Change 28.4.7.4 [locale.moneypunct] paragraph 2 as indicated:

   > -2- Where `none` or `space` appears, white space is permitted in the format, except where `none` appears at the end, in which case no white space is permitted. For input, the value `space` indicates that at least one space is required at that position. For output, the value `space` indicates one instance of the fill character (28.4.7.3.2 [locale.money.put.virtuals]).The value `space` indicates that at least one space is required at that position. Where `symbol` appears, the sequence of characters returned by `curr_symbol()` is permitted, and can be required. Where `sign` appears, the first (if any) of the sequence of characters returned by `positive_sign()` or `negative_sign()` (respectively as the monetary value is non-negative or negative) is required. Any remaining characters of the sign sequence are required after all other format components. Where `value` appears, the absolute numeric monetary value is required.

### 2695(i). "As if" unclear in [member.functions]

Section: 16.4.6.5 [member.functions] Status: New Submitter: Hubert Tong Opened: 2016-04-15 Last modified: 2017-02-02

Priority: 3

View all other issues in [member.functions].

View all issues with New status.

Discussion:

In N4582 subclause 17.6.5.5 [member.functions], the requirement that:

> any call to the member function that would select an overload from the set of declarations described in this standard behaves as if that overload were selected

is unclear in the extent of the "as if". For example, in providing:

>     basic_string(const charT* s);

for a one-argument call to:

>     basic_string(const charT* s, const Allocator& a = Allocator());

it can be read that an implementation may be required to call the copy constructor for the allocator since the core language rules for copy elision would not allow the "a" argument to be constructed directly into the member used to store the allocator.

Clarification (even if just a note) would be appreciated.

[2016-05 Issues Telecon]

This is related to issue 2563.

Proposed resolution:

### 2702(i). `num_put::do_put(..., bool)` performs ill-formed `do_put` call

Section: 28.4.3.3.3 [facet.num.put.virtuals] Status: New Submitter: Hubert Tong Opened: 2016-05-07 Last modified: 2016-05-22

Priority: 3

View other active issues in [facet.num.put.virtuals].

View all other issues in [facet.num.put.virtuals].

View all issues with New status.

Discussion:

The call to `do_put(out, str, fill, (int)val)` in N4582 subclause 28.4.3.3.3 [facet.num.put.virtuals] paragraph 6 cannot select a best viable function in overload resolution given the overloads listed for `do_put` in 28.4.3.3 [locale.nm.put].

There is implementation divergence:

- Some implementations call the `long` overload (as overriden);

- some implementations call the `unsigned long` overload (as overriden);

- some implementations call something else.

It appears that the resolution to DR 359 attempted a fix; however, the relevant portion of the change was not applied to the WP.

Proposed resolution:

### 2703(i). No provision for fill-padding when `boolalpha` is set

Section: 28.4.3.3.3 [facet.num.put.virtuals] Status: New Submitter: Hubert Tong Opened: 2016-05-07 Last modified: 2018-02-11

Priority: 3

View other active issues in [facet.num.put.virtuals].

View all other issues in [facet.num.put.virtuals].

View all issues with New status.

Discussion:

N4582 subclause 28.4.3.3.3 [facet.num.put.virtuals] paragraph 6 makes no provision for fill-padding in its specification of the behaviour when `(str.flags() & ios_base::boolalpha) != 0`.

[2017-07-06, Marshall comments]

All the other cases from `num_put` — `int`, `long`, etc all are covered in 28.4.3.3.3 [facet.num.put.virtuals] p1 .. p5, which describe how to align and pad the output. (Specifically, stage 3) p6 does not.

With this description:

>     cout << std::setw(15) << false;

outputs:

                  0
    ﹎﹎﹎﹎﹎﹎﹎﹎﹎﹎﹎﹎﹎﹎// Column counter

but

>     cout << std::setw(15) << boolalpha << false;

outputs:

    false

libc++ implements this exactly.
Dinkumware, libstdc++ and MSVC apply padding and alignment.

I think that applying padding and alignment is more appropriate.

Proposed resolution:

### 2705(i). Questionable precondition on Sequence containers `a.assign(n, t)`

Section: 22.2.3 [sequence.reqmts] Status: New Submitter: Kazutoshi Satoda Opened: 2016-05-08 Last modified: 2020-09-06

Priority: 3

View other active issues in [sequence.reqmts].

View all other issues in [sequence.reqmts].

View all issues with New status.

Discussion:

Please look through the following modifications on a value `v` of type `vector<T>`:

>     assert(v.size() > 0);
>     v.push_back(v[0]);
>     v.insert(v.begin(), v[0]);
>     v.resize(v.size() * 2, v[0]);
>     v.assign(v.size() * 2, v[0]);

All of these use an element of itself which may be moved or destroyed by the modification.

From what I see so far, the first three are required to work. Please see library issue 526 for validity of them.

But only the last one is undefined because it violates a precondition of a sequence container operation. I think this is too subtle.

Should it be like that, really?

The precondition is in Table 107 "Sequence container requirements" at the next of 22.2.3 [sequence.reqmts] p3.

> In Tables 107 and 108, `X` denotes a sequence container class, `a` denotes a value of `X` containing elements of type `T`, […] `n` denotes a value of `X::size_type`, […] `t` denotes an lvalue or a `const` rvalue of `X::value_type`, […]

> […]

> Table 107 — Sequence container requirements (in addition to container)
> Expression | Return type | Assertion/note pre-/post-condition
> --- | --- | ---
> `[…]`
> `a.assign(n, t)` | `void` | Requires: `T` shall be `CopyInsertable` into `X` and `CopyAssignable`. pre: `t` is not a reference into `a`. Replaces elements in `a` with `n` copies of `t`.

I looked into the following implementations:

- libc++ relies on the precondition.

  It deallocates first on `n > capacity()` case, see here.

- libstdc++ doesn't rely on the precondition.

  It creates temporary `vector(n, t)` and `swap()` on `n > capacity()` case, see here.

- MSVC relies on the precondition.

  It unconditionally does `clear()` and then `insert(begin(), n, t)`. I looked into my local "`%PROGRAMFILES(X86)%/Microsoft Visual Studio 14.0/VC/include/vector`".

One drawback of libstdc++ implementation, I could find so far, is possibly increased peek memory usage (both old and new buffer exist at the same time). But, because the same can happen on the most other modifications, it seems a reasonable trade-off to remove the precondition to fill the subtle gap. Users who really needs less memory usage can do `clear()` and `insert()` by themselves.

I also found that `basic_string::assign(n, c)` is safe on this point. At 21.3.3.7.3 [string.assign] p17:

>     basic_string& assign(size_type n, charT c);

> > Effects: Equivalent to `assign(basic_string(n, c))`.

> > Returns: `*this`.

This can be seen as another gap.

Looking back on the history, I found that the definition of `assign(n, t)` was changed at C++14 for library issue 2209. There were more restricting definitions like this:

>     void assign(size_type n, const T& t);

> > Effects:

> > >     erase(begin(), end());
> > >     insert(begin(), n, t);

I think the precondition was probably set to accept this old definition and is not required inherently. And if the less memory usage was really intended, the standard is now underspecifying about that.

[2016-05 Issues Telecon]

Howard believes this should be NAD, but we tabled the discussion.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4582.

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

>    > Table 107 — Sequence container requirements (in addition to container)
>    > Expression | Return type | Assertion/note pre-/post-condition
>    > --- | --- | ---
>    > `[…]`
>    > `a.assign(n, t)` | `void` | Requires: `T` shall be `CopyInsertable` into `X` and `CopyAssignable`. pre: `t` is not a reference into `a`. Replaces elements in `a` with `n` copies of `t`.

[2020-04-25, Daniel syncs current wording with recent working draft]

Proposed resolution:

This wording is relative to N4861.

1. In 22.2.3 [sequence.reqmts], edit Table [tab:container.seq.req] (Sequence container requirements) as indicated:

   > Table 77 — Sequence container requirements (in addition to container) [tab:container.seq.req]
   > Expression | Return type | Assertion/note pre-/post-condition
   > --- | --- | ---
   > `[…]`
   > `a.assign(n, t)` | `void` | Preconditions: `T` is Cpp17CopyInsertable into `X` and Cpp17CopyAssignable. `t` is not a reference into `a`. Effects: Replaces elements in `a` with `n` copies of `t`. Invalidates all references, pointers and iterators referring to the elements of `a`. For `vector` and `deque`, also invalidates the past-the-end iterator.

### 2708(i). `recursive_directory_iterator::recursion_pending()` is incorrectly specified

Section: 29.12.12.2 [fs.rec.dir.itr.members] Status: Open Submitter: Eric Fiselier Opened: 2016-05-09 Last modified: 2018-08-24

Priority: 2

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

View all issues with Open status.

Discussion:

The current specification of `recursion_pending()` says (29.12.12.2 [fs.rec.dir.itr.members]/24):

> Returns: `true` if `disable_recursion_pending()` has not been called subsequent to the prior construction or increment operation, otherwise `false`.

This language does not take into account cases where the prior construction was a copy construction from a iterator, `it`, where `it.recursion_pending() == false`.

[2016-08 Chicago]

Wed AM: Move to Open

[2018-1-26 issues processing telecon]

Status to 'Tentatively Ready'; Casey will explore whether making `recursion_pending` an exposition-only member makes this clearer.

Previous resolution from Eric [SUPERSEDED]:

> This wording is relative to N4582.

> 1. Change 29.12.12.2 [fs.rec.dir.itr.members] as indicated:

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

>    > > […]

>    > > -3- Postcondition: `options() == options` for the signatures with a `directory_options` argument, otherwise `options() == directory_options::none`.

>    > > - `options() == options` for the signatures with a `directory_options` argument, otherwise `options() == directory_options::none`.

>    > > - `recursion_pending() == true`.

>    > > […]

>    > > [Drafting note: The following changes the specification of `recursion_pending()` seemingly recursive. Perhaps it would be easier to specify `recursion_pending()` in terms of a exposition only member in `recursive_directory_iterator`.]

>    >     bool recursion_pending() const;

>    > > […]

>    > > -24- Returns: `true` if `disable_recursion_pending()` has not been called subsequent to the prior construction or increment operation, otherwise `false` `false` if `disable_recursion_pending()` has been called subsequent to the prior construction or increment operation, otherwise the value of `recursion_pending()` set by that operation.

>    > > […]

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

>    > > […]

>    > > -27- Effects: As specified by Input iterators (24.2.3), except that: […]

>    > > -?- Postcondition: `recursion_pending() == true`.

[2018-01-29: Casey provides a PR with an exposition-only member]

Status to 'Review'.

Previous resolution from Casey [SUPERSEDED]:

> This wording is relative to N4713.

> 1. Change [fs.rec.dir.itr] as indicated:

>    >         […]

>    >         // other members as required by 23.3.5.3 [input.iterators], input iterators

>    >       private:
>    >         bool recurse_; // exposition-only
>    >       };
>    >     }

> 2. Change 29.12.12.2 [fs.rec.dir.itr.members] as indicated:

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

>    > > […]

>    > > -3- Postconditions: `options() == options` for the signatures with a `directory_options` argument, otherwise `options() == directory_options::none`.

>    > > - `options() == options` for the signatures with a `directory_options` argument, otherwise `options() == directory_options::none`.

>    > > - `recurse_ == true`.

>    > > […]

>    >     recursive_directory_iterator(const recursive_directory_iterator& rhs);

>    > > […]

>    > > -8- Postconditions:

>    > > […]

>    > > (8.3) — `recursion_pending() == rhs.recursion_pending()``recurse_ == rhs.recurse_`

>    >     recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept;

>    > > […]

>    > > -10- Postconditions: `options()`, `depth()`, and `recursion_pending()``recurse_` have the values that `rhs.options()`, `rhs.depth()`, and `rhs.recursion_pending()``rhs.recurse_`, respectively, had before the function call.

>    >     recursive_directory_iterator& operator=(const recursive_directory_iterator& rhs);

>    > > […]

>    > > -12- Postconditions:

>    > > […]

>    > > (12.3) — `recursion_pending() == rhs.recursion_pending()``recurse_ == rhs.recurse_`

>    > > […]

>    >     recursive_directory_iterator& operator=(recursive_directory_iterator&& rhs) noexcept;

>    > > […]

>    > > -15- Postconditions: `options()`, `depth()`, and `recursion_pending()``recurse_` have the values that `rhs.options()`, `rhs.depth()`, and `rhs.recursion_pending()``rhs.recurse_`, respectively, had before the function call.

>    > > […]

>    >     bool recursion_pending() const;

>    > > -21- Returns: `true` if `disable_recursion_pending()` has not been called subsequent to the prior construction or increment operation, otherwise `false` recurse_.

>    > > […]

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

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

>    > > […]

>    > > -?- Postcondition: `recurse_ == true`.

>    >     void disable_recursion_pending();

>    > > -28- Postconditions: `recursion_pending()recurse_ == false`.

>    > > […]

[2018-05-23: Casey restores the intended design with an expansion of the original PR]

The intended design is that all copies of a single `recursive_directory_iterator` share a common block of state which includes the values returned by `options`, `depth`, and `recursion_pending` - hence the mandate that those functions not be called on a non-dereferenceable iterator in 29.12.12 [fs.class.rec.dir.itr] para 2. To allow an implementation with such shared state, it's necessary to make changes to the value returned by `recursion_pending()` visible to all copies of the same dereferenceable iterator.

Also:

- `pop` notionally calls `increment` repeatedly until the current directory is exhausted, `pop` should affect the value of `recursion_pending` similarly to `increment`.

- `options` is not valid for all constructor signatures described by 29.12.12.2 [fs.rec.dir.itr.members] para 2.

- the copies and moves don't specify what they actually do

- it's not quite kosher for the copies and moves to have postconditions on the value of expressions that have UB if the iterator copied/moved from is not dereferenceable.

[2018-06, Rapperswil, Wednesday evening]

JW: p21 currently can just say "unspecified"
BO: if we are OK with only remote implementations we can remove the unspecifiedness
BO: the problematic business is the "recursion pending" bit
JW: I want time to work on this

Move to open and note that Jonathan is reviewing and making recommendations.

[2018-08-23 Batavia Issues processing]

General agreement that flag should be shared; Casey to reword.

Proposed resolution:

This wording is relative to N4750.

1. Change 29.12.12.2 [fs.rec.dir.itr.members] as indicated:

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

   > > -?- For the signatures with no parameter `options`, let `options` be `directory_options::none`.

   > > -2- Effects: […]

   > > -3- Postconditions: `options() == options` for the signatures with a `directory_options` argument, otherwise `options() == directory_options::none`.

   > > - `this->options() == options`

   > > - `recursion_pending() == true`

   > > […]

   >     recursive_directory_iterator(const recursive_directory_iterator& rhs);

   > > -7- Effects: Constructs an object of class `recursive_directory_iterator` iterator that denotes the same directory entry as `rhs`, if any..

   > > -8- Postconditions: If `rhs` is dereferenceable,

   > > […]

   >     recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept;

   > > -9- Effects: Constructs an object of class `recursive_directory_iterator` iterator that denotes the directory entry denoted by `rhs` before the function call, if any..

   > > -10- Postconditions: If `rhs` is dereferenceable, […]

   >     recursive_directory_iterator& operator=(const recursive_directory_iterator& rhs);

   > > -11- Effects: If `*this` and `rhs` are the same object, the member has no effect. Causes `*this` to denote the same directory entry denoted by `rhs`, if any.

   > > -12- Postconditions: If `rhs` is dereferenceable,

   > > […]

   >     recursive_directory_iterator& operator=(recursive_directory_iterator&& rhs) noexcept;

   > > -14- Effects: If `*this` and `rhs` are the same object, the member has no effect. Causes `*this` to denote the directory entry denoted by `rhs` before the function call, if any.

   > > -15- Postconditions: If `rhs` was dereferenceable before the function call, […]

   > > -16- Returns: `*this`.

   > > -x- Remarks: If `*this` and `rhs` do not refer to the same object, the resulting state of `rhs` is unspecified (16.4.6.15 [lib.types.movedfrom]).

   >     directory_options options() const;

   > > -17- Returns: The value of the argument passed to the constructor for the `options` parameter, if present, otherwise `directory_options::none` established by the most recently called member that has a postcondition for `options()`.

   > > […]

   >     bool recursion_pending() const;

   > > -21- Returns: `true` if `disable_recursion_pending()` has not been called subsequent to the prior construction or increment operation, otherwise `false`. If `disable_recursion_pending()` has been called on a copy of `*this`, an unspecified value. Otherwise, the value established for `recursion_pending()` by the postcondition of the most recent construction, assignment, increment, or `disable_recursion_pending` operation.

   > > […]

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

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

   > > -?- Postconditions: If `*this` is dereferenceable, `recursion_pending() == true`.

   > > […]

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

   > > -26- Effects: If `depth() == 0`, set `*this` to `recursive_directory_iterator()`. […]

   > > -?- Postconditions: If `*this` is dereferenceable, `recursion_pending() == true`.

   > > […]

### 2713(i). More missing allocator-extended constructors for unordered containers

Section: 22.5 [unord] Status: New Submitter: Billy Robert O'Neal III Opened: 2016-05-20 Last modified: 2020-11-29

Priority: 3

View all other issues in [unord].

View all issues with New status.

Discussion:

The resolution of LWG 2210 missed constructors accepting a range or initializer list and allocator.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4582.

> 1. Add to the synopsis in 22.5.4.1 [unord.map.overview] p3:

>    >     namespace std {
>    >       template <class Key, class T,
>    >         class Hash = hash<Key>,
>    >         class Pred = std::equal_to<Key>,
>    >         class Allocator = std::allocator<std::pair<const Key, T> > > {
>    >       class unordered_map {
>    >       public:
>    >         […]
>    >         unordered_map(size_type n, const hasher& hf, const allocator_type& a)
>    >           : unordered_map(n, hf, key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_map(InputIterator f, InputIterator l, const allocator_type& a)
>    >           : unordered_map(f, l, see below, hasher(), key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_map(InputIterator f, InputIterator l, size_type n, const allocator_type& a)
>    >           : unordered_map(f, l, n, hasher(), key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_map(InputIterator f, InputIterator l, size_type n, const hasher& hf,
>    >                 const allocator_type& a)
>    >           : unordered_map(f, l, n, hf, key_equal(), a) { }
>    >         unordered_map(initializer_list<value_type> il, const allocator_type& a)
>    >           : unordered_map(il, see below, hasher(), key_equal(), a) { }
>    >         unordered_map(initializer_list<value_type> il, size_type n, const allocator_type& a)
>    >           : unordered_map(il, n, hasher(), key_equal(), a) { }
>    >         […]
>    >       };
>    >     }

> 2. Add to the synopsis in 22.5.5.1 [unord.multimap.overview] p3:

>    >     namespace std {
>    >       template <class Key, class T,
>    >         class Hash = hash<Key>,
>    >         class Pred = std::equal_to<Key>,
>    >         class Allocator = std::allocator<std::pair<const Key, T> > > {
>    >       class unordered_multimap {
>    >       public:
>    >         […]
>    >         unordered_multimap(size_type n, const hasher& hf, const allocator_type& a)
>    >           : unordered_multimap(n, hf, key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_multimap(InputIterator f, InputIterator l, const allocator_type& a)
>    >           : unordered_multimap(f, l, see below, hasher(), key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_multimap(InputIterator f, InputIterator l, size_type n, const allocator_type& a)
>    >           : unordered_multimap(f, l, n, hasher(), key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_multimap(InputIterator f, InputIterator l, size_type n, const hasher& hf,
>    >                 const allocator_type& a)
>    >           : unordered_multimap(f, l, n, hf, key_equal(), a) { }
>    >         unordered_multimap(initializer_list<value_type> il, const allocator_type& a)
>    >           : unordered_multimap(il, see below, hasher(), key_equal(), a) { }
>    >         unordered_multimap(initializer_list<value_type> il, size_type n, const allocator_type& a)
>    >           : unordered_multimap(il, n, hasher(), key_equal(), a) { }
>    >         […]
>    >       };
>    >     }

> 3. Add to the synopsis in 22.5.6.1 [unord.set.overview] p3:

>    >     namespace std {
>    >       template <class Key,
>    >         class Hash = hash<Key>,
>    >         class Pred = std::equal_to<Key>,
>    >         class Allocator = std::allocator<Key> > {
>    >       class unordered_set {
>    >       public:
>    >         […]
>    >         unordered_set(size_type n, const hasher& hf, const allocator_type& a)
>    >           : unordered_set(n, hf, key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_set(InputIterator f, InputIterator l, const allocator_type& a)
>    >           : unordered_set(f, l, see below, hasher(), key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_set(InputIterator f, InputIterator l, size_type n, const allocator_type& a)
>    >           : unordered_set(f, l, n, hasher(), key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_set(InputIterator f, InputIterator l, size_type n, const hasher& hf,
>    >                 const allocator_type& a)
>    >           : unordered_set(f, l, n, hf, key_equal(), a) { }
>    >         unordered_set(initializer_list<value_type> il, const allocator_type& a)
>    >           : unordered_set(il, see below, hasher(), key_equal(), a) { }
>    >         unordered_set(initializer_list<value_type> il, size_type n, const allocator_type& a)
>    >           : unordered_set(il, n, hasher(), key_equal(), a) { }
>    >         […]
>    >       };
>    >     }

> 4. Add to the synopsis in 22.5.7.1 [unord.multiset.overview] p3:

>    >     namespace std {
>    >       template <class Key,
>    >         class Hash = hash<Key>,
>    >         class Pred = std::equal_to<Key>,
>    >         class Allocator = std::allocator<Key> > {
>    >       class unordered_multiset {
>    >       public:
>    >         […]
>    >         unordered_multiset(size_type n, const hasher& hf, const allocator_type& a)
>    >           : unordered_multiset(n, hf, key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_multiset(InputIterator f, InputIterator l, const allocator_type& a)
>    >           : unordered_multiset(f, l, see below, hasher(), key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_multiset(InputIterator f, InputIterator l, size_type n, const allocator_type& a)
>    >           : unordered_multiset(f, l, n, hasher(), key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_multiset(InputIterator f, InputIterator l, size_type n, const hasher& hf,
>    >                 const allocator_type& a)
>    >           : unordered_multiset(f, l, n, hf, key_equal(), a) { }
>    >         unordered_multiset(initializer_list<value_type> il, const allocator_type& a)
>    >           : unordered_multiset(il, see below, hasher(), key_equal(), a) { }
>    >         unordered_multiset(initializer_list<value_type> il, size_type n, const allocator_type& a)
>    >           : unordered_multiset(il, n, hasher(), key_equal(), a) { }
>    >         […]
>    >       };
>    >     }

[2016-06, Oulu — Daniel comments and provides new wording]

During the LWG discussion of this issue it has been observed, that the interpretation of the embedded see below is not really clear and that we should split declaration and definition of the new overloads, so that we have a place that allows us to specify what "see below" stands for. In addition, the new wording wraps the "see below" as "`size_type(see below)`" to clarify the provided expression type, similar as we did for the default constructor of `unordered_map`.

[Oulu, 2016-06]

Alisdair to review wording.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4594.

> 1. Add to the synopsis in 22.5.4.1 [unord.map.overview] p3:

>    >     namespace std {
>    >       template <class Key, class T,
>    >         class Hash = hash<Key>,
>    >         class Pred = std::equal_to<Key>,
>    >         class Allocator = std::allocator<std::pair<const Key, T> > > {
>    >       class unordered_map {
>    >       public:
>    >         […]
>    >         unordered_map(size_type n, const hasher& hf, const allocator_type& a)
>    >           : unordered_map(n, hf, key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_map(InputIterator f, InputIterator l, const allocator_type& a);
>    >         template <class InputIterator>
>    >           unordered_map(InputIterator f, InputIterator l, size_type n, const allocator_type& a)
>    >           : unordered_map(f, l, n, hasher(), key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_map(InputIterator f, InputIterator l, size_type n, const hasher& hf,
>    >                 const allocator_type& a)
>    >           : unordered_map(f, l, n, hf, key_equal(), a) { }
>    >         unordered_map(initializer_list<value_type> il, const allocator_type& a);
>    >         unordered_map(initializer_list<value_type> il, size_type n, const allocator_type& a)
>    >           : unordered_map(il, n, hasher(), key_equal(), a) { }
>    >         […]
>    >       };
>    >     }

> 2. Insert the following new prototype specification just after 22.5.4.2 [unord.map.cnstr] p2

>    >     template <class InputIterator>
>    >       unordered_map(InputIterator f, InputIterator l, const allocator_type& a)
>    >         : unordered_map(f, l, size_type(see below), hasher(), key_equal(), a) { }

>    >     unordered_map(initializer_list<value_type> il, const allocator_type& a)
>    >       : unordered_map(il, size_type(see below), hasher(), key_equal(), a) { }

>    > > -?- Remarks: The number of buckets is implementation-defined.

> 3. Add to the synopsis in 22.5.5.1 [unord.multimap.overview] p3:

>    >     namespace std {
>    >       template <class Key, class T,
>    >         class Hash = hash<Key>,
>    >         class Pred = std::equal_to<Key>,
>    >         class Allocator = std::allocator<std::pair<const Key, T> > > {
>    >       class unordered_multimap {
>    >       public:
>    >         […]
>    >         unordered_multimap(size_type n, const hasher& hf, const allocator_type& a)
>    >           : unordered_multimap(n, hf, key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_multimap(InputIterator f, InputIterator l, const allocator_type& a);
>    >         template <class InputIterator>
>    >           unordered_multimap(InputIterator f, InputIterator l, size_type n, const allocator_type& a)
>    >           : unordered_multimap(f, l, n, hasher(), key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_multimap(InputIterator f, InputIterator l, size_type n, const hasher& hf,
>    >                 const allocator_type& a)
>    >           : unordered_multimap(f, l, n, hf, key_equal(), a) { }
>    >         unordered_multimap(initializer_list<value_type> il, const allocator_type& a);
>    >         unordered_multimap(initializer_list<value_type> il, size_type n, const allocator_type& a)
>    >           : unordered_multimap(il, n, hasher(), key_equal(), a) { }
>    >         […]
>    >       };
>    >     }

> 4. Insert the following new prototype specification just after 22.5.5.2 [unord.multimap.cnstr] p2

>    >     template <class InputIterator>
>    >       unordered_multimap(InputIterator f, InputIterator l, const allocator_type& a)
>    >         : unordered_multimap(f, l, size_type(see below), hasher(), key_equal(), a) { }

>    >     unordered_multimap(initializer_list<value_type> il, const allocator_type& a)
>    >       : unordered_multimap(il, size_type(see below), hasher(), key_equal(), a) { }

>    > > -?- Remarks: The number of buckets is implementation-defined.

> 5. Add to the synopsis in 22.5.6.1 [unord.set.overview] p3:

>    >     namespace std {
>    >       template <class Key,
>    >         class Hash = hash<Key>,
>    >         class Pred = std::equal_to<Key>,
>    >         class Allocator = std::allocator<Key> > {
>    >       class unordered_set {
>    >       public:
>    >         […]
>    >         unordered_set(size_type n, const hasher& hf, const allocator_type& a)
>    >           : unordered_set(n, hf, key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_set(InputIterator f, InputIterator l, const allocator_type& a);
>    >         template <class InputIterator>
>    >           unordered_set(InputIterator f, InputIterator l, size_type n, const allocator_type& a)
>    >           : unordered_set(f, l, n, hasher(), key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_set(InputIterator f, InputIterator l, size_type n, const hasher& hf,
>    >                 const allocator_type& a)
>    >           : unordered_set(f, l, n, hf, key_equal(), a) { }
>    >         unordered_set(initializer_list<value_type> il, const allocator_type& a);
>    >         unordered_set(initializer_list<value_type> il, size_type n, const allocator_type& a)
>    >           : unordered_set(il, n, hasher(), key_equal(), a) { }
>    >         […]
>    >       };
>    >     }

> 6. Insert the following new prototype specification just after 22.5.6.2 [unord.set.cnstr] p2

>    >     template <class InputIterator>
>    >       unordered_set(InputIterator f, InputIterator l, const allocator_type& a)
>    >         : unordered_set(f, l, size_type(see below), hasher(), key_equal(), a) { }

>    >     unordered_set(initializer_list<value_type> il, const allocator_type& a)
>    >       : unordered_set(il, size_type(see below), hasher(), key_equal(), a) { }

>    > > -?- Remarks: The number of buckets is implementation-defined.

> 7. Add to the synopsis in 22.5.7.1 [unord.multiset.overview] p3:

>    >     namespace std {
>    >       template <class Key,
>    >         class Hash = hash<Key>,
>    >         class Pred = std::equal_to<Key>,
>    >         class Allocator = std::allocator<Key> > {
>    >       class unordered_multiset {
>    >       public:
>    >         […]
>    >         unordered_multiset(size_type n, const hasher& hf, const allocator_type& a)
>    >           : unordered_multiset(n, hf, key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_multiset(InputIterator f, InputIterator l, const allocator_type& a);
>    >         template <class InputIterator>
>    >           unordered_multiset(InputIterator f, InputIterator l, size_type n, const allocator_type& a)
>    >           : unordered_multiset(f, l, n, hasher(), key_equal(), a) { }
>    >         template <class InputIterator>
>    >           unordered_multiset(InputIterator f, InputIterator l, size_type n, const hasher& hf,
>    >                 const allocator_type& a)
>    >           : unordered_multiset(f, l, n, hf, key_equal(), a) { }
>    >         unordered_multiset(initializer_list<value_type> il, const allocator_type& a);
>    >         unordered_multiset(initializer_list<value_type> il, size_type n, const allocator_type& a)
>    >           : unordered_multiset(il, n, hasher(), key_equal(), a) { }
>    >         […]
>    >       };
>    >     }

> 8. Insert the following new prototype specification just after 22.5.7.2 [unord.multiset.cnstr] p2

>    >     template <class InputIterator>
>    >       unordered_multiset(InputIterator f, InputIterator l, const allocator_type& a)
>    >         : unordered_multiset(f, l, size_type(see below), hasher(), key_equal(), a) { }

>    >     unordered_multiset(initializer_list<value_type> il, const allocator_type& a)
>    >       : unordered_multiset(il, size_type(see below), hasher(), key_equal(), a) { }

>    > > -?- Remarks: The number of buckets is implementation-defined.

[2017-08-04, Daniel and Alisdair finetune wording]

We decided to improve the added Remarks: elements by changing from the previous form:

> Remarks: The number of buckets is implementation-defined.

to the more elaborate form:

> Remarks: The initial number of buckets supplied by the `size_type` argument is implementation-defined.

[2020-11-29; Reflector discussions]

It has been pointed out that this issue is related to LWG 1199, LWG 2210, and LWG 3506.

Proposed resolution:

This resolution is relative to N4687.

1. Add to the synopsis in 22.5.4.1 [unord.map.overview] p3:

   >     namespace std {
   >       template <class Key, class T,
   >         class Hash = hash<Key>,
   >         class Pred = std::equal_to<Key>,
   >         class Allocator = std::allocator<std::pair<const Key, T> > > {
   >       class unordered_map {
   >       public:
   >         […]
   >         unordered_map(size_type n, const hasher& hf, const allocator_type& a)
   >           : unordered_map(n, hf, key_equal(), a) { }
   >         template <class InputIterator>
   >           unordered_map(InputIterator f, InputIterator l, const allocator_type& a);
   >         template <class InputIterator>
   >           unordered_map(InputIterator f, InputIterator l, size_type n, const allocator_type& a)
   >           : unordered_map(f, l, n, hasher(), key_equal(), a) { }
   >         template <class InputIterator>
   >           unordered_map(InputIterator f, InputIterator l, size_type n, const hasher& hf,
   >                 const allocator_type& a)
   >           : unordered_map(f, l, n, hf, key_equal(), a) { }
   >         unordered_map(initializer_list<value_type> il, const allocator_type& a);
   >         unordered_map(initializer_list<value_type> il, size_type n, const allocator_type& a)
   >           : unordered_map(il, n, hasher(), key_equal(), a) { }
   >         […]
   >       };
   >     }

2. Insert the following new prototype specification just after 22.5.4.2 [unord.map.cnstr] p2

   >     template <class InputIterator>
   >       unordered_map(InputIterator f, InputIterator l, const allocator_type& a)
   >         : unordered_map(f, l, size_type(see below), hasher(), key_equal(), a) { }

   >     unordered_map(initializer_list<value_type> il, const allocator_type& a)
   >       : unordered_map(il, size_type(see below), hasher(), key_equal(), a) { }

   > > -?- Remarks: The initial number of buckets supplied by the `size_type` argument is implementation-defined.

3. Add to the synopsis in 22.5.5.1 [unord.multimap.overview] p3:

   >     namespace std {
   >       template <class Key, class T,
   >         class Hash = hash<Key>,
   >         class Pred = std::equal_to<Key>,
   >         class Allocator = std::allocator<std::pair<const Key, T> > > {
   >       class unordered_multimap {
   >       public:
   >         […]
   >         unordered_multimap(size_type n, const hasher& hf, const allocator_type& a)
   >           : unordered_multimap(n, hf, key_equal(), a) { }
   >         template <class InputIterator>
   >           unordered_multimap(InputIterator f, InputIterator l, const allocator_type& a);
   >         template <class InputIterator>
   >           unordered_multimap(InputIterator f, InputIterator l, size_type n, const allocator_type& a)
   >           : unordered_multimap(f, l, n, hasher(), key_equal(), a) { }
   >         template <class InputIterator>
   >           unordered_multimap(InputIterator f, InputIterator l, size_type n, const hasher& hf,
   >                 const allocator_type& a)
   >           : unordered_multimap(f, l, n, hf, key_equal(), a) { }
   >         unordered_multimap(initializer_list<value_type> il, const allocator_type& a);
   >         unordered_multimap(initializer_list<value_type> il, size_type n, const allocator_type& a)
   >           : unordered_multimap(il, n, hasher(), key_equal(), a) { }
   >         […]
   >       };
   >     }

4. Insert the following new prototype specification just after 22.5.5.2 [unord.multimap.cnstr] p2

   >     template <class InputIterator>
   >       unordered_multimap(InputIterator f, InputIterator l, const allocator_type& a)
   >         : unordered_multimap(f, l, size_type(see below), hasher(), key_equal(), a) { }

   >     unordered_multimap(initializer_list<value_type> il, const allocator_type& a)
   >       : unordered_multimap(il, size_type(see below), hasher(), key_equal(), a) { }

   > > -?- Remarks: The initial number of buckets supplied by the `size_type` argument is implementation-defined.

5. Add to the synopsis in 22.5.6.1 [unord.set.overview] p3:

   >     namespace std {
   >       template <class Key,
   >         class Hash = hash<Key>,
   >         class Pred = std::equal_to<Key>,
   >         class Allocator = std::allocator<Key> > {
   >       class unordered_set {
   >       public:
   >         […]
   >         unordered_set(size_type n, const hasher& hf, const allocator_type& a)
   >           : unordered_set(n, hf, key_equal(), a) { }
   >         template <class InputIterator>
   >           unordered_set(InputIterator f, InputIterator l, const allocator_type& a);
   >         template <class InputIterator>
   >           unordered_set(InputIterator f, InputIterator l, size_type n, const allocator_type& a)
   >           : unordered_set(f, l, n, hasher(), key_equal(), a) { }
   >         template <class InputIterator>
   >           unordered_set(InputIterator f, InputIterator l, size_type n, const hasher& hf,
   >                 const allocator_type& a)
   >           : unordered_set(f, l, n, hf, key_equal(), a) { }
   >         unordered_set(initializer_list<value_type> il, const allocator_type& a);
   >         unordered_set(initializer_list<value_type> il, size_type n, const allocator_type& a)
   >           : unordered_set(il, n, hasher(), key_equal(), a) { }
   >         […]
   >       };
   >     }

6. Insert the following new prototype specification just after 22.5.6.2 [unord.set.cnstr] p2

   >     template <class InputIterator>
   >       unordered_set(InputIterator f, InputIterator l, const allocator_type& a)
   >         : unordered_set(f, l, size_type(see below), hasher(), key_equal(), a) { }

   >     unordered_set(initializer_list<value_type> il, const allocator_type& a)
   >       : unordered_set(il, size_type(see below), hasher(), key_equal(), a) { }

   > > -?- Remarks: The initial number of buckets supplied by the `size_type` argument is implementation-defined.

7. Add to the synopsis in 22.5.7.1 [unord.multiset.overview] p3:

   >     namespace std {
   >       template <class Key,
   >         class Hash = hash<Key>,
   >         class Pred = std::equal_to<Key>,
   >         class Allocator = std::allocator<Key> > {
   >       class unordered_multiset {
   >       public:
   >         […]
   >         unordered_multiset(size_type n, const hasher& hf, const allocator_type& a)
   >           : unordered_multiset(n, hf, key_equal(), a) { }
   >         template <class InputIterator>
   >           unordered_multiset(InputIterator f, InputIterator l, const allocator_type& a);
   >         template <class InputIterator>
   >           unordered_multiset(InputIterator f, InputIterator l, size_type n, const allocator_type& a)
   >           : unordered_multiset(f, l, n, hasher(), key_equal(), a) { }
   >         template <class InputIterator>
   >           unordered_multiset(InputIterator f, InputIterator l, size_type n, const hasher& hf,
   >                 const allocator_type& a)
   >           : unordered_multiset(f, l, n, hf, key_equal(), a) { }
   >         unordered_multiset(initializer_list<value_type> il, const allocator_type& a);
   >         unordered_multiset(initializer_list<value_type> il, size_type n, const allocator_type& a)
   >           : unordered_multiset(il, n, hasher(), key_equal(), a) { }
   >         […]
   >       };
   >     }

8. Insert the following new prototype specification just after 22.5.7.2 [unord.multiset.cnstr] p2

   >     template <class InputIterator>
   >       unordered_multiset(InputIterator f, InputIterator l, const allocator_type& a)
   >         : unordered_multiset(f, l, size_type(see below), hasher(), key_equal(), a) { }

   >     unordered_multiset(initializer_list<value_type> il, const allocator_type& a)
   >       : unordered_multiset(il, size_type(see below), hasher(), key_equal(), a) { }

   > > -?- Remarks: The initial number of buckets supplied by the `size_type` argument is implementation-defined.

### 2714(i). `complex` stream extraction underspecified

Section: 26.4.7 [complex.ops] Status: New Submitter: Tim Song Opened: 2016-05-23 Last modified: 2018-10-16

Priority: 3

View all other issues in [complex.ops].

View all issues with New status.

Discussion:

The specification of `operator>>(istream&, complex<T>&)` is extremely short on details. It currently reads, in its entirety (26.4.7 [complex.ops]/12-15):

>     template<class T, class charT, class traits>
>     basic_istream<charT, traits>& operator>>(basic_istream<charT, traits>& is, complex<T>& x);

> > Effects: Extracts a complex number `x` of the form: `u`, `(u)`, or `(u,v)`, where `u` is the real part and `v` is the imaginary part (29.7.4.3 [istream.formatted]).

> > Requires: The input values shall be convertible to `T`.

> > If bad input is encountered, calls `is.setstate(ios_base::failbit)` (which may throw `ios::failure` (29.5.4.4 [iostate.flags])).

> > Returns: `is`.

> > Remarks: This extraction is performed as a series of simpler extractions. Therefore, the skipping of whitespace is specified to be the same for each of the simpler extractions.

It is completely unclear:

- which "simpler extractions" are performed,
- how the extracted characters are matched to the special characters `'('`, `')'` and `','` (by `==`, or by `traits::eq`),
- what is left in the stream on failure. (For example, with `"(0, 0]"`, libstdc++ extracts the `]` while libc++ leaves it in the stream.)

Previous resolution [SUPERSEDED]:

> > Drafting note: the following wording is based on:
> > - Characters are extracted using `operator>>` and compared using `traits::eq`.
> > - Mismatched characters are returned to the stream.

> This wording is relative to N4582.

> 1. Replace 26.4.7 [complex.ops]/12-15 with the following paragraphs:

>    >     template<class T, class charT, class traits>
>    >     basic_istream<charT, traits>&
>    >     operator>>(basic_istream<charT, traits>& is, complex<T>& x);

>    > > -?- Effects: First, extracts a character from `is`.

>    > > - If the character extracted is equal to `is.widen('(')`, extracts an object `u` of type `T` from `is`, then extracts a character from `is`.
>    > >   - If this character is equal to `is.widen(')')`, then assigns `complex<T>(u)` to `x`.
>    > >   - Otherwise, if this character is equal to `is.widen(',')`, extracts an object `v` of type `T` from `is`, then extracts a character from `is`. If this character is equal to `is.widen(')')`, then assigns `complex<T>(u, v)` to `x`; otherwise returns the character to `is` and the extraction fails.
>    > >   - Otherwise, returns the character to `is` and the extraction fails.
>    > > - Otherwise, returns the character to `is`, extracts an object `u` of type `T` from `is`, and assigns `complex<T>(u)` to `x`.
>    > > In the description above, characters are extracted from `is` as if by `operator>>` (29.7.4.3.3 [istream.extractors]), and returned to the stream as if by `basic_istream::putback` (29.7.4.4 [istream.unformatted]). Character equality is determined using `traits::eq`. An object `t` of type `T` is extracted from `is` as if by `is >> t`.

>    > > If any extraction operation fails, no further operation is performed and the whole extraction fails.

>    > > On failure, calls `is.setstate(ios_base::failbit)` (which may throw `ios::failure` (29.5.4.4 [iostate.flags])).

>    > > -?- Returns: `is`.

>    > > -?- [Note: This extraction is performed as a series of simpler extractions. Therefore, the skipping of whitespace is specified to be the same for each of the simpler extractions. — end note]

[2017-12-13 Tim Song adjusts the P/R to avoid relying on `putback`.]

Proposed resolution:

> Drafting note: the following wording assumes that:
> - Characters are extracted using `operator>>` and compared using `traits::eq`.
> - Mismatched characters are not extracted.
> - `x` is assigned a value-initialized `complex` on failure for consistency with the arithmetic extractors (compare LWG 696).

This wording is relative to N4778.

1. Replace 26.4.7 [complex.ops]/12-16 with the following paragraphs:

   >     template<class T, class charT, class traits>
   >     basic_istream<charT, traits>&
   >     operator>>(basic_istream<charT, traits>& is, complex<T>& x);

   > > -?- Effects: Let `PEEK(is)` be a formatted input function (29.7.4.3.1 [istream.formatted.reqmts]) of `is` that returns the next character that would be extracted from `is` by `operator>>`. [Note: The `sentry` object is constructed and destroyed, but the returned character is not extracted from the stream. — end note]

   > > - If `PEEK(is)` is not equal to `is.widen('(')`, extracts an object `u` of type `T` from `is`, and assigns `complex<T>(u)` to `x`.
   > > - Otherwise, extracts that character from `is`, then extracts an object `u` of type `T` from `is`, then:
   > >   - If `PEEK(is)` is equal to `is.widen(')')`, then extracts that character from `is` and assigns `complex<T>(u)` to `x`.
   > >   - Otherwise, if it is equal to `is.widen(',')`, then extracts that character from `is` and then extracts an object `v` of type `T` from `is`, then:
   > >     - If `PEEK(is)` is equal to `is.widen(')')`, then extracts that character from `is` and assigns `complex<T>(u, v)` to `x`.
   > >     - Otherwise, the extraction fails.
   > >   - Otherwise, the extraction fails.
   > > In the description above, characters are extracted from `is` as if by `operator>>` (29.7.4.3.3 [istream.extractors]), character equality is determined using `traits::eq`, and an object `t` of type `T` is extracted from `is` as if by `is >> t`.

   > > If any extraction operation fails, no further operation is performed and the whole extraction fails.

   > > On failure, assigns `complex<T>()` to `x` and calls `is.setstate(ios_base::failbit)` (which may throw `ios::failure` (29.5.4.4 [iostate.flags])).

   > > -?- Returns: `is`.

   > > -?- [Note: This extraction is performed as a series of simpler extractions. Therefore, the skipping of whitespace is specified to be the same for each of the simpler extractions. — end note]

### 2730(i). `numeric_limits` primary template definition

Section: 17.3.5 [numeric.limits] Status: Open Submitter: Richard Smith Opened: 2016-06-09 Last modified: 2018-11-12

Priority: 3

View other active issues in [numeric.limits].

View all other issues in [numeric.limits].

View all issues with Open status.

Discussion:

I've received this report at the project editor mail alias, and it seems like it may be worthy of a LWG issue:

> I recently had this problem:

> - I was storing data in a vector of `__uint128_t`s
> - I used a sorting library which used `numeric_limits<T>::max()` as a sentinel value
> - GCC's libstdc++ provides a `numeric_limits` specialisation for that type, but
> - Clang's libc++ does not.

> This broke the sorting for me on different platforms, and it was quite difficult to determine why. If the default `numeric_limits` didn't default to `0`s and `false` values (18.3.2.4 of N4582), and instead `static_assert`ed, causing my code to not compile, I would have found the solution immediately.

> I know that `__uint128_t` is non-standard, so neither GCC nor Clang is doing the wrong thing nor the right thing here. I could just submit a patch to libc++ providing the specialisations, but it doesn't fix the problem at its core.

> I am wondering, what is the rationale behind the defaults being `0` and `false`? It seems like it is inviting a problem for any future numeric types, whether part of a library, compiler extension, and possibly even future updates to C++'s numeric types. I think it would be much better to prevent code that tries to use unspecified `numeric_limits` from compiling.

An alternative to this suggestion would be to still define the primary template, but not provide any of the members except `is_specialized`. Either way, this would make `numeric_limits` members SFINAEable.

Along the same lines, one might wonder why the members that only make sense for floating-point types are required to be defined to nonsense values for integer types.

[2016-11-12, Issaquah]

Sat PM: This looks like a good idea. Jonathan and Marshall will do post C++17 implementations and report back.

[2018-11 San Diego Thursday night issue processing]

See Walter's paper P0437 for ideas and/or future directions.

Proposed resolution:

### 2737(i). Consider relaxing object size restrictions for single-object allocation functions

Section: 17.6.3.2 [new.delete.single] Status: New Submitter: Clark Nelson Opened: 2016-06-21 Last modified: 2016-08-01

Priority: 3

View other active issues in [new.delete.single].

View all other issues in [new.delete.single].

View all issues with New status.

Discussion:

It should be considered whether the description of the single-object allocation functions should say "or smaller", like the array allocation functions. For example, according to 17.6.3.2 [new.delete.single] p1 (emphasis mine):

> The allocation function (3.7.4.1) called by a new-expression (5.3.4) to allocate `size` bytes of storage suitably aligned to represent any object of that size.

In contrast to this, 17.6.3.3 [new.delete.array] p1 says (emphasis mine):

> The allocation function (3.7.4.1) called by the array form of a new-expression (5.3.4) to allocate `size` bytes of storage suitably aligned to represent any array object of that size or smaller. (footnote: It is not the direct responsibility of `operator new[](std::size_t)` or `operator delete[](void*)` to note the repetition count or element size of the array. Those operations are performed elsewhere in the array `new` and `delete` expressions. The array `new` expression, may, however, increase the size argument to operator `new[](std::size_t)` to obtain space to store supplemental information.)

Proposed resolution:

### 2746(i). Inconsistency between requirements for `emplace` between `optional` and `variant`

Section: 20.6.3.4 [optional.assign], 20.7.3.5 [variant.mod], 20.8.4.4 [any.modifiers] Status: New Submitter: Richard Smith Opened: 2016-07-13 Last modified: 2020-05-10

Priority: 3

View all issues with New status.

Discussion:

Referring to N4604:

In [optional.object.assign]: `emplace` (normal form) has a Requires that the construction works.

> Requires: `is_constructible_v<T, Args&&...>` is `true`.

`emplace` (`initializer_list` form) has a SFINAE condition:

> Remarks: […] unless `is_constructible_v<T, initializer_list<U>&, Args&&...>` is `true`.

In 20.8.4.4 [any.modifiers]: `emplace` (normal form) has a Requires that the construction works:

> Requires: `is_constructible_v<T, Args...>` is `true`.

`emplace` (`initializer_list` form) has a SFINAE condition:

> Remarks: […] unless `is_constructible_v<T, initializer_list<U>&, Args...>` is `true`.

In 20.7.3.5 [variant.mod]: `emplace` (`T`, normal form) has a SFINAE condition:

> Remarks: […] unless `is_constructible_v<T, Args...>` is `true`, and `T` occurs exactly once in `Types...`.

`emplace` (Idx, normal form) has a both a Requires and a SFINAE condition:

> Requires: `I < sizeof...(Types)`

> Remarks: […] unless `is_constructible_v<T, Args...>` is `true`, and `T` occurs exactly once in `Types...`.

`emplace` (`T`, `initializer_list` form) has a SFINAE condition:

> Remarks: […] unless `is_constructible_v<T, initializer_list<U>&, Args...>` is `true`, and `T` occurs exactly once in `Types...`.

`emplace` (Idx, `initializer_list` form) has a both a Requires and a SFINAE condition:

> Requires: `I < sizeof...(Types)`

> Remarks: […] unless `is_constructible_v<T, Args...>` is true, and `T` occurs exactly once in `Types...`.

Why the inconsistency? Should all the cases have a SFINAE requirement?

I see that variant has an additional requirement (`T` occurs exactly once in `Types...`), but that only agues that it must be a SFINAE condition — doesn't say that the other cases (any/variant) should not.

`map`/`multimap`/`unordered_map`/`unordered_multimap` have SFINAE'd versions of `emplace` that don't take `initializer_list`s, but they don't have any `emplace` versions that take ILs.

Suggested resolution:

Add SFINAE requirements to `optional::emplace(Args&&... args)` and `any::emplace(Args&&... args);`

[2016-08 Chicago]

During issue prioritization, people suggested that this might apply to `any` as well.

Ville notes that 2746, 2754 and 2756 all go together.

[2020-05-10; Daniel comments and provides wording]

The inconsistency between the two `any::emplace` overloads have been removed by resolving LWG 2754 to use Constraints: elements. The last Mandating paper (P1460R1), adopted in Prague, changed the Requires: elements for `variant::emplace`, "`I < sizeof...(Types)`" to Mandates:, but that paper was focused on fixing inappropriate preconditions, not searching for consistency here. Given that the `in_place_index_t` constructors of `variant` uses SFINAE-conditions for this form of static precondition violation, I recommend that its `emplace` functions use the same style, which would bring them also in consistency with their corresponding type-based `emplace` forms that are Mandates:-free but delegate to the index-based forms.

Proposed resolution:

This wording is relative to N4861.

1. Modify 20.6.3.4 [optional.assign], as indicated:

   >     template<class... Args> T& emplace(Args&&... args);

   > > -29- Mandates Constraints: `is_constructible_v<T, Args...>` is `true`.

   > > […]

   >     template<class U, class... Args> T& emplace(initializer_list<U> il, Args&&... args);

   > > -35- Constraints: `is_constructible_v<T, initializer_list<U>&, Args...>` is `true`.

   > > […]

2. Modify 20.7.3.5 [variant.mod], as indicated:

   >     template<class T, class... Args> T& emplace(Args&&... args);

   > > -1- Constraints: `is_constructible_v<T, Args...>` is `true`, and `T` occurs exactly once in `Types`.

   > > […]

   >     template<class T, class U, class... Args> T& emplace(initializer_list<U> il, Args&&... args);

   > > -3- Constraints: `is_constructible_v<T, initializer_list<U>&, Args...>` is `true`, and `T` occurs exactly once in `Types`.

   > > […]

   >     template<size_t I, class... Args>
   >       variant_alternative_t<I, variant<Types...>>& emplace(Args&&... args);

   > > -5- Mandates: `I < sizeof...(Types)`.

   > > -6- Constraints: `is_constructible_v<TI, Args...>` is `true` and `I < sizeof...(Types)` is `true`.

   > > […]

   >     template<size_t I, class U, class... Args>
   >       variant_alternative_t<I, variant<Types...>>& emplace(initializer_list<U> il, Args&&... args);

   > > -12- Mandates: `I < sizeof...(Types)`.

   > > -13- Constraints: `is_constructible_v<TI, initializer_list<U>&, Args...>` is `true` and `I < sizeof...(Types)` is `true`.

   > > […]

### 2751(i). `shared_ptr` deleter not specified to observe expired `weak_ptr` instances

Section: 20.11.3.3 [util.smartptr.shared.dest] Status: New Submitter: Aaron Jacobs Opened: 2016-07-21 Last modified: 2017-10-08

Priority: 4

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

View all issues with New status.

Discussion:

The C++14 standard contains no language that guarantees the deleter run by a `shared_ptr` will see all associated `weak_ptr` instances as expired. For example, the standard doesn't appear to guarantee that the assertion in the following snippet won't fire:

>     std::weak_ptr<Foo> weak;
>     std::shared_ptr<Foo> strong{
>       new Foo,
>       [&weak] (Foo* f) {
>         assert(weak.expired());
>         delete f;
>       },
>     };

>     weak = strong;
>     strong.reset();

It seems clear that the intent is that associated `weak_ptr`s are expired, because otherwise `shared_ptr` deleters could resurrect a reference to an object that is being deleted.

Suggested fix: 20.11.3.3 [util.smartptr.shared.dest] should specify that the decrease in `use_count()` caused by the destructor is sequenced before the call to the deleter or the call to `delete p`.

[2016-11-08, Jonathan and STL suggest NAD]

STL and Jonathan feel that the example has unspecified behaviour, and the assertion is allowed to fire, and that's OK (the program's expectation is not reasonable). Otherwise it's necessary to move-construct a copy of the deleter and use that copy to destroy the owned pointer. We do not want to be required to do that.

See also 2262.

[2017-09-20, Jonathan comments]

I'd like to withdraw my NAD suggestion. The value of `use_count()` is already observable during the destructor via `shared_ptr` and `weak_ptr` objects that share ownership, so specifying when it changes ensures correct behaviour.

Proposed resolution:

### 2766(i). Swapping non-swappable types

Section: 20.4.3 [pairs.spec], 20.5.10 [tuple.special], 20.6.9 [optional.specalg], 20.7.10 [variant.specalg], 20.11.1.6 [unique.ptr.special], 22.3.7.4 [array.special], 22.6.4.5 [queue.special], 22.6.5.5 [priqueue.special], 22.6.6.6 [stack.special] Status: New Submitter: Agustín K-ballo Bergé Opened: 2016-08-15 Last modified: 2020-09-06

Priority: 3

View all other issues in [pairs.spec].

View all issues with New status.

Discussion:

Related: 2748 swappable traits for optionals, 2749 swappable traits for variants.

The adoption of P0185R1 "Adding [nothrow-]swappable traits" makes certain non-swappable types indirectly swappable. Consider a type defined as follows:

>     struct non_swappable {
>       friend void swap(non_swappable&, non_swappable&) = delete;
>     };

>     non_swappable ns1, ns2;
>     using std::swap;
>     swap(ns1, ns2); // ill-formed

>     static_assert(std::is_swappable_v<non_swappable> == false); // holds

Lvalues of type `non_swappable` are not swappable, as defined by 16.4.4.3 [swappable.requirements], overload resolution selects the deleted function. Consistently, `is_swappable_v<non_swappable>` yields false. It should be noted that since `non_swappable` is move constructible and move assignable, a qualified call to `std::swap` would be well-formed, even under P0185. Now consider the following snippet:

>     std::tuple<non_swappable> tns1, tns2;
>     using std::swap;
>     swap(tns1, tns2); // previously ill-formed, now well-formed

>     static_assert(std::is_swappable_v<std::tuple<non_swappable>> == false); // fires

Before P0185, this snippet would violate the implicit requirement of specialized swap for tuples that each tuple element be swappable. After P0185, this specialized swap overload for tuples would be SFINAEd away, resulting in overload resolution selecting the base swap overload, and performing the exchange via move construction and move assignment of tuples.

This issue affects all of `pair`, `tuple`, `unique_ptr`, `array`, `queue`, `priority_queue`, `stack`, and should eventually also apply to `optional` and `variant`. Previous resolution [SUPERSEDED]:

> This wording is relative to N4606, except when otherwise noted.

> 1. Modify 20.4.3 [pairs.spec] as indicated:

>    >     template<class T1, class T2> void swap(pair<T1, T2>& x, pair<T1, T2>& y)
>    >       noexcept(noexcept(x.swap(y)));

>    > > -7- Effects: As if by `x.swap(y)`.

>    > > -8- Remarks: This function shall not participate in overload resolution be defined as deleted unless `is_swappable_v<T1>` is `true` and `is_swappable_v<T2>` is `true`.

> 2. Modify 20.5.10 [tuple.special] as indicated:

>    >     template <class... Types>
>    >       void swap(tuple<Types...>& x, tuple<Types...>& y) noexcept(see below);

>    > > -1- Remarks: This function shall not participate in overload resolution be defined as deleted unless `is_swappable_v<`Ti`>` is `true` for all `i`, where `0 <= i` and `i < sizeof...(Types)`. The expression inside `noexcept` is equivalent to:

>    > > >     noexcept(x.swap(y))

>    > > -2- Effects: As if by `x.swap(y)`.

> 3. Modify 20.11.1.6 [unique.ptr.special] as indicated:

>    >     template <class T, class D> void swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y) noexcept;

>    > > -1- Remarks: This function shall not participate in overload resolution be defined as deleted unless `is_swappable_v<D>` is `true`.

>    > > -2- Effects: Calls `x.swap(y)`.

> 4. Modify 22.3.7.4 [array.special] as indicated:

>    >     template <class T, size_t N>
>    >       void swap(array<T, N>& x, array<T, N>& y) noexcept(noexcept(x.swap(y)));

>    > > -1- Remarks: This function shall not participate in overload resolution be defined as deleted unless `N == 0` or `is_swappable_v<T>` is `true`.

>    > > -2- Effects: As if by `x.swap(y)`.

>    > > […]

> 5. Modify 22.6.4.5 [queue.special] as indicated:

>    >     template <class T, class Container>
>    >       void swap(queue<T, Container>& x, queue<T, Container>& y) noexcept(noexcept(x.swap(y)));

>    > > -1- Remarks: This function shall not participate in overload resolution be defined as deleted unless `is_swappable_v<Container>` is `true`.

>    > > -2- Effects: As if by `x.swap(y)`.

> 6. Modify 22.6.5.5 [priqueue.special] as indicated:

>    >     template <class T, class Container, class Compare>
>    >       void swap(priority_queue<T, Container, Compare>& x,
>    >                 priority_queue<T, Container, Compare>& y) noexcept(noexcept(x.swap(y)));

>    > > -1- `Remarks:` This function shall not participate in overload resolution be defined as deleted unless `is_swappable_v<Container>` is `true` and `is_swappable_v<Compare>` is `true`.

>    > > -2- Effects: As if by `x.swap(y)`.

> 7. Modify 22.6.6.6 [stack.special] as indicated:

>    >     template <class T, class Container>
>    >       void swap(stack<T, Container>& x, stack<T, Container>& y) noexcept(noexcept(x.swap(y)));

>    > > -1- Remarks: This function shall not participate in overload resolution be defined as deleted unless `is_swappable_v<Container>` is `true`.

>    > > -2- Effects: As if by `x.swap(y)`.

> 8. Modify 20.6.9 [optional.specalg] as indicated:

>    > This change should be performed if and only if LWG 2748 is accepted and is against the wording of 2748:

>    >     template <class T> void swap(optional<T>& x, optional<T>& y) noexcept(noexcept(x.swap(y)));

>    > > -1- Effects: Calls `x.swap(y)`.

>    > > -2- Remarks: This function shall not participate in overload resolution be defined as deleted unless `is_move_constructible_v<T>` is `true` and `is_swappable_v<T>` is `true`.

> 9. Modify 20.7.10 [variant.specalg] as indicated:

>    > This change should be performed if and only if LWG 2749 is accepted and is against the wording of 2749:

>    >     template <class... Types> void swap(variant<Types...>& v, variant<Types...>& w) noexcept(see below);

>    > > -1- Effects: Equivalent to `v.swap(w)`.

>    > > -2- Remarks: This function shall not participate in overload resolution be defined as deleted unless `is_move_constructible_v<Ti> && is_swappable_v<Ti>` is `true` for all `i`. The expression inside `noexcept` is equivalent to `noexcept(v.swap(w))`.

[2019-04-17 Jonathan updates proposed resolution based on Ville's 2016-11-17 observation that the container adaptors always require swappable sequences anyway. The new proposed resolution is based on the latest WP, "de-shalled", and Remarks elements are repositioned after the Effects.]

Proposed resolution:

This wording is relative to N4810.

1. Modify 20.4.3 [pairs.spec] as indicated:

   >     template<class T1, class T2>
   >       constexpr void swap(pair<T1, T2>& x, pair<T1, T2>& y) noexcept(noexcept(x.swap(y)));

   > > -7- Effects: As if by `x.swap(y)`.

   > > -8- Remarks: This function shall not participate in overload resolution is defined as deleted unless `is_swappable_v<T1>` is `true` and `is_swappable_v<T2>` is `true`.

2. Modify 20.5.10 [tuple.special] as indicated:

   >     template <class... Types>
   >       constexpr void swap(tuple<Types...>& x, tuple<Types...>& y) noexcept(see below);

   > > -?- Effects: As if by `x.swap(y)`.

   > > -1- Remarks: This function shall not participate in overload resolution is defined as deleted unless `is_swappable_v<`Ti`>` is `true` for all `i`, where `0 <= i` and `i < sizeof...(Types)`. The expression inside `noexcept` is equivalent to:

   > > >     noexcept(x.swap(y))

   > > -2- Effects: As if by `x.swap(y)`.

3. Modify 20.6.9 [optional.specalg] as indicated:

   >     template <class T> void swap(optional<T>& x, optional<T>& y) noexcept(noexcept(x.swap(y)));

   > > -1- Effects: Calls `x.swap(y)`.

   > > -2- Remarks: This function shall not participate in overload resolution is defined as deleted unless `is_move_constructible_v<T>` is `true` and `is_swappable_v<T>` is `true`.

4. Modify 20.7.10 [variant.specalg] as indicated:

   >     template <class... Types> void swap(variant<Types...>& v, variant<Types...>& w) noexcept(see below);

   > > -1- Effects: Equivalent to `v.swap(w)`.

   > > -2- Remarks: This function shall not participate in overload resolution is defined as deleted unless `is_move_constructible_v<Ti> && is_swappable_v<Ti>` is `true` for all `i`. The expression inside `noexcept` is equivalent to `noexcept(v.swap(w))`.

5. Modify 20.11.1.6 [unique.ptr.special] as indicated:

   >     template <class T, class D> void swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y) noexcept;

   > > -?- Effects: Calls `x.swap(y)`.

   > > -1- Remarks: This function shall not participate in overload resolution is defined as deleted unless `is_swappable_v<D>` is `true`.

   > > -2- Effects: Calls `x.swap(y)`.

6. Modify 22.3.7.4 [array.special] as indicated:

   >     template <class T, size_t N>
   >       void swap(array<T, N>& x, array<T, N>& y) noexcept(noexcept(x.swap(y)));

   > > -1- Constraints: `N == 0` or `is_swappable_v<T>` is `true`.

   > > -2- Effects: As if by `x.swap(y)`.

   > > -3- Complexity: Linear in `N`.

   > > -?- Remarks: This function is defined as deleted unless `N == 0` or `is_swappable_v<T>` is `true`.

### 2811(i). "Selected constructor" wording is incorrect for `optional`/`variant`/`any`

Section: 20.6.3.2 [optional.ctor], 20.6.3.4 [optional.assign], 20.7.3.2 [variant.ctor], 20.8.4.2 [any.cons], 20.8.4.4 [any.modifiers] Status: New Submitter: Tim Song Opened: 2016-10-29 Last modified: 2020-06-13

Priority: 3

View all other issues in [optional.ctor].

View all issues with New status.

Discussion:

Throughout `optional`/`variant`/`any`'s specification references are made to "the selected constructor of `T`". For example, 20.6.3.2 [optional.ctor]/16 says of the constructor from `const T&`:

> -16- Remarks: If `T`'s selected constructor is a `constexpr` constructor, this constructor shall be a `constexpr` constructor.

Similarly, the in-place constructor has this wording (20.6.3.2 [optional.ctor]/25-26):

> -25- Throws: Any exception thrown by the selected constructor of `T`.

> -26- Remarks: If `T`'s constructor selected for the initialization is a `constexpr` constructor, this constructor shall be a `constexpr` constructor.

If `T` is a scalar type, it has no constructor at all. Moreover, even for class types, the in-place constructor wording ignores any implicit conversion done on the argument before the selected constructor is called, which 1) may not be valid in constant expressions and 2) may throw an exception; such exceptions aren't thrown "by the selected constructor of `T`" but outside it.

The wording should probably be recast to refer to the entire initialization.

[Issues Telecon 16-Dec-2016]

Priority 3; Jonathan to provide wording.

[2020-06-11; Nina Dinka Ranns comments and provides initial wording]

This wording depends on the current resolution for LWG 2833, which covers the `constexpr` portion of this issue.

Proposed resolution:

This wording is relative to N4861.

1. Modify 20.6.3.2 [optional.ctor] as indicated:

   >     constexpr optional(const optional& rhs);

   > > -3- […]

   > > -4- […]

   > > -5- Throws: Any exception thrown by the selected constructor of `T` initialization of the contained value.

   >     constexpr optional(optional&& rhs) noexcept(see below);

   > > -7- […]

   > > […]

   > > -10- Throws: Any exception thrown by the selected constructor of `T` initialization of the contained value.

   >     template<class... Args> constexpr explicit optional(in_place_t, Args&&... args);

   > > -12- […]

   > > […]

   > > -15- Throws: Any exception thrown by the selected constructor of `T` initialization of the contained value.

   >     template<class U, class... Args>
   >       constexpr explicit optional(in_place_t, initializer_list<U> il, Args&&... args);

   > > -17- […]

   > > […]

   > > -20- Throws: Any exception thrown by the selected constructor of `T` initialization of the contained value.

   >     template<class U = T> constexpr explicit(see below) optional(U&& v);

   > > -22- […]

   > > […]

   > > -25- Throws: Any exception thrown by the selected constructor of `T` initialization of the contained value.

   >     template<class U> explicit(see below) optional(const optional<U>& rhs);

   > > -27- […]

   > > […]

   > > -30- Throws: Any exception thrown by the selected constructor of `T` initialization of the contained value.

   >     template<class U> explicit(see below) optional(optional<U>&& rhs);

   > > -32- […]

   > > […]

   > > -35- Throws: Any exception thrown by the selected constructor of `T` initialization of the contained value.

2. Modify 20.7.3.2 [variant.ctor] as indicated:

   >     template<class T, class... Args> constexpr explicit variant(in_place_type_t<T>, Args&&... args);

   > > -20- […]

   > > […]

   > > -23- Throws: Any exception thrown by calling the selected constructor of `T` the initialization of the contained value.

   >     template<class T, class U, class... Args>
   >       constexpr explicit variant(in_place_type_t<T>, initializer_list<U> il, Args&&... args);

   > > -25- […]

   > > […]

   > > -28- Throws: Any exception thrown by calling the selected constructor of `T` the initialization of the contained value.

   >     template<size_t I, class... Args> constexpr explicit variant(in_place_index_t<I>, Args&&... args);

   > > -30 […]

   > > […]

   > > -33- Throws: Any exception thrown by calling the selected constructor of `TI` the initialization of the contained value.

3. Modify 20.8.4.2 [any.cons] as indicated:

   >     any(const any& other);

   > > -2- Effects: […]

   > > -3- Throws: Any exceptions arising from calling the selected constructor for thrown by the initialization of the contained value.

   > […]

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

   > > -5- […]

   > > […]

   > > -9- Throws: Any exception thrown by the selected constructor of `VT` initialization of the contained value.

   >     template<class T, class... Args>
   >       explicit any(in_place_type_t<T>, Args&&... args);

   > > -10- […]

   > > […]

   > > -15- Throws: Any exception thrown by the selected constructor of `VT` initialization of the contained value.

   >     template<class T, class U, class... Args>
   >       explicit any(in_place_type_t<T>, initializer_list<U> il, Args&&... args);

   > > -16- […]

   > > […]

   > > -21- Throws: Any exception thrown by the selected constructor of `VT` initialization of the contained value.

4. Modify 20.8.4.4 [any.modifiers] as indicated:

   >     template<class T, class... Args>
   >       decay_t<T>& emplace(Args&&... args);

   > > -1- […]

   > > […]

   > > -7- Throws: Any exception thrown by the selected constructor of `VT` initialization of the contained value.

   > > -8- […]

   >     template<class T, class U, class... Args>
   >       decay_t<T>& emplace(initializer_list<U> il, Args&&... args);

   > > -9- […]

   > > […]

   > > -15- Throws: Any exception thrown by the selected constructor of `VT` initialization of the contained value.

### 2813(i). `std::function` should not return dangling references

Section: 20.14.17.3.2 [func.wrap.func.con] Status: EWG Submitter: Brian Bi Opened: 2016-11-03 Last modified: 2020-09-06

Priority: 2

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

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

View all issues with EWG status.

Discussion:

If a `std::function` has a reference as a return type, and that reference binds to a prvalue returned by the callable that it wraps, then the reference is always dangling. Because any use of such a reference results in undefined behaviour, the `std::function` should not be allowed to be initialized with such a callable. Instead, the program should be ill-formed.

A minimal example of well-formed code under the current standard that exhibits this issue:

>     #include <functional>

>     int main()
>     {
>       std::function<const int&()> F([]{ return 42; });
>       int x = F(); // oops!
>     }

[2016-11-22, David Krauss comments and suggests wording]

Indirect bindings may also introduce temporaries inside `std::function`, e.g.:

>     void f(std::function<long const&()>); // Retains an observer to a long.

>     void g() {
>       int v;
>       f([&]()->int& { return v; } ); // int lvalue binds to long const& through a temporary.
>     }

A fix has been implemented. Conversions that may be conversion operators are allowed, though, because those can produce legitimate glvalues. Before adopting this, it need to be considered considered whether there should be SFINAE or a hard error.

[Issues Telecon 16-Dec-2016]

Priority 2

[2016-07, Toronto Saturday afternoon issues processing]

Billy to work with Brian to rework PR. Status to Open

[2018-08-23 Batavia Issues processing]

Really needs a language change to fix this. Status to EWG.

Proposed resolution:

This wording is relative to N4618.

1. Add a second paragraph to the remarks section of 20.14.17.3.2 [func.wrap.func.con]:

   >     template<class F> function(F f);

   > > -7- Requires: `F` shall be `CopyConstructible`.

   > > -8- Remarks: This constructor template shall not participate in overload resolution unless

   > > - `F` is Lvalue-Callable (20.14.17.3 [func.wrap.func]) for argument types `ArgTypes...` and return type `R`, and

   > > - If `R` is type "reference to `T`" and `INVOKE(ArgTypes...)` has value category `V` and type `U`:

   > >   - `V` is a prvalue, `U` is a class type, and `T` is not reference-related (9.4.4 [dcl.init.ref]) to `U`, and

   > >   - `V` is an lvalue or xvalue, and either `U` is a class type or `T` is reference-related to `U`.

   > > […]

### 2815(i). `quick_exit` can deadlock

Section: 17.5 [support.start.term] Status: New Submitter: Jean-François Bastien Opened: 2016-11-07 Last modified: 2020-09-06

Priority: 3

View other active issues in [support.start.term].

View all other issues in [support.start.term].

View all issues with New status.

Discussion:

While SG1 was processing NB comments CA1 and LATE2 regarding P0270R1, we decided to remove the proposed guarantee that `quick_exit` be made signal safe.

Our reasoning is that functions registered with `at_quick_exit` aren't forbidden from calling `quick_exit`, but `quick_exit` implementations likely acquire some form of a lock before processing all registered functions (because a note forbids the implementation from introducing data races).

The following code can therefore deadlock:

>     #include <cstdlib>

>     int main()
>     {
>       std::at_quick_exit([] () { std::quick_exit(0); });
>       std::quick_exit(1);
>       return 0;
>     }

The same applies if a function registered in `at_quick_exit` handles a signal, and that signal calls `quick_exit`. SG1 believes that both issues (same thread deadlock, and signal deadlock) can be resolved in the same manner. Either:

1. Specify that calling `quick_exit` while servicing `quick_exit` is undefined; or
2. Specifying that calling `quick_exit` while servicing `quick_exit` is defined to not deadlock, and instead calls `_Exit` without calling further registered functions.

Option 2. seems preferable, and can be implemented along the lines of:

>     #include <array>
>     #include <atomic>
>     #include <cstddef>

>     namespace {

>       typedef void (*func)();

>       std::array<func, 32> quick_exit_functions;

>       const auto* quick_exit_functions_ptr = &quick_exit_functions;

>       std::atomic_flag lock = ATOMIC_FLAG_INIT;

>       struct scope
>       {
>         scope() { while (lock.test_and_set(std::memory_order_acquire)) ; }
>         ~scope() { lock.clear(std::memory_order_release); }
>       };

>     }

>     namespace std {

>       extern "C" void quick_exit(int status) noexcept
>       {
>         decltype(quick_exit_functions_ptr) f;
>         {
>           scope s;
>           f = quick_exit_functions_ptr;
>           quick_exit_functions_ptr = nullptr;
>         }
>         if (f) {
>           size_t pos = f->size();
>           while (pos > 0)
>             (*f)[--pos]();
>         }
>         _Exit(status);
>       }

>       extern "C++" int at_quick_exit(func f) noexcept
>       {
>         scope s;
>         if (!quick_exit_functions_ptr || quick_exit_functions.size() == quick_exit_functions.max_size())
>           return -1;
>         quick_exit_functions[quick_exit_functions.size()] = f;
>         return 0;
>       }

>     }

Ideally, the resolution would also add back the wording which SG1 dropped from P0270R1:

> Add at new element to the end of 17.5 [support.start.term] p13 (`quick_exit()`):

> > Remarks: The function `quick_exit()` is signal-safe (17.13.4 [csignal.syn]). [Note: It might still be unsafe to call `quick_exit()` from a handler, because the functions registered with `at_quick_exit()` might not be signal-safe. — end note]

[Issues Telecon 16-Dec-2016]

Priority 3

Proposed resolution:

This wording is relative to N4606.

1. Add at new element to the end of 17.5 [support.start.term] p13 (`quick_exit()`):

   >     [[noreturn]] void quick_exit(int status) noexcept;

   > > -13- Effects: Functions registered by calls to `at_quick_exit` are called in the reverse order of their registration, except that a function shall be called after any previously registered functions that had already been called at the time it was registered. Objects shall not be destroyed as a result of calling `quick_exit`. If control leaves a registered function called by `quick_exit` because the function does not provide a handler for a thrown exception, `std::terminate()` shall be called. [Note: `at_quick_exit` may call a registered function from a different thread than the one that registered it, so registered functions should not rely on the identity of objects with thread storage duration. — end note] After calling registered functions, `quick_exit` shall call `_Exit(status)`. [Note: The standard file buffers are not flushed. See: ISO C 7.22.4.5. — end note]

   > > -?- Remarks: The function `quick_exit()` is signal-safe (17.13.4 [csignal.syn]). [Note: It might still be unsafe to call `quick_exit()` from a handler, because the functions registered with `at_quick_exit()` might not be signal-safe. — end note]

### 2819(i). Unspecified Return type: elements

Section: 32.2.5 [thread.req.lockable], 32.5.4 [thread.mutex.requirements] Status: New Submitter: Agustín K-ballo Bergé Opened: 2016-11-12 Last modified: 2020-05-12

Priority: 3

View all issues with New status.

Discussion:

The current draft contains 14 occurrences of a Return type: clause. That clause is not covered by 16.3.2.4 [structure.specifications] p3. This was reported as editorial request #266.

[Issues Telecon 16-Dec-2016]

Priority 3; Jonathan to provide wording.

[12-May-2020, Jonathan provides wording to correct the 13 occurences.]

Proposed resolution:

This wording is relative to N4681.

1. Modify 32.2.5.3 [thread.req.lockable.req] as indicated:

   > -1- A type `L` meets the Cpp17Lockable requirements if it meets the Cpp17BasicLockable requirements and the following expressions are well-formed, have type `bool`, and have the specified semantics (`m` denotes a value of type `L`).

   > `m.try_lock()`

   > > -2- Effects: [...]

   > > -3- Return type: `bool`.

   > > -4- Returns: `true` if the lock was acquired, `false` otherwise.

2. Modify 32.2.5.4 [thread.req.lockable.timed] as indicated:

   > -1- A type `L` meets the Cpp17TimedLockable requirements if it meets the Cpp17BasicLockable requirements and the following expressions are well-formed, have type `bool`, and have the specified semantics (`m` denotes a value of type `L`, `rel_time` denotes a value of an instantiation of `duration` (27.5 [time.duration]), and `abs_time` denotes a value of an instantiation of `time_point` (27.6 [time.point])).

   > `m.try_lock_for(rel_time)`

   > > -2- Effects: [...]

   > > -3- Return type: `bool`.

   > > -4- Returns: `true` if the lock was acquired, `false` otherwise.

   > `m.try_lock_until(abs_time)`

   > > -2- Effects: [...]

   > > -3- Return type: `bool`.

   > > -4- Returns: `true` if the lock was acquired, `false` otherwise.

3. Modify 32.5.4.2 [thread.mutex.requirements.mutex] as indicated:

   > -6- The expression `m.lock()` is well-formed, has type `void`, and has the following semantics:

   > > -7- Preconditions: [...]

   > > -8- Effects: [...]

   > > -9- Postconditions: [...]

   > > -10- Return type: `void`.

   > > -11- Synchronization: [...]

   > > -12- Throws: [...]

   > > -13- Error conditions: [...]

   > -14- The expression `m.try_lock()` is well-formed, has type `bool`, and has the following semantics:

   > > -15- Preconditions: [...]

   > > -16- Effects: [...]

   > > -17- Return type: `bool`.

   > > -18- Returns: `true` if ownership of the mutex was obtained for the calling thread, otherwise `false`.

   > > -19- Synchronization: [...]

   > > -20- Throws: Nothing.

   > -21- The expression `m.unlock()` is well-formed, has type `void`, and has the following semantics:

   > > -22- Preconditions: [...]

   > > -23- Effects: [...]

   > > -24- Return type: `void`.

   > > -25- Synchronization: [...]

   > > -26- Throws: Nothing.

4. Modify 32.5.4.3 [thread.timedmutex.requirements] as indicated:

   > -1- The timed mutex types are the standard library types [...]

   > -2- The timed mutex types meet the Cpp17TimedLockable requirements (32.2.5.4 [thread.req.lockable.timed]).

   > -3- The expression `m.try_lock_for(rel_time)` is well-formed, has type `bool`, and has the following semantics:

   > > -4- Preconditions: [...]

   > > -5- Effects: [...]

   > > -6- Return type: `bool`.

   > > -7- Returns: `true` if the shared lock was acquired, `false` otherwise.

   > > -8- Synchronization: [...]

   > > -9- Throws: [...]

   > -10- The expression `m.try_lock_until(abs_time)` is well-formed, has type `bool`, and has the following semantics:

   > > -11- Preconditions: [...]

   > > -12- Effects: [...]

   > > -13- Return type: `bool`.

   > > -14- Returns: `true` if ownership was obtained, otherwise `false`.

   > > -15- Synchronization: [...]

   > > -16- Throws: [...]

5. Modify 32.5.4.4 [thread.sharedmutex.requirements] as indicated:

   > -1- The standard library types `shared_mutex` and `shared_timed_mutex` are shared mutex types. [...]

   > -2- In addition to the exclusive lock ownership mode [...]

   > -3- The expression `m.lock_shared()` is well-formed, has type `void`, and has the following semantics:

   > > -4- Preconditions: [...]

   > > -5- Effects: [...]

   > > -6- Postconditions: [...]

   > > -7- Return type: `void`.

   > > -8- Synchronization: [...]

   > > -9- Throws: [...]

   > > -10- Error conditions: [...]

   > -11- The expression `m.unlock_shared()` is well-formed, has type `void`, and has the following semantics:

   > > -12- Preconditions: [...]

   > > -13- Effects: [...]

   > > -14- Return type: `void`.

   > > -15- Synchronization: [...]

   > > -16- Throws: [...]

   > -17- The expression `m.try_lock_shared()` is well-formed, has type `bool`, and has the following semantics:

   > > -18- Preconditions: [...]

   > > -19- Effects: [...]

   > > -20- Return type: `bool`.

   > > -21- Returns: `true` if the shared ownership lock was acquired, `false` otherwise.

   > > -22- Synchronization: [...]

   > > -23- Throws: [...]

6. Modify 32.5.4.5 [thread.sharedtimedmutex.requirements] as indicated:

   > -1- The standard library type `shared_timed_mutex` is a shared timed mutex type. [...]

   > -2- The expression `m.try_lock_shared_for(rel_time)` is well-formed, has type `bool`, and has the following semantics:

   > > -3- Preconditions: [...]

   > > -4- Effects: [...]

   > > -5- Return type: `bool`.

   > > -6- Returns: `true` if the shared lock was acquired, `false` otherwise.

   > > -7- Synchronization: [...]

   > > -8- Throws: [...]

   > -9- The expression `m.try_lock_shared_until(abs_time)` is well-formed, has type `bool`, and has the following semantics:

   > > -10- Preconditions: [...]

   > > -11- Effects: [...]

   > > -12- Return type: `bool`.

   > > -13- Returns: `true` if the shared lock was acquired, `false` otherwise.

   > > -14- Synchronization: [...]

   > > -15- Throws: [...]

### 2823(i). `std::array` initialization is still not permissive enough

Section: 22.3.7.1 [array.overview] Status: Open Submitter: Robert Haberlach Opened: 2016-11-16 Last modified: 2018-03-19

Priority: 3

View other active issues in [array.overview].

View all other issues in [array.overview].

View all issues with Open status.

Discussion:

LWG 2590's resolution is incomplete:

>     std::array<int, 1> arr{{0}};

should be fine, but isn't guaranteed, since `{0}` has no type. We should rather go for implicit conversion:

> An array is an aggregate (9.4.2 [dcl.init.aggr]) that can be list-initialized with up to `N` elements whose types are convertible to `T` that can be implicitly converted to `T`.

[2016-11-26, Tim Song comments]

This is not possible as written, because due to the brace elision rules for aggregate initialization, `std::array<int, 2> arr{{0}, {1}};` will never work: the `{0}` is taken as initializing the inner array, and the `{1}` causes an error.

[2017-01-27 Telecon]

Priority 2; consensus is that the P/R is not quite right.

[2018-3-14 Wednesday evening issues processing; priority to 3; move to Open]

Jens: There's nothing you can do about the double braces in std::array. That's a core thing.

STL to write paper to resolve this.

Proposed resolution:

This wording is relative to N4606.

1. Change 22.3.7.1 [array.overview] p2 as indicated:

   > -2- An `array` is an aggregate (9.4.2 [dcl.init.aggr]) that can be list-initialized with up to `N` elements whose types are convertible that can be implicitly converted to `T`.

### 2827(i). `is_trivially_constructible` and non-trivial destructors

Section: 20.15.5.4 [meta.unary.prop] Status: New Submitter: Richard Smith Opened: 2016-11-17 Last modified: 2020-01-25

Priority: 3

View other active issues in [meta.unary.prop].

View all other issues in [meta.unary.prop].

View all issues with New status.

Discussion:

>     struct S
>     {
>       ~S(); // non-trivial
>     };

>     static_assert(std::is_trivially_constructible<S>::value, "");

Should the assert pass? Implementations disagree.

Per 20.15.5.4 [meta.unary.prop]'s Table 38, this trait looks at whether the following variable definition is known to call no operation that is not trivial:

>     S t(create<Args>()...);

... where `Args` is an empty pack in this case. That variable definition results in a call to the `S` destructor. Should that call be considered by the trait?

[2017-01-27 Telecon]

Priority 3

This issue interacts with 2116

[2020-01-24; Peter Dimov comments]

`std::is_trivially_copy_constructible_v<D>`, where `D` is

>     struct D
>     {
>       ~D() {}
>     };

reports `false`. This is because the definition of `is_trivially_copy_constructible` requires the invented variable definition `T t(declval<Args>()...);`, which in our case is `D t(declval<D>());`, to not call any nontrivial operations.

This is interpreted by implementations to include the destructor call, presumably for consistency with `is_nothrow_copy_constructible`. But that's wrong; the copy constructor is trivial.

As a consequence, `variant<D>` also doesn't have a trivial copy constructor, which causes (completely unnecessary) inefficiencies when said `variant` is copied.

Proposed resolution:

### 2829(i). LWG 2740 leaves behind vacuous words

Section: 20.6.3.6 [optional.observe] Status: Open Submitter: Richard Smith Opened: 2016-11-24 Last modified: 2020-06-13

Priority: 2

View other active issues in [optional.observe].

View all other issues in [optional.observe].

View all issues with Open status.

Discussion:

After applying LWG 2740, we have:

>     constexpr const T* operator->() const;
>     constexpr T* operator->();

> > -1- Requires: `*this` contains a value.

> > -2- Returns: `val`.

> > -3- Throws: Nothing.

> > -4- Remarks: These functions shall be `constexpr` functions.

Paragraph 4 is completely superfluous. We already said these functions were `constexpr` in the synopsis. Can it be removed?

[Issues Telecon 16-Dec-2016]

Priority 2

Jonathan notes: Although Richard is correct, I suggest we don't strike the paragraph, so that we remember to fix it as part of 2833, when we know how to say this properly.

[2018-06 Rapperswil Thursday issues processing]

Status to Open; also see 7.7 [expr.const]/6 and 2289.

[2020-06-08 Nina Dinka Ranns comments]

The revised wording provided by LWG 2833 should resolve this issue as well.

Proposed resolution:

### 2833(i). Library needs to specify what it means when it declares a function `constexpr`

Section: 20.7.3.2 [variant.ctor] Status: Open Submitter: Richard Smith Opened: 2016-11-28 Last modified: 2020-12-19

Priority: 2

View other active issues in [variant.ctor].

View all other issues in [variant.ctor].

View all issues with Open status.

Discussion:

The library has lots of functions declared `constexpr`, but it's not clear what that means. The `constexpr` keyword implies that there needs to be some invocation of the function, for some set of template arguments and function arguments, that is valid in a constant expression (otherwise the program would be ill-formed, with no diagnostic required), along with a few side conditions. I suspect the library intends to require something a lot stronger than that from implementations (something along the lines of "all calls that could reasonably be constant subexpressions are in fact constant subexpressions, unless otherwise stated").

[variant.ctor]/1 contains this, which should also be fixed:

> "This function shall be `constexpr` if and only if the value-initialization of the alternative type `T0` would satisfy the requirements for a `constexpr` function."

This is the wrong constraint: instead of constraining whether the function is `constexpr`, we should constrain whether a call to it is a constant subexpression.

Daniel:

This is has some considerable overlap with LWG 2289 but is phrased in a more general way.

[2016-12-16, Issues Telecon]

Priority 2; this is also the general case of 2829.

[2017-02-20, Alisdair comments and suggests concrete wording]

Below is is draft wording I was working on at Issaquah to try to address both issues.

[2017-11 Albuquerque Wednesday issue processing]

Status to Open; really needs a paper.

STL says "What about `plus<T>`?" `plus<int>` needs to be usable in a constexpr context, but `plus<string>` can't be.

[2017-11 Albuquerque Saturday issues processing]

Geoffrey to write a paper resolving this.

[2018-06 Rapperswil Thursday issues processing]

Geoffrey has been unable to write this paper due to time constraints. He wrote up his progress here. Daniel has offered to help someone to write this paper; he's willing to be a co-author.

[2018-08-23 Batavia Issues processing]

Michael Wong to investigate.

Previous resolution from Daniel [SUPERSEDED]:

> This wording is relative to N4640.

> 1. Modify 16.4.6.7 [constexpr.functions] as indicated:

>    > ### 17.6.5.6 `constexpr` functions and constructors [constexpr.functions]

>    > -1- This International Standard explicitly requires that certain standard library functions are `constexpr` (9.2.6 [dcl.constexpr]). If the specification for a templated entity requires that it shall be a `constexpr` templated entity, then that templated entity shall be usable in a constant expression.. An implementation shall not may declare any additional standard library function signature as `constexpr` except for those where it is explicitly required. Within any header that provides any non-defining declarations of `constexpr` functions or constructors an implementation shall provide corresponding definitions.

[2020-06-08 Nina Dinka Ranns comments and provides alternative wording]

The revised wording draft also resolves LWG 2289, LWG 2829, and LWG 3215.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4861.

> 1. 1. Modify 16.4.6.7 [constexpr.functions] as indicated:

>    > -1- This document explicitly requires that certain standard library functions are `constexpr` (9.2.6 [dcl.constexpr]). An implementation shall not declare any standard library function signature as `constexpr` except for those where it is explicitly required. Within any header that provides any non-defining declarations of constexpr functions or constructors an implementation shall provide corresponding definitions.

>    > -?- Let `F` denote a standard library function template or member function of a class template. If the specification of `F` declares it to be `constexpr`, unless otherwise specified, then `F` can be used in a constant expression if and only if all the expressions that are evaluated as specified in the description of `F`'s semantics can be used in a constant expression.

> 2. 2. - 10. […] // Remainder of Nina's update

[2020-10-02 Jens Maurer improves wording]

Specifically the wording for 16.4.6.7 [constexpr.functions] needs improvement and is updated below.

[2020-10-02 Tim Song comments]

The new wording doesn't cover the following example:

>     // global scope
>     int x;
>     int y;

>     constexpr int j = (std::swap(x, y), 0); // error

- `swap` is a "standard library function template...declared `constexpr`"

- `x` and `y` are (lvalue) constant expressions

- `std::swap(x, y)` is plainly not a constant expression

[2020-10-04 Jens Maurer comments]

Yes, we're still lacking text for that (and maybe Nina's old text helps for that).

[2020-12-14; Jiang An comments]

The item "constexpr functions" is also used in 22.2.1 [container.requirements.general]/14 and 23.3.1 [iterator.requirements.general]/16, and such usage should also be modified by this issue here.

Proposed resolution:

This wording is relative to N4861.

1. Modify 16.4.6.7 [constexpr.functions] as indicated:

   > -1- This document explicitly requires that certain standard library functions are `constexpr` (9.2.6 [dcl.constexpr]). An implementation shall not declare any standard library function signature as `constexpr` except for those where it is explicitly required. Within any header that provides any non-defining declarations of constexpr functions or constructors an implementation shall provide corresponding definitions.

   > -?- Let `F` denote a standard library function template or member function of a class template declared `constexpr`. Unless otherwise specified, a function call expression (7.6.1.3 [expr.call]) whose postfix-expression names `F` is a constant expression if all of the argument subexpressions are constant expressions.

2. Modify 20.4.2 [pairs.pair] as indicated:

   > -2- The defaulted move and copy constructors, respectively, of `pair` is a constexpr function can be used in a constant expression if and only if all required element-wise initializations for move and copy, respectively, would satisfy the requirements for a constexpr function can be used in a constant expression.

3. Modify 20.5.3.1 [tuple.cnstr] as indicated:

   > -3- The defaulted move and copy constructors, respectively, of `tuple` is a constexpr function can be used in a constant expression if and only if all required element-wise initializations for move and copy, respectively, would satisfy the requirements for a constexpr function can be used in a constant expression. The defaulted move and copy constructors of `tuple<>` are constexpr functions can be used in a constant expression.

4. Modify 20.6.3.2 [optional.ctor] as indicated:

   >     constexpr optional() noexcept;
   >     constexpr optional(nullopt_t) noexcept;

   > > -1- […]

   > > -2- Remarks: No contained value is initialized. For every object type `T` these constructors are constexpr constructors (9.2.6 [dcl.constexpr]).

   > […]

   >     template<class... Args> constexpr explicit optional(in_place_t, Args&&... args);

   > > -12- […]

   > > -13- […]

   > > -14- […]

   > > -15- […]

   > > -16- Remarks: If `T`'s constructor selected for the initialization is a constexpr constructor, this constructor is a constexpr constructor.

   >     template<class U, class... Args>
   >       constexpr explicit optional(in_place_t, initializer_list<U> il, Args&&... args);

   > > -17- […]

   > > -18- […]

   > > -19- […]

   > > -20- […]

   > > -21- Remarks: If `T`'s constructor selected for the initialization is a constexpr constructor, this constructor is a constexpr constructor.

   >     template<class U = T> constexpr explicit(see below) optional(U&& v);

   > > -22- […]

   > > -23- […]

   > > -24- […]

   > > -25- […]

   > > -26- Remarks: If `T`'s constructor selected for the initialization is a constexpr constructor, this constructor is a constexpr constructor. The expression inside `explicit` is equivalent to:

   > > >     !is_convertible_v<U, T>

5. Modify 20.6.3.6 [optional.observe] as indicated:

   >     constexpr const T* operator->() const;
   >     constexpr T* operator->();

   > > -1- […]

   > > -2- […]

   > > -3- […]

   > > -4- Remarks: These functions are constexpr functions.

   >     constexpr const T& operator*() const&;
   >     constexpr T& operator*() &;

   > > -5- […]

   > > -6- […]

   > > -7- […]

   > > -8- Remarks: These functions are constexpr functions.

   > […]

   >     constexpr explicit operator bool() const noexcept;

   > > -11- Returns: `true` if and only if `*this` contains a value.

   > > -12- Remarks: This function is a constexpr function.

   >     constexpr bool has_value() const noexcept;

   > > -13- Returns: `true` if and only if `*this` contains a value.

   > > -14- Remarks: This function is a constexpr function.

6. Modify 20.6.6 [optional.relops] as indicated:

   >     template<class T, class U> constexpr bool operator==(const optional<T>& x, const optional<U>& y);

   > > -1- […]

   > > -2- […]

   > > -3- Remarks: Specializations of this function template for which `*x == *y` is a core constant expression are constexpr functions.

   >     template<class T, class U> constexpr bool operator!=(const optional<T>& x, const optional<U>& y);

   > > -4- […]

   > > -5- […]

   > > -6- Remarks: Specializations of this function template for which `*x != *y` is a core constant expression are constexpr functions.

   >     template<class T, class U> constexpr bool operator<(const optional<T>& x, const optional<U>& y);

   > > -7- […]

   > > -8- […]

   > > -9- Remarks: Specializations of this function template for which `*x < *y` is a core constant expression are constexpr functions.

   >     template<class T, class U> constexpr bool operator>(const optional<T>& x, const optional<U>& y);

   > > -10- […]

   > > -11- […]

   > > -12- Remarks: Specializations of this function template for which `*x > *y` is a core constant expression are constexpr functions.

   >     template<class T, class U> constexpr bool operator<=(const optional<T>& x, const optional<U>& y);

   > > -13- […]

   > > -14- […]

   > > -15- Remarks: Specializations of this function template for which `*x <= *y` is a core constant expression are constexpr functions.

   >     template<class T, class U> constexpr bool operator>=(const optional<T>& x, const optional<U>& y);

   > > -16- […]

   > > -17- […]

   > > -18- Remarks: Specializations of this function template for which `*x >= *y` is a core constant expression are constexpr functions.

   >     template<class T, three_way_comparable_with<T> U>
   >       constexpr compare_three_way_result_t<T,U>
   >         operator<=>(const optional<T>& x, const optional<U>& y);

   > > -19- Returns: If `x && y`, `*x <=> *y`; otherwise `bool(x) <=> bool(y)`.

   > > -20- Remarks: Specializations of this function template for which `*x <=> *y` is a core constant expression are constexpr functions.

7. Modify 20.7.3.2 [variant.ctor] as indicated:

   >     constexpr variant() noexcept(see below);

   > > -1- […]

   > > -2- […]

   > > -3- […]

   > > -4- […]

   > > -5- […]

   > > -6- Remarks: This function is `constexpr` if and only if the value-initialization of the alternative type `T0` would satisfy the requirements for a constexpr function. The expression inside `noexcept` is equivalent to `is_nothrow_default_constructible_v<T0>`. [Note: See also class `monostate`. — end note]

   > […]

   >     template<class T> constexpr variant(T&& t) noexcept(see below);

   > > -14- […]

   > > […]

   > > -19- Remarks: The expression inside `noexcept` is equivalent to `is_nothrow_constructible_v<Tj, T>`. If `Tj`'s selected constructor is a constexpr constructor, this constructor is a constexpr constructor.

   >     template<class T, class... Args> constexpr explicit variant(in_place_type_t<T>, Args&&... args);

   > > -20- […]

   > > […]

   > > -24- Remarks: If `T`'s selected constructor is a constexpr constructor, this constructor is a constexpr constructor.

   >     template<class T, class U, class... Args>
   >       constexpr explicit variant(in_place_type_t<T>, initializer_list<U> il, Args&&... args);

   > > -25- […]

   > > […]

   > > -29- Remarks: If `T`'s selected constructor is a constexpr constructor, this constructor is a constexpr constructor.

   >     template<size_t I, class... Args> constexpr explicit variant(in_place_index_t<I>, Args&&... args);

   > > -30- […]

   > > […]

   > > -34- Remarks: If `TI`'s selected constructor is a constexpr constructor, this constructor is a constexpr constructor.

   >     template<size_t I, class U, class... Args>
   >       constexpr explicit variant(in_place_index_t<I>, initializer_list<U> il, Args&&... args);

   > > -35- […]

   > > […]

   > > -38- Remarks: If `TI`'s selected constructor is a constexpr constructor, this constructor is a constexpr constructor.

8. Modify 23.5.3.11 [move.sent.ops] as indicated:

   >     constexpr move_sentinel();

   > > -1- Effects: Value-initializes `last`. If `is_trivially_default_constructible_v<S>` is `true`, then this constructor is a constexpr constructor.

9. Modify 26.5.3 [bit.cast] as indicated:

   >     template<class To, class From>
   >       constexpr To bit_cast(const From& from) noexcept;

   > > -1- […]

   > > -3- Remarks: This function is `constexpr` can be used in a constant expression if and only if `To`, `From`, and the types of all subobjects of `To` and From are types `T` such that:

   > > 1. (3.1) — `is_union_v<T>` is `false`;

   > > 2. (3.2) — `is_pointer_v<T>` is `false`;

   > > 3. (3.3) — `is_member_pointer_v<T>` is `false`;

   > > 4. (3.4) — `is_volatile_v<T>` is `false`; and

   > > 5. (3.5) — `T` has no non-static data members of reference type.

10. Modify 27.5 [time.duration] as indicated:

    > -5- The defaulted copy constructors of duration shall be a constexpr function can be used in a constant expression if and only if the required initialization of the member `rep_` for copy and move, respectively, would satisfy the requirements for a constexpr function can be used in a constant expression.

### 2844(i). Stability of `a_uniq.insert(i, j)`

Section: 22.2.6 [associative.reqmts], 22.2.7 [unord.req] Status: Open Submitter: Matt Austern Opened: 2016-12-14 Last modified: 2020-02-14

Priority: 3

View other active issues in [associative.reqmts].

View all other issues in [associative.reqmts].

View all issues with Open status.

Discussion:

If we write `a_uniq.insert(i, j)` and `[i, j)` has multiple elements with keys that compare equivalent, which ones get inserted? Consider, for example, inserting into a `map<string, int>` with

>     m.insert({{"red", 5}, {"green", 3}, {"red", 7}, {"blue", 2}, {"pink", 6}});

Which value for `"red"` will the map have?

On my implementation we got `"red" -> 5`, and I suspect that's true on most or all implementations, but I don't believe that's guaranteed by anything in the requirements. The wording in Table 90 just says that it "inserts each element from the range `[i, j)` if and only if there is no element with key equivalent to the key of that element", but that doesn't tell us what happens if `[i, j)` contains duplicate keys because it doesn't say what order the insertions are performed in. The standard should either guarantee that the first value is the one that gets inserted, or explicitly say that this is unspecified.

The same issue applies to the range constructor, and to the unordered associative containers.

[2017-01-27 Telecon]

Priority 3; Nico to provide wording.

[2020-02-14, Prague]

LWG discussion. Suggestion to specify that we like the direction of the wording for `insert` of unordered containers, but would also like to clarify that the loop is meant to be "in order" of the sequence elements.

Daniel K. volunteered to provide such wording.

Proposed resolution:

### 2845(i). `enable_if`, `result_of`, `common_type` and `aligned_storage` do not meet the definition of `TransformationTrait`

Section: 20.15.2 [meta.rqmts] Status: New Submitter: Tim Song Opened: 2016-12-14 Last modified: 2017-02-02

Priority: 3

View all other issues in [meta.rqmts].

View all issues with New status.

Discussion:

[meta.rqmts]/3 defines `TransformationTrait` as follows:

> A `TransformationTrait` modifies a property of a type. It shall be a class template that takes one template type argument and, optionally, additional arguments that help define the modification. It shall define a publicly accessible nested type named `type`, which shall be a synonym for the modified type.

`enable_if`, `result_of` and `common_type` do not necessarily "define a publicly accessible nested type named `type`". `aligned_storage` takes no template type argument (it only has two non-type parameters). Yet [meta.trans]/2 says that they are all `TransformationTraits`.

Incidentally, with the exception of `decay`, it's not clear that any of the traits in [meta.trans.other] could really be described as "modify[ing] a property of a type".

[2017-01-27 Telecon]

Priority 3

Proposed resolution:

### 2846(i). Undefined phrase "effectively cast"

Section: 26.4.10 [cmplx.over], 26.8.1 [cmath.syn] Status: New Submitter: Jens Maurer Opened: 2016-12-15 Last modified: 2019-03-18

Priority: 3

View all other issues in [cmplx.over].

View all issues with New status.

Discussion:

In [cmplx.over] and [cmath.syn], when talking about "sufficient additional overloads", we use the phrase "effectively cast", but that is not a defined term.

A hostile interpretation could read "`reinterpret_cast`" here.

Likely we mean "apply floating-point promotions, floating-integral conversions, and floating-point conversions", but that should be spelled out somewhere, e.g. in the library definitions section.

(Source: Editorial issue #1248)

[2017-01-27 Telecon]

Priority 3

[2019-03-16; Daniel comments and provides wording]

I decided to use the form "implicitly converted" and to refer to 7.3 [conv] for 26.8.1 [cmath.syn] and 26.4.10 [cmplx.over], because those conversions can all be done implicitly. This also holds for the `pow` specification 26.4.10 [cmplx.over] p3, because the described conversions of `complex<T>` to `complex<U>` involve only the need of non-explicit constructors.

Proposed resolution:

This wording is relative to N4810.

1. Change 26.4.10 [cmplx.over], as indicated:

   > -2- The additional overloads shall be sufficient to ensure:

   > > 1. (2.1) — If the argument has type `long double`, then it is effectively cast implicitly converted (7.3 [conv]) to `complex<long double>`.

   > > 2. (2.2) — Otherwise, if the argument has type `double` or an integer type, then it is effectively cast implicitly converted to `complex<double>`.

   > > 3. (2.3) — Otherwise, if the argument has type `float`, then it is effectively cast implicitly converted to `complex<float>`.

   > -3 Function template `pow` shall have additional overloads sufficient to ensure, for a call with at least one argument of type `complex<T>`:

   > > 1. (3.1) — If either argument has type `complex<long double>` or type `long double`, then both arguments are effectively cast implicitly converted (7.3 [conv]) to `complex<long double>`.

   > > 2. (3.2) — Otherwise, if either argument has type `complex<double>`, `double`, or an integer type, then both arguments are effectively cast implicitly converted to `complex<double>`.

   > > 3. (3.3) — Otherwise, if either argument has type `complex<float>` or `float`, then both arguments are effectively cast implicitly converted to `complex<float>`.

2. Change 26.8.1 [cmath.syn], as indicated:

   > -2- For each set of overloaded functions within `<cmath>`, with the exception of `abs`, there shall be additional overloads sufficient to ensure:

   > > 1. If any argument of arithmetic type corresponding to a `double` parameter has type `long double`, then all arguments of arithmetic type (6.8.2 [basic.fundamental]) corresponding to `double` parameters are effectively cast implicitly converted (7.3 [conv]) to `long double`.

   > > 2. Otherwise, if any argument of arithmetic type corresponding to a `double` parameter has type `double` or an integer type, then all arguments of arithmetic type corresponding to `double` parameters are effectively cast implicitly converted to `double`.

   > > 3. Otherwise, all arguments of arithmetic type corresponding to `double` parameters have type `float`.

### 2847(i). `sin(float)` should call `sinf(float)`

Section: 26.8.1 [cmath.syn] Status: New Submitter: Jens Maurer Opened: 2016-12-15 Last modified: 2020-09-06

Priority: 3

View other active issues in [cmath.syn].

View all other issues in [cmath.syn].

View all issues with New status.

Discussion:

With P0175R1, we now show in [cmath.syn] three overloads for the `sin` function: One taking a `float`, one taking a `double`, and one taking a `long double`. However, there is no statement that `sin(long double)` should actually invoke `sinl`, presumably delivering extra precision.

An implementation like

>     inline long double sin(long double x)
>     { return sinf(x); }

seems to satisfy the "effectively cast" requirement, but is certainly unintentional.

The same issue arises for all math functions inherited from C.

(Source: Editorial issue #1247)

[2017-01-27 Telecon]

Priority 3

Proposed resolution:

### 2848(i). Pass-through threshold for pool allocator

Section: 20.12.5.2 [mem.res.pool.options] Status: New Submitter: Jens Maurer Opened: 2016-12-15 Last modified: 2017-02-02

Priority: 3

View all issues with New status.

Discussion:

20.12.5.2 [mem.res.pool.options] p3 talks about a "pass-through-threshold".

First, the phrase is not defined and it seems it could be easily avoided given the context.

Second, given the phrasing here, it seems the implementation is essentially allowed to ignore the value `largest_required_pool_block` as it sees fit. It is unclear whether that is the intention.

[2017-01-27 Telecon]

Priority 3; Jonathan will ask Alisdair for wording.

Proposed resolution:

### 2858(i). LWG 2472: actually an incompatibility with C++03

Section: 23.5.1 [reverse.iterators] Status: New Submitter: Hubert Tong Opened: 2017-01-28 Last modified: 2020-09-06

Priority: 4

View all other issues in [reverse.iterators].

View all issues with New status.

Discussion:

Further to LWG 2472, the case of `reverse_iterator` comparisons is a regression introduced by LWG 280.

Consider the following program:

>     #include <utility>
>     #include <iterator>

>     using namespace std::rel_ops;

>     bool f(std::reverse_iterator<int *> it) { return it != it; }

Under C++03, the `operator!=` in lib.reverse.iterator is more specialized than the `operator!=` in `std::rel_ops`.

Following LWG 280, neither `operator!=` candidate is more specialized than the other. The program is observed to fail with libc++.

Online compiler example, see here.

Suggested resolution:

Reintroduce the homogeneous comparison operators from C++03 alongside the new ones.

[2017-03-04, Kona]

Set priority to 4. STL to write a paper deprecating `relops` Alisdair to provide an example for Annex C.

Proposed resolution:

This wording is relative to N4618.

1. Modify 23.5.1 [reverse.iterators], class template `reverse_iterator` synopsis, as indicated:

   >     template <class Iterator1, class Iterator2>
   >       constexpr bool operator==(
   >         const reverse_iterator<Iterator1>& x,
   >         const reverse_iterator<Iterator2>& y);
   >     template <class Iterator1, class Iterator2>
   >       constexpr bool operator<(
   >         const reverse_iterator<Iterator1>& x,
   >         const reverse_iterator<Iterator2>& y);
   >     template <class Iterator1, class Iterator2>
   >       constexpr bool operator!=(
   >         const reverse_iterator<Iterator1>& x,
   >         const reverse_iterator<Iterator2>& y);
   >     template <class Iterator1, class Iterator2>
   >       constexpr bool operator>(
   >         const reverse_iterator<Iterator1>& x,
   >         const reverse_iterator<Iterator2>& y);
   >     template <class Iterator1, class Iterator2>
   >       constexpr bool operator>=(
   >         const reverse_iterator<Iterator1>& x,
   >         const reverse_iterator<Iterator2>& y);
   >     template <class Iterator1, class Iterator2>
   >       constexpr bool operator<=(
   >         const reverse_iterator<Iterator1>& x,
   >         const reverse_iterator<Iterator2>& y);
   >     template <class Iterator>
   >       constexpr bool operator==(
   >         const reverse_iterator<Iterator>& x,
   >         const reverse_iterator<Iterator>& y);
   >     template <class Iterator>
   >       constexpr bool operator<(
   >         const reverse_iterator<Iterator>& x,
   >         const reverse_iterator<Iterator>& y);
   >     template <class Iterator>
   >       constexpr bool operator!=(
   >         const reverse_iterator<Iterator>& x,
   >         const reverse_iterator<Iterator>& y);
   >     template <class Iterator>
   >       constexpr bool operator>(
   >         const reverse_iterator<Iterator>& x,
   >         const reverse_iterator<Iterator>& y);
   >     template <class Iterator>
   >       constexpr bool operator>=(
   >         const reverse_iterator<Iterator>& x,
   >         const reverse_iterator<Iterator>& y);
   >     template <class Iterator>
   >       constexpr bool operator<=(
   >         const reverse_iterator<Iterator>& x,
   >         const reverse_iterator<Iterator>& y);

2. Modify [reverse.iter.op==] as indicated:

   >     template <class Iterator1, class Iterator2>
   >       constexpr bool operator==(
   >         const reverse_iterator<Iterator1>& x,
   >         const reverse_iterator<Iterator2>& y);
   >     template <class Iterator>
   >       constexpr bool operator==(
   >         const reverse_iterator<Iterator>& x,
   >         const reverse_iterator<Iterator>& y);

   > > -1- Returns: `x.current == y.current`.

3. Modify [reverse.iter.op<] as indicated:

   >     template <class Iterator1, class Iterator2>
   >       constexpr bool operator<(
   >         const reverse_iterator<Iterator1>& x,
   >         const reverse_iterator<Iterator2>& y);
   >     template <class Iterator>
   >       constexpr bool operator<(
   >         const reverse_iterator<Iterator>& x,
   >         const reverse_iterator<Iterator>& y);

   > > -1- Returns: `x.current > y.current`.

4. Modify [reverse.iter.op!=] as indicated:

   >     template <class Iterator1, class Iterator2>
   >       constexpr bool operator!=(
   >         const reverse_iterator<Iterator1>& x,
   >         const reverse_iterator<Iterator2>& y);
   >     template <class Iterator>
   >       constexpr bool operator!=(
   >         const reverse_iterator<Iterator>& x,
   >         const reverse_iterator<Iterator>& y);

   > > -1- Returns: `x.current != y.current`.

5. Modify [reverse.iter.op>] as indicated:

   >     template <class Iterator1, class Iterator2>
   >       constexpr bool operator>(
   >         const reverse_iterator<Iterator1>& x,
   >         const reverse_iterator<Iterator2>& y);
   >     template <class Iterator>
   >       constexpr bool operator>(
   >         const reverse_iterator<Iterator>& x,
   >         const reverse_iterator<Iterator>& y);

   > > -1- Returns: `x.current < y.current`.

6. Modify [reverse.iter.op>=] as indicated:

   >     template <class Iterator1, class Iterator2>
   >       constexpr bool operator>=(
   >         const reverse_iterator<Iterator1>& x,
   >         const reverse_iterator<Iterator2>& y);
   >     template <class Iterator>
   >       constexpr bool operator>=(
   >         const reverse_iterator<Iterator>& x,
   >         const reverse_iterator<Iterator>& y);

   > > -1- Returns: `x.current <= y.current`.

7. Modify [reverse.iter.op<=] as indicated:

   >     template <class Iterator1, class Iterator2>
   >       constexpr bool operator<=(
   >         const reverse_iterator<Iterator1>& x,
   >         const reverse_iterator<Iterator2>& y);
   >     template <class Iterator>
   >       constexpr bool operator<=(
   >         const reverse_iterator<Iterator>& x,
   >         const reverse_iterator<Iterator>& y);

   > > -1- Returns: `x.current >= y.current`.

### 2881(i). Adopt section III of P0308R0

Section: 20.7.3 [variant.variant] Status: New Submitter: Switzerland Opened: 2017-02-03 Last modified: 2020-09-06

Priority: 3

View all other issues in [variant.variant].

View all issues with New status.

Discussion:

Addresses CH 7

Consider making the variant statically `!valueless_by_exception()` for cases where `is_nothrow_move_constructible_v<T_i>` for all alternative types `Ti`

Proposed change: Adopt section III of P0308R0.

[2017-07 Toronto Thurs Issue Prioritization]

Priority 3. This is similar to 2904, Casey to investigate

Proposed resolution:

### 2883(i). The standard library should provide `string_view` parameters instead or in addition for functions defined with `char const *` or `string const &` as parameter types.

Section: 21.4 [string.view] Status: LEWG Submitter: Switzerland Opened: 2017-02-03 Last modified: 2017-07-16

Priority: Not Prioritized

View all other issues in [string.view].

View all issues with LEWG status.

Discussion:

Addresses CH 9

The standard library should provide `string_view` parameters instead or in addition for functions defined with `char const *` or `string const &` as parameter types. Most notably in cases where both such overloads exist or where an internal copy is expected anyway.

It might be doubted that the non-null termination of `string_view` could be an issue with functions that pass the `char *` down to OS functions, such as `fstream_buf::open()` etc. and those shouldn't provide it and favour generating a `std::string` temporary instead in that case. However, `std::path` demonstrates it is usable to have `string_view` overloads and there might be many places where it can be handy, or even better.

Proposed change: Provide the overloads for `std::regex`, the exception classes, `std::bitset`, `std::locale` and more.

[Post-Kona 2017]

Most (all?) of these changes were proposed in P0506r1, which was discussed by LEWG in Kona.

[2017-07 Toronto Thurs Issue Prioritization]

Status LEWG - they're already looking at this.

Proposed resolution:

### 2884(i). Relational operators for containers should sfinae; if the underlying type is not comparable, neither should the container be

Section: 22 [containers], 20 [utilities] Status: LEWG Submitter: Finland Opened: 2017-02-03 Last modified: 2017-06-27

Priority: Not Prioritized

View other active issues in [containers].

View all other issues in [containers].

View all issues with LEWG status.

Discussion:

Addresses FI 16

Relational operators for containers should sfinae; if the underlying type is not comparable, neither should the container be. Same applies to `tuple` and `pair`.

Proposed change: Make the relational operators of containers and utility components reflect the validity of the underlying element types.

[ 2017-06-27 Moved to LEWG after 5 positive votes on c++std-lib. ]

Proposed resolution:

### 2885(i). The relational operators of `optional` and `variant` completely reflect the semantics of the element types — this is inconsistent with other types in the library

Section: 22 [containers], 20 [utilities] Status: LEWG Submitter: Finland Opened: 2017-02-03 Last modified: 2017-07-16

Priority: Not Prioritized

View other active issues in [containers].

View all other issues in [containers].

View all issues with LEWG status.

Discussion:

Addresses FI 17

The relational operators of optional and variant completely reflect the semantics of the element types; this is inconsistent with other types in the library, like `pair`, `tuple` and containers. If we believe it's important that we don't synthesize relational operators for wrapper types, we should believe it's important for other types as well. Otherwise comparing containers of floating-point types and tuples/pairs etc. of floating point types will give incorrect answers.

Proposed change: Make the relational operators of containers and utility components reflect the semantics of the operators for the underlying element types.

[2017-07 Toronto Thurs Issue Prioritization]

Move to LEWG

Proposed resolution:

### 2906(i). There is no ability to supply an allocator for the control block when constructing a `shared_ptr` from a `unique_ptr`

Section: 20.11.3.2 [util.smartptr.shared.const] Status: New Submitter: United States Opened: 2017-02-03 Last modified: 2017-07-16

Priority: 3

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

View all issues with New status.

Discussion:

Addresses US 130

There is no ability to supply an allocator for the control block when constructing a `shared_ptr` from a `unique_ptr`. Note that no further `shared_ptr` constructors need an allocator, as they all have pre-existing control blocks that are shared, or already have the allocator overload.

Proposed change: Add an additional `shared_ptr` constructor, `template <class Y, class D, class A> shared_ptr(unique_ptr<Y, D>&& r, A alloc)`, with the same semantics as the existing constructor taking a `unique_ptr`, but using the `alloc` argument to supply memory as required.

[2017-07 Toronto Thurs Issue Prioritization]

Priority 3; Alisdair to provide wording

Proposed resolution:

### 2922(i). The `*_constant<>` templates do not make use of `template<auto>`

Section: 20.15.3 [meta.type.synop] Status: LEWG Submitter: United States Opened: 2017-02-03 Last modified: 2017-07-16

Priority: Not Prioritized

View other active issues in [meta.type.synop].

View all other issues in [meta.type.synop].

View all issues with LEWG status.

Discussion:

Addresses US 171

The `*_constant<>` templates (including the proposed addition, `bool_constant<>`) do not make use of the new `template<auto>` feature.

Proposed change: Add a `constant<>` (subject to bikeshedding) template which uses `template<auto>`.

Define `integral_constant<>` as `using integral_constant<T, V> = constant<T(V)>` or `integral_constant<T, V> = constant<V>`.

Either remove `bool_constant`, define it as using `bool_constant = constant<bool(B)>` or `using bool_constant = constant<B>`.

[2017-03-03, Kona, LEWG]

Straw polls:

Name:
`constant` | 3
`numeric_constant` | 8
`static_constant` | 1
`scalar_constant` | 7
`integer_constant` (Over LWG's dead body) | 1
`auto_constant` | 4
`integral_c` | 7
`int_` | 0
`​`
`scalar_constant` | 6
`numeric_constant` | 3
`integral_c` | 5

Accept P0377 with "`scalar_constant`" for C++17 to address LWG 2922 and US 171:

SF | F | N | A | SA

0 | 1 | 3 | 7 | 5

[2017-07 Toronto Thurs Issue Prioritization]

Status LEWG with P0377

Proposed resolution:

### 2923(i). `noexcept` is inconsistently applied across headers which import components of the C standard library

Section: 26.8.1 [cmath.syn] Status: New Submitter: United States Opened: 2017-02-03 Last modified: 2017-07-16

Priority: 4

View other active issues in [cmath.syn].

View all other issues in [cmath.syn].

View all issues with New status.

Discussion:

Addresses US 172

`noexcept` is inconsistently applied across headers which import components of the C standard library into the C++ library; some functions (`std::abort()`, `std::_Exit()`, etc) are defined as `noexcept` in some places, but not in others. Some functions which seem like they should be `noexcept` (`std::abs()`, `std::div()`, etc) are not defined as `noexcept`.

Proposed change: Make the majority of the C library functions (with exceptions such as `std::qsort()` and `std::bsearch()`, which can call user code) `noexcept`.

[2017-07 Toronto Thurs Issue Prioritization]

Priority 4

Proposed resolution:

### 2931(i). Missed optimization opportunity with single-argument `std::next`

Section: 23.4.3 [iterator.operations] Status: Open Submitter: Morwenn Opened: 2017-02-04 Last modified: 2018-12-03

Priority: 3

View other active issues in [iterator.operations].

View all other issues in [iterator.operations].

View all issues with Open status.

Discussion:

It seems that `std::next` is missing an optimization opportunity when taking a single parameter. The standard mandates that `std::next` shall call `std::advance` on the passed iterator and return it. For random-access iterators, it means that `operator+=` will be called on the iterator. However, if a single-argument overload was added to `std::next`, it could call `++it` directly instead of `std::advance(it, 1)`, which means that `operator++` would be called instead of `operator+=`. This might make a small performance difference for complicated iterators such as `std::deque`'s ones, where `operator++` has a simpler logic than `operator+=`.

An equivalent optimization could be allowed by adding a single-argument overload to `std::prev` too.

[2017-03-04, Kona]

Set priority to 3. Alisdair to provide wording.

[2018-11-30, Jonathan comments, recommending NAD]

Jonathan suggested NAD, because the proposed "just use increment when `n==1`" optimization can be done in `std::next` (and/or `std::advance`, and/or complicated iterators like `deque::iterator`) without adding an overload. Billy said the overload would avoid metaprogramming costs for dispatching to the right `std::advance`, and help in non-optimized builds. Zhihao said the overload would make it clear to users that the `n==1` case is optimized (Jonathan thinks this is irrelevant as there's no requirement that we tell users what we optimize).

Proposed resolution:

### 2933(i). PR for LWG 2773 could be clearer

Section: 20.5.4 [tuple.creation] Status: New Submitter: Eric Fiselier Opened: 2017-02-06 Last modified: 2020-09-06

Priority: 3

View all other issues in [tuple.creation].

View all issues with New status.

Discussion:

The current PR for LWG 2773 changes `std::ignore` to be a `constexpr` variable. However it says nothing about whether using `std::ignore` in `std::tie` is a constant expression. I think the intent was clearly to allow this. Therefore I suggest we update the resolution to explicitly call this out in a note. (I don't think new normative wording is needed).

I propose we update the current PR as follows:

1. Keep the current changes proposed by the PR.

2. Add a note after [tuple.creation]/p7 (`std::tie`):

   > [Note: The constructors and assignment operators provided by `ignore` shall be `constexpr`]

Perhaps LWG feels the existing wording is clear enough, but if not I think the above changes sufficiently clarify it.

The ability to `constexpr` assign to `std::ignore` can be important: Here is an extremely contrived example:

>     constexpr bool foo() {
>       auto res = std::tie(std::ignore);
>       std::get<0>(res) =42;
>       return true;
>     }
>     static_assert(foo());

[2017-03-04, Kona]

Set priority to 3. P/R is incorrect; it should NOT be a note. Marshall to work with Eric to get better wording. STL says "use an exposition-only class".

Proposed resolution:

This wording is relative to N4640.

1. Modify 20.5.4 [tuple.creation] as indicated:

   >     template<class... TTypes>
   >       constexpr tuple<TTypes&...> tie(TTypes&... t) noexcept;

   > > -7- Returns: […]

   > > -?- [Note: The constructors and assignment operators provided by `ignore` shall be `constexpr`. — end note]

   > > -8- [Example: […] — end example]

### 2939(i). Some type-completeness constraints of traits are overspecified

Section: 20.15.3 [meta.type.synop] Status: New Submitter: Daniel Krügler Opened: 2017-03-02 Last modified: 2020-02-13

Priority: 2

View other active issues in [meta.type.synop].

View all other issues in [meta.type.synop].

View all issues with New status.

Discussion:

LWG 2797 (RU 2) suggests that certain type-traits should be required to diagnose violations of their pre-conditions. The basic idea is founded and I see no problems for requiring this for the mentioned traits `alignment_of` or `is_base_of`, for example. But if we want to require this diagnostics for some other traits, such as `is_convertible`, `is_constructible` (and friends), or `is_callable` (and possibly some others), we really should be sure that our current requirements are OK.

Unfortunately, there exists some cases, where we currently overspecify imposing complete type requirements where they are not actually required. For example, for the following situation the answer of the trait could be given without ever needing the complete type of `X`:

>     struct X; // Never defined

>     static_assert(std::is_convertible_v<X, const X&>);

Unfortunately we cannot always allow incomplete types, because most type constructions or conversions indeed require a complete type, so generally relaxing the current restrictions is also not an option.

The core language has a solution for this "small" gap of situations, where the response of the compiler might depend on type completeness: Undefined behaviour. So, I believe we need a somewhat more detailled form to express the intend here. Informally, I would suggest that the program should only be ill-formed in the situation described by LWG 2797, if there exists the possibility that the compiler would require complete types for the considered operation. The example shown above, `std::is_convertible_v<X, const X&>`, would never require the need to complete `X`, so here no violation should exist.

The presented example might seem a tiny one, but the Standard Library type traits are extreme fundamental tools and we should try to not give the impression that an approximate rule of the current type constraints breaks reasonable code.

It is correct, that above example has currently undefined behaviour due to the breakage of pre-conditions, therefore this issue suggests to fix the current situation before enforcing a diagnostic for such valid situations.

[2017-03-04, Kona]

Set priority to 2. Is related to 2797, but really needs an audit of the type traits.

[2018-08 Batavia Monday issue discussion]

Issues 2797, 2939, 3022, and 3099 are all closely related. Walter to write a paper resolving them.

[2020-02 Prague Thursday issue discussion]

Two of the issues (2797 and 3022) had been resolved by the acceptance of P1285R0.

Proposed resolution:

### 2947(i). Clarify several filesystem terms

Section: 29.12.8.1 [fs.enum.path.format], 99 [fs.class.directory_iterator], 29.12.13.4 [fs.op.copy] Status: New Submitter: Thomas Köppe Opened: 2017-03-14 Last modified: 2020-09-06

Priority: 3

View all issues with New status.

Discussion:

During the application of P0430R2, we came across several terms that seem insufficiently clear and lacking proper definitions.

We would like clarification on what those terms mean, and we would welcome wording suggestions, or alternatively a verbose explanation and dispensation to change the presentation editorially.

The items in question are:

- What does it mean to 'always interpret [the character sequence] in the same way'? ([fs.enum.path.format], which is [path.format] in the paper)

- What is a "directory-like" file type? ([fs.class.directory_iterator])

- What is an "implementation-defined file type"? (e.g. [fs.op.copy])

[2017-07 Toronto Wed Issue Prioritization]

Priority 3

[2018-01-16, Jonathan comments]

In 29.12.8.1 [fs.enum.path.format] "always interpreted in the same way" means irrespective of the `path::format` value, or the content of the string. Maybe add ", rather than depending on the `path::format` value or the content of the character sequence".

In 99 [fs.class.directory_iterator] an "implementation-defined directory-like file type" is an implementation-defined file type (see [fs.enum.file_type] and Table 115) that is treated like a directory by the special rules that the OS has for non-regular files (see 29.12.6.2 [fs.path.generic]).

In 29.12.13.4 [fs.op.copy], an "implementation-defined file type" is exactly that, see [fs.enum.file_type] and Table 115 again. I don't see what isn't clear about that. Maybe add a cross-reference to [fs.enum.file_type].

Proposed resolution:

### 2949(i). Unclear complexity requirements: space vs. time

Section: 16 [library] Status: New Submitter: Jens Maurer Opened: 2017-03-20 Last modified: 2017-07-15

Priority: 4

View other active issues in [library].

View all other issues in [library].

View all issues with New status.

Discussion:

This is from editorial issue #1088:

It is not always made explicit whether the requirement is referring to time or space complexity, or both.

> "Linear time." vs. "Linear."
> "Constant time." vs. "Constant."

16.3.2.4 [structure.specifications] says that the Complexity element specifies "the time and/or space complexity of the function", so being explicit about this would be good.

Examples:

- [sequence.reqmts] `a.clear()`

- [deque.cons]

- [vector.cons]

- [map.cons]

- [multimap.cons]

- [set.cons]

- [multiset.cons]

- [unord.map.cnstr]

- [unord.multimap.cnstr]

etc.

[2017-07 Toronto Wed Issue Prioritization]

Priority 4; Robert to look at

Proposed resolution:

### 2959(i). `char_traits<char16_t>::eof` is a valid UTF-16 code unit

Section: 21.2.4.4 [char.traits.specializations.char16.t] Status: New Submitter: Jonathan Wakely Opened: 2017-05-05 Last modified: 2019-04-02

Priority: 3

View all other issues in [char.traits.specializations.char16.t].

View all issues with New status.

Discussion:

The standard requires that `char_traits<char16_t>::int_type` is `uint_least16_t`, so when that has the same representation as `char16_t` there are no bits left to represent the `eof` value.

21.2.4.4 [char.traits.specializations.char16.t] says:

> — The member `eof()` shall return an implementation-defined constant that cannot appear as a valid UTF-16 code unit.

Existing practice is to use the "noncharacter" `u'\uffff'` for this value, but the Unicode spec is clear that `U+FFFF` and other noncharacters are valid, and their appearance in a UTF-16 string does not make it ill-formed. See here and here:

> The fact that they are called "noncharacters" and are not intended for open interchange does not mean that they are somehow illegal or invalid code points which make strings containing them invalid.

In practice this means there's no way to tell if `basic_streambuf<char16_t>::sputc(u'\uffff')` succeeded or not. If it can insert the character it returns `to_int_type(u'\uffff')` and otherwise it returns `eof()`, which is the same value.

I believe that `char_traits<char16_t>::to_int_type(char_type c)` can be defined to transform `U+FFFF` into `U+FFFD`, so that the invariant `eq_int_type(eof(), to_int_type(c)) == false` holds for any `c` (and the return value of `sputc` will be distinct from `eof`). I don't think any implementation currently meets that invariant.

I think at the very least we need to correct the statement "The member `eof()` shall return an implementation-defined constant that cannot appear as a valid UTF-16 code unit", because there are no such constants if `sizeof(uint_least16_t) == sizeof(char16_t)`.

This issue is closely related to LWG 1200, but there it's a slightly different statement of the problem, and neither the submitter's recommendation nor the proposed resolution solves this issue here. It seems that was closed as NAD before the Unicode corrigendum existed, so at the time our standard just gave "surprising results" but wasn't strictly wrong. Now it makes a normative statement that conflicts with Unicode.

[2017-07 Toronto Wed Issue Prioritization]

Priority 3

Proposed resolution:

### 2962(i). Iterators of Containers of move-only types do not model `InputIterator`

Section: 23.3.5.3 [input.iterators] Status: Open Submitter: Gašper Ažman Opened: 2017-05-10 Last modified: 2020-09-06

Priority: 2

View other active issues in [input.iterators].

View all other issues in [input.iterators].

View all issues with Open status.

Discussion:

In Table 95 in 23.3.5.3 [input.iterators], it is specified that the expression `*a` returns `reference`, which must be convertible to `value_type`. This is not true for move-only types, which incidentally means that `std::vector<std::unique_ptr<int>>` does not possess even a lowly `InputIterator`, which is, of course, absurd.

With the advent of concepts as first-class citizens in the language, getting this right as soon as possible is a priority.

This issue seems to be similar to both LWG 448 and LWG 484, but not the same.

The proposed resolution stems from two considerations outlined below:

> Convertibility is too strong for all algorithms

> No algorithm in the standard library requires convertibility to `value_type`. If algorithms require things that smell of that, they specify the assignment or constructibility flavor they need directly. I checked this by going through the specification of each and every one of them in `<algorithm>` and `<numeric>`, which highlighted several issues unrelated to this one. These issues are presented in Algorithms with underspecified iterator requirements (LWG 2963).

> `reference` needs to be related to `value_type`

> Algorithms need this for the following reasons:

> - lifetime-extension: served as adequately by `T const&` as by `T`. Also works for iterators that return by value. `T&&` also correctly binds to `T const&`.

> - passing to predicates: again, served adequately by `T const&`

> - writing to `*result`: not provided by the requirement anyway.

> - capture-by-copy: currently implicitly guaranteed, but unused in the standard library (always specified separately). A separate specification can always be made for algorithms that need to capture-by-copy.

> We must give due consideration to code that so far required its inputs to be `CopyConstructible` implicitly by requiring convertibility to `T`. This is done in the issue LWG 2963, which presents the results of a comb-through of `<algorithm>` and `<numeric>` to find algorithms that have this requirement, but where it is not specified. While related issues have been identified, no algorithms seems to require more than `T const&` convertibility without separately requiring convertibility to `T`.

> Since such code is already compiling today, relaxing this requirement does not break code.

> The only code this could possibly break is if, in a concept checking library, the `InputIterator` concept requirement on `reference` being convertible to `value_type` gets relaxed. Such a library, if it offered overloading based on most-specific modeled concept, could now, once fixed, resolve the call to a different algorithm, which could break user code that uses a hypothetical algorithm with a move-only container and was relying to select some other overload for move-only types based on the implicit `CopyConstructible` assertion provided by the iterator.

> In our internal concepts-checking library, we have had this issue "fixed" since the very beginning — move-only types were too important for our internal algorithms library, and also no algorithm in it seems to require something like `Iterator::value_type x = *first` without also requiring copy-constructibility anyway.

[2017-07 Toronto Monday issue prioritization]

Priority 2; also could affect the ranges TS

Previous resolution [SUPERSEDED]:

> This wording is relative to N4659.

> 1. Change Table 95 — "Input iterator requirements", 23.3.5.3 [input.iterators] as indicated:

>    > Table 107 — Input iterator requirements (in addition to Iterator)
>    > Expression | Return type | Operational semantics | Assertion/note pre-/post-condition
>    > --- | --- | --- | ---
>    > `…`
>    > `*a` | `reference`, convertible to `T` that binds to `const T&` | `` | […]
>    > `…`
>    > `*r++` | convertible to `T` that binds to `const T&` | `{ Tauto&& tmp = *r; ++r; return tmp; }` |

[2018-04-20; Eric Niebler provides improved wording]

The revised wording makes it clear that you can only rely on those operational semantics when the value type is constructible from the reference type and is movable. When those conditions aren't met, we can make no guarantees about the operational semantics of `*r++` (which is why `*r++` is no longer a required expression of the `InputIterator` concept in the Ranges TS).

Really, no generic code should be doing `*r++` on input iterators. Another option would be to simply deprecate this requirement for input iterators, but that might need a paper. (For forward iterators, `*r++` is already required to return `reference` exactly, and the multi-pass guarantee gives it the proper semantics.)

I also now have a question about the proposed return type of `*a` and `*r++`, which says they must be something that "binds to `const T&`". Does this mean that an iterator with a reference type reference-to-[`const`?]-`volatile`-`T` is no longer considered an iterator? I don't think that's what we want to say. Perhaps these should read "binds to `const volatile T&` instead, except that has the problem for InputIterators that return prvalues that a prvalue is not bindable to a volatile reference.

[2018-11 San Diego Thursday night issue processing]

Look at Ranges; EricWF to investigate. Status to Open

Proposed resolution:

This wording is relative to N4741.

1. Change Table 89 — "Input iterator requirements", 23.3.5.3 [input.iterators] as indicated:

   > Table 89 — Input iterator requirements (in addition to Iterator)
   > Expression | Return type | Operational semantics | Assertion/note pre-/post-condition
   > --- | --- | --- | ---
   > `…`
   > `*a` | `reference`, convertible to `T` that binds to `const T&` | `` | […]
   > `…`
   > `*r++` | convertible to `T` that binds to `const T&` | When `T tmp = *r` is well-formed and `T` is `MoveConstructible`, then `{ T tmp = *r; ++r; return tmp; }` |

### 2963(i). Algorithms with underspecified iterator requirements

Section: 25 [algorithms], 26 [numerics] Status: New Submitter: Gašper Ažman Opened: 2017-05-10 Last modified: 2017-07-12

Priority: 3

View other active issues in [algorithms].

View all other issues in [algorithms].

View all issues with New status.

Discussion:

While researching whether the proposed resolution of Iterators of Containers of move-only types do not model `InputIterator` (LWG 2962), I came across several algorithms that underspecify their requirements, mostly with regard to some associated type of the iterator type they operate on. A list can be found below.

The list of algorithms with underspecified requirements from `<algorithm>` and `<numeric>` follows.

With the advent of concepts, these algorithms will need better specifications if we are ever hoping to be allowed to overload based on them. I want this issue to bring the standard algorithms closer to having their concept requirements directly transcribable to library annotations.

Suggested resolution:

1. `copy`, `copy_if`, `copy_n`, `copy_backward`

   Add to description: `*result` shall be assignable from `*first`.

2. `move`, `move_backward`

   Add to description: `*result` shall be move-assignable from `*first`.

3. `transform`

   Add to description: The result of the expression `op(*first)` or `binary_op(*first1, *first2)` shall be writable to `result`.

4. `rotate_copy`

   Add to description: `*first` shall be writable to `result`.

5. `merge`

   Add to description: `*first1` and `*first2` shall be writable to `result`..

6. `set_union`, `set_intersection`, `set_difference`, `set_symmetric_difference`

   Add to description: `*first1` and `*first2` shall be writable to `result`.

7. `partial_sum`

   `acc` is not defined.

   Change description: `acc`, a variable of `InputIterator`'s value type, shall be constructible

8. `adjacent_difference`

   `acc` is not defined.

   Change description: `acc`, a variable of `InputIterator`'s value type, shall be `MoveAssignable` and shall be `constructible` from the type of `*first`.

9. `iota`

   `iota` is mis-specified. Since the expression we need to support is `*first = value`: `*first` is required to be of type `InputIterator::reference`, and value is an lvalue of type `T`. The current specification allows calling `iota` with a `const` output iterator!

   `T` shall be convertible to `ForwardIterator`'s value type `value` shall be writable to `first`. The expression `*first = value` shall not modify `value`.

[2017-07 Toronto Monday issue prioritization]

Priority 3; Marshall to work with Gaspar to improve wording.

Proposed resolution:

### 2973(i). `inplace_merge` exact comparison count complexity prohibits useful real-world optimizations

Section: 25.8.6 [alg.merge] Status: LEWG Submitter: Billy Robert O'Neal III Opened: 2017-06-08 Last modified: 2020-09-06

Priority: Not Prioritized

View all other issues in [alg.merge].

View all issues with LEWG status.

Discussion:

At the moment, `inplace_merge` requires exactly `N - 1` comparisons, if enough additional memory is available (and in practice enough additional memory is always available). However, this prohibits implementing the merge operation using forms of binary search, as in Timsort's 'Galloping Mode', a useful optimization for non-uniform input data. It's not really useful to prohibit standard libraries from trying a few extra speculative compares like this, given that users must be prepared for the fallback "not enough memory" 𝒪(`N lg N`) algorithm.

[2017-07 Toronto Monday issue prioritization]

Status to LEWG

Proposed resolution:

This wording is relative to N4659.

1. Edit 25.8.6 [alg.merge] as indicated:

   >     template<class BidirectionalIterator>
   >     void inplace_merge(BidirectionalIterator first,
   >         BidirectionalIterator middle,
   >         BidirectionalIterator last);
   >     template<class ExecutionPolicy, class BidirectionalIterator>
   >     void inplace_merge(ExecutionPolicy&& exec,
   >         BidirectionalIterator first,
   >         BidirectionalIterator middle,
   >         BidirectionalIterator last);
   >     template<class BidirectionalIterator, class Compare>
   >     void inplace_merge(BidirectionalIterator first,
   >         BidirectionalIterator middle,
   >         BidirectionalIterator last, Compare comp);
   >     template<class ExecutionPolicy, class BidirectionalIterator, class Compare>
   >     void inplace_merge(ExecutionPolicy&& exec,
   >         BidirectionalIterator first,
   >         BidirectionalIterator middle,
   >         BidirectionalIterator last, Compare comp);

   > > […]

   > > -8- Complexity: Let `N = last - first`:

   > > 1. (8.1) — For the overloads with no `ExecutionPolicy`, if enough additional memory is available, exactly `N - 1` comparisons on average, 𝒪(`N`) comparisons in the worst case.

   > > 2. (8.2) — For the overloads with no `ExecutionPolicy` if no additional memory is available, 𝒪(`N log N`) comparisons.

   > > 3. (8.3) — For the overloads with an `ExecutionPolicy`, 𝒪(`N log N`) comparisons.

   > > -9- Remarks: Stable (16.4.6.8 [algorithm.stable]).

### 2983(i). `money_put::do_put` underspecified

Section: 28.4.7.3.2 [locale.money.put.virtuals] Status: New Submitter: Jonathan Wakely Opened: 2017-06-21 Last modified: 2017-06-27

Priority: 3

View all other issues in [locale.money.put.virtuals].

View all issues with New status.

Discussion:

Whether you get "`.99`" or "`0.99`" for the following depends on the implementation:

>     std::cout.imbue(std::locale("en_US"));
>     std::cout << std::put_money(99.L);

I don't see any justification in [locale.money.put.virtuals] for the leading `0`, although that seems more useful.

If we want the leading zero, we should say so.

[2017-06-27, Jonathan comments and provides wording]

I suggest that we require a leading zero. The wording below is similar to how C specifies the `%f` format specifier for `fprintf`.

Proposed resolution:

This wording is relative to N4659.

1. Edit 28.4.7.3.2 [locale.money.put.virtuals] as indicated:

   >     iter_type do_put(iter_type s, bool intl, ios_base& str,
   >                      char_type fill, long double units) const;
   >     iter_type do_put(iter_type s, bool intl, ios_base& str,
   >                      char_type fill, const string_type& digits) const;

   > > […]

   > > -2- Remarks: The currency symbol is generated if and only if `(str.flags() & str.showbase)` is nonzero. If the format specifies a decimal point, at least one digit character appears before it. If the number of characters generated for the specified format is less than the value returned by `str.width()` on entry to the function, then copies of `fill` are inserted as necessary to pad to the specified width. For the value `af` equal to `(str.flags() & str.adjustfield)`, if `(af == str.internal)` is `true`, the fill characters are placed where `none` or `space` appears in the formatting pattern; otherwise if `(af == str.left)` is `true`, they are placed after the other characters; otherwise, they are placed before the other characters.

### 2984(i). `put_money(99)` is unnecessarily undefined

Section: 29.7.7 [ext.manip] Status: New Submitter: Jonathan Wakely Opened: 2017-06-22 Last modified: 2017-06-26

Priority: 3

View all other issues in [ext.manip].

View all issues with New status.

Discussion:

[ext.manip] p5 says:

> Requires: The type `moneyT` shall be either `long double` or a specialization of the `basic_string` template (Clause 24).

This means that `put_money(99)`, `put_money(99.)`, `put_money("99")`, and `put_money(string_view{"99"})` are all undefined, when in practice they will compile fine and do the right thing, converting the argument to `long double` or `std::string` as needed.

We could change it to be "otherwise the program is ill-formed", or to remove the function templates from overload resolution when the argument is not `long double` or a `std::basic_string`, but that will unnecessarily break code that works fine today. We should accept types convertible to `long double` or the relevant `money_put` facet's `string_type` (which is not known until we attempt to write the unspecified type to an ostream).

The requirement is also insufficient, because `cout << put_money(wstring(L"99"))` won't compile on any implementation, despite the argument type being a specialization of `basic_string`. This same problem exists for `std::get_money`.

[2017-06-24, Daniel comments and provides wording]

The wording changes below are supposed to support all `moneyT` types that are convertible to either `long double` or to `money_put/get<Ch, o/istreambuf_iterator<Ch, Tr>>::string_type` (but not to both), where `Ch` and `Tr` are determined by the concrete instantiated specialization of the exposition-only function template `f` that is used to specify the semantics of `put_money` and `get_money`, respectively. XOR-ing the requirements outlaws types that are convertible to both, which would cause an ambiguity unless we would provide wording that would introduce an ordered application of these convertibility constraints. This is the rationale for the seemingly odd new Remarks formulation. Note also, that the wording provided below intentionally attempts to distinguish between the statically testable conditions based on the `is_convertible_v` expressions within the Remarks: element and the well-defined runtime behaviour requirement of the actually provided argument of deduced type `moneyT` within the pre-existing Requires: element. Another point worth pointing out is that the wording attempts to fix an currently existing ambiguity of the meaning of the type `moneyT` (and to a lesser extend for `charT` and `traits`) as either the template parameter of `put/get_money` or that of the corresponding template argument of the exposition-only `f` templates. The revised form makes it clearer that it refers to the latter.

It should be emphasized that this extension of the current wording would provide support for `put_money(99)`, `put_money(99.)`, and `put_money("99")`, but not yet for `put_money(string_view{"99"})`, because `string_view` is not convertible to `string`. To realize support for the latter, this wording approach could be extended by referring to `is_constructible` instead of `is_convertible`, though.

Proposed resolution:

This wording is relative to N4659.

1. Edit 29.7.7 [ext.manip] as indicated:

   >     template <class moneyT> unspecified get_money(moneyT& mon, bool intl = false);

   > > -?- For an expression `in >> get_money(mon, intl)` described below, let `Mo`, `Ch`, and `Tr` be the deduced template argument types of the template parameters `moneyT`, `charT`, and `traits`, respectively, of the instantiated specialization of the template `f`.

   > > -2- Requires: The type `moneyT` shall be either `long double` or a specialization of the `basic_string` template (Clause 21 [strings])`Mo` shall be either convertible to `long double` or shall be convertible to `money_get<Ch, istreambuf_iterator<Ch, Tr>>::string_type`.

   > > -?- Remarks: If `is_convertible_v<Mo, long double> == is_convertible_v<Mo, money_get<Ch, istreambuf_iterator<Ch, Tr>>::string_type>`, the program is ill-formed.

   > > -3- Effects: The expression `in >> get_money(mon, intl)` described below behaves as a formatted input function (29.7.4.3.1 [istream.formatted.reqmts]).

   > > -4- Returns: An object of unspecified type such that if `in` is an object of type `basic_istream<charTCh, traitsTr>` then the expression `in >> get_money(mon, intl)` behaves as if it called `f(in, mon, intl)`, where the function `f` is defined as:

   > > >     template <class charT, class traits, class moneyT>
   > > >     void f(basic_ios<charT, traits>& str, moneyT& mon, bool intl) {
   > > >       using Iter = istreambuf_iterator<charT, traits>;
   > > >       using MoneyGet = money_get<charT, Iter>;
   > > >       ios_base::iostate err = ios_base::goodbit;
   > > >       const MoneyGet& mg = use_facet<MoneyGet>(str.getloc());
   > > >       mg.get(Iter(str.rdbuf()), Iter(), intl, str, err, mon);
   > > >       if (ios_base::goodbit != err)
   > > >         str.setstate(err);
   > > >     }

   > > The expression `in >> get_money(mon, intl)` shall have type `basic_istream<charTCh, traitsTr>&` and value `in`.

   >     template <class moneyT> unspecified put_money(const moneyT& mon, bool intl = false);

   > > -?- For an expression `out << put_money(mon, intl)` described below, let `Mo`, `Ch`, and `Tr` be the deduced template argument types of the template parameters `moneyT`, `charT`, and `traits`, respectively, of the instantiated specialization of the template `f`.

   > > -5- Requires: The type `moneyT` shall be either `long double` or a specialization of the `basic_string` template (Clause 21 [strings])`Mo` shall be either convertible to `long double` or shall be convertible to `money_put<Ch, ostreambuf_iterator<Ch, Tr>>::string_type`.

   > > -?- Remarks: If `is_convertible_v<Mo, long double> == is_convertible_v<Mo, money_put<Ch, ostreambuf_iterator<Ch, Tr>>::string_type>`, the program is ill-formed.

   > > -6- Returns: An object of unspecified type such that if `out` is an object of type `basic_ostream<charTCh, traitsTr>` then the expression `out << put_money(mon, intl)` behaves as a formatted output function (29.7.5.3.1 [ostream.formatted.reqmts]) that calls `f(out, mon, intl)`, where the function `f` is defined as:

   > > >     template <class charT, class traits, class moneyT>
   > > >     void f(basic_ios<charT, traits>& str, const moneyT& mon, bool intl) {
   > > >       using Iter = ostreambuf_iterator<charT, traits>;
   > > >       using MoneyPut = money_put<charT, Iter>;
   > > >       const MoneyPut& mp = use_facet<MoneyPut>(str.getloc());
   > > >       const Iter end = mp.put(Iter(str.rdbuf()), intl, str, str.fill(), mon);
   > > >       if (end.failed())
   > > >         str.setstate(ios::badbit);
   > > >     }

   > > The expression `out << put_money(mon, intl)` shall have type `basic_ostream<charTCh, traitsTr>&` and value `out`.

### 2985(i). `std::reverse` should be permitted to be vectorized

Section: 25.7.10 [alg.reverse] Status: LEWG Submitter: Billy O'Neal III Opened: 2017-06-24 Last modified: 2018-04-03

Priority: Not Prioritized

View all other issues in [alg.reverse].

View all issues with LEWG status.

Discussion:

The fine folks on our backend team suggested that we special case `std::reverse` of 1/2/4/8 to take advantage of vector units. Unfortunately, at present `std::reverse` says it does `N/2 iter_swap`s, which doesn't permit our vector implementation even if the iterator inputs are pointers to trivially copyable `T`s.

The vectorized version for pointers to `short`s is ~8x faster on Skylake than the serial version, and about 7x faster for `unsigned long long`s; and users don't actually care whether or not we call `swap` here.

[2017-07 Toronto Monday issue prioritization]

Status to LEWG; this is similar to 2973

[2018-04-02, Billy comments]

This issue should be resolved by P0551, because it prohibits user specialization of `std::swap` and `std::iter_swap`, which means the proposed vectorization optimization for pointers-to-trivially-copyable is now implementable without changes to `reverse`'s specification (We can detect if the user has provided an alternate `swap` in their own namespace, but not if they explicitly specialized `swap` or `iter_swap`).

Proposed resolution:

This wording is relative to N4659.

1. Edit 25.7.10 [alg.reverse] as indicated:

   >     template<class BidirectionalIterator>
   >       void reverse(BidirectionalIterator first, BidirectionalIterator last);
   >     template<class ExecutionPolicy, class BidirectionalIterator>
   >       void reverse(ExecutionPolicy&& exec,
   >                    BidirectionalIterator first, BidirectionalIterator last);

   > > -1- Requires: `*first` shall be swappable (16.4.4.3 [swappable.requirements]).

   > > -2- Effects: For each non-negative integer `i < (last - first) / 2`, applies `iter_swap` to all pairs of iterators `first + i, (last - i) - 1`. If `is_trivially_copyable_v<typename iterator_traits<BidirectionalIterator>::value_type>` is `true`, an implementation may permute the elements by making temporary copies, rather than by calling `iter_swap`. [Note: this allows the implementation to be vectorized. — end note]

### 2986(i). Handling of multi-character collating elements by the `regex` FSM is underspecified

Section: 30.12 [re.grammar] Status: New Submitter: Hubert Tong Opened: 2017-06-25 Last modified: 2017-07-12

Priority: 4

View other active issues in [re.grammar].

View all other issues in [re.grammar].

View all issues with New status.

Discussion:

In N4660 subclause 31.13 [re.grammar] paragraph 5:

> The productions `ClassAtomExClass`, `ClassAtomCollatingElement` and `ClassAtomEquivalence` provide functionality equivalent to that of the same features in regular expressions in POSIX.

The broadness of the above statement makes it sound like it is merely a statement of intent; however, this appears to be a necessary normative statement insofar as identifying the general semantics to be associated with the syntactic forms identified. In any case, if it is meant for `ClassAtomCollatingElement` to provide functionality equivalent to a collating symbol in a POSIX bracket expression, multi-character collating elements need to be considered.

In [re.grammar] paragraph 14:

> The behavior of the internal finite state machine representation when used to match a sequence of characters is as described in ECMA-262. The behavior is modified according to any `match_flag_type` flags specified when using the regular expression object in one of the regular expression algorithms. The behavior is also localized by interaction with the traits class template parameter as follows: [bullets 14.1 to 14.4]

In none of the bullets does the wording handle multi-character collating elements in a clear manner:

- 14.1 deals in characters.

- 14.2 deals in characters (`traits_inst.translate` accepts only a single character).

- 14.3 might handle a multi-character collating element; however, there is no specification of how such a collating element is to be identified from the sequence of characters. Additionally, the definition of primary equivalence class specifies that it is a set of characters (not of collating elements).

- 14.4 deals in characters.

The ECMA-262 specification for ClassRanges also deals in characters.

[2017-07 Toronto Monday issue prioritization]

Priority 4

Proposed resolution:

### 2987(i). Relationship between `traits_inst.lookup_collatename` and the `regex` FSM is underspecified with regards to `ClassAtomCollatingElement`

Section: 30.12 [re.grammar] Status: New Submitter: Hubert Tong Opened: 2017-06-25 Last modified: 2017-07-12

Priority: 3

View other active issues in [re.grammar].

View all other issues in [re.grammar].

View all issues with New status.

Discussion:

For a user to implement a regular expression traits class meaningfully, the relationship between the return value of `traits_inst.lookup_collatename` to the behaviour of the finite state machine corresponding to a regular expression needs to be better specified.

From N4660 subclause 31.13 [re.grammar], `traits_inst.lookup_collatename` only feeds clearly into two operations:

1. a test if the returned string is empty ([re.grammar]/8), and

2. a test if the result of `traits_inst.transform_primary`, with the returned string, is empty ([re.grammar]/10).

Note: It is unclear if bullet 14.3 in [re.grammar]/14 refers to the result of `traits_inst.lookup_collatename` when it refers to a "collating element"; and if it does, it is unclear what input is to be used.

It is therefore unclear what the effect is if `traits_inst.lookup_collatename` substitutes another member of the equivalence class as its output.

For example, when processing `"[[.AA.]]"` as a pattern under a locale `da_DK.utf8`, what is the expected behaviour difference (if any) should `traits_inst.lookup_collatename` return, for `"AA"`, `"\u00C5"` (where `U+00C5` is A with ring, which sorts the same as `"AA"`)?

[2017-07 Toronto Monday issue prioritization]

Priority 3

Proposed resolution:

### 2990(i). `optional::value_type` is not always a value type

Section: 20.6.3 [optional.optional] Status: Open Submitter: Casey Carter Opened: 2017-06-27 Last modified: 2018-01-28

Priority: 3

View all other issues in [optional.optional].

View all issues with Open status.

Discussion:

`optional<T>::value_type` is `T`, which can be a cv-qualified object type. This is inconsistent with the uses of the name `value_type` elsewhere in the standard. We should either require `optional<T>::value_type` to be `remove_cv_t<T>` — a true value type — or rename the type alias to `element_type`.

[2017-07 Toronto Tuesday PM issue prioritization]

Priority 3; may also affect `array`

[2018-1-26 issues processing telecon]

Status to 'Open'

Proposed resolution:

This wording is relative to N4659.

1. Edit 20.6.3 [optional.optional], class template `optional` synopsis, as indicated:

   >     template <class T>
   >       class optional {
   >       public:
   >         using value_type = remove_cv_t<T>;
   >         […]
   >       };

### 2991(i). `variant` copy constructor missing `noexcept(see below)`

Section: 20.7.3.2 [variant.ctor] Status: LEWG Submitter: Peter Dimov Opened: 2017-06-27 Last modified: 2017-07-12

Priority: Not Prioritized

View other active issues in [variant.ctor].

View all other issues in [variant.ctor].

View all issues with LEWG status.

Discussion:

The copy constructor of `std::variant` is not conditionally `noexcept` (I think it was in the original proposal.)

It should be, for two reasons: first, this would be consistent with the other three constructors

>     constexpr variant() noexcept(see below);

>     variant(variant&&) noexcept(see below);

>     template <class T>
>     constexpr variant(T&&) noexcept(see below);

and second, `variant` itself makes use of `is_nothrow_copy_constructible`, so it's inconsistent for it to take a stance against it.

[2017-07 Toronto Tuesday PM issue prioritization]

Status to LEWG

Proposed resolution:

This wording is relative to N4659.

1. Edit 20.7.3 [variant.variant], class template `variant` synopsis, as indicated:

   >     template <class... Types>
   >       class variant {
   >       public:
   >         // 23.7.3.1, constructors
   >         constexpr variant() noexcept(see below);
   >         variant(const variant&) noexcept(see below);
   >         variant(variant&&) noexcept(see below);
   >         […]
   >       };

2. Edit 20.7.3.2 [variant.ctor] as indicated:

   >     variant(const variant& w) noexcept(see below);

   > > […]

   > > -8- Remarks: This function shall not participate in overload resolution unless `is_copy_constructible_v<Ti>` is `true` for all `i`. The expression inside `noexcept` is equivalent to the logical AND of `is_nothrow_copy_constructible_v<Ti>` for all `i`.

### 2994(i). Needless UB for `basic_string` and `basic_string_view`

Section: 21.2 [char.traits], 21.3.3.2 [string.require], 21.4.3 [string.view.template] Status: Open Submitter: Gennaro Prota Opened: 2017-07-03 Last modified: 2018-11-25

Priority: 3

View all other issues in [char.traits].

View all issues with Open status.

Discussion:

`basic_string` and `basic_string_view` involve undefined behavior in a few cases where it's simple for the implementation to add a `static_assert` and make the program ill-formed.

With regards to basic_string, 21.2 [char.traits]/3 states:

> `Traits::char_type` shall be the same as `CharT`.

Here, the implementation can add a `static_assert` using the `is_same` type trait. Similar issues exist in 21.3.3.2 [string.require] and, for `basic_string_view`, in 21.4.3 [string.view.template]/1.

[2017-07 Toronto Tuesday PM issue prioritization]

Priority 3; need to check general container requirements

Partially by the adoption of P1148 in San Diego.

Tim opines: "the remainder deals with allocator value type mismatch, which I think is NAD."

Proposed resolution:

This wording is relative to N4659.

1. Edit 21.2 [char.traits] as indicated:

   > -3- To specialize those templates to generate a string or iostream class to handle a particular character container type `CharT`, that and its related character traits class `Traits` are passed as a pair of parameters to the string or iostream template as parameters `charT` and `traits`. If `Traits::char_type` shall be the same is not the same type as `CharT`, the program is ill-formed.

2. Edit 21.3.3.2 [string.require] as indicated:

   > -3- In every specialization `basic_string<charT, traits, Allocator>`, if the type `allocator_traits<Allocator>::value_type` shall name the same type is not the same type as `charT`, the program is ill-formed. Every object of type `basic_string<charT, traits, Allocator>` shall use an object of type `Allocator` to allocate and free storage for the contained `charT` objects as needed. The `Allocator` object used shall be obtained as described in 22.2.1 [container.requirements.general]. In every specialization `basic_string<charT, traits, Allocator>`, the type `traits` shall satisfy the character traits requirements (21.2 [char.traits]). If, and the type `traits::char_type` shall name the same type is not the same type as `charT`, the program is ill-formed.

3. Edit 21.4.3 [string.view.template] as indicated:

   > -1- In every specialization `basic_string_view<charT, traits>`, the type `traits` shall satisfy the character traits requirements (21.2 [char.traits]). If, and the type `traits::char_type` shall name the same type is not the same type as `charT`, the program is ill-formed.

### 3003(i). `<future>` still has type-erased allocators in `promise`

Section: 32.9.6 [futures.promise] Status: Open Submitter: Billy O'Neal III Opened: 2017-07-16 Last modified: 2020-09-06

Priority: 2

View other active issues in [futures.promise].

View all other issues in [futures.promise].

View all issues with Open status.

Discussion:

In Toronto Saturday afternoon LWG discussed LWG 2976 which finishes the job of removing allocator support from `packaged_task`. LWG confirmed that, despite the removal of `packaged_task` allocators "because it looks like `std::function`" was incorrect, they wanted to keep the allocator removals anyway, in large part due to this resolution being a response to an NB comment.

If we don't want the type erased allocator situation at all, then we should remove them from the remaining place they exist in `<future>`, namely, in `promise`.

This change also resolves potential implementation divergence on whether `allocator::construct` is intended to be used on elements constructed in the shared state, and allows the emplace-construction-in-`future` paper, P0319, to be implemented without potential problems there.

[28-Nov-2017 Mailing list discussion - set priority to P2]

Lots of people on the ML feel strongly about this; the suggestion was made that a paper would be welcomed laying out the rationale for removing allocator support here (and in other places).

[2018-1-26 issues processing telecon]

Status to 'Open'; Billy to write a paper.

[2019-06-03]

Jonathan observes that this resolution conflicts with 2095.

Proposed resolution:

This resolution is relative to N4659.

1. Edit 32.9.6 [futures.promise], class template `promise` synopsis, as indicated:

   >     template<class R>
   >     class promise {
   >     public:
   >       promise();
   >       template <class Allocator>
   >         promise(allocator_arg_t, const Allocator& a);
   >       […]
   >     };
   >     template <class R>
   >       void swap(promise<R>& x, promise<R>& y) noexcept;
   >     template <class R, class Alloc>
   >       struct uses_allocator<promise<R>, Alloc>;

   > […]

   >     template <class R, class Alloc>
   >       struct uses_allocator<promise<R>, Alloc>
   >         : true_type { };

   > > -3- Requires: `Alloc` shall be an Allocator (16.4.4.6 [allocator.requirements]).

   >     promise();
   >     template <class Allocator>
   >       promise(allocator_arg_t, const Allocator& a);

   > > -4- Effects: constructs a `promise` object and a shared state. The second constructor uses the allocator a to allocate memory for the shared state.

### 3011(i). Requirements for `assert(E)` inconsistent with C

Section: 19.3 [assertions] Status: Open Submitter: Jonathan Wakely Opened: 2017-08-18 Last modified: 2018-08-20

Priority: 2

View other active issues in [assertions].

View all other issues in [assertions].

View all issues with Open status.

Discussion:

The C standard says that the expression in an `assert` must have a scalar type, and implies (or at least allows) that the condition is tested by comparison to zero. C++ says that the expression is a constant subexpression if it can be contextually converted to `bool`. Those ways to test the condition are not equivalent.

It's possible to have expressions that meet the C++ requirements for a constant subexpression, but fail to meet the C requirements, and so don't compile.

>     #include <stdlib.h>

>     // A toy implementation of assert:
>     #define assert(E) (void)(((E) != 0) || (abort(), 0))

>     struct X {
>       constexpr explicit operator bool() const { return true; }
>     };

>     constexpr bool f(const X& x) {
>       assert(x);
>       return true;
>     }

C++ says that `assert(x)` is a constant subexpression, but as it doesn't have scalar type it's not even a valid expression.

I think either 19.3.2 [cassert.syn] or 19.3.3 [assertions.assert] should repeat the requirement from C that E has scalar type, either normatively or in a note. We should also consider whether "contextually converted to `bool`" is the right condition, or if we should use comparison to zero instead.

[2017-11 Albuquerque Wednesday night issues processing]

Priority set to 2; status to Open

Jonathan is discussing this with WG14

[2018-08-20, Jonathan comments]

This was reported to WG14 as N2207.

Proposed resolution:

### 3019(i). Presentation of "program defined classes derived from `error_category`" [syserr.errcat.derived] unclear and contains mistakes

Section: 19.5.3.4 [syserr.errcat.derived] Status: New Submitter: Thomas Köppe Opened: 2017-09-20 Last modified: 2017-11-09

Priority: 3

View all issues with New status.

Discussion:

The presentation of section [syserr.errcat.derived] is currently somewhat problematic:

- It is not clear why this section exists and what it is specifying. Presumably, it is the subject of the phrase "in this subclause" of the sibling section [syserr.errcat.overview], but that's confusing (because this would require the interpretation of "this subclause" as the containing superclause). It would be an improvement to say "shall behave as specified in [syserr.errcat.derived]" in the introduction.

- The current wording of [syserr.errcat.derived] requires that derived classes keep the `name` member function pure-virtual, making it impossible to have non-abstract derived classes. This appears to be an editorial error. Surely `name` should just not be required to be pure-virtual.

- There seems to be no requirement concerning the `message` virtual member function.

- We should use `override` rather than `virtual`.

- I would welcome a short, introductory paragraph in [syserr.errcat.derived] that states (non-redundantly) that the following are requirements on users' derived classes.

Partial wording proposal:

1. In 19.5.3.1 [syserr.errcat.overview] p1, change:

   > -1- The class `error_category` serves as a base class for types used to identify the source and encoding of a particular category of error code. Classes may be derived from `error_category` to support categories of errors in addition to those defined in this International Standard. Such classes shall behave as specified in this subclause 19.5.3.4 [syserr.errcat.derived]. [Note: `error_category` objects are passed by reference, and two such objects are equal if they have the same address. This means that applications using custom `error_category` types should create a single object of each such type. — end note]

2. In 19.5.3.4 [syserr.errcat.derived], change:

   >     virtual const char* name() const noexcept override  = 0;

   > > -1- Returns: A string naming the error category.

   >     virtual error_condition default_error_condition(int ev) const noexcept override;

   > > -2- Returns: An object of type `error_condition` that corresponds to `ev`.

   >     virtual bool equivalent(int code, const error_condition& condition) const noexcept override;

   > > -3- Returns: `true` if, for the category of error represented by `*this`, `code` is considered equivalent to `condition`; otherwise, `false`.

   >     virtual bool equivalent(const error_code& code, int condition) const noexcept override;

   > > -4- Returns: `true` if, for the category of error represented by `*this`, `code` is considered equivalent to condition; otherwise, `false`.

[2017-11 Albuquerque Wednesday night issues processing]

Priority set to 3.

Jonathan to talk to Chris K and Walter about writing a paper describing the use of `error_code`, `error_condition` and defining your own.

Proposed resolution:

### 3021(i). [networking.ts] Relax pointer equivalence requirement for `ConstBufferSequence`

Section: 16.2.2 [networking.ts::buffer.reqmts.constbuffersequence] Status: New Submitter: Vinnie Falco Opened: 2017-09-20 Last modified: 2020-09-06

Priority: 3

View all issues with New status.

Discussion:

Addresses: networking.ts

The post-condition buffer sequence requirements mandate pointer equivalence. This means that a copies of buffer sequences must point to the same pieces of underlying memory. While this is appropriate for `MutableBufferSequence`, it is unnecessary for `ConstBufferSequence` and can actually prevent useful implementation strategies such as the following constant buffer sequence which avoids dynamic allocations:

>     /// A buffer sequence containing a chunk-encoding header
>     class chunk_size
>     {
>     public:
>         // Storage for the longest hex string we might need
>         class value_type
>         {
>             friend class chunk_size;

>             // First byte holds the length
>             char buf_[1 + 2 * sizeof(std::size_t)];

>             template<class = void>
>             void prepare(std::size_t n);

>             template<class OutIter>
>             static OutIter to_hex(OutIter last, std::size_t n)
>             {
>                 if (n == 0)
>                 {
>                     *--last = '0';
>                     return last;
>                 }
>                 while (n)
>                 {
>                     *--last = "0123456789abcdef"[n & 0xf];
>                     n >>= 4;
>                 }
>                 return last;
>             }
>         public:
>             operator boost::asio::const_buffer() const
>             {
>                 return {
>                     buf_ + sizeof(buf_) - buf_[0],
>                     static_cast(buf_[0])
>                 };
>             }
>         };

>         using const_iterator = value_type const*;

>         chunk_size(chunk_size const& other) = default;

>         /** Construct a chunk header

>             @param n The number of octets in this chunk.
>         */
>         chunk_size(std::size_t n)
>         {
>             value_.prepare(n);
>         }

>         const_iterator begin() const
>         {
>             return &value_;
>         }

>         const_iterator end() const
>         {
>             return begin() + 1;
>         }

>     private:
>         value_type value_;
>     };

Proposed resolution:

This wording is relative to N4588.

1. Modify 16.2.2 [networking.ts::buffer.reqmts.constbuffersequence] Table 13 "`ConstBufferSequence` requirements" as indicated:

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

### 3027(i). [networking.ts] `DynamicBuffer` `prepare` exception specification

Section: 16.2.4 [networking.ts::buffer.reqmts.dynamicbuffer] Status: New Submitter: Vinnie Falco Opened: 2017-10-16 Last modified: 2020-09-06

Priority: 3

View other active issues in [networking.ts::buffer.reqmts.dynamicbuffer].

View all other issues in [networking.ts::buffer.reqmts.dynamicbuffer].

View all issues with New status.

Discussion:

Addresses: networking.ts

The current wording for the `DynamicBuffer` `prepare` member function implies that `std::length_error` is the only allowable thrown exception. This should be changed to reflect that any exception may be thrown, with `std::length_error` thrown in particular when `size() + n` exceeds `max_size()`.

[2017-11-08]

Priority set to 3 after five votes on mailing list

Proposed resolution:

This wording is relative to N4588.

1. Change 16.2.4 [networking.ts::buffer.reqmts.dynamicbuffer], Table 14 "DynamicBuffer requirements", as indicated:

   > Table 14 — `DynamicBuffer` requirements
   > expression | return type | assertion/note pre/post-condition
   > --- | --- | ---
   > `[…]`
   > `x.prepare(n)` | `X::mutable_buffers_type` | Returns a mutable buffer sequence `u` representing the writable bytes, and where `buffer_size(u) == n` . The dynamic buffer reallocates memory as required. All constant or mutable buffer sequences previously obtained using `data()` or `prepare()` are invalidated. Throws: `length_error` if `size() + n` exceeds `max_size()` or any other exception if the request cannot otherwise be satisfied.

### 3028(i). Container requirements tables should distinguish `const` and non-`const` variables

Section: 22.2.1 [container.requirements.general] Status: New Submitter: Jonathan Wakely Opened: 2017-10-17 Last modified: 2020-09-06

Priority: 3

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

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

View all issues with New status.

Discussion:

[container.requirements.general] p4 says:

> In Tables 83, 84, and 85 `X` denotes a container class containing objects of type `T`, `a` and `b` denote values of type `X`, `u` denotes an identifier, `r` denotes a non-`const` value of type `X`, and `rv` denotes a non-`const` rvalue of type `X`.

This doesn't say anything about whether `a` and `b` are allowed to be `const`, or must be non-`const`. In fact Table 83 uses them inconsistently, e.g. the rows for "`a = rv`" and "`a.swap(b)`" most certainly require them to be non-`const`, but all other uses are valid for either `const` or non-`const X`.

[2017-11 Albuquerque Wednesday night issues processing]

Priority set to 3; Jonathan to provide updated wording.

Wording needs adjustment - could use "possibly const values of type X"

Will distinguish between lvalue/rvalue

Previous resolution [SUPERSEDED]:

> This wording is relative to N4687.

> 1. Change 22.2.1 [container.requirements.general] p4 as indicated:

>    > -4- In Tables 83, 84, and 85 `X` denotes a container class containing objects of type `T`, `a` and `b` denote values of type `X`, `u` denotes an identifier, `r` and s denotes a non-`const` values of type `X`, and `rv` denotes a non-`const` rvalue of type `X`.

> 2. Change 22.2.1 [container.requirements.general], Table 83 "Container requirements", as indicated:

>    > Table 83 — Container requirements
>    > Expression | Return type | Operational semantics | Assertion/note pre/post-condition | Complexity
>    > --- | --- | --- | --- | ---
>    > `[…]`
>    > `ar = rv` | `X&` | All existing elements of `ar` are either move assigned to or destroyed | `ar` shall be equal to the value that `rv` had before this assignment | linear
>    > `[…]`
>    > `ar.swap(bs)` | `void` |  | exchanges the contents of `ar` and `bs` | (Note A)
>    > `[…]`
>    > `swap(ar, bs)` | `void` | `ar.swap(bs)` |  | (Note A)

[2020-05-03; Daniel provides alternative wording]

Proposed resolution:

This wording is relative to N4861.

1. Change 22.2.1 [container.requirements.general] as indicated:

   > [Drafting note:

   > - The following presentation also transforms the current list into a bullet list as we already have in 22.2.7 [unord.req] p11

   > - It has been decided to replace the symbol `r` by `s`, because it is easy to confuse with `rv` but means an lvalue instead, and the other container tables use it rarely and for something completely different (iterator value)

   > - A separate symbol `v` is introduced to unambigiously distinguish the counterpart of a non-`const` rvalue (See 16.4.4.2 [utility.arg.requirements])

   > - Two separate symbols `b` and `c` represent now "(possibly `const`) values, while the existing symbol `a` represents an unspecified value, whose meaning becomes defined when context is provided, e.g. for overloads like `begin()` and `end`

   > -4- In Tables 73, 74, and 75:

   > 1. (4.1) — `X` denotes a container class containing objects of type `T`,

   > 2. (4.2) — `a` and `b` denotes a values of type `X`,

   > 3. (4.2) — `b` and `c` denote (possibly `const`) values of type `X`,

   > 4. (4.3) — `i` and `j` denote values of type (possibly `const`) `X::iterator`,

   > 5. (4.4) — `u` denotes an identifier,

   > 6. (?.?) — `v` denotes an lvalue of type (possibly `const`) `X` or an rvalue of type `const X`,

   > 7. (4.5) — `r` `s` and `t` denotes a non-`const` value lvalues of type `X`, and

   > 8. (4.6) — `rv` denotes a non-`const` rvalue of type `X`.

2. Change 22.2.1 [container.requirements.general], Table 73 "Container requirements" [tab:container.req], as indicated:

   > [Drafting note: The following presentation also moves the copy-assignment expression just before the move-assignment expression]

   > Table 73: — Container requirements [tab:container.req]
   > Expression | Return type | Operational semantics | Assertion/note pre/post-condition | Complexity
   > --- | --- | --- | --- | ---
   > `[…]`
   > `X(av)` |  |  | Preconditions: `T` is Cpp17CopyInsertable into `X` (see below). Postconditions: `av == X(av)`. | linear
   > `X u(av); X u = av;` |  |  | Preconditions: `T` is Cpp17CopyInsertable into `X` (see below). Postconditions: `u == av`. | linear
   > `X u(rv); X u = rv;` |  |  | Postconditions: `u` is equal to the value that `rv` had before this construction | (Note B)
   > `t = v` | `X&` |  | Postconditions: `t == v`. | linear
   > `at = rv` | `X&` | All existing elements of `at` are either move assigned to or destroyed | `at` shall be equal to the value that `rv` had before this assignment | linear
   > `[…]`
   > `ac == b` | convertible to `bool` | `==` is an equivalence relation. `equal(ac.begin(), ac.end(), b.begin(), b.end())` | Preconditions: `T` meets the Cpp17EqualityComparable requirements | Constant if `ac.size() != b.size()`, linear otherwise
   > `ac != b` | convertible to `bool` | Equivalent to `!(ac == b)` |  | linear
   > `at.swap(bs)` | `void` |  | exchanges the contents of `at` and `bs` | (Note A)
   > `swap(at, bs)` | `void` | `at.swap(bs)` |  | (Note A)
   > `r = a` | `X&` |  | Postconditions: `r == a`. | linear
   > `ac.size()` | `size_type` | `distance(ac.begin(), ac.end())` |  | constant
   > `ac.max_size()` | `size_type` | `distance(begin(), end())` for the largest possible container |  | constant
   > `ac.empty()` | convertible to `bool` | `ac.begin() == ac.end()` |  | constant

### 3029(i). `pop_heap` over-constrains input

Section: 25.8.8.3 [pop.heap] Status: Open Submitter: Mathias Stearn Opened: 2017-11-04 Last modified: 2020-09-06

Priority: 3

View all issues with Open status.

Discussion:

The spec for `<algorithms>` `pop_heap` includes

> -1- Requires: The range `[first, last)` shall be a valid non-empty heap.

This has the unfortunate consequence that to pop a value and push a new value is substantially less efficient than necessary. The popped value must be extracted by `pop_heap` (using up to 2 log `N` compares and swaps), and then, in `push_heap`, the new value must be inserted (for up to `N` compares and swaps, but more usually something like log `N`).

Simply relaxing the requirement to

> -1- Requires: The range `[first, last - 1)` shall be a valid heap.

enables use of `pop_heap` in an integrated push-and-pop operation, with less than half the number of expected compare and swap operations. Furthermore, if, as is often the case, the newly pushed value would have ended up at position `first`, the push/pop operation could complete in time `𝒪(1)`, instead of (3 log `N`).

The effect of the proposed relaxation on existing library implementations would be minimal in the extreme, and on existing user code nil. The base algorithm code remains exactly identical. The only changes needed would be to any instrumentation in a debugging version of the library, which would just need to relax its check, and to test suites that should exercise the newly tolerated input.

Users today are tempted to get the improved performance by relying on existing implementations' tacit tolerance of input that only satisfies the proposed, relaxed requirements. In fact, the cppreference.com page on `pop_heap` offers no hint that this usage is not already allowed. This change would bless such reliance as formally permitted.

After this change, minor extensions to `std::priority_queue` would enable it to take advantage of the newly efficient operation, perhaps:

>     void pop_push(const Type&);
>     void pop_push(Type&&);
>     template <class... Args> void pop_emplace(Args&&... args);

These will appear in a formal proposal if the resolution is accepted.

[2017-11 Albuquerque Wednesday night issues processing]

Priority set to 3

[2017-11 Albuquerque Saturday issues processing]

status to Open; Marshall to review

Proposed resolution:

This wording is relative to N4700.

1. Change 25.8.8.3 [pop.heap] as indicated:

   >     template<class RandomAccessIterator>
   >       void pop_heap(RandomAccessIterator first, RandomAccessIterator last);
   >     template<class RandomAccessIterator, class Compare>
   >       void pop_heap(RandomAccessIterator first, RandomAccessIterator last,
   >                     Compare comp);

   > > -1- Requires: The range `[first, last - 1)` shall be a valid non-empty heap. `RandomAccessIterator` shall satisfy the requirements of `ValueSwappable` (16.4.4.3 [swappable.requirements]). The type of `*first` shall satisfy the requirements of `MoveConstructible` (Table 23) and of `MoveAssignable` (Table 25).

### 3032(i). `ValueSwappable` requirement missing for `push_heap` and `make_heap`

Section: 25.8.8 [alg.heap.operations] Status: New Submitter: Robert Douglas Opened: 2017-11-08 Last modified: 2020-09-06

Priority: 3

View all other issues in [alg.heap.operations].

View all issues with New status.

Discussion:

In discussion of D0202R3 in Albuquerque, it was observed that `pop_heap` and `sort_heap` had `constexpr` removed for their requirement of `ValueSwappable`. It was then observed that `push_heap` and `make_heap` were not similarly marked as having the `ValueSwappable` requirement. The room believed this was likely a specification error, and asked to open an issue to track it.

[2017-11 Albuquerque Wednesday night issues processing]

Priority set to 3; Marshall to investigate

Proposed resolution:

This wording is relative to N4700.

1. Change 25.8.8.2 [push.heap] as indicated:

   >     template<class RandomAccessIterator>
   >       void push_heap(RandomAccessIterator first, RandomAccessIterator last);
   >     template<class RandomAccessIterator, class Compare>
   >       void push_heap(RandomAccessIterator first, RandomAccessIterator last,
   >                      Compare comp);

   > > -1- Requires: The range `[first, last - 1)` shall be a valid heap. `RandomAccessIterator` shall satisfy the requirements of `ValueSwappable` (16.4.4.3 [swappable.requirements]). The type of `*first` shall satisfy the `MoveConstructible` requirements (Table 23) and the `MoveAssignable` requirements (Table 25).

2. Change 25.8.8.4 [make.heap] as indicated:

   >     template<class RandomAccessIterator>
   >       void make_heap(RandomAccessIterator first, RandomAccessIterator last);
   >     template<class RandomAccessIterator, class Compare>
   >       void make_heap(RandomAccessIterator first, RandomAccessIterator last,
   >                      Compare comp);

   > > -1- Requires: `RandomAccessIterator` shall satisfy the requirements of `ValueSwappable` (16.4.4.3 [swappable.requirements]). The type of `*first` shall satisfy the `MoveConstructible` requirements (Table 23) and the `MoveAssignable` requirements (Table 25).

### 3044(i). Strange specification of `max_size()` for an allocator

Section: 16.4.4.6 [allocator.requirements] Status: New Submitter: Jon Cohen Opened: 2017-12-06 Last modified: 2018-08-21

Priority: 3

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with New status.

Discussion:

Table 31 in the C++17 standard specifies `X::max_size()` (where `X` is an allocator type) as "The largest value that can meaningfully be passed to `X::allocate()`". Noticeably missing is the statement "Throws: Nothing".

As an example of why this is an issue, note that `vector::max_size()` and `allocator_traits::max_size()` are both marked `noexcept`. We must then interpret `max_size()` as being allowed to sometimes call `std::terminate`, or else `{vector, allocator_traits, ...}::max_size()` must be allowed to directly calculate `numeric_limits<size_type>::max() / sizeof(value_type)` instead of querying the allocator, even if `Alloc::max_size()` exists. This seems like a bug in the wording for the requirements of `max_size()` in an allocator type. I think an issue should be opened on this subject to add Throws: Nothing or similar to the requirements of `max_size()` for an allocator.

As an example consider writing up a framework to test the exception-safety of types in a given framework, since they were all written in an exception-free environment. One of the types in the framework is an allocator which, in a controlled way, can throw an exception at any point where it is allowed by the standard. It's important that the test framework be as pedantic as possible, so the allocator type throws on `max_size()`, since it is currently allowed to by the standard. When a reasonable `vector` implementation (at least those in libstdc++ and msvc) is, for example, asked to construct a `vector` from an `initializer_list`, it will call `allocator_traits<Alloc>::max_size()`, which will terminate the program because the exception thrown in `Alloc::max_size()` propagated through the `noexcept` traits function. Although this is conformant behavior, I think it's a bug in the standard that a function as benign as `max_size()` can terminate the program in this manner, and I think the fix is that a conformant allocator should be required to supply a non-throwing `max_size()` member function.

Daniel:

This problem was shortly discussed during review of LWG 2162 (see comment 2012-08-05). At that time the more drastic but also more consistent requirement that an allocator's `max_size` function shall not throw exceptions has not been added. IMO this position should be reconsidered to follow the spirit of the new issue LWG 3044.

[2018-01; Priority set to 3 after mailing list discussion]

[2018-08-21, Jonathan comments and provides wording]

The phrase "the largest value that can meaningfully be passed to `X::allocate()`" is meaningless. Is it a requirement on the caller, so that larger values must not be passed? Or a hint from the allocator implementor that larger values will produce a `bad_alloc exception`? Can the return value change dynamically, based on the free memory available to the allocator?! — LWG 197 says it can't change.

As noted in the LWG 2162 comments, we don't currently guarantee it can be called on a `const` object (so `allocator_traits` will not use the allocator's `max_size()` if it's non-`const`, although that was unclear before DR 2284). In addition to adding "Throws: nothing" we should ensure it's callable on `const` lvalues, and clarify what "meaningfully" means and who is supposed to care about it. My proposed resolution doesn't achieve all of this, but is a start.

Proposed resolution:

This wording is relative to N4762.

1. Change 16.4.4.6 [allocator.requirements], Table 32 — "Descriptive variable definitions", as indicated:

   > Table 32 — Descriptive variable definitions
   > Variable | Definition
   > --- | ---
   > `T, U, C` | any cv-unqualified object type (3.9)
   > `…`
   > `a, a1, a2` | lvalues of type `X`
   > `a3` | an lvalue of type `const X`
   > `…`

2. Change 16.4.4.6 [allocator.requirements], Table 33 — "Cpp17Allocator requirements", as indicated:

   > Table 33 — Cpp17Allocator requirements
   > Expression | Return type | Assertion/note pre-/post-condition | Default
   > --- | --- | --- | ---
   > `…`
   > `a3.max_size()` | `X::size_type` | the largest value that can meaningfully be passed to `X::allocate()`. [Note: Larger values might cause an exception to be thrown. — end note] Throws: Nothing. | `numeric_limits<size_type>::max() / sizeof(value_type)`
   > `…`

### 3046(i). Do not require `reference_wrapper` to support non-referenceable function types

Section: 20.14.6 [refwrap] Status: New Submitter: Jonathan Wakely Opened: 2017-12-14 Last modified: 2020-09-06

Priority: 3

View all other issues in [refwrap].

View all issues with New status.

Discussion:

[refwrap] says that `reference_wrapper<T>` is a "wrapper around a reference to an object or function of type `T`" but this doesn't actually constrain it, and doesn't forbid non-referenceable function types like `int() const`.

There is no way to construct a `reference_wrapper<int() const>` but implementations are required to provide partial specializations for functions with cv-qualifiers and ref-qualifiers in order to define a nested `result_type`. It should be undefined to instantiate `reference_wrapper<T>` with a non-referenceable type, or with a reference type (since references to references are not possible). Making it undefined (rather than ill-formed or unspecified) means implementations are not required to diagnose such invalid specializations, but also don't have to go to the effort of supporting weak result types etc.

[2018-01; Priority set to 3 after mailing list discussion]

Previous resolution [SUPERSEDED]:

> This wording is relative to N4713.

> 1. Modify 20.14.6 [refwrap] as indicated:

>    > -1- `reference_wrapper<T>` is a `CopyConstructible` and `CopyAssignable` wrapper around a reference to an object or function of type `T`. `T` shall be a referenceable type (3.45 [defns.referenceable]) that is not a reference type.

>    > -2- `reference_wrapper<T>` shall be a trivially copyable type (6.8 [basic.types]).

[2019-03-15; Daniel comments and provides revised wording]

The current wording is now far behind the working draft and a synchronization is therefore recommended. In particular, with the acceptance of P0357R1, the specification of `reference_wrapper` has no longer any weak result type. Second, I would like to concur with a remark from Tomasz to change the wording to replace the undefined behavior by an ill-formed program instead, because every attempt to instantiate the definition of `reference_wrapper` will instantiate its member declarations, and this would cause the program to become ill-formed anyway because of the illegal formation of references to non-referenceable function types for member functions such as `T& get() const noexcept`.

As concrete wording suggestion I would recommend wording that ensures that an ill-formed program is only required when a specialization of `reference_wrapper` is instantiated, because in the absence of a constrained template parameter we shouldn't require implementations to diagnose even forming the name of a `reference_wrapper` specialization such as in the following example:

>     using X = reference_wrapper<int() const>;

The wording below does not take advantage of a Mandates: element to prevent a dependency on LWG 3193 and because such an element is rarely used to specify class templates. If the committee wishes to use such an element, the equivalent wording would be:

> Mandates: `reference_wrapper` is instantiated with a referenceable type (3.45 [defns.referenceable]) as the argument for the template parameter `T`.

Proposed resolution:

This wording is relative to N4800.

1. Modify 20.14.6 [refwrap] as indicated:

   > -1- `reference_wrapper<T>` is a Cpp17CopyConstructible and Cpp17CopyAssignable wrapper around a reference to an object or function of type `T`. If `reference_wrapper` is instantiated with a non-referenceable type (3.45 [defns.referenceable]) as the argument for the template parameter `T`, the program is ill-formed.

   > -2- `reference_wrapper<T>` is a trivially copyable type (6.8 [basic.types]).

   > -3- The template parameter `T` of `reference_wrapper` may be an incomplete type.

### 3047(i). `atomic` compound assignment operators can cause undefined behavior when corresponding `fetch_meow` members don't

Section: 31.8.3 [atomics.types.int], 31.8.5 [atomics.types.pointer], 31.8.6 [atomics.types.memop] Status: New Submitter: Tim Song Opened: 2017-12-15 Last modified: 2020-09-06

Priority: 3

View all issues with New status.

Discussion:

Given `atomic<int> meow{INT_MAX};`, `meow.fetch_add(1)` has well-defined behavior because 31.8.3 [atomics.types.int] p7 says that

> Remarks: For signed integer types, arithmetic is defined to use two's complement representation. There are no undefined results.

but `meow += 1` and `++meow` have undefined behavior, because these operator functions are defined (by, respectively, 31.8.3 [atomics.types.int] p8 and 31.8.6 [atomics.types.memop]) to be equivalent to `return fetch_add(1) + 1;`, and so the addition of 1 to the result of `fetch_add` — which causes an integer overflow in this case — occurs outside the protection of `fetch_add` magic. Additionally, the return value might differ from what `fetch_add` actually wrote since that addition isn't required to use two's complement. This seems like a trap for the unwary. Is it intended?

A similar issue affects the `atomic<T*>` partial specialization for pointers.

[2018-01; Priority set to 3 after mailing list discussion]

[2019-04-15; JF Bastien comments and provides wording]

As discussed by LWG during the San Diego 2018 meeting, Jens removed LWG 3047 from "P1236R1: Alternative Wording for P 0907R4 Signed Integers are Two's Complement".

Proposed resolution:

This wording is relative to N4810.

1. Modify 31.7.3 [atomics.ref.int] as indicated:

   >     integral operator op=(integral operand) const noexcept;

   > > -7- Effects: Equivalent to: `return static_cast<integral>(static_cast<make_unsigned_t<integral>>(fetch_key(operand)) op static_cast<make_unsigned_t<integral>>(operand));`

2. Modify 31.7.6 [atomics.ref.memop] as indicated:

   >     T* operator++() const noexcept;

   > > -3- Effects: Equivalent to: `return static_cast<T>(static_cast<make_unsigned_t<T>>(fetch_add(1)) + static_cast<make_unsigned_t<T>>(1));`

   >     T* operator--(int) const noexcept;

   > > -4- Effects: Equivalent to: `return static_cast<T>(static_cast<make_unsigned_t<T>>(fetch_sub(1)) - static_cast<make_unsigned_t<T>>(1));`

3. Modify 31.8.3 [atomics.types.int] as indicated:

   >     T operator op=(T operand) volatile noexcept;
   >     T operator op=(T operand) noexcept;

   > > -8- Effects: Equivalent to: `return static_cast<T>(static_cast<make_unsigned_t<T>>(fetch_key(operand)) op static_cast<make_unsigned_t<T>>(operand));`

   > [Drafting note: `atomic<integral>`'s working for `operator++/operator--` is shared with `atomic<T*>`. — end drafting note]

   > [Drafting note: `atomic<floating-point>` seems to be correct, LWG should confirm that it is. — end drafting note]

4. Modify 31.8.5 [atomics.types.pointer] as indicated:

   >     T* operator op=(ptrdiff_t operand) volatile noexcept;
   >     T* operator op=(ptrdiff_t operand) noexcept;

   > > -8- Effects: Equivalent to: `return reinterpret_cast<T*>(reinterpret_cast<ptrdiff_t>(fetch_key(operand)) op operand);`

   > > Remarks: The result may be an undefined address, but the operations otherwise have no undefined behavior.

5. Modify 31.8.6 [atomics.types.memop] as indicated:

   >     T operator++() volatile noexcept;
   >     T operator++() noexcept;

   > > -3- Effects: Equivalent to: `return static_cast<T>(static_cast<make_unsigned_t<T>>(fetch_add(1)) + static_cast<make_unsigned_t<T>>(1));`

   >     T operator--() volatile noexcept;
   >     T operator--() noexcept;

   > > -4- Effects: Equivalent to: `return static_cast<T>(static_cast<make_unsigned_t<T>>(fetch_sub(1)) - static_cast<make_unsigned_t<T>>(1));`

   > [Drafting note: Alternatively, LWG may want to separate the integral overload of `operator++/operator--` from that of `atomic<T*>`. end drafting note]

### 3049(i). Missing wording allowing algorithms to use copies of function objects as substitutes for their parameters

Section: 25.2 [algorithms.requirements] Status: Open Submitter: Jared Hoberock Opened: 2017-12-04 Last modified: 2020-09-06

Priority: 3

View all other issues in [algorithms.requirements].

View all issues with Open status.

Discussion:

When designing the parallel algorithms library, we intended for parallel algorithms to copy their function objects parameters when it is possible and useful to do so, but there doesn't appear to be any wording to enable that latitude. To the contrary, algorithm specifications refer to their function object parameters by name, implying that a copy of the parameter may not be used as a substitute.

This was noticed when Billy O'Neal observed that parallel `generate()` did not share parallel `for_each()` and `for_each_n()`'s special requirement for a `CopyConstructible` user-provided function object.

This `CopyConstructible Function` requirement was added to relax legacy `for_each()`'s `MoveConstructible Function` requirement to allow parallel implementations to make copies as necessary. All parallel algorithms need similar permissions, but a strong requirement for `CopyConstructible` in all algorithms is too restrictive.

What we require is to allow algorithm implementations to use copies of function objects as substitutes for their original parameters, while not requiring that all function object parameters be copyable.

Casey Carter noted that 25.2 [algorithms.requirements] p8 grants permission to all algorithms to copy their function object parameters. However, this paragraph is not normative and does not indicate how the algorithm is allowed to use such copies. Additionally, it does not specify which algorithm parameters are the ones called out as function objects. For example, 25.7.7 [alg.generate] refers to `gen` as a function object, but 25.6.4 [alg.foreach] does not refer to `f` as a function object. All the other types of callable algorithm parameters (i.e. `Predicate`, `BinaryPredicate`, `Compare`, `UnaryOperation`, `BinaryOperation`, `BinaryOperation1`, and `BinaryOperation2`) are defined to be function objects in 25.2 [algorithms.requirements] and 25.3.2 [algorithms.parallel.user]. This list intentionally omits `Function` and `Generator` by design.

A potential resolution would introduce normative wording to explicitly allow algorithms to use copies of function object parameters as substitutes for their function object parameters, and remove ambiguity in algorithm specifications about which parameters are function objects.

[2018-01; Priority set to 3 after mailing list discussion]

[2018-3-14 Wednesday evening issues processing; move to Open]

We thought that the notes in [alg.foreach]/1 and /11 should be unwrapped as well. Bryce to work with Jared on updated wording.

Proposed resolution:

This wording is relative to N4713.

1. Modify 25.2 [algorithms.requirements] as indicated:

   > -8- [Note: Unless otherwise specified, algorithms that take function objects as arguments are permitted to copy those function objects freely. When an algorithm's specification requires the invocation of a function object parameter, such a copy may be invoked as a substitute for the original function object parameter. [Note: This implies that copyable user-supplied function objects should not rely on their identity. Programmers for whom object identity is important should consider using a wrapper class that points to a noncopied implementation object such as `reference_wrapper<T>` (20.14.6 [refwrap]), or some equivalent solution. — end note]

2. Modify 25.6.4 [alg.foreach] as indicated:

   >     template<class InputIterator, class Function>
   >       constexpr Function for_each(InputIterator first, InputIterator last, Function f);

   > > […]

   > > -2- Effects: Applies the function object `f` to the result of dereferencing every iterator in the range `[first, last)`, […]

   > > […]

   >     template<class ExecutionPolicy, class ForwardIterator, class Function>
   >       void for_each(ExecutionPolicy&& exec,
   >                     ForwardIterator first, ForwardIterator last,
   >                     Function f);

   > > -6- Requires: `Function` shall meet the requirements of `CopyConstructible`.

   > > -7- Effects: Applies the function object `f` to the result of dereferencing every iterator in the range `[first, last)`. […]

   > > […]

   >     template<class InputIterator, class Size, class Function>
   >     constexpr InputIterator for_each_n(InputIterator first, Size n, Function f);

   > > […]

   > > -13- Effects: Applies the function object `f` to the result of dereferencing every iterator in the range `[first, first + n)` in order. […]

   > > […]

   >     template<class ExecutionPolicy, class ForwardIterator, class Size, class Function>
   >       ForwardIterator for_each_n(ExecutionPolicy&& exec, ForwardIterator first, Size n,
   >                                  Function f);

   > > -16- Requires: `Function` shall meet the requirements of `CopyConstructible`.

   > > […]

   > > -18- Effects: Applies the function object `f` to the result of dereferencing every iterator in the range `[first, first + n).` […]

   > > […]

### 3053(i). Prohibit `error_code` construction from rvalues of `error_category`

Section: 19.5.4.1 [syserr.errcode.overview] Status: New Submitter: Antony Polukhin Opened: 2018-01-24 Last modified: 2020-09-06

Priority: 3

View all other issues in [syserr.errcode.overview].

View all issues with New status.

Discussion:

Constructor `error_code(int val, const error_category& cat)` and member function `void assign(int val, const error_category& cat)` could be misused if a custom `error_category` is provided:

>     error_code ec{1, test_category{}}; // ec holds a pointer/reference to a temporary

[2018-06-18 after reflector discussion]

Priority set to 3

Proposed resolution:

This wording is relative to N4713.

1. Modify 19.5.4.1 [syserr.errcode.overview] as indicated:

   >     namespace std {
   >       class error_code {
   >       public:
   >         // 19.5.4.2 [syserr.errcode.constructors], constructors
   >         […]
   >         error_code(int val, const error_category& cat) noexcept;
   >         error_code(int val, const error_category&& cat) = delete;
   >         […]
   >         // 19.5.4.3 [syserr.errcode.modifiers], modifiers
   >         void assign(int val, const error_category& cat) noexcept;
   >         void assign(int val, const error_category&& cat) = delete;
   >         […]
   >       };
   >       […]
   >     }

### 3056(i). `copy_file()` copies which attributes?

Section: 29.12.13.5 [fs.op.copy.file] Status: New Submitter: Davis Herring Opened: 2018-01-26 Last modified: 2020-09-06

Priority: 3

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

View all issues with New status.

Discussion:

(To resolve C++17 CD comment Late 25.) It is not stated which attributes are copied by `copy_file()`.

[2018-1-26 issues processing telecon]

Priority 3

Proposed resolution:

This wording is relative to N4713.

1. Modify 29.12.13.5 [fs.op.copy.file] as indicated:

   > Rationale:

   > The attributes specified are the useful subset of the attributes that can be queried in C++17. Existing practice is complicated: POSIX "cp -p" attempts to preserve user/group IDs, for instance, but cannot in general do so, and `setuid/setgid` permissions may be stripped.

   >     bool copy_file(const path& from, const path& to, copy_options options);
   >     bool copy_file(const path& from, const path& to, copy_options options,
   >                    error_code& ec) noexcept;

   > > […]

   > > 1. […]

   > > 2. (4.2) — Otherwise, copy the contents, permissions, and data modification time and attributes of the file `from` resolves to, to the file `to` resolves to, if:

   > > 3. […]

   > > 4. 1. (4.2.3) — `(options & copy_options::update_existing) != copy_options::none` and `from` is more recent than `to`, determined as if by use of the `last_write_time` function (29.12.13.26 [fs.op.last.write.time]).

   > >    Other implementation-defined attributes may be copied. Failure (or partial failure) to copy attributes is not an error.

   > > 5. […]

   > > […]

### 3057(i). Correct `copy_options` handling

Section: 29.12.13.4 [fs.op.copy] Status: Open Submitter: Davis Herring Opened: 2018-01-29 Last modified: 2020-09-06

Priority: 2

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

View all issues with Open status.

Discussion:

(The resolution of #3 resolves part of C++17 NB comment US 36.)

The handling of several options for `filesystem::copy()` is wrong:

1. Single-level directory copying is silently suppressed by any flag other than `copy_options::recursive` (even `copy_options::directories_only`). Single-level directory copying operates via using some unspecified flag to trigger this misfeature.

2. `copy_options::create_symlinks` and `copy_options::skip_symlinks` affect the interpretation of the destination name; the latter shouldn't ever, and the former should affect only broken symlinks (since it would want to replace them).

3. The `copy_options` groups for existing target files and the form of copying are consulted only for creating regular files.

4. `copy("file", "dir")` creates dir/file, but `copy("symlink", "dir", copy_options::copy_symlinks)` fails.

5. If a symlink is encountered with `copy_options::copy_symlinks` and `copy_options::create_symlinks`, the latter flag is ignored (but its otherwise sensible restriction to absolute paths applies) rather than the former.

6. `copy_options::create_symlinks` without `copy_options::copy_symlinks` fails if it encounters a symlink. (This is particularly damaging for recursive operation.)

This issue, since it replaces so much text, also addresses two error-handling concerns in passing:

1. The significance of `equivalent(from, to)` failing is unspecified. (Ignoring such failures entirely would make dangerous those operations that replace the target with a link.)

2. Copying a directory involves several operations. When an `error_code` is being used, the process continues past errors and (because successful functions call `ec.clear()`) may suppress them.

This expands on the resolution for LWG 2681.

This also addresses the same issue as LWG 2682, but has a different result (based on the fact that the Example successfully copies directories to new, non-existent names).

[2018-06; Rapperswil Wednesday evening, discussing LWG 2682]

JW: can we use the words we are shipping already since two years?
BO: what we got is better than what we had before
no objection to moving to Ready
ACTION move to Ready
ACTION link LWG 2682 and LWG 3057 and set a priority 2 and look at 3057 in San Diego

[2018-11 San Diego Thursday night issue processing]

Need to gather implementation experience; revisit in Kona. Status to Open.

[2018-11-13; Billy O'Neal comments]

I (Billy O'Neal) prefer Davis' solution to LWG 3057, as I think the wording follows the meaning of the individual enum values more closely, and enables more scenarios to function correctly instead of reporting such cases as errors.

However, I don't want to adopt that wording as is because it requires my implementation to detect errors in places that force us to do a bunch of extra system calls, and I don't believe those specific ways error handling happens is relevant to what the copy API wants to do.

Ideally, the wording would be structured such that it said "here's a list of error conditions, if they happen we aren't going to tell you when exactly they are detected" and then listed the behavior irrespective of when errors happen. That way implementations can do the error checks when it makes sense according to what their system APIs report. For example, anything that requires symlink resolution is very expensive on my platform so I'd want to be able to defer anything related to status (rather than `symlink_status`) to after I've detected that there's actually a symlink (or junction) involved.

Proposed resolution:

This wording is relative to N4750.

1. Modify Table 115 — "Enum class `copy_options`" as indicated:

   > Option group controlling `copy` and `copy_file` function effects for existing target files
   > Constant | Meaning
   > […] | […]

2. Modify 29.12.13.4 [fs.op.copy] as indicated:

   > Rationale:

   > POSIX.1-2008 allows the implementation to create hard links "to" symbolic links, and provides `linkat()` to choose between the symlink and its target.

   > 29.12.13.4 [fs.op.copy]/4.9 is redundant given 29.12.5 [fs.err.report]/3.1.

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

   > > -3- Requires: At most one element from each option group (29.12.8.3 [fs.enum.copy.opts]) is set in `options`.

   > > -4- Effects: Before the first use of `f` and `t`:

   > > 1. (4.1) — If […]

   > > 2. […]

   > > 3. (4.10) — Otherwise, no effects.

   > > If each is needed below,

   > > >     auto linkf = (options & (copy_options::copy_symlinks |
   > > >                              copy_options::skip_symlinks)) != copy_options::none;
   > > >     auto f = linkf ? symlink_status(from) : status(from), t = status(to);
   > > >     auto to2 = !is_directory(f) && is_directory(t) ? to/from.filename() : to.
   > > >     bool linkt = (options & (copy_options::create_symlinks |
   > > >                              copy_options::create_hard_links)) != copy_options::none ||
   > > >                 is_symlink(f);
   > > >     auto t2 = linkt ? symlink_status(to2) : status(to2);

   > > > [Drafting note: `copy_options::create_symlinks` is intentionally omitted for linkf; it may simply have been a typo for `copy_options::copy_symlinks` (which was added by LWG 2681) since at least N3940.]

   > > Effects are then as follows:

   > > 1. (?.?) — If `f.type()` or `t.type()` is an implementation-defined file type [fs.enum.file_type], then the effects are implementation-defined.

   > >    > [Drafting note: the text between the previous drafting note and this one is the only unchanged text under /4.]

   > > 2. (?.?) — Otherwise, if `exists(f)` is `false`, report an error as specified in 29.12.5 [fs.err.report].

   > > 3. (?.?) — Otherwise, do nothing if

   > >    1. (?.?.?) — `(options & copy_options::directories_only) != copy_options::none` and `is_directory(f)` is `false`, or

   > >    2. (?.?.?) — `(options & copy_options::skip_symlinks) != copy_options::none` and `is_symlink(f)` is `true`, or

   > >    3. (?.?.?) — `(options & copy_options::skip_existing) != copy_options::none` and `exists(t2)` is `true`.

   > > 4. (?.?) — Otherwise, report an error as specified in 29.12.5 [fs.err.report] if:

   > >    1. (?.?.?) — `is_other(f) || is_other(t2)` is `true`, or

   > >    2. (?.?.?) — `exists(t2) && exists(from) == exists(to2) && equivalent(from, to)` is `true`.

   > > 5. (?.?) — Otherwise, if `is_directory(f)` is `true`, then:

   > >    1. (?.?.?) — `create_directory(to, from)`.

   > >    2. (?.?.?) — If `(options & copy_options::recursive) != copy_options::none` or if `(options & copy_options::directories_only) == copy_options::none`, iterate over the files in `from`, as if by

   > >       >     for (const directory_entry& x : directory_iterator(from))
   > >       >       if ((options & copy_options::recursive) != copy_options::none ||
   > >       >          !is_directory(linkf ? symlink_status(x.path()) : status(x.path())))
   > >       >            copy(x.path(), to/x.path().filename(), options);

   > > 6. (?.?) — Otherwise, do nothing if `(options & copy_options::update_existing) != copy_options::none, exists(to2)` is `true`, and `from` is not more recent than `to2`, determined as if by use of the `last_write_time` function ( [fs.op.last_write_time]).

   > > 7. (?.?) — Otherwise, report an error as specified in 29.12.5 [fs.err.report] if:

   > >    1. (?.?.?) — `is_directory(t2)` is `true`, or

   > >    2. (?.?.?) — `(options & (copy_options::overwrite_existing | copy_options::update_existing)) == copy_options::none` and `exists(t2)` is `true`.

   > > 8. (?.?) — Otherwise, if `linkt` is `true`, then:

   > >    1. (?.?.?) — `remove(to2)` if an existing `to2` would prevent the following link creation.

   > >    2. (?.?.?) — If `(options & copy_options::create_symlinks) != copy_options::none`, `create_symlink(from, to2)`. [Note: If `from` is a symbolic link, it is not followed. — end note]

   > >    3. (?.?.?) — Otherwise, if `(options & copy_options::create_hard_links) != copy_options::none`, then create a hard link to `from`, if `linkf` is `true`, or else to the file that `from` resolves to. [Note: Not all file systems that support hard links and symbolic links support creating hard links to symbolic links. — end note]

   > >    4. (?.?.?) — Otherwise, `copy_symlink(from, to2)`.

   > > 9. (?.?) — Otherwise, `copy_file(from, to2, options)`.

   > > -5- Throws: As specified in 29.12.5 [fs.err.report].

   > > -6- Remarks: For the signature with argument `ec`, any library functions called by the implementation shall have an `error_code` argument if applicable. If any such function fails, `copy` returns immediately without (further) modifying `ec`.

### 3059(i). Wrong requirements for map-like associative container assignment?

Section: 22.2 [container.requirements] Status: New Submitter: Richard Smith Opened: 2018-02-05 Last modified: 2018-02-14

Priority: 3

View all other issues in [container.requirements].

View all issues with New status.

Discussion:

What are the requirements for

>     a = b;

... where `a` and `b` are of map-like associative container type (`map`, `multimap`, `unordered_map`, `unordered_multimap`)?

The general container requirements say just:

>     r = a  // Postconditions: r == a

(Incidentally, earlier in the table, there is a clear error: the general container requirements permit "`a = rv`" for assignment from an rvalue, but "`a`" here is a potentially-const container. Oops.) Oddly. there are no requirements at all on `T` here.

The allocator-aware container requirements add:

>     a = t  // Requires: T is CopyInsertable into X and CopyAssignable.

... where `T` is the container's `value_type`, that is, `pair<const key_type, mapped_type>`. Note that such a pair is not `CopyAssignable` for "normal" key types that disallow assignment to `const` objects. They also add:

>     a = rv  // Requires: if !POCMA, T is MoveInsertable into X and MoveAssignable.

... which has the same problem in the !POCMA case.

The associative container requirements and unordered associative container requirements have a similar problem for assignment from an initializer list:

>     a = il  // Requires: value_type is CopyInsertable into X and CopyAssignable.

Presumably these assignments are intended to actually work, but what are the intended constraints? Do we wish to allow implementations to perform node reuse for these map-like containers? Presumably yes, and if so, the `key_type` portion of the node must be assigned as well as the `value_type` portion (for instance, with whatever implementation technique is used to power `node_handle`) as we cannot assume that key equivalence (or, for `unordered_*map`, even key equality) implies substitutability.

I think, then, that the associative container requirements and unordered associative container requirements should specify different requirements for the "`a = t`", "`a = rv`", and "`a = il`" for the map-like containers; specifically:

- for "`a = t`" and "`a = il`", we should require that `value_type` is `CopyInsertable` into `X`, and `key_type` and `mapped_type` are `CopyAssignable`

- for "`a = rv`", if !POCMA, we should require that `value_type` is `MoveInsertable` into `X` and `key_type` and `mapped_type` are `MoveAssignable`

(And we should fix the general container requirements to constrain "`r = rv`", not "`a = rv`".)

Daniel:

The "`a = rv`" problematic is already handled by LWG 3028.

[2018-02-13, Priority set to 3 after mailing list discussion]

Proposed resolution:

### 3060(i). `XXX_scan` algorithms are specified to work with move-only `T`, but are specified to make `N` copies of `T` into the destination range

Section: 25.10.8 [exclusive.scan], 25.10.9 [inclusive.scan], 25.10.10 [transform.exclusive.scan], 25.10.11 [transform.inclusive.scan] Status: New Submitter: Billy O'Neal III Opened: 2018-02-06 Last modified: 2019-01-20

Priority: 2

View all other issues in [exclusive.scan].

View all issues with New status.

Discussion:

All of the scan algorithms ([exclusive.scan], [inclusive.scan], [transform.exclusive.scan], [transform.inclusive.scan]) have language like "If `init` is provided, `T` shall be `MoveConstructible` (Table 23); otherwise, `ForwardIterator1`'s value type shall be `MoveConstructible`.". However, the algorithms operational semantics require that that type be written "by copy" to the destination range, making support for move only types impossible.

We probably need to examine real implementations of these things and see what requirements are actually necessary, as in general `GENERALIZED_SUM` and `GENERALIZED_NONCOMMUTATIVE_SUM` need to specify the type used to store intermediate calculations.

[2019-01-20 Reflector prioritization]

Set Priority to 2

Proposed resolution:

### 3063(i). Parallel algorithms in `<memory>` are underspecified

Section: 25.11 [specialized.algorithms] Status: New Submitter: Alisdair Meredith Opened: 2018-02-12 Last modified: 2020-09-06

Priority: 3

View other active issues in [specialized.algorithms].

View all other issues in [specialized.algorithms].

View all issues with New status.

Discussion:

The parallel forms of the uninitialized memory algorithms in `<memory>` are underspecified in two ways. First, they missed the change that all parallel algorithms require at least Forward Iterators, even for input ranges. See P0467R2 for more details.

The second problem is that they do not have a separate specification to the serial forms. This is a problem in two ways. First, there is no more blanket wording saying a parallel policy algorithm has the same semantics as the serial form unless otherwise specified, so in principle these algorithms are totally unspecified. However, assuming that intent, all of the existing specifications use an as-if formulation with code that is explicitly serial in nature, so need a new specification that talks about the effects on each element without including the iteration order.

[2018-02-20, Priority set to 3 after mailing list discussion]

Proposed resolution:

### 3064(i). How do uninitialized memory algorithms obtain pointer without undefined behavior?

Section: 25.11 [specialized.algorithms] Status: New Submitter: Alisdair Meredith Opened: 2018-02-12 Last modified: 2020-05-02

Priority: 3

View other active issues in [specialized.algorithms].

View all other issues in [specialized.algorithms].

View all issues with New status.

Discussion:

A typical specification of the algorithms for initializing raw memory in `<memory>` looks like:

> Effects: Equivalent to:

> >     for (; first != last; ++first)
> >       ::new (static_cast<void*>(addressof(*first)))
> >         typename iterator_traits<ForwardIterator>::value_type;

However, this hides a nasty question:

How do we bind a reference to an uninitialized object when dereferencing our iterator, so that `static_cast<void*>(addressof(*first))` does not trigger undefined behavior on the call to `*first`?

When pointers are the only iterators we cared about, we could simply cast the iterator value to `void*` without dereferencing. I don't see how to implement this spec safely without introducing another customization point for iterators that performs the same function as casting a pointer to `void*` in order to get the address of the element.

[2018-02-20, Priority set to 3 after mailing list discussion]

Proposed resolution:

### 3066(i). "report a domain error" in [sf.cmath]/1 is underspecified

Section: 26.8.6 [sf.cmath] Status: New Submitter: Casey Carter Opened: 2018-02-17 Last modified: 2018-06-19

Priority: 3

View all issues with New status.

Discussion:

26.8.6 [sf.cmath]/1 uses the phrase "report a domain error" (emphasis mine):

> If any argument value to any of the functions specified in this subclause is a NaN (Not a Number), the function shall return a NaN but it shall not report a domain error. Otherwise, the function shall report a domain error for just those argument values for which:

> - the function description's Returns: clause explicitly specifies a domain and those argument values fall outside the specified domain, or

> - the corresponding mathematical function value has a nonzero imaginary component, or

> - the corresponding mathematical function is not mathematically defined.

The behavior this phrase is attempting to convey is unclear. A quick search through the text of the standard for "domain error" finds only the `domain_error` exception type defined in 19.2.4 [domain.error]. Is the intent of "report a domain error" that the special math functions throw an exception of type `domain_error`, or is it that they behave as specified in C11 7.12.1 "Treatment of error conditions" para 2 which defines the term "domain error"?

[2018-06-18 after reflector discussion]

Priority set to 3

Proposed resolution:

### 3068(i). Forbid assigning an rvalue `basic_string` to `basic_string_view`

Section: 21.4.3 [string.view.template] Status: Open Submitter: Antony Polukhin Opened: 2018-02-19 Last modified: 2020-09-06

Priority: 2

View other active issues in [string.view.template].

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

View all issues with Open status.

Discussion:

It is known that we cannot disable move construction of `basic_string_view` from rvalues of `basic_string`, because it breaks a valid use case:

>     string foo();
>     void bar(string_view );
>     bar(foo());

Though it is still possible to disable an absolutely wrong case of assigning an rvalue `basic_string` to `basic_string_view`:

>     string_view sw = "Hello";
>     sw = foo();

Some tests that make sure that other use cases are not affected are available here

[2018-06-18 after reflector discussion]

Priority set to 2; status to LEWG

[2020-05-28; LEWG issue reviewing]

LEWG issue processing voted to reject 3068 as NAD. Status change to Open.

>     SF F N A SA
>     15 5 1 0 0

Proposed resolution:

This wording is relative to N4727.

1. Change 21.4.3 [string.view.template], class template `basic_string_view` synopsis, as indicated:

   >     […]
   >     // 21.4.3.2 [string.view.cons], construction and assignment
   >     constexpr basic_string_view() noexcept;
   >     constexpr basic_string_view(const basic_string_view&) noexcept = default;
   >     constexpr basic_string_view& operator=(const basic_string_view&) noexcept = default;
   >     template <class A>
   >     basic_string_view& operator=(const basic_string<charT, traits, A>&&) = delete;
   >     constexpr basic_string_view(const charT* str);
   >     constexpr basic_string_view(const charT* str, size_type len);
   >     […]

### 3069(i). Move assigning `variant`'s subobject corrupts data

Section: 20.7.3.4 [variant.assign] Status: New Submitter: Antony Polukhin Opened: 2018-02-20 Last modified: 2020-09-06

Priority: 3

View all other issues in [variant.assign].

View all issues with New status.

Discussion:

`variant::emplace` functions in 20.7.3.5 [variant.mod] destroy the currently contained value before initializing it to a new value. Assignments in 20.7.3.4 [variant.assign] are described in terms on `emplace`.

This leads to situation, when move/copy assigning subobject from `variant` into the same `variant` corrupts data:

>     #include <variant>
>     #include <memory>
>     #include <iostream>

>     using str_t = std::string;
>     using str_ptr_t = std::unique_ptr<str_t>;
>     using var_t = std::variant<str_t, str_ptr_t>;

>     int main()
>     {
>       var_t v = str_ptr_t{
>         new str_t{"Long string that does not fit into SS buffer and forces dynamic allocation"}
>       };

>       // Any of the following lines corrupt the variant's content:
>       v = *std::get<str_ptr_t>(v);
>       //v = std::move(*std::get<str_ptr_t>(v));

>       std::cout << std::get<str_t>(v) << std::endl; // SEGV - 'str_t' inside 'v' is invalid
>     }

Such behavior confuses users, especially those users who are used to `boost::variant`'s behavior. Consider making `variant` assignments safer by defining them close to copy-and-swap.

[2018-06-18 after reflector discussion]

Priority set to 3; Antony volunteered to write a paper for Rapperswil.

Proposed resolution:

This wording is relative to N4727.

1. Change 20.7.3.4 [variant.assign] as indicated:

   >     variant& operator=(const variant& rhs);

   > > -1- Let `j` be `rhs.index()`.

   > > -2- Effects:

   > > 1. (2.1) — If neither `*this` nor `rhs` holds a value, there is no effect.

   > > 2. (2.2) — Otherwise, if `*this` holds a value but `rhs` does not, destroys the value contained in `*this` and sets `*this` to not hold a value.

   > > 3. (2.3) — Otherwise, if `index() == j`, assigns the value contained in `rhs` to the value contained in `*this`.

   > > 4. (2.4) — Otherwise, if either `is_nothrow_copy_constructible_v<Tj>` is `true` or `is_nothrow_move_constructible_v<Tj>` is `false`, equivalent to `emplace<j>(get<j>(rhs))`.

   > > 5. (2.5) — Otherwise, equivalent to `emplace<j>(Tj{get<j>(rhs)})``operator=(variant(rhs))`.

   > > […]

   >     variant& operator=(variant&& rhs) noexcept(see below);

   > > -6- Let `j` be `rhs.index()`.

   > > -7- Effects:

   > > 1. (7.1) — If neither `*this` nor `rhs` holds a value, there is no effect.

   > > 2. (7.2) — Otherwise, if `*this` holds a value but `rhs` does not, destroys the value contained in `*this` and sets `*this` to not hold a value.

   > > 3. (7.3) — Otherwise, if `index() == j`, assigns `get<j>(std::move(rhs))` to the value contained in `*this`.

   > > 4. (7.4) — Otherwise, equivalent to `emplace<j>(Tj{get<j>(std::move(rhs))})`.

   > > […]

   > > -10- Let `Tj` be a type that is determined as follows: build an imaginary function `FUN(Ti)` for each alternative type `Ti`. The overload `FUN(Tj)` selected by overload resolution for the expression `FUN(std::forward<T>(t))` defines the alternative `Tj` which is the type of the contained value after assignment.

   > > -11- Effects:

   > > 1. (11.1) — If `*this` holds a `Tj`, assigns `std::forward<T>(t)` to the value contained in `*this`.

   > > 2. (11.2) — Otherwise, if `is_nothrow_constructible_v<Tj, T> || !is_nothrow_move_constructible_v<Tj>` is `true`, equivalent to `emplace<j>(std::forward<T>(t))`.

   > > 3. (11.3) — Otherwise, equivalent to `emplace<j>(Tj{std::forward<T>(t)})operator=(variant(std::forward<T>(t)))`.

   > > […]

### 3072(i). [networking.ts] `DynamicBuffer` object lifetimes underspecified

Section: 16.2.4 [networking.ts::buffer.reqmts.dynamicbuffer], 17.6 [networking.ts::buffer.async.read], 17.8 [networking.ts::buffer.async.write], 17.10 [networking.ts::buffer.async.read.until] Status: New Submitter: Christopher Kohlhoff Opened: 2018-02-26 Last modified: 2020-09-06

Priority: 3

View other active issues in [networking.ts::buffer.reqmts.dynamicbuffer].

View all other issues in [networking.ts::buffer.reqmts.dynamicbuffer].

View all issues with New status.

Discussion:

Addresses: networking.ts

The `DynamicBuffer` overloads of `async_read` and `async_write`, and `async_read_until`, are underspecified with respect to the lifetime of the dynamic buffer argument `b`.

Asio's implementation (and the intended specification) performs `DECAY_COPY(b)` in the `async_read`, `async_write`, and `async_read_until` initiating functions. All operations performed on `b` are actually performed on that decay-copy, or on a move-constructed descendant of it. The copy is intended to refer to the same underlying storage and be otherwise interchangeable with the original in every way.

Most initiating functions' argument lifetimes are covered by [async.reqmts.async.lifetime]. As an rvalue reference it falls under the second bullet, which specifies that the object is copied (but doesn't say decay-copied).

The proposed resolution adds a postcondition for `DynamicBuffer` move construction, and specifies that `DECAY_COPY(b)` be used for each of these functions. The following two alternative resolutions may also be considered:

- Add an extra bullet to [async.reqmts.async.lifetime] to cover rvalue parameters (but specifically exclude CompletionTokens).

- Change the `DynamicBuffer` arguments to be by-value. (And also change the corresponding synchronous operations to be consistent.)

However, the proposed resolution below is presented as a change that minimizes the scope of the impact.

[2018-06-18 after reflector discussion]

Priority set to 3

Proposed resolution:

This wording is relative to N4711.

1. Edit 16.2.4 [networking.ts::buffer.reqmts.dynamicbuffer] as indicated:

   > -3- In Table 14, `x` denotes a value of type `X`, `x1` denotes a (possibly const) value of type `X`, and `mx1` denotes an xvalue of type `X`, `n` denotes a (possibly const) value of type `size_t`, and `u` denotes an identifier.

   > Table 14 — DynamicBuffer requirements
   > expression | type | assertion/note pre/post-conditions
   > --- | --- | ---
   > `X u(mx1);` |  | post: `u.size()` is equal to the prior value of `mx1.size()`. `u.max_size()` is equal to the prior value of `mx1.max_size()`. `u.capacity()` is equal to the prior value of `mx1.capacity()`. `u.data()` satisfies the ConstBufferSequence requirements (16.2.2 [buffer.reqmts.constbuffersequence]) as if copy constructed from the prior value of `mx1.data()`. All valid const or mutable buffer sequences that were previously obtained using `mx1.data()` or `mx1.prepare()` remain valid.

2. Edit 17.6 [networking.ts::buffer.async.read] as indicated:

   > -11- Let `bd` be the result of `DECAY_COPY(b)`. Data is placed into the dynamic buffer (16.2.4 [buffer.reqmts.dynamicbuffer]) object `bbd`. A mutable buffer sequence (16.2.1 [buffer.reqmts.mutablebuffersequence]) is obtained prior to each `read_some` call using `bd.prepare(N)`, where `N` is an unspecified value less than or equal to `bd.max_size() - bd.size()`. [Note: Implementations are encouraged to use `bd.capacity()` when determining `N`, to minimize the number of `read_some` calls performed on the stream. -- end note] After each `read_some` call, the implementation performs `bd.commit(n)`, where `n` is the return value from `read_some`.

   > […]

   > -13- The synchronous read operation continues until:

   > - `bd.size() == bd.max_size()`; or

   > - the completion condition returns `0`.

3. Edit 17.8 [networking.ts::buffer.async.write] as indicated:

   > -11- Let `bd` be the result of `DECAY_COPY(b)`. Data is written from the dynamic buffer (16.2.4 [buffer.reqmts.dynamicbuffer]) object `bd`. A constant buffer sequence (16.2.2 [buffer.reqmts.constbuffersequence]) is obtained using `bd.data()`. After the data has been written to the stream, the implementation performs `bd.consume(n)`, where `n` is the number of bytes successfully written.

   > […]

   > -13- The asynchronous write operation continues until:

   > - `bd.size() == 0`; or

   > - the completion condition returns `0`.

4. Edit 17.10 [networking.ts::buffer.async.read.until] as indicated:

   > -3- Effects: Let `bd` be the result of `DECAY_COPY(b)`. Initiates an asynchronous operation to read data from the buffer-oriented asynchronous read stream (17.1.2 [buffer.stream.reqmts.asyncreadstream]) object `stream` by performing zero or more asynchronous read_some operations on the stream, until the readable bytes of the dynamic buffer (16.2.4 [buffer.reqmts.dynamicbuffer]) object `bd` contain the specified delimiter `delim`.

   > -4- Data is placed into the dynamic buffer object `bd`. A mutable buffer sequence (16.2.1 [buffer.reqmts.mutablebuffersequence]) is obtained prior to each `async_read_some` call using `bd.prepare(N)`, where `N` is an unspecified value such that `N <= max_size() - size()`. [Note: Implementations are encouraged to use `bd.capacity()` when determining `N`, to minimize the number of asynchronous read_some operations performed on the stream. — end note] After the completion of each asynchronous `read_some` operation, the implementation performs `bd.commit(n)`, where `n` is the value passed to the asynchronous `read_some` operation's completion handler.

   > -5- The asynchronous `read_until` operation continues until:

   > - the readable bytes of `bd` contain the delimiter `delim`; or

   > - `bd.size() == bd.max_size()`; or

   > - an asynchronous `read_some` operation fails.

   > […]

   > -8- On completion of the asynchronous operation, if the readable bytes of `bd` contain the delimiter, `ec` is set such that `!ec` is `true`. Otherwise, if `bd.size() == bd.max_size()`, `ec` is set such that `ec == stream_errc::not_found`. If `bd.size() < bd.max_size()`, `ec` is the `error_code` from the most recent asynchronous `read_some` operation. `n` is the number of readable bytes in `bd` up to and including the delimiter, if present, otherwise `0`.

### 3073(i). [networking.ts] (`async_`)`read` and (`async_`)`write` don't support `DynamicBuffer` lvalues

Section: 17 [networking.ts::buffer.stream] Status: New Submitter: Christopher Kohlhoff Opened: 2018-02-27 Last modified: 2020-09-06

Priority: 3

View all issues with New status.

Discussion:

Addresses: networking.ts

Suppose that we have a user-defined class `dyn_buf` that satisfies the DynamicBuffer requirements ([buffer.reqmts.dynamicbuffer]), and is additionally copy-constructible. The following snippet compiles, as expected:

>     dyn_buf b;
>     net::read_until(my_socket, b, "\n");

However, this next snippet will not compile, when it should:

>     dyn_buf b;
>     net::read(my_socket, b);

This is due to:

- the `DynamicBuffer` template parameter being deduced as `dyn_buf&`, and
- the `read` overload being specified to not participate in overload resolution unless `is_dynamic_buffer_v<DynamicBuffer>` is `true`.

This can fixed by changing the test to `is_dynamic_buffer_v<decay_t<DynamicBuffer>>`.

[2019-01-20 Reflector prioritization]

Set Priority to 3

Proposed resolution:

This wording is relative to N4711.

1. Edit 17.5 [networking.ts::buffer.read] as indicated:

   > -14- Remarks: This function shall not participate in overload resolution unless `is_dynamic_buffer_v<decay_t<DynamicBuffer>>` is `true`.

2. Edit 17.6 [networking.ts::buffer.async.read] as indicated:

   > -16- Remarks: This function shall not participate in overload resolution unless `is_dynamic_buffer_v<decay_t<DynamicBuffer>>` is `true`.

3. Edit 17.7 [networking.ts::buffer.write] as indicated:

   > -14- Remarks: This function shall not participate in overload resolution unless `is_dynamic_buffer_v<decay_t<DynamicBuffer>>` is `true`.

4. Edit 17.8 [networking.ts::buffer.async.write] as indicated:

   > -16- Remarks: This function shall not participate in overload resolution unless `is_dynamic_buffer_v<decay_t<DynamicBuffer>>` is `true`.

### 3078(i). `directory_entry`, `directory_iterator` and `recursive_directory_iterator` perform needless path copies

Section: 29.12.10 [fs.class.directory.entry], 29.12.11 [fs.class.directory.iterator], 29.12.12 [fs.class.rec.dir.itr] Status: New Submitter: Gor Nishanov Opened: 2018-03-05 Last modified: 2019-04-02

Priority: 3

View all other issues in [fs.class.directory.entry].

View all issues with New status.

Discussion:

An implementation of `directory_entry` class is likely to store a `filesystem::path` as a member. Constructors and assign member functions take `filesystem::path` by `const&` thus forcing creation of a copy.

An implementation of `directory_iterator` class is likely to store a `directory_entry` or a `path` as a part of its state. Constructors take `filesystem::path` by `const&` thus forcing creation of a copy.

An implementation of `recursive_directory_iterator` class is likely to store a `directory_entry` or a `path` as a part of its state. Constructors take `filesystem::path` by `const&` thus forcing creation of a copy.

Suggested resolution:

Add overloads to `directory_entry`, `directory_iterator`, and `recursive_directory_iterator` that take `filesystem::path` by `&&`.

Make it unspecified in case an exception is thrown from those new members where an argument was moved from or not.

>     explicit directory_entry(const filesystem::path& p);
>     explicit directory_entry(filesystem::path&& p);
>     directory_entry(const filesystem::path& p, error_code& ec);
>     directory_entry(filesystem::path&& p, error_code& ec);

>     void directory_entry::assign(const filesystem::path& p);
>     void directory_entry::assign(filesystem::path&& p);
>     void directory_entry::assign(const filesystem::path& p, error_code& ec);
>     void directory_entry::assign(filesystem::path&& p, error_code& ec);

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

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

[2018-03-20 Priority set to 3 after discussion on the reflector.]

Proposed resolution:

### 3081(i). Floating point `from_chars` API does not distinguish between overflow and underflow

Section: 20.19.3 [charconv.from.chars] Status: Open Submitter: Greg Falcon Opened: 2018-03-12 Last modified: 2020-09-06

Priority: 2

View other active issues in [charconv.from.chars].

View all other issues in [charconv.from.chars].

View all issues with Open status.

Discussion:

`strtod()` distinguishes between overflow and underflow by returning a value that is either very large or very small. Floating point `from_chars` does not currently offer any way for callers to distinguish these two cases.

It would be beneficial if users could migrate from `strtod()` to `from_chars` without loss of functionality.

I recommend that floating point `from_chars` use `value` as an overflow-vs-underflow reporting channel, in the same manner as `strtod()`.

My proposed wording gives `from_chars` the same wide latitude that `strtod()` enjoys for handling underflow. A high-quality implementation would likely set `ec == result_out_of_range` for underflow only when the nearest representable `float` to the parsed value is a zero and the parsed mantissa was nonzero. In this case `value` would be set to (an appropriately-signed) zero. It is worth considering giving `from_chars` this more predictable behavior, if library writers feel they can provide this guarantee for all platforms. (I have a proof-of-concept integer-based implementation for IEEE doubles with this property.)

[2018-06 Rapperswil Wednesday issues processing]

Marshall to provide updated wording and propose Tentatively Ready on the reflector.

Priority set to 2

[2018-08-23 Batavia Issues processing]

Status to Open; Marshall to reword

Proposed resolution:

This wording is relative to N4727.

1. Edit 20.19.3 [charconv.from.chars] as indicated:

   > […] Otherwise, the characters matching the pattern are interpreted as a representation of a value of the type of `value`. The member `ptr` of the return value points to the first character not matching the pattern, or has the value `last` if all characters match. If the parsed value is not in the range representable by the type of `value`, `value` is unmodified and the member `ec` of the return value is equal to `errc::result_out_of_range`. Otherwise, `value` is set to the parsed value, after rounding according to `round_to_nearest` (17.3.4.1 [round.style]), and the member `ec` is value-initialized.

   >     from_chars_result from_chars(const char* first, const char* last,
   >                                  see below& value, int base = 10);

   > > -2- Requires: `base` has a value between 2 and 36 (inclusive).

   > > -3- Effects: The pattern is the expected form of the subject sequence in the `"C"` locale for the given nonzero base, as described for `strtol`, except that no `"0x"` or `"0X"` prefix shall appear if the value of `base` is 16, and except that `'-'` is the only sign that may appear, and only if `value` has a signed type. On overflow, `value` is unmodified.

   > > […]

   >     from_chars_result from_chars(const char* first, const char* last, float& value,
   >                                  chars_format fmt = chars_format::general);
   >     from_chars_result from_chars(const char* first, const char* last, double& value,
   >                                  chars_format fmt = chars_format::general);
   >     from_chars_result from_chars(const char* first, const char* last, long double& value,
   >                                  chars_format fmt = chars_format::general);

   > > -6- Requires: `fmt` has the value of one of the enumerators of `chars_format`.

   > > -7- Effects: The pattern is the expected form of the subject sequence in the `"C"` locale, as described for `strtod`, except that

   > > 1. (7.1) […]

   > > 2. (7.2) […]

   > > 3. (7.3) […]

   > > 4. (7.4) […]

   > > In any case, the resulting value is one of at most two floating-point values closest to the value of the string matching the pattern. On overflow, `value` is set to plus or minus `std::numeric_limits<T>::max()` of the appropriate type. On underflow, `value` is set to a value with magnitude no greater than `std::numeric_limits<T>::min()`.

   > > […]

### 3082(i). `from_chars` specification regarding floating point rounding is inconsistent

Section: 20.19.3 [charconv.from.chars] Status: Open Submitter: Greg Falcon Opened: 2018-03-12 Last modified: 2020-09-06

Priority: 2

View other active issues in [charconv.from.chars].

View all other issues in [charconv.from.chars].

View all issues with Open status.

Discussion:

P0682R1 added the requirement that `from_chars` use `round_to_nearest` when converting from string, but later text in the section suggests that the implementation has latitude in its choice of rounding logic.

If the intent is merely that the floating point environment should not affect `from_chars` behavior, the rounding-mode text should be weakened. If the intent is to always require `round_to_nearest`, the text suggesting a latitude in rounding logic should be removed.

[2018-03-27 Priority set to 2 after discussion on the reflector.]

[2018-06 Rapperswil Wednesday issues processing]

Status to open; also this needs to say that the intent is to be independent of the floating point environment.

[2018-08-23 Batavia Issues processing]

Marshall to talk to Jens about this

Proposed resolution:

This wording is relative to N4727.

1. Edit 20.19.3 [charconv.from.chars] as indicated:

   >     from_chars_result from_chars(const char* first, const char* last, float& value,
   >                                  chars_format fmt = chars_format::general);
   >     from_chars_result from_chars(const char* first, const char* last, double& value,
   >                                  chars_format fmt = chars_format::general);
   >     from_chars_result from_chars(const char* first, const char* last, long double& value,
   >                                  chars_format fmt = chars_format::general);

   > > -6- Requires: `fmt` has the value of one of the enumerators of `chars_format`.

   > > -7- Effects: The pattern is the expected form of the subject sequence in the `"C"` locale, as described for `strtod`, except that

   > > 1. (7.1) […]

   > > 2. (7.2) […]

   > > 3. (7.3) […]

   > > 4. (7.4) […]

   > > In any case, the resulting value is one of at most two the floating-point values closest to the value of the string matching the pattern, with ties broken according to `round_to_nearest`.

   > > […]

### 3084(i). Termination in C++ is unclear

Section: 17.5 [support.start.term], 17.9.5 [exception.terminate] Status: New Submitter: JF Bastien Opened: 2018-03-15 Last modified: 2018-04-03

Priority: 3

View other active issues in [support.start.term].

View all other issues in [support.start.term].

View all issues with New status.

Discussion:

It's unclear how different termination facilities in C++ interact (and how they interact with the C termination facilities). Individually some of these functions try to handle corner cases, but hilarity ensues when combined with each other. As a simple example, can an `atexit` handler call `exit`? If not, can it call `quick_exit`, and can then `at_quick_exit` handler call `exit`? Is it possible to install an `atexit` handler from an `at_quick_exit`, without strongly happens before, while handling a separate `atexit` handler (and what happens then)?

The termination handlers and termination conditions I collected:

- returning from `main` calls `atexit` handlers.

- `atexit` / `exit`

- `at_quick_exit` / `quick_exit`

- `set_terminate`

- violating `noexcept` and other things that call `std::terminate` (see `[except.terminate]`)

- violating exception specification

- parallel algorithms leaving with uncaught exception

- some `std::signal` such as `SIGTERM`, `SIGSEGV`, `SIGINT`, `SIGILL`, `SIGABRT`, and (maybe?) `SIGFPE`.

- `set_unexpected` (now a zombie)

- `unexpected_handler` (now a zombie)

What's unclear is:

- Is termination handling a DAG?

- Which thread(s) are termination handlers called on?

- Is program termination Turing complete?

I've written a sample program which exercises some of this, see here.

[2018-04-02, Jens comments]

Any potential wording should carefully take [basic.start] into account, and maybe should actually be integrated into the core wording, not the library wording.

[2018-04-02 Priority set to 3 after discussion on the reflector.]

Proposed resolution:

### 3085(i). `char_traits::copy` precondition too weak

Section: 21.2.2 [char.traits.require] Status: Open Submitter: Jonathan Wakely Opened: 2018-03-16 Last modified: 2020-09-06

Priority: 2

View all other issues in [char.traits.require].

View all issues with Open status.

Discussion:

Table 54, Character traits requirements, says that `char_traits::move` allows the ranges to overlap, but `char_traits::copy` requires that `p` is not in the range `[s, s + n)`. This appears to be an attempt to map to the requirements of `memmove` and `memcpy` respectively, allowing those to be used to implement the functions, however the requirements for `copy` are weaker than those for `memcpy`. The C standard says for `memcpy` "If copying takes place between objects that overlap, the behavior is undefined" which is a stronger requirement than the start of the source range not being in the destination range.

All of libstdc++, libc++ and VC++ simply use `memcpy` for `char_traits<char>::copy`, resulting in undefined behaviour in this example:

>     char p[] = "abc";
>     char* s = p + 1;
>     std::char_traits<char>::copy(s, p, 2);
>     assert(std::char_traits<char>::compare(p, "aab", 3) == 0);

If the intention is to allow `memcpy` as a valid implementation then the precondition is wrong (unfortunately nobody realized this when fixing `char_traits::move` in LWG DR 7). If the intention is to require `memmove` then it is strange to have separate `copy` and `move` functions that both use `memmove`.

N.B. `std::copy` and `std::copy_backward` are not valid implementations of `char_traits::copy` either, due to different preconditions.

Changing the precondition implicitly applies to `basic_string::copy` (21.3.3.7.7 [string.copy]), and `basic_string_view::copy` (21.4.3.7 [string.view.ops]), which are currently required to support partially overlapping ranges:

>     std::string s = "abc";
>     s.copy(s.data() + 1, s.length() - 1);
>     assert(s == "aab");

[2018-04-03 Priority set to 2 after discussion on the reflector.]

[2018-08-23 Batavia Issues processing]

No consensus for direction; revisit in San Diego. Status to Open.

Proposed resolution:

This wording is relative to N4727.

Option A:

> 1. Edit 21.2.2 [char.traits.require], Table 54 — "Character traits requirements", as indicated:

>    > Table 54 — Character traits requirements
>    > Expression | Return type | Assertion/note pre/post-condition | Complexity
>    > --- | --- | --- | ---
>    > `[…]`
>    > `X::copy(s,p,n)` | `X::char_type*` | Requires: `p` not in `[s,s+n)`The ranges `[p,p+n)` and `[s,s+n)` do not overlap. Returns: `s`. for each `i` in `[0,n)`, performs `X::assign(s[i],p[i])`. | linear
>    > `[…]`

Option B:

> NAD (i.e. implementations need to be fixed, in practice `char_traits::copy` and `char_traits::move` might be equivalent).

### 3086(i). Possible problem in §[new.delete.single]

Section: 17.6.3.2 [new.delete.single] Status: New Submitter: William M. Miller Opened: 2018-03-16 Last modified: 2020-09-06

Priority: 3

View other active issues in [new.delete.single].

View all other issues in [new.delete.single].

View all issues with New status.

Discussion:

In general requirements on a whole program, as opposed to a single translation unit, generally specify "no diagnostic required", since we don't want to require implementations to do multi-translation-unit analysis. However, 17.6.3.2 [new.delete.single] paragraph 11 says,

> If a function with a `size` parameter is defined, the program shall also define the corresponding version without the `size` parameter.

This is clearly not restricted to a single translation unit; should "no diagnostic required" be added?

[2018-04-03; Thomas Köppe and Tim Song suggest wording]

[2018-06-18 after reflector discussion]

Priority set to 3

Proposed resolution:

This wording is relative to N4727.

1. Edit 17.6.3.2 [new.delete.single] as indicated:

   >     void operator delete(void* ptr) noexcept;
   >     void operator delete(void* ptr, std::size_t size) noexcept;
   >     void operator delete(void* ptr, std::align_val_t alignment) noexcept;
   >     void operator delete(void* ptr, std::size_t size, std::align_val_t alignment) noexcept;

   > > -10- Effects: […]

   > > -11- Replaceable: A C++ program may define functions with any of these function signatures, and thereby displace the default versions defined by the C++ standard library. If a function without a `size` parameter is defined, the program should also define the corresponding function with a `size` parameter. If a function with a `size` parameter is defined, the program shall also define the corresponding version without the `size` parameter; no diagnostic is required. [Note: The default behavior below may change in the future, which will require replacing both deallocation functions when replacing the allocation function. — end note]

2. Edit 17.6.3.3 [new.delete.array] as indicated:

   >     void operator delete[](void* ptr) noexcept;
   >     void operator delete[](void* ptr, std::size_t size) noexcept;
   >     void operator delete[](void* ptr, std::align_val_t alignment) noexcept;
   >     void operator delete[](void* ptr, std::size_t size, std::align_val_t alignment) noexcept;

   > > -9- Effects: […]

   > > -10- Replaceable: A C++ program may define functions with any of these function signatures, and thereby displace the default versions defined by the C++ standard library. If a function without a `size` parameter is defined, the program should also define the corresponding function with a `size` parameter. If a function with a `size` parameter is defined, the program shall also define the corresponding version without the `size` parameter; no diagnostic is required. [Note: The default behavior below may change in the future, which will require replacing both deallocation functions when replacing the allocation function. — end note]

### 3089(i). `copy_n` should require non-overlapping ranges

Section: 25.7.1 [alg.copy] Status: New Submitter: Marshall Clow Opened: 2018-03-21 Last modified: 2020-09-06

Priority: 3

View other active issues in [alg.copy].

View all other issues in [alg.copy].

View all issues with New status.

Discussion:

All the copy algorithms have some kind of prohibition on having the input and output ranges overlap.

The serial version of `copy` says:

> Requires: `result` shall not be in the range `[first, last)`.

The parallel version of `copy` says:

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

`copy_if` says:

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

`copy_backwards` says:

> Requires: `result` shall not be in the range `[first, last)`.

But `copy_n` has no such requirement.

I think it should. I checked the minutes of the LWG discussion from 2008 when this was added, and there was no discussion of overlapping ranges.

What formulation do we want here? Is it sufficient to say "... shall not be in the range ..." or should we use the stronger "... shall not overlap ..."? Some `copy` variants use one, some use the other. Should we be consistent? Issue 3085 is a similar issue for `char_traits::copy`.

[2018-06-18 after reflector discussion]

Priority set to 3

Proposed resolution:

This wording is relative to N4727.

1. Edit 25.7.1 [alg.copy] as indicated:

   > [Drafting note: I'm using the permission in 25.2 [algorithms.requirements]/10 to do random-access arithmetic on (possibly) input iterators.]

   >     template<class InputIterator, class Size, class OutputIterator>
   >       constexpr OutputIterator copy_n(InputIterator first, Size n,
   >                                       OutputIterator result);
   >     template<class ExecutionPolicy, class ForwardIterator1, class Size, class ForwardIterator2>
   >       ForwardIterator2 copy_n(ExecutionPolicy&& exec,
   >                               ForwardIterator1 first, Size n,
   >                               ForwardIterator2 result);

   > > -?- Requires: `result` shall not be in the range `[first, first + n)`.

   > > -9- Effects: For each non-negative integer `i < n`, performs `*(result + i) = *(first + i)`.

   > > -10- Returns: `result + n`.

   > > -11- Complexity: Exactly `n` assignments.

### 3090(i). What is §[time.duration.cons]p4's "no overflow is induced in the conversion" intended to mean?

Section: 27.5.2 [time.duration.cons] Status: New Submitter: Richard Smith Opened: 2018-03-22 Last modified: 2020-09-12

Priority: 3

View all other issues in [time.duration.cons].

View all issues with New status.

Discussion:

27.5.2 [time.duration.cons] p4 says:

>     template<class Rep2, class Period2>
>       constexpr duration(const duration<Rep2, Period2>& d);

> > Remarks: This constructor shall not participate in overload resolution unless no overflow is induced in the conversion and `treat_as_floating_point_v<rep>` is `true` or both `ratio_divide<Period2, period>::den` is 1 and `treat_as_floating_point_v<Rep2>` is `false`.

with this example:

>     duration<int, milli> ms(3);
>     duration<int, micro> us = ms;  // OK
>     duration<int, milli> ms2 = us; // error

It's unclear to me what "no overflow is induced in the conversion" means in the above. What happens here:

>     duration<int, milli> ms(INT_MAX);
>     duration<int, micro> us = ms;  // ???

An overflow is clearly induced in the conversion here: internally, we'll multiply `INT_MAX` by 1000. But that cannot be determined statically (in general), and so can't affect the result of overload resolution.

So what's actually supposed to happen? Are we actually just supposed to check that `Rep2` is no larger than `Rep`? (If so, what happens on overflow? Undefined behavior?)

It has been pointed out by Howard Hinnant:

> This refers to the compile-time conversion factor to convert `Period2` to `Period`. If that conversion factor is not representable as a (reduced) `ratio<N, D>`, then the constructor is SFINAE'd out. This might happen (for example) converting years to picoseconds.

I would not have guessed that from the wording. Maybe replacing "no overflow is induced in the conversion" with "the result of `ratio_divide<Period2, Period>` is representable as a `ratio`" or similar would help?

[2018-06-18 after reflector discussion]

Priority set to 3

[2020-09-12 Jonathan adds a proposed resolution]

Since the result of the `ratio_divide` has to be a `ratio`, if it's not representable then the result simply isn't a valid type. Implementations are not required to make `ratio_divide` SFINAE-friendly to implement this constraint. They can perform the equivalent calculations to check if they would overflow, without actually using `ratio_divide`.

Proposed resolution:

This wording is relative to N4861.

1. Modify 27.5.2 [time.duration.cons] as indicated:

   >     template<class Rep2, class Period2>
   >       constexpr duration(const duration<Rep2, Period2>& d);

   -3- Constraints: `is_convertible_v<const Rep2&, rep>` is `true`. `ratio_divide<typename Period2::type, period>` is a valid `ratio` specialization. Either:

   - `treat_as_floating_point_v<rep>` is `true`; or
   - `ratio_divide<Period2, period>::den` is `1` and `treat_as_floating_point_v<Rep2>` is `false`.

   No overflow is induced in the conversion and `treat_as_floating_point_v<rep>` is `true` or both `ratio_divide<Period2, period>::den` is `1` and `treat_as_floating_point_v<Rep2>` is `false`. [Note: This requirement prevents implicit truncation errors when converting between integral-based `duration` types. Such a construction could easily lead to confusion about the value of the `duration`. — end note]

### 3092(i). Unclear semantics of `enum class` bitmask types

Section: 16.3.3.3.4 [bitmask.types] Status: Open Submitter: Geoffrey Romer Opened: 2018-03-26 Last modified: 2020-09-06

Priority: 3

View all other issues in [bitmask.types].

View all issues with Open status.

Discussion:

[bitmask.types] specifies the semantics of a bitmask type in terms of an "exposition only" `enum` definition, together with some constants and overloads. Notably, it is depicted as an unscoped enum, which implies among other things that it is implicitly convertible to `int_type`. At least some sources treat that as normative (as of this writing, cppreference.com's documentation for `BitmaskType` says the expression `(X & Y) != 0` is guaranteed to be well-formed), and it's hard to argue that they're wrong on the basis of the existing wording.

On the other hand, many standard library types are depicted as scoped enums, but still specified to be "bitmask types". As far as I can tell, it's impossible in library code to make a scoped enum implicitly convertible to its underlying type, and even if you could, what would be the point? Presumably the specification of those types as scoped enums is intended to have some sort of observable consequences.

In addition, some library types (notably in clause 31) are specified to be bitmask types, without indicating whether they are scoped or unscoped. It's not clear what the standard guarantees about e.g. whether they can be implicitly converted.

I assume the intent is that "bitmask type" doesn't specify an implicit conversion, or any of the other ways unscoped and scoped enums differ, but the standard doesn't actually say that. We really ought to rewrite [bitmask.types] as a requirements table, but here's a quick hack to the existing wording as a stopgap.

[2018-04-23 Priority set to 2 after discussion on the reflector.]

[2018-08-23 Batavia Issues processing]

N3110 also touches on this.

Nico to survey the enums in the library and report back on which ones should be class.

[2019 Cologne Wednesday night]

Changing existing enums to class enums is an ABI break on some platforms; current wording does not require the use of enums. See N3110.

Daniel to provide requirements tables, Jonathan to assist. Reduce priority to 3

Proposed resolution:

This wording is relative to N4727.

1. Edit 16.3.3.3.4 [bitmask.types] as indicated:

   > -2- The bitmask type `bitmask` can be written:

   > >     // For exposition only.
   > >     // int_type is an integral type capable of representing all values of the bitmask type.
   > >     enumE bitmask : int_type {
   > >       V0 = 1 << 0, V1 = 1 << 1, V2 = 1 << 2, V3 = 1 << 3, .....
   > >     };
   > >     […]

   > -3- Here, `E` may represent either `enum` or `enum class` (the choice is implementation-defined unless otherwise specified), and the names `C0`, `C1`, etc. represent bitmask elements for this particular bitmask type. The zero value `bitmask{}` is used to represent an empty bitmask, in which no bitmask elements are set. All such bitmask elements have distinct, nonzero values such that, for any pair `Ci` and `Cj` where `i ≠ j`, `Ci & Ci` is nonzero and `Ci & Cj` is zero. Additionally, the value `0` is used to represent an empty bitmask, in which no bitmask elements are set.

### 3093(i). LWG 2294/2192 missed a `std::abs` overload

Section: 26.8.2 [c.math.abs], 17.2.2 [cstdlib.syn], 29.13.2 [cinttypes.syn] Status: New Submitter: Richard Smith Opened: 2018-03-30 Last modified: 2018-06-19

Priority: 3

View all issues with New status.

Discussion:

LWG 2192 changed the library specification so that you always get all the `std::abs` overloads for fundamental types if you get any of them.

Except that it missed one: `<cinttypes>` provides a `std::abs` (and `std::div`) overload for `intmax_t` if it's not `long long` (since LWG 1449). Presumably that one should also follow the `<cstdlib>`/`<cmath>` pattern and we should make the complete `abs` overload set available whenever any of the three headers is included? (And likewise we should make the complete `std::div` overload set available whenever either `<cstdlib>` or `<cinttypes>` is included.)

[2018-06-18 after reflector discussion]

Priority set to 3

Proposed resolution:

### 3095(i). `strstreambuf` refers to nonexistent member of `fpos`, `fpos::offset`

Section: D.12.2.4 [depr.strstreambuf.virtuals] Status: New Submitter: Billy O'Neal III Opened: 2018-04-04 Last modified: 2020-09-06

Priority: 4

View all other issues in [depr.strstreambuf.virtuals].

View all issues with New status.

Discussion:

`strstreambuf` refers to a nonexistent member function of `fpos` in the specification of the member function `seekpos`, D.12.2.4 [depr.strstreambuf.virtuals]/18 (emphasize mine):

> For a sequence to be positioned, if its next pointer is a null pointer, the positioning operation fails. Otherwise, the function determines `newoff` from `sp.offset()`:

The intent is clearly to get the corresponding `streamoff` from the `fpos`, as p19 says "the resultant offset `newoff` (of type `off_type`)". The mechanism to make that conversion is a normal explicit conversion, as indicated in the last row of the table in [fpos.operations].

[2018-06-18 after reflector discussion]

Priority set to 4

Proposed resolution:

This wording is relative to N4727.

1. Edit D.12.2.4 [depr.strstreambuf.virtuals] as indicated:

   >     pos_type seekpos(pos_type sp, ios_base::openmode which
   >                      = ios_base::in | ios_base::out) override;

   > > -17- Effects: […]

   > > -18- For a sequence to be positioned, if its next pointer is a null pointer, the positioning operation fails. Otherwise, the function determines `newoff` from `static_cast<off_type>(sp).offset()`:

   > > […]

### 3097(i). `basic_stringbuf seekoff` effects trigger undefined behavior and have contradictory returns

Section: 29.8.2.5 [stringbuf.virtuals] Status: New Submitter: Billy O'Neal III Opened: 2018-04-07 Last modified: 2020-09-06

Priority: 3

View other active issues in [stringbuf.virtuals].

View all other issues in [stringbuf.virtuals].

View all issues with New status.

Discussion:

Paragraph citations relative to N4727.

[stringbuf.virtuals]/10 says that `newoff` might be calculated from `xnext - xbegin`, or from `high_mark - xbegin`. After `newoff` is calculated, it does the null pointer check against and zero offset check. However, that means the effects may have already done `nullptr -` non-`nullptr`, or non-`nullptr - nullptr`, which [expr.add]/5 says is undefined behavior.

Moreover, the attempt at avoiding this problem only tests `newoff`, not the value actually used which is `newoff + off`. For example, `buf.seekoff(100, ios_base::beg, ios_base::out)` on a read-only `streambuf` would try to assign `pptr() + newoff + off to pptr()`, but `pptr()` may have been `nullptr`, giving `nullptr + 0 + 100` which triggers UB. (Perhaps the "refers to an uninitialized character" bit protects that though).

Last, the Returns: element says that it returns `newoff`, but then also says it returns the resulting stream position, which should be something like `newoff + off`. (I checked libc++ and MSVC++ and we both return `newoff + off`)

We probably want to resolve that by renaming the value that comes out of Table 108 to something like "`basis`" and make "`newoff`" actually be the new offset instead of the starting offset.

[2018-04-16 Priority set to 3 after discussion on the reflector.]

Proposed resolution:

### 3098(i). Misleading example for `filesystem::path::filename()`

Section: 29.12.6.5.9 [fs.path.decompose] Status: New Submitter: Jonathan Wakely Opened: 2018-04-06 Last modified: 2020-09-06

Priority: 3

View all other issues in [fs.path.decompose].

View all issues with New status.

Discussion:

The example in [fs.path.decompose] p7 includes:

>     path("//host").filename();  // yields ""

This result isn't guaranteed, it depends whether the implementation interprets `"//host"` as a root-name or as a root-directory (with a redundant directory-separator) followed by the filename `"host"`.

The example should make it clear that this interpretation is allowed.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4727.

> 1. Edit 29.12.6.5.9 [fs.path.decompose] as indicated:

>    >     path filename() const;

>    > > -6- Returns: `relative_path().empty() ? path() : *--end()`.

>    > > [Example:

>    > > >     path("/foo/bar.txt").filename(); // yields "bar.txt"
>    > > >     path("/foo/bar").filename();     // yields "bar"
>    > > >     path("/foo/bar/").filename();    // yields ""
>    > > >     path("/").filename();            // yields ""
>    > > >     path("//host").filename();       // yields "" or "host"
>    > > >     path(".").filename();            // yields "."
>    > > >     path("..").filename();           // yields ".."

>    > > — end example]

[2018-04-10, Jonathan comments and provides revised wording]

Based on the reflector discussion I'd like to change the P/R to Billy's suggestion of simply removing that line from the example.

[2018-06-18 after reflector discussion]

Priority set to 3

Proposed resolution:

This wording is relative to N4741.

1. Edit 29.12.6.5.9 [fs.path.decompose] as indicated:

   >     path filename() const;

   > > -6- Returns: `relative_path().empty() ? path() : *--end()`.

   > > [Example:

   > > >     path("/foo/bar.txt").filename(); // yields "bar.txt"
   > > >     path("/foo/bar").filename();     // yields "bar"
   > > >     path("/foo/bar/").filename();    // yields ""
   > > >     path("/").filename();            // yields ""
   > > >     path("//host").filename();       // yields ""
   > > >     path(".").filename();            // yields "."
   > > >     path("..").filename();           // yields ".."

   > > — end example]

### 3099(i). `is_assignable<Incomplete&, Incomplete&>`

Section: 20.15.3 [meta.type.synop] Status: New Submitter: Casey Carter Opened: 2018-04-10 Last modified: 2020-09-06

Priority: 2

View other active issues in [meta.type.synop].

View all other issues in [meta.type.synop].

View all issues with New status.

Discussion:

LWG 2939 suggests that the the preconditions of the type traits need reevaluation. This issue focuses specifically on `is_assignable` and, by extension, its variants:

- `is_copy_assignable<T>`, equivalent to `is_assignable<T&, const T&>`,
- `is_move_assignable<T>`, equivalent to `is_assignable<T&, T>`,
- `is_trivially_assignable<T, U>`, equivalent to `is_assignable<T, U> && /* magic */`,
- `is_trivially_copy_assignable<T>`, equivalent to `is_assignable<T&, const T&> && /* magic */`,
- `is_trivially_move_assignable<T>`, equivalent to `is_assignable<T&, T> && /* magic */`,
- `is_nothrow_assignable<T, U>`, equivalent to `is_assignable<T, U> && noexcept(declval<T>() = declval<U>())`,
- `is_nothrow_copy_assignable<T>`, equivalent to `is_assignable<T&, const T&> && noexcept(declval<T&>() = declval<const T&>())`,
- `is_nothrow_move_assignable<T>`, equivalent to `is_assignable<T&, T> && noexcept(declval<T&>() = declval<T>())`, and

We note a discrepancy: `is_copy_assignable<T>` requires `T` to be a complete type, but the equivalent form `is_assignable<T&, const T&>` does not. The requirement for `is_copy_assignable<T>` seems sensible, since there's no way to determine whether or not the assignment `declval<T&>() = declval<const T&>()` is well-formed when `T` is incomplete. It seems that the same argument should apply to all of the above "assignable" traits, and that they must require that the referent type is complete when given a reference type parameter to be implementable.

[2018-08 Batavia Monday issue discussion]

Issues 2797, 2939, 3022, and 3099 are all closely related. Walter to write a paper resolving them.

[2020-02-14, Prague]

LWG discussions. Set priority to 2.

Proposed resolution:

This wording is relative to N4741.

> 1. In 20.15.5.4 [meta.unary.prop] Table 42, change the Precondition text for `is_assignable`, `is_trivially_assignable`, and `is_nothrow_assignable` as follows:

>    > `remove_cvref_t<``T``>` and `remove_cvref_t<``U``>` shall be complete types, cv `void`, or arrays of unknown bound.

> 2. In 20.15.5.4 [meta.unary.prop] Table 42, change the Precondition text for `is_copy_assignable`, `is_move_assignable`, `is_trivially_copy_assignable`, `is_trivially_move_assignable`, `is_nothrow_copy_assignable`, and `is_nothrow_move_assignable` as follows:

>    > `remove_cvref_t<``T``>` shall be a complete type, cv `void`, or an array of unknown bound.

### 3105(i). `T1` is convertible to `T2`

Section: 16 [library] Status: New Submitter: Jens Maurer Opened: 2018-04-24 Last modified: 2018-06-19

Priority: 3

View other active issues in [library].

View all other issues in [library].

View all issues with New status.

Discussion:

The library wording frequently uses the construction "type `T1` is convertible to type `T2`", but this is an undefined phrase.

For requirements on user code (e.g. [tuple.rel]), it is unclear whether all expressions of type `T1` must satisfy the convertibility requirement, regardless of value category, or whether a single value category is in view only.

Consider:

>     struct C
>     {
>       operator int() &&;
>     };

>     int main()
>     {
>       int x = C(); // prvalue can be implicitly converted to int
>       C c;
>       int y = c;   // lvalue can't
>     }

The library has an "`is_convertible<T1, T2>`" trait, but that checks convertibility only for a single value category, not all possible ones.

[2018-06-18 after reflector discussion]

Priority set to 3

Proposed resolution:

### 3107(i). `istreambuf_iterator` has public exposition-only member

Section: 23.6.4 [istreambuf.iterator] Status: New Submitter: Billy O'Neal III Opened: 2018-04-26 Last modified: 2020-09-06

Priority: 4

View other active issues in [istreambuf.iterator].

View all other issues in [istreambuf.iterator].

View all issues with New status.

Discussion:

LWG has said recently that we don't want public exposition-only things, as that may encourage users to try to use those names (and some implementers to actually use those names).

[2018-06-18 after reflector discussion]

Priority set to 4

Proposed resolution:

This wording is relative to N4741.

1. Edit 23.6.4 [istreambuf.iterator] as indicated:

   >     namespace std {
   >       template<class charT, class traits = char_traits<charT>>
   >       class istreambuf_iterator {
   >       public:
   >         […]
   >         using istream_type = basic_istream<charT,traits>;

   >         class proxy; // exposition only

   >         constexpr istreambuf_iterator() noexcept;
   >         […]
   >       private:
   >         class proxy; // exposition only
   >         streambuf_type* sbuf_; // exposition only
   >       };
   >       […]
   >     }

### 3108(i). `istreambuf_iterator::proxy::operator*` should be `const`

Section: 23.6.4.2 [istreambuf.iterator.proxy] Status: New Submitter: Billy O'Neal III Opened: 2018-04-26 Last modified: 2020-09-06

Priority: 3

View all issues with New status.

Discussion:

`operator*` on iterators is usually intended to be `const`; see 23.3.5.3 [input.iterators] Table 87, `*a`, where `a` is of type `X` or `const X`. (Technically, `proxy` is implementing the `*r++` requirement in this table, and `r` doesn't imply a const iterator, but there's no reason for the iterator's `operator*` to differ from the proxy)

[2018-06-18 after reflector discussion]

Priority set to 3

Proposed resolution:

This wording is relative to N4741.

1. Edit 23.6.4.2 [istreambuf.iterator.proxy] as indicated:

   >     namespace std {
   >       template<class charT, class traits = char_traits<charT>>
   >       class istreambuf_iterator<charT, traits>::proxy { // exposition only
   >         charT keep_;
   >         basic_streambuf<charT,traits>* sbuf_;
   >         proxy(charT c, basic_streambuf<charT,traits>* sbuf)
   >           : keep_(c), sbuf_(sbuf) { }
   >         public:
   >           charT operator*() const { return keep_; }
   >       };
   >     }

### 3109(i). `strstreambuf` is copyable

Section: D.12.2 [depr.strstreambuf] Status: New Submitter: Jonathan Wakely Opened: 2018-05-02 Last modified: 2018-06-19

Priority: 4

View all issues with New status.

Discussion:

In C++03 `strstreambuf` was not copyable, because `basic_streambuf` wasn't copyable. In C++11 we made `basic_streambuf` copyable by derived classes, and `strstreambuf` doesn't define any special members, so it (unintentionally?) became copyable, with completely unspecified semantics.

VC++ and libc++ make it movable not copyable, and libstdc++ still follows C++03, so it's neither movable nor copyable. Making it movable seems to be the sane option, and consistent with `filebuf` and `stringbuf`.

[2018-06-18 after reflector discussion]

Priority set to 4

Proposed resolution:

### 3114(i). [networking.ts] Permit efficient composition when using `DynamicBuffer`

Section: 16 [networking.ts::buffer], 17 [networking.ts::buffer.stream] Status: LEWG Submitter: Vinnie Falco Opened: 2018-05-18 Last modified: 2020-09-06

Priority: Not Prioritized

View all issues with LEWG status.

Discussion:

Addresses: networking.ts

Asynchronous algorithms are started by a call to an initiating function. When these algorithms are constructed from calls to other initiating functions, the result is called a composed operation. For example, `async_read` may be implemented in terms of zero or more calls to a stream's `async_read_some` algorithm. For operations where the caller cannot easily determine ahead of time the storage requirements needed for an algorithm to meet its post-conditions, [networking.ts] introduces the DynamicBuffer concept:

> A dynamic buffer encapsulates memory storage that may be automatically resized as required, where the memory is divided into two regions: readable bytes followed by writable bytes. [buffer.reqmts.dynamicbuffer]

Signatures for algorithms in the technical specification which accept dynamic buffers use forwarding references:

>     // 17.10 [networking.ts::buffer.async.read.until], asynchronous delimited read operations:

>     template<
>       class AsyncReadStream,
>       class DynamicBuffer,
>       class CompletionToken>
>     DEDUCED async_read_until(
>       AsyncReadStream& s,
>       DynamicBuffer&& b,
>       char delim,
>       CompletionToken&& token);

Because the initiating function returns immediately, and the associated composed operation executes later, it is necessary for the algorithm to manage the lifetime of the dynamic buffer. Guidance for doing so is given in the TS:

> 13.2.7.5 Lifetime of initiating function arguments [async.reqmts.async.lifetime]

> 1. Unless otherwise specified, the lifetime of arguments to initiating functions shall be treated as follows: […] the implementation does not assume the validity of the argument after the initiating function completes […] The implementation may make copies of the argument, and all copies shall be destroyed no later than immediately after invocation of the completion handler.

Given the guidance above, the most sensible approach is for the implementation to move or make a decay-copy of the argument. An implementation of the TS, authored by the principal architect of the TS itself, does precisely that:

>     template <
>         typename AsyncReadStream,
>         typename DynamicBuffer,
>         typename ReadHandler>
>     class read_until_delim_op
>     {
>     public:
>         template <typename DeducedBuffers>
>         read_until_delim_op(
>             AsyncReadStream& stream,
>             DeducedBuffers&& buffers,
>             char delim, ReadHandler& handler)
>         : […]
>           buffers_(std::forward<DeducedBuffers>(buffers))
>           […]
>         {
>         }
>         […]
>         DynamicBuffer buffers_;
>         […]
>     };

>     template <
>         typename AsyncReadStream,
>         typename DynamicBuffer,
>         typename ReadHandler>
>     NET_TS_INITFN_RESULT_TYPE(ReadHandler,
>         void (std::error_code, std::size_t))
>     async_read_until(
>         AsyncReadStream& s,
>         DynamicBuffer&& buffers,
>         char delim,
>         ReadHandler&& handler)
>     {
>       // If you get an error on the following line it means that your handler does
>       // not meet the documented type requirements for a ReadHandler.
>       NET_TS_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

>       async_completion<ReadHandler,
>         void (std::error_code, std::size_t)> init(handler);

>       detail::read_until_delim_op<
>         AsyncReadStream,
>         typename decay<DynamicBuffer>::type,
>         NET_TS_HANDLER_TYPE(ReadHandler, void (std::error_code, std::size_t))>(
>             s,
>             DynamicBuffer&&buffers,
>             delim,
>             init.completion_handler)(std::error_code(), 0, 1);

>       return init.result.get();
>     }

Given the semantics of dynamic buffers implied by the wording, instances of dynamic buffers behave more like references to storage types rather than storage types, as copies refer to the same underlying storage. This can be seen in the declaration of `dynamic_string_buffer` which meets the requirements of DynamicBuffer:

>     template <typename Elem, typename Traits, typename Allocator>
>     class dynamic_string_buffer
>     {
>       […]
>     private:
>       std::basic_string<Elem, Traits, Allocator>& string_;
>       std::size_t size_;
>       const std::size_t max_size_;
>     };

A dynamic string buffer contains a reference to the underlying string. Copies of a dynamic string buffer refer to the same string. Note that the dynamic string buffer also contains some state: the `size_` and `max_size_` data members. This additional metadata informs the dynamic string buffer of the boundaries between the readable and writable bytes, as well as the maximum allowed size of the total of the readable and writable bytes.

When only one composed operation handles the dynamic buffer, things seem to work. However, if a composed operation wishes to invoke another composed operation and pass that dynamic buffer, a problem arises. Consider two composed operations `f` and `g`, which both operate on an instance of dynamic buffer. When `f` is invoked, it makes a copy of the dynamic buffer and then calls `g` with the copy. At this point, `g` must also make a copy. Copies share the underlying storage, but in the case of dynamic string buffers each copy maintains its own distinct metadata. When `g` has finished mutating the dynamic buffer and returns control back to `f` by invoking the completion handler, the metadata in the copy of the dynamic buffer held by `f` will not have the changes made by `g`.

Another design problem caused by adding metadata to the dynamic buffer concept is illustrated in the following example code:

>     template<class MutableBufferSequence>
>     std::size_t read(const MutableBufferSequence&)
>     {
>       throw std::exception{};
>     }

>     int main()
>     {
>       std::string s;
>       assert(s.empty());
>       try
>       {
>         auto b = boost::asio::dynamic_buffer(s);
>         b.commit(read(b.prepare(32)));
>       }
>       catch(const std::exception&)
>       {
>         assert(s.empty()); // fails
>       }
>     }

While not technically incorrect, it may be surprising to the user that the string contains additional value-initialized data which was not part of the original readable bytes (which in this case was empty). The wording of the dynamic buffer concept does not address this case.

The solution we propose is to change the semantics of DynamicBuffer to represent a true storage type rather than a hybrid reference with metadata. Instances of dynamic buffers will be passed by reference, and callers will be required to manage the lifetime of dynamic buffer objects for the duration of any asynchronous operations. An additional benefit of this change is that it also solves the problem of exceptions described above.

[2018-06-18 after reflector discussion]

Status to LEWG; there will be a paper P1100R0 in the post-Rapperswil mailing addressing this.

[2020-05-28; Billy Baker comments]

From Cologne 2019 paper discussion: P1100 has been superseded by P1790.

Proposed resolution:

This wording is relative to N4734.

> [Drafting note: The project editor is kindly asked to replace all occurrences of `DynamicBuffer&&` with `DynamicBuffer&` as indicated by the provided wording changes below. — end drafting note]

1. Modify 16.1 [networking.ts::buffer.synop], header `<experimental/buffer>` synopsis, as indicated:

   >     […]
   >     // 16.11 [networking.ts::buffer.creation], buffer creation:
   >     […]

   >     template<class T, class Allocator>
   >     class dynamic_vector_buffer;

   >     template<class CharT, class Traits, class Allocator>
   >     class basic_dynamic_string_buffer;

   >     // 16.14 [networking.ts::buffer.dynamic.creation], dynamic buffer creation:

   >     template<class T, class Allocator>
   >       dynamic_vector_buffer<T, Allocator>
   >       dynamic_buffer(vector<T, Allocator>& vec) noexcept;
   >     template<class T, class Allocator>
   >       dynamic_vector_buffer<T, Allocator>
   >       dynamic_buffer(vector<T, Allocator>& vec, size_t n) noexcept;

   >     template<class CharT, class Traits, class Allocator>
   >       dynamic_string_buffer<CharT, Traits, Allocator>
   >       dynamic_buffer(basic_string<CharT, Traits, Allocator>& str) noexcept;
   >     template<class CharT, class Traits, class Allocator>
   >       dynamic_string_buffer<CharT, Traits, Allocator>
   >       dynamic_buffer(basic_string<CharT, Traits, Allocator>& str, size_t n) noexcept;

   >     […]
   >     // 17.5 [networking.ts::buffer.read], synchronous read operations:
   >     […]

   >     template<class SyncReadStream, class DynamicBuffer>
   >       size_t read(SyncReadStream& stream, DynamicBuffer&& b);
   >     template<class SyncReadStream, class DynamicBuffer>
   >       size_t read(SyncReadStream& stream, DynamicBuffer&& b, error_code& ec);
   >     template<class SyncReadStream, class DynamicBuffer, class CompletionCondition>
   >       size_t read(SyncReadStream& stream, DynamicBuffer&& b,
   >                   CompletionCondition completion_condition);
   >     template<class SyncReadStream, class DynamicBuffer, class CompletionCondition>
   >       size_t read(SyncReadStream& stream, DynamicBuffer&& b,
   >                   CompletionCondition completion_condition, error_code& ec);

   >     // 17.6 [networking.ts::buffer.async.read], asynchronous read operations:
   >     […]

   >     template<class AsyncReadStream, class DynamicBuffer, class CompletionToken>
   >       DEDUCED async_read(AsyncReadStream& stream,
   >                          DynamicBuffer&& b, CompletionToken&& token);
   >     template<class AsyncReadStream, class DynamicBuffer,
   >       class CompletionCondition, class CompletionToken>
   >         DEDUCED async_read(AsyncReadStream& stream,
   >                            DynamicBuffer&& b,
   >                            CompletionCondition completion_condition,
   >                            CompletionToken&& token);

   >     // 17.7 [networking.ts::buffer.write], synchronous write operations:
   >     […]

   >     template<class SyncWriteStream, class DynamicBuffer>
   >       size_t write(SyncWriteStream& stream, DynamicBuffer&&; b);
   >     template<class SyncWriteStream, class DynamicBuffer>
   >       size_t write(SyncWriteStream& stream, DynamicBuffer&& b, error_code& ec);
   >     template<class SyncWriteStream, class DynamicBuffer, class CompletionCondition>
   >       size_t write(SyncWriteStream& stream, DynamicBuffer&& b,
   >                    CompletionCondition completion_condition);
   >     template<class SyncWriteStream, class DynamicBuffer, class CompletionCondition>
   >       size_t write(SyncWriteStream& stream, DynamicBuffer&& b,
   >                    CompletionCondition completion_condition, error_code& ec);

   >     // 17.8 [networking.ts::buffer.async.write], asynchronous write operations:
   >     […]

   >     template<class AsyncWriteStream, class DynamicBuffer, class CompletionToken>
   >       DEDUCED async_write(AsyncWriteStream& stream,
   >                           DynamicBuffer&& b, CompletionToken&& token);
   >     template<class AsyncWriteStream, class DynamicBuffer,
   >       class CompletionCondition, class CompletionToken>
   >         DEDUCED async_write(AsyncWriteStream& stream,
   >                             DynamicBuffer&& b,
   >                             CompletionCondition completion_condition,
   >                             CompletionToken&& token);

   >     // 17.9 [networking.ts::buffer.read.until], synchronous delimited read operations:

   >     template<class SyncReadStream, class DynamicBuffer>
   >       size_t read_until(SyncReadStream& s, DynamicBuffer&& b, char delim);
   >     template<class SyncReadStream, class DynamicBuffer>
   >       size_t read_until(SyncReadStream& s, DynamicBuffer&& b,
   >                         char delim, error_code& ec);
   >     template<class SyncReadStream, class DynamicBuffer>
   >       size_t read_until(SyncReadStream& s, DynamicBuffer&& b, string_view delim);
   >     template<class SyncReadStream, class DynamicBuffer>
   >       size_t read_until(SyncReadStream& s, DynamicBuffer&& b,
   >                         string_view delim, error_code& ec);

   >     // 17.10 [networking.ts::buffer.async.read.until], asynchronous delimited read operations:

   >     template<class AsyncReadStream, class DynamicBuffer, class CompletionToken>
   >       DEDUCED async_read_until(AsyncReadStream& s,
   >                                DynamicBuffer&& b, char delim,
   >                                CompletionToken&& token);
   >     template<class AsyncReadStream, class DynamicBuffer, class CompletionToken>
   >       DEDUCED async_read_until(AsyncReadStream& s,
   >                                DynamicBuffer&& b, string_view delim,
   >                                CompletionToken&& token);

   >     […]

2. Modify 16.2.4 [networking.ts::buffer.reqmts.dynamicbuffer], as indicated:

   > -1- […]

   > -2- A type `X` meets the `DynamicBuffer` requirements if it satisfies the requirements of `Destructible` (C++ 2014 [destructible]) and `MoveConstructible` (C++ 2014 [moveconstructible]), as well as the additional requirements listed in Table 14.

3. Modify 16.12 [networking.ts::buffer.dynamic.vector], as indicated:

   > >     […]

   > >     template<class T, class Allocator = allocator<T>>
   > >     class dynamic_vector_buffer
   > >     {
   > >     public:
   > >       // types:
   > >       using value_type = vector<T, Allocator>;
   > >       using const_buffers_type = const_buffer;
   > >       using mutable_buffers_type = mutable_buffer;

   > >       // constructors:
   > >       dynamic_vector_buffer() = default;
   > >       explicit dynamic_vector_buffer(size_t maximum_size);
   > >       explicit dynamic_vector_buffer(vector<T, Allocator>& vec) noexcept;
   > >       dynamic_vector_buffer(vector<T, Allocator>& vec, size_t maximum_size) noexcept;
   > >       dynamic_vector_buffer(dynamic_vector_buffer&&) = default;

   > >       // members:
   > >       size_t size() const noexcept;
   > >       size_t max_size() const noexcept;
   > >       void max_size(size_t maximum_size);
   > >       size_t capacity() const noexcept;
   > >       const_buffers_type data() const noexcept;
   > >       mutable_buffers_type prepare(size_t n);
   > >       void commit(size_t n);
   > >       void consume(size_t n);
   > >       span<const T> get() const noexcept
   > >       value_type release();

   > >     private:
   > >       vector<T, Allocator>& vec_; // exposition only
   > >       size_t size_; // exposition only
   > >       const size_t max_size_; // exposition only
   > >     };

   > >     […]

   > -2- […]

   > -3- […]

   >     explicit dynamic_vector_buffer(size_t maximum_size)

   > > -?- Effects: Default-constructs `vec_`. Initializes `size_` with `0`, and `max_size_` with `maximum_size`.

   >     explicit dynamic_vector_buffer(vector<T, Allocator>& vec) noexcept

   > > -4- Effects: Initializes `vec_` with `move(vec)`, `size_` with `vec_.size()`, and `max_size_` with `vec_.max_size()`

   >     dynamic_vector_buffer(vector<T, Allocator>& vec,
   >                           size_t maximum_size) noexcept;

   > > -5- Requires: `vec.size() <= maximum_size`

   > > -6- Effects: Initializes `vec_` with `move(vec)`, `size_` with `vec_.size()`, and `max_size_` with `maximum_size`.

   > > […]

   >     size_t max_size() const noexcept;

   > > -8- Returns: `max_size_`.

   >     void max_size(size_t maximum_size)

   > > -?- Effects: Performs `max_size_ = maximum_size`.

   > […]

   >     void consume(size_t n);

   > > -15- Effects: […]

   >     span<const T> get() const noexcept

   > > -?- Returns: `span<const T>(vec_.data(), size_)`.

   >     value_type release()

   > > -?- Returns: `move(vec_)`.

4. Modify 16.13 [networking.ts::buffer.dynamic.string], as indicated:

   > >     template<class CharT, class Traits, class Allocator>
   > >     class basic_dynamic_string_buffer
   > >     {
   > >     public:
   > >       // types:
   > >       using value_type = basic_string<CharT, Traits, Allocator>;
   > >       using const_buffers_type = const_buffer;
   > >       using mutable_buffers_type = mutable_buffer;

   > >       // constructors:
   > >       basic_dynamic_string_buffer() = default;
   > >       explicit basic_dynamic_string_buffer(size_t maximum_size);
   > >       explicit basic_dynamic_string_buffer(basic_string<CharT, Traits, Allocator>& str) noexcept;
   > >       basic_dynamic_string_buffer(basic_string<CharT, Traits, Allocator>& str, size_t maximum_size) noexcept;
   > >       basic_dynamic_string_buffer(basic_dynamic_string_buffer&&) = default;

   > >       // members:
   > >       size_t size() const noexcept;
   > >       size_t max_size() const noexcept;
   > >       void max_size(size_t maximum_size)
   > >       size_t capacity() const noexcept;
   > >       const_buffers_type data() const noexcept;
   > >       mutable_buffers_type prepare(size_t n);
   > >       void commit(size_t n) noexcept;
   > >       void consume(size_t n);
   > >       basic_string_view<CharT, Traits> get() const noexcept
   > >       value_type release();

   > >     private:
   > >       basic_string<CharT, Traits, Allocator>& str_; // exposition only
   > >       size_t size_; // exposition only
   > >       const size_t max_size_; // exposition only
   > >     };

   > >     using dynamic_string_buffer =
   > >       basic_dynamic_string_buffer<char, char_traits<char>, allocator<char>>

   > -2- […]

   > -3- […]

   >     explicit basic_dynamic_string_buffer(size_t maximum_size)

   > > -?- Effects: Default-constructs `str_`. Initializes `size_` with `0`, and `max_size_` with `maximum_size`.

   > > […]

   >     explicit basic_dynamic_string_buffer(basic_string<CharT, Traits, Allocator>& str) noexcept

   > > -4- Effects: Initializes `str_` with `move(str)`, `size_` with `str_.size()`, and `max_size_` with `str_.max_size()`

   >     basic_dynamic_string_buffer(string<CharT, Traits, Allocator>& str,
   >                                 size_t maximum_size) noexcept;

   > > -5- Requires: `str.size() <= maximum_size`.

   > > -6- Effects: Initializes `str_` with `move(str)`, `size_` with `str_.size()`, and `max_size_` with `maximum_size`.

   > > […]

   >     size_t max_size() const noexcept;

   > > -8- Returns: `max_size_`.

   >     void max_size(size_t maximum_size)

   > > -?- Effects: Performs `max_size_ = maximum_size`.

   > […]

   >     void consume(size_t n);

   > > -15- Effects: […]

   >     basic_string_view<CharT, Traits> get() const noexcept

   > > -?- Returns: `basic_string_view<CharT, Traits>(str_)`.

   >     value_type release()

   > > -?- Returns: `move(str_)`.

5. Remove 16.14 [networking.ts::buffer.dynamic.creation] entirely

6. Modify 17.5 [networking.ts::buffer.read], as indicated:

   >     […]

   >     template<class SyncReadStream, class DynamicBuffer>
   >       size_t read(SyncReadStream& stream, DynamicBuffer&& b);
   >     template<class SyncReadStream, class DynamicBuffer>
   >       size_t read(SyncReadStream& stream, DynamicBuffer&& b, error_code& ec);
   >     template<class SyncReadStream, class DynamicBuffer,
   >       class CompletionCondition>
   >         size_t read(SyncReadStream& stream, DynamicBuffer&& b,
   >                     CompletionCondition completion_condition);
   >     template<class SyncReadStream, class DynamicBuffer,
   >       class CompletionCondition>
   >         size_t read(SyncReadStream& stream, DynamicBuffer&& b,
   >                     CompletionCondition completion_condition,
   >                     error_code& ec);

   >     […]

7. Modify 17.6 [networking.ts::buffer.async.read], as indicated:

   >     […]

   >     template<class AsyncReadStream, class DynamicBuffer, class CompletionToken>
   >       DEDUCED async_read(AsyncReadStream& stream,
   >                          DynamicBuffer&& b, CompletionToken&& token);
   >     template<class AsyncReadStream, class DynamicBuffer, class CompletionCondition,
   >       class CompletionToken>
   >         DEDUCED async_read(AsyncReadStream& stream,
   >                            DynamicBuffer&& b,
   >                            CompletionCondition completion_condition,
   >                            CompletionToken&& token);

   >     […]

   > -14- The program shall ensure both the `AsyncReadStream` object `stream` and the `DynamicBuffer` object `b` are is valid until the completion handler for the asynchronous operation is invoked.

8. Modify 17.7 [networking.ts::buffer.write], as indicated:

   >     […]

   >     template<class SyncWriteStream, class DynamicBuffer>
   >       size_t write(SyncWriteStream& stream, DynamicBuffer&& b);
   >     template<class SyncWriteStream, class DynamicBuffer>
   >       size_t write(SyncWriteStream& stream, DynamicBuffer&& b, error_code& ec);
   >     template<class SyncWriteStream, class DynamicBuffer, class CompletionCondition>
   >       size_t write(SyncWriteStream& stream, DynamicBuffer&& b,
   >                    CompletionCondition completion_condition);
   >     template<class SyncWriteStream, class DynamicBuffer, class CompletionCondition>
   >       size_t write(SyncWriteStream& stream, DynamicBuffer&& b,
   >                    CompletionCondition completion_condition,
   >                    error_code& ec);

   >     […]

9. Modify 17.8 [networking.ts::buffer.async.write], as indicated:

   >     […]

   >     template<class AsyncWriteStream, class DynamicBuffer, class CompletionToken>
   >       DEDUCED async_write(AsyncWriteStream& stream,
   >                           DynamicBuffer&& b, CompletionToken&& token);
   >     template<class AsyncWriteStream, class DynamicBuffer, class CompletionCondition,
   >       class CompletionToken>
   >         DEDUCED async_write(AsyncWriteStream& stream,
   >                             DynamicBuffer&& b,
   >                             CompletionCondition completion_condition,
   >                             CompletionToken&& token);

   >     […]

   > -14- The program shall ensure both the `AsyncWriteStream` object `stream` and the `DynamicBuffer` object `b` memory associated with the dynamic buffer `b` are valid until the completion handler for the asynchronous operation is invoked.

10. Modify 17.9 [networking.ts::buffer.read.until], as indicated:

    >     template<class SyncReadStream, class DynamicBuffer>
    >       size_t read_until(SyncReadStream& s, DynamicBuffer&& b, char delim);
    >     template<class SyncReadStream, class DynamicBuffer>
    >       size_t read_until(SyncReadStream& s, DynamicBuffer&& b,
    >                         char delim, error_code& ec);
    >     template<class SyncReadStream, class DynamicBuffer>
    >       size_t read_until(SyncReadStream& s, DynamicBuffer&& b, string_view delim);
    >     template<class SyncReadStream, class DynamicBuffer>
    >       size_t read_until(SyncReadStream& s, DynamicBuffer&& b,
    >                         string_view delim, error_code& ec);

    >     […]

11. Modify 17.10 [networking.ts::buffer.async.read.until], as indicated:

    >     template<class AsyncReadStream, class DynamicBuffer, class CompletionToken>
    >       DEDUCED async_read_until(AsyncReadStream& s,
    >                                DynamicBuffer&& b, char delim,
    >                                CompletionToken&& token);
    >     template<class AsyncReadStream, class DynamicBuffer, class CompletionToken>
    >       DEDUCED async_read_until(AsyncReadStream& s,
    >                                DynamicBuffer&& b, string_view delim,
    >                                CompletionToken&& token);

    >     […]

    > -6- The program shall ensure both the `AsyncReadStream` object `stream` and the `DynamicBuffer` object `b` are is valid until the completion handler for the asynchronous operation is invoked.

### 3118(i). `fpos` equality comparison unspecified

Section: 29.5.3.2 [fpos.operations] Status: New Submitter: Jonathan Wakely Opened: 2018-06-04 Last modified: 2020-09-06

Priority: 4

View all other issues in [fpos.operations].

View all issues with New status.

Discussion:

The `fpos` requirements do not give any idea what is compared by `operator==` (even after Daniel's P0759R1 paper). I'd like something to make it clear that `return true;` is not a valid implementation of `operator==(const fpos<T>&, const fpos<T>&)`. Maybe in the `P(o)` row state that "`p == P(o)`" and "`p != P(o + 1)`", i.e. two `fpos` objects constructed from the same `streamoff` values are equal, and two `fpos` objects constructed from two different `streamoff` values are not equal.

[2018-06-23 after reflector discussion]

Priority set to 4

Proposed resolution:

### 3124(i). [networking.ts] Unclear how `execution_context` is intended to store services

Section: 13.7.5 [networking.ts::async.exec.ctx.globals] Status: New Submitter: Billy O'Neal III Opened: 2018-06-23 Last modified: 2020-09-06

Priority: 3

View all issues with New status.

Discussion:

Addresses: networking.ts

`make_service` and `use_service` create arbitrary numbers of type `Service`, a type provided by the user, similar to how locale's `use_facet` works. As a result there's no amount of storage that could be reserved inside `execution_context` to avoid allocating memory. However, there's no allocator support here, and `make_service` is forbidden from throwing allocation related exceptions by N4734 [async.exec.ctx.globals]/7.

If the intent is for `execution_context` to allocate memory, are user overloads of `operator new` on type `Service` intended to be used?

[2018-07-20 Priority set to 3 after reflector discussion]

[Jonathan provides wording.]

Proposed resolution:

This wording is relative to the N4762.

1. Modify 13.7.5 [networking.ts::async.exec.ctx.globals] p7:

   -7- Throws: `service_already_exists` if a corresponding service object of type `Service::key_type` is already present in the set , `bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained. Any exception thrown by the constructor of `Service`.

### 3126(i). There's no `std::sub_match::compare(string_view)` overload

Section: 30.8 [re.submatch] Status: New Submitter: Jonathan Wakely Opened: 2018-06-26 Last modified: 2020-09-06

Priority: 3

View other active issues in [re.submatch].

View all other issues in [re.submatch].

View all issues with New status.

Discussion:

`std::sub_match::compare` can be called with a `basic_string` or a pointer to a null-terminated character sequence, but can't be called with a `basic_string_view`. To compare to a `string_view` requires either conversion to `basic_string` (with a potential allocation) or a redundant call to `traits_type::length` to calculate a length that is already known.

[2018-07-02, Jonathan comments and completes proposed wording]

To make the relational and equality operators for `sub_match` support string views I propose specifying the semantics, not adding another 12 overloaded operators to namespace `std`, in addition to the 42 already there. This allows them to be implemented as "hidden friends" if the implementation so desires, or to retain namespace-scope declaration if backwards compatibility with C++11 - C++17 is preferred.

[2018-07-20 Priority set to 3 after reflector discussion]

Proposed resolution:

This wording is relative to N4750.

1. Change 30.3 [re.syn], header `<regex>` synopsis, as indicated:

   >     #include <initializer_list>

   >     namespace std {
   >       […]
   >       using csub_match = sub_match<const char*>;
   >       using wcsub_match = sub_match<const wchar_t*>;
   >       using ssub_match = sub_match<string::const_iterator>;
   >       using wssub_match = sub_match<wstring::const_iterator>;

   >       // 30.8.3 [re.submatch.op], sub_match non-member operators
   >       template<class BiIter>
   >       bool operator==(const sub_match<BiIter>& lhs, const sub_match<BiIter>& rhs);
   >       […]
   >       template<class BiIter>
   >         bool operator>=(const sub_match<BiIter>& lhs,
   >                        const typename iterator_traits<BiIter>::value_type& rhs);

   >       template<class charT, class ST, class BiIter>
   >       basic_ostream<charT, ST>&
   >       operator<<(basic_ostream<charT, ST>& os, const sub_match<BiIter>& m);
   >       […]
   >     }

2. Change 30.8 [re.submatch], class template `sub_match` synopsis, as indicated:

   >     namespace std {
   >       template<class BidirectionalIterator>
   >       class sub_match : public pair<BidirectionalIterator, BidirectionalIterator> {
   >       public:
   >         using value_type =
   >           typename iterator_traits<BidirectionalIterator>::value_type;
   >         […]
   >         int compare(const sub_match& s) const;
   >         int compare(const string_type& s) const;
   >         int compare(const value_type* s) const;
   >         int compare(basic_string_view<value_type> s) const;
   >       };
   >     }

3. Change 30.8.2 [re.submatch.members] as indicated:

   >     int compare(const value_type* s) const;

   > > -7- Returns: `str().compare(s)`.

   >     int compare(basic_string_view<value_type> s) const;

   > > -?- Returns: `str().compare(s)`.

4. Change sub-clause 30.8.3 [re.submatch.op] as indicated:

   > 31.9.2 `sub_match` non-member operators [re.submatch.op]

   >     template<class BiIter>
   >     bool operator==(const sub_match<BiIter>& lhs, const sub_match<BiIter>& rhs);

   > > -1- Returns: `lhs.compare(rhs) == 0`.

   > […]

   >     template<class BiIter>
   >       bool operator>=(const sub_match<BiIter>& lhs,
   >         const typename iterator_traits<BiIter>::value_type& rhs);

   > > -42- Returns: `!(lhs < rhs)`.

   >     template<class charT, class ST, class BiIter>
   >       basic_ostream<charT, ST>&
   >         operator<<(basic_ostream<charT, ST>& os, const sub_match<BiIter>& m);

   > > -43- Returns: `os << m.str()`.

   > Class template `sub_match` provides overloaded relational operators (7.6.9 [expr.rel]) and equality operators (7.6.10 [expr.eq]) for comparisons with another `sub_match`, with a `string`, or with a single character. The expressions shown in Table ?? are valid when one of the operands is a type `S`, that is a specialization of `sub_match`, and the other expression is one of:

   > 1. (?.?) — a value `x` of a type `S`, in which case `STR(x)` is `x.str()`;

   > 2. (?.?) — a value `x` of type `basic_string<S::value_type, T, A>` for any types `T` and `A`, in which case `STR(x)` is `basic_string_view<S::value_type>(x.data(), x.length())`;

   > 3. (?.?) — a value `x` of type `basic_string_view<S::value_type, T>` for any type `T`, in which case `STR(x)` is `basic_string_view<S::value_type>(x.data(), x.length())`;

   > 4. (?.?) — a value `x` of a type convertible to `const S::value_type*`, in which case `STR(x)` is `basic_string_view<S::value_type>(x)`;

   > 5. (?.?) — a value `x` of type convertible to `S::value_type`, in which case `STR(x)` is `basic_string_view<S::value_type>(&x, 1)`.

   > Table ?? — `sub_match` comparisons
   > Expression | Return type | Operational semantics
   > --- | --- | ---
   > `s == t` | `bool` | `STR(s).compare(STR(t)) == 0`
   > `s != t` | `bool` | `STR(s).compare(STR(t)) != 0`
   > `s < t` | `bool` | `STR(s).compare(STR(t)) < 0`
   > `s > t` | `bool` | `STR(s).compare(STR(t)) > 0`
   > `s <= t` | `bool` | `STR(s).compare(STR(t)) <= 0`
   > `s >= t` | `bool` | `STR(s).compare(STR(t)) >= 0`

### 3136(i). [fund.ts.v3] LFTSv3 awkward wording in `propagate_const` requirements

Section: 3.2.2.2.1 [fund.ts.v3::propagate_const.class_type_requirements] Status: New Submitter: Thomas Köppe Opened: 2018-07-02 Last modified: 2020-09-06

Priority: 3

View all issues with New status.

Discussion:

Addresses: fund.ts.v3

In the LFTSv3 prospective-working-paper N4758, [propagate_const.class_type_requirements] uses a strange turn of phrase:

> "In this sub-clause, `t` denotes a non-`const` lvlaue of type `T`, `ct` is a `const T&` bound to `t`, […]"

The last bit is strange: "`ct` is a `const T&` bound to `t`" is not how we usually say things. The specification-variables usually denote values, and values can't be references. Perhaps we could just say, "`ct` is `as_const(t)`"?

[2018-07-20 Priority set to 3 after reflector discussion]

Proposed resolution:

This wording is relative to N4758.

1. Edit 3.2.2.2.1 [fund.ts.v3::propagate_const.class_type_requirements] as indicated:

   > -1- If `T` is class type then it shall satisfy the following requirements. In this sub-clause `t` denotes a non-`const` lvalue of type `T`, `ct` is a `const T&` bound to `t` `as_const(t)`, `element_type` denotes an object type.

### 3142(i). `std::foo<incomplete>` should be ill-formed NDR

Section: 16.4.5.8 [res.on.functions] Status: New Submitter: Casey Carter Opened: 2018-07-07 Last modified: 2018-11-27

Priority: 3

View all other issues in [res.on.functions].

View all issues with New status.

Discussion:

16.4.5.8 [res.on.functions]/2 states:

> -2- In particular, the effects are undefined in the following cases:

> […]

> (2.5) — if an incomplete type (6.8 [basic.types]) is used as a template argument when instantiating a template component or evaluating a concept, unless specifically allowed for that component.

While undefined behavior is appropriate for the other cases specified in the earlier bullets, which describe failure to meet (runtime) semantic requirements, "instantiating a template component or evaluating a concept" with an incomplete type happens at compile-time, and could potentially be diagnosed. It would therefore be more appropriate to specify that programs which do so are ill-formed with no diagnostic required.

[2018-11 Reflector prioritization]

Set Priority to 3

Proposed resolution:

This wording is relative to N4762.

Change 16.4.5.8 [res.on.functions] as indicated:

> (2.5) — if an incomplete type (6.8 [basic.types]) is used as a template argument when instantiating a template component or evaluating a concept, unless specifically allowed for that component.

> -?- Unless explicitly stated otherwise, a program that instantiates a template component or evaluates a concept with an incomplete type (6.8 [basic.types]) as a template argument is ill-formed with no diagnostic required.

### 3157(i). Allocator `destroy` and fancy pointer operations must be non-throwing

Section: 16.4.4.6 [allocator.requirements] Status: New Submitter: Billy O'Neal III Opened: 2018-09-07 Last modified: 2018-12-16

Priority: 3

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with New status.

Discussion:

In annotating things required to be called by `~vector`, Casey pointed out that several operations I guarded with `noexcept` aren't actually mandated by the standard to be `noexcept`. However, the STL, and more specifically here, containers, consider inability to destroy an element an unrecoverable condition. This is evidenced for the whole STL by 16.4.6.13 [res.on.exception.handling]/3 "Every destructor in the C ++ standard library shall behave as if it had a non-throwing exception specification.".

As a result, `allocator::destroy` and fancy pointer operations must be non-throwing for valid input, or the containers don't make any sense. This is obvious for things like `vector::~vector`, but less obviously the containers rely on these guarantees whenever inserting more than one element, etc.

Moreover, we too narrowly specify the domain of the `pointer_traits::pointer_to` requirement in the `Cpp17Allocator` requirements, because any node-based container that uses container-internal sentinel nodes needs to be able to form pointers to said sentinel nodes; that operation must also be non-throwing.

[2018-09 Reflector prioritization]

Set Priority to 3

Proposed resolution:

This wording is relative to N4762.

1. Modify 16.4.4.6 [allocator.requirements], Table 32 "Descriptive variable definitions" as indicated:

   > Table 32 — Descriptive variable definitions
   > Variable | Definition
   > --- | ---
   > `…`
   > `YY` | the type `allocator_traits<Y>`
   > `Z` | an allocator-aware container type (22.2.1 [container.requirements.general])
   > `…`
   > `y` | a value of type `XX::const_void_pointer` obtained by conversion from a result value of `YY::allocate`, or else a value of type (possibly `const`) `std::nullptr_t`.
   > `z` | an lvalue of type `Z` such that `z.get_allocator() == a`
   > `r1` | a reference to any member subobject of `z`
   > `n` | a value of type `XX::size_type`.
   > `…`

2. Modify 16.4.4.6 [allocator.requirements], Table 33 "`Cpp17Allocator` requirements" as indicated:

   > Table 33 — `Cpp17Allocator` requirements
   > Expression | Return type | Assertion/note pre-/post-condition | Default
   > --- | --- | --- | ---
   > `…`
   > `pointer_traits< X::pointer >::pointer_to(r)` | `X::pointer` | S same as `p`. Throws: Nothing. |
   > `pointer_traits< X::pointer >::pointer_to(r1)` |  | A value of type `YY::pointer` or `YY::const_pointer` `k` such that `*k` is `r1`. Throws: Nothing. |
   > `…`
   > `a.destroy(c)` | (not used) | Effects: Destroys the object at `c`. Throws: Nothing. | `c->~C()`
   > `…`

3. Modify 16.4.4.6 [allocator.requirements], p5, as indicated:

   > -5- An allocator type `X` shall satisfy the `Cpp17CopyConstructible` requirements (Table 26). The `X::pointer`, `X::const_pointer`, `X::void_pointer`, and `X::const_void_pointer` types shall satisfy the `Cpp17NullablePointer` requirements (Table 30). No constructor, comparison function, 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 (23.3.5.7 [random.access.iterators]) and of a contiguous iterator (23.3.1 [iterator.requirements.general]) and operations in those requirements shall not exit via an exception so long as resulting iterators are dereferencable or past-the-end.

4. Modify 20.10.8.3 [allocator.traits.members], as indicated:

   >     template<class T>
   >       static void destroy(Alloc& a, T* p);

   > > -6- Effects: Calls `a.destroy(p)` if that call is well-formed; otherwise, invokes `p->~T()`.

   > > -?- Throws: Nothing.

### 3159(i). §[unique.ptr.single] requirements on deleter may be too strict

Section: 20.11.1.3 [unique.ptr.single] Status: New Submitter: Jonathan Wakely Opened: 2018-09-17 Last modified: 2018-10-06

Priority: 3

View other active issues in [unique.ptr.single].

View all other issues in [unique.ptr.single].

View all issues with New status.

Discussion:

20.11.1.3 [unique.ptr.single] p1 says:

> The default type for the template parameter `D` is `default_delete`. A client-supplied template argument `D` shall be a function object type (19.14), lvalue reference to function, or lvalue reference to function object type for which, given a value `d` of type `D` and a value ptr of type `unique_ptr<T, D>::pointer`, the expression `d(ptr)` is valid and has the effect of disposing of the pointer as appropriate for that deleter.

That means this is undefined:

>     #include <memory>

>     struct IncompleteBase;

>     struct Deleter {
>       void operator()(IncompleteBase*) const;
>     };

>     struct IncompleteDerived;

>     struct X {
>       std::unique_ptr<IncompleteDerived, Deleter> p;
>       ~X();
>     };

`unique_ptr::pointer` is `IncompleteDerived*`, but `is_invocable<Deleter, IncompleteDerived*>` is unknowable until the type is complete (see LWG 3099 etc).

The intention is that `IncompleteDerived` only needs to be complete when the deleter is invoked, which is in the definition of `X::~X()` for this example. But the requirement for `d(ptr)` to be valid requires a complete type. If the `unique_ptr` implementation adds `static_assert(is_invocable_v<D, pointer>)` to enforce the requirement, the example above fails to compile. GCC recently added that assertion.

Do we want to relax that requirement, or do we want to force the code above to define `Deleter::pointer` as `IncompleteBase*` so that the `is_invocable` condition can be checked?

The destructor and `reset` member function already require that the deleter can be invoked (and that Requires: element will be turned into a Mandates: one soon). We can just remove that requirement from the preamble for the class template, or say that the expression only needs to be valid when the destructor and `reset` member are instantiated. We could also rephrase it in terms of `is_invocable_v<D, unique_ptr<T, D>::pointer>`.

[2018-10 Reflector prioritization]

Set Priority to 3

Proposed resolution:

### 3161(i). Container adapters mandate use of `emplace_back` but don't require it

Section: 22.6.6 [stack], 22.6.4 [queue] Status: Open Submitter: Marshall Clow Opened: 2018-10-02 Last modified: 2020-05-09

Priority: 3

View all other issues in [stack].

View all issues with Open status.

Discussion:

22.6.6 [stack] p1 says:

> Any sequence container supporting operations `back()`, `push_back()` and `pop_back()` can be used to instantiate `stack`.

but then in 22.6.6.2 [stack.defn] we have the following code:

    template<class... Args>
      decltype(auto) emplace(Args&&... args)
        { return c.emplace_back(std::forward<Args>(args)...); }

The same pattern appears in 22.6.4 [queue].

I see two ways to resolve this:

The first is to add `emplace_back()` to the list of requirements for underlying containers for `stack` and `queue`

The second is to replace the calls to `c.emplace_back(std::forward<Args>(args)...)` with `c.emplace(c.end(), std::forward<Args>(args)...)`. We can do this w/o messing with the list above because `emplace` is part of the sequence container requirements, while `emplace_back` is not. I checked the libc++ implementation of `vector`, `deque`, and `list`, and they all do the same thing for `emplace(end(), ...)` and `emplace_back(...)`.

[2019-02; Kona Wednesday night issue processing]

Status to Open; Casey to provide updated wording, and re-vote on reflector.

Polls were: NAD - 5-1-3; "Option B" - 2-5-2 and "Probe the container" - 7-2-0

Previous resolution [SUPERSEDED]:

> This wording is relative to N4762.

> > I have prepared two mutually exclusive options.
> > Option A a requirement for `emplace_back` to the underlying container.
> > Option B one replaces the calls to `emplace_back` with calls to `emplace`.

> Option A

> 1. Edit 22.6.6 [stack], as indicated:

>    Any sequence container supporting operations `back()`, `push_back()`, `emplace_back()` and `pop_back()` can be used to instantiate `stack`.

> 2. Edit 22.6.4.1 [queue.defn], as indicated:

>    Any sequence container supporting operations `front()`, `back()`, `push_back()`, `emplace_back()` and `pop_front()` can be used to instantiate `queue`.

> Option B

> 1. Edit 22.6.6.2 [stack.defn], class template `stack` definition, as indicated:

>    >     template<class... Args>
>    >       decltype(auto) emplace(Args&&... args)
>    >         { return c.emplace_back(c.end(), std::forward<Args>(args)...); }

> 2. Edit 22.6.4.1 [queue.defn], class template `queue` definition, as indicated:

>    >     template<class... Args>
>    >       decltype(auto) emplace(Args&&... args)
>    >         { return c.emplace_back(c.end(), std::forward<Args>(args)...); }

[2020-05 Casey provides new wording]

This is the "probe for `emplace_back` with fallback to `emplace`" approach that LWG wanted to see wording for in Kona.

[2020-05-09; Reflector prioritization]

Set priority to 3 after reflector discussions.

Proposed resolution:

This wording is relative to N4861.

1. Edit 22.6.6.2 [stack.defn], class template `stack` definition, as indicated:

   >     template<class... Args>
   >       decltype(auto) emplace(Args&&... args) {
   >         if constexpr (requires { c.emplace_back(std::forward<Args>(args)...); }) {
   >           return c.emplace_back(std::forward<Args>(args)...);
   >         } else {
   >           return c.emplace(c.end(), std::forward<Args>(args)...);
   >         }
   >       }

2. Edit 22.6.4.1 [queue.defn], class template `queue` definition, as indicated:

   >     template<class... Args>
   >       decltype(auto) emplace(Args&&... args) {
   >         if constexpr (requires { c.emplace_back(std::forward<Args>(args)...); }) {
   >           return c.emplace_back(std::forward<Args>(args)...);
   >         } else {
   >           return c.emplace(c.end(), std::forward<Args>(args)...);
   >         }
   >       }

### 3162(i). `system_error::system_error(error_code ec)` not explicit

Section: 19.5.8.2 [syserr.syserr.members] Status: New Submitter: Peter Dimov Opened: 2018-10-02 Last modified: 2020-04-07

Priority: 3

View all other issues in [syserr.syserr.members].

View all issues with New status.

Discussion:

The constructor for `std::system_error` taking a single argument of type `std::error_code` is not marked explicit, which allows implicit conversions from `error_code` to `system_error`. I think that this is an oversight and not intentional, and that we should make this constructor explicit.

[2020-04-07 Issue Prioritization]

Priority to 3 after reflector discussion.

Proposed resolution:

This wording is relative to N4762.

1. Change 19.5.8.1 [syserr.syserr.overview] p2, class `system_error` synopsis, as indicated

   >     namespace std {
   >       class system_error : public runtime_error {
   >       public:
   >         system_error(error_code ec, const string& what_arg);
   >         system_error(error_code ec, const char* what_arg);
   >         explicit system_error(error_code ec);
   >         system_error(int ev, const error_category& ecat, const string& what_arg);
   >         system_error(int ev, const error_category& ecat, const char* what_arg);
   >         system_error(int ev, const error_category& ecat);
   >         const error_code& code() const noexcept;
   >         const char* what() const noexcept override;
   >       };
   >     }

2. Change 19.5.8.2 [syserr.syserr.members] as indicated

   >     explicit system_error(error_code ec);

   > > -5- Effects: […]

   > > -6- Ensures: […]

### 3166(i). No such descriptive element as Value:

Section: 20.4.4 [pair.astuple], 20.7.4 [variant.helper], 22.3.7.7 [array.tuple], 20.10.3.2 [pointer.traits.types], 20.10.8.2 [allocator.traits.types], 20.13.2 [allocator.adaptor.types] Status: New Submitter: Walter Brown Opened: 2018-11-08 Last modified: 2020-09-06

Priority: 3

View all other issues in [pair.astuple].

View all issues with New status.

Discussion:

In N4778, 20.4.4 [pair.astuple], 20.7.4 [variant.helper], and 22.3.7.7 [array.tuple], are partly specified via a fictitious descriptive element Value: Moreover, 99 [span.tuple] is on track to do likewise in the near future.

Let's invent such a Value: element and properly document it within 16.3.2.4 [structure.specifications], or else let's respecify the offending uses.

[2018-11 Reflector prioritization]

Set Priority to 3

[2020-05-01; Daniel comments]

It should be pointed out that the originally referred to Value: element has since then be renamed to Type: but the reported problem (its lack of definition) still exists in N4861.

Proposed resolution:

### 3167(i). [fund.ts.v3] Does `observer_ptr` support function types?

Section: 5.2 [fund.ts.v3::memory.observer.ptr] Status: New Submitter: Alisdair Meredith Opened: 2018-11-14 Last modified: 2018-11-27

Priority: 3

View all issues with New status.

Discussion:

Addresses: fund.ts.v3

From the wording, function pointers are never clearly considered. P1 infers support for only objects, but it is not clear that wording is intended to be a deliberate restriction, or is casual wording.

Paragraph 2 mandates that we cannot instantiate for reference types, and do support incomplete types, but still does not consider function types. Calling out references specifically, as they are not object types, suggests the inferred support for only objects in p1 is more a case of casual phrasing, than deliberate intent.

However, if we did intend to support function pointers, we may want to consider adding a function-call operator, constrained to supporting pointer-to function types. One other possibility is that the explicit conversion to `pointer` already serves that purpose, although I need to double-check the core language that contextual conversions to function pointer are considered when invoking the function call operator. If this is the case, then I suggest a note to that effect in [memory.observer.ptr.conv] instead.

[2018-11 Reflector prioritization]

Set Priority to 3

Proposed resolution:

### 3172(i). 3-arg `std::hypot` is underspecified compared to the 2-arg overload

Section: 26.8.3 [c.math.hypot3] Status: New Submitter: Matthias Kretz Opened: 2018-12-06 Last modified: 2018-12-21

Priority: 3

View all issues with New status.

Discussion:

The 2-arg `hypot` function specified in the C standard is required to avoid overflow and underflow (7.12.7.3 p2). Furthermore C's Annex F (IEC 60559 floating-point arithmetic) defines special cases for inputs of `±0` and `±inf` (F. 10.4.3). The 3-arg `hypot` function 26.8.3 [c.math.hypot3] is only specified as "Returns: x 2+ y 2+z 2.". This is inconsistent with the 2-arg overload.

It is not clear whether C's Annex F is "imported" into the C++ standard. [cmath.syn] p1 suggests that it is: "The contents and meaning of the header `<cmath>` are the same as the C standard library header `<math.h>`, […]".

[2018-12-21 Reflector prioritization]

Set Priority to 3

Proposed resolution:

This wording is relative to N4778.

> [Drafting Note: Two mutually exclusive options are prepared, depicted below by Option A and Option B, respectively.]

Option A

1. Modify 26.8.3 [c.math.hypot3] as indicated:

   > >     float hypot(float x, float y, float z);
   > >     double hypot(double x, double y, double z);
   > >     long double hypot(long double x, long double y, long double z);

   > > > -?- Effects: The `hypot` functions compute the square root of the sum of the squares of `x`, `y`, and `z`, without undue overflow or underflow. A range error may occur.

   > > > -1- Returns: x 2+ y 2+z 2.

   > > > -?- Remarks: If `__STDC_IEC_559__` is defined, the following guarantees hold:

   > > > - `hypot(x, y, z)`, `hypot(x, z, y)`, `hypot(z, y, x)`, and `hypot(x, y, -z)` are equivalent.

   > > > - if `y2 + z2 == ±0`, `hypot(x, y, z)` is equivalent to `fabs(x)`.

   > > > - `hypot(±∞, y, z)` returns `+∞`, even if `y` and/or `z` is a NaN.

Option B

1. Add a note that clarifies that the behavior of the 3-arg `hypot` function differs from the C specification. I.e. that no special guarantees wrt. over-/underflow or special values are given.

### 3174(i). Precondition on `is_convertible` is too strong

Section: 20.15.7 [meta.rel] Status: New Submitter: Casey Carter Opened: 2018-12-09 Last modified: 2019-03-16

Priority: 3

View other active issues in [meta.rel].

View all other issues in [meta.rel].

View all issues with New status.

Discussion:

Per Table 49 in 20.15.7 [meta.rel], the preconditions for both `is_convertible<From, To>` and `is_nothrow_convertible<From, To>` are:

> `From` and `To` shall be complete types, arrays of unknown bound, or cv `void` types.

Consequently, this program fragment:

>     struct S;
>     static_assert(is_convertible_v<S, const S&>);

has undefined behavior despite that the actual behavior of `is_convertible` specified in [meta.rel]/5:

> -5- The predicate condition for a template specialization `is_convertible<From, To>` shall be satisfied if and only if the return expression in the following code would be well-formed, including any implicit conversions to the return type of the function:

> >     To test() {
> >       return declval<From>();
> >     }

> [ Note: …]

is well-formed: `declval<S>()` is an xvalue of type `S`, which certainly does implicitly convert to `const S&`. We should relax the precondition to allow this perfectly valid case (and similar cases like `is_convertible<S, S&&>`), letting the cases that would in fact be invalid fall through to the blanket "incompletely-defined object type" wording in [meta.rqmts]/5.

[2018-12-21 Reflector prioritization]

Set Priority to 3

Proposed resolution:

This wording is relative to N4791.

1. Modify Table 49 in 20.15.7 [meta.rel] as follows:

   Table 49 — Type relationship predicates
   Template | Condition | Comments
   --- | --- | ---
   […] | […] | […]
       template<class From, class To>
       struct is_convertible;
   | see below | `From` and `To` shall be a complete types, an arrays of unknown bound, or cv `void` types.
       template<class From, class To>
       struct is_nothrow_convertible;
   | `is_convertible_v<From, To>` is `true` and the conversion, as defined by `is_convertible`, is known not to throw any exceptions (7.6.2.7 [expr.unary.noexcept]) | `From` and `To` shall be a complete types, an arrays of unknown bound, or cv `void` types.
   […] | […] | […]

### 3177(i). Limit permission to specialize variable templates to program-defined types

Section: 16.4.5.2.1 [namespace.std] Status: New Submitter: Johel Ernesto Guerrero Peña Opened: 2018-12-11 Last modified: 2018-12-21

Priority: 3

View other active issues in [namespace.std].

View all other issues in [namespace.std].

View all issues with New status.

Discussion:

The permission denoted by [namespace.std]/3 should be limited to program-defined types.

[2018-12-21 Reflector prioritization]

Set Priority to 3

Proposed resolution:

This wording is relative to N4791.

1. Change 16.4.5.2.1 [namespace.std] as indicated:

   > -2- Unless explicitly prohibited, a program may add a template specialization for any standard library class template to namespace `std` provided that (a) the added declaration depends on at least one program-defined type and (b) the specialization meets the standard library requirements for the original template.(footnote 174)

   > -3- The behavior of a C++ program is undefined if it declares an explicit or partial specialization of any standard library variable template, except where explicitly permitted by the specification of that variable template, provided that the added declaration depends on at least one program-defined type.

### 3188(i). `istreambuf_iterator::pointer` should not be unspecified

Section: 23.6.4 [istreambuf.iterator] Status: New Submitter: Jonathan Wakely Opened: 2019-02-21 Last modified: 2019-10-30

Priority: 3

View other active issues in [istreambuf.iterator].

View all other issues in [istreambuf.iterator].

View all issues with New status.

Discussion:

The current working paper requires `iterator_traits<Iter>::pointer` to be `void` if `Iter` doesn't define `operator->` (23.3.2.3 [iterator.traits]). We recently removed `operator->` from `istreambuf_iterator` via LWG 2790, therefore either its `pointer` member should be `void`, or there should be a partial specialization of `iterator_traits`. Do we want to change unspecified to `void` in the class synopsis in [istreambuf.iterator]?

[2019-03-03, Daniel provides concrete wording]

[2019-03-05 Priority set to 3 after reflector discussion]

[2019-03-05, Daniel comments]

With the acceptance of P1252R2 the committee decided to deprecate `operator->` of `move_iterator`, interestingly without mentioning what should happen with its current `pointer` typedef (which is equal to the template parameter `Iterator` and thus never `void`). Effectively this is a very similar situation as for the here discussed `istreambuf_iterator` case and it seems attractive to me to solve both cases similarly.

[2019-10-30, Jonathan comments]

Also, `reverse_iterator::operator->()` is now constrained and so not always defined, but `reverse_iterator::pointer` is defined unconditionally.

Proposed resolution:

This wording is relative to N4800.

1. Change class template `istreambuf_iterator` synopsis, 23.6.4 [istreambuf.iterator], as indicated:

   >     template<class charT, class traits = char_traits<charT>>
   >     class istreambuf_iterator {
   >     public:
   >       using iterator_category = input_iterator_tag;
   >       using value_type        = charT;
   >       using difference_type   = typename traits::off_type;
   >       using pointer           = voidunspecified;
   >       using reference         = charT;
   >       […]
   >     };

### 3189(i). Missing requirement for `std::priority_queue`

Section: 22.6.5 [priority.queue] Status: New Submitter: Jonathan Wakely Opened: 2019-02-21 Last modified: 2019-03-05

Priority: 3

View all other issues in [priority.queue].

View all issues with New status.

Discussion:

We don't require that the `Compare` template parameter can be invoked with arguments of the queue's value type. It seems like something we can use Mandates: for, since it'll be ill-formed otherwise. Something like `is_invocable_r_v<bool, Compare&, value_type&, value_type&>`.

This might also apply to the `Compare` parameter for the `merge` and `sort` functions of `forward_list` and `list`.

[2019-03-05 Priority set to 3 after reflector discussion]

Proposed resolution:

### 3192(i). §[allocator.uses.construction] functions misbehave for `const` types

Section: 20.10.7.2 [allocator.uses.construction] Status: New Submitter: Jonathan Wakely Opened: 2019-02-28 Last modified: 2020-05-01

Priority: 3

View other active issues in [allocator.uses.construction].

View all other issues in [allocator.uses.construction].

View all issues with New status.

Discussion:

The new functions added by P0591R4 misbehave for cv-qualified types. A specialization `std::uses_allocator<X, Alloc>` will not match `const X`, so `std::uses_allocator_construction_args<const X>` will return a different result from `std::uses_allocator_construction_args<X>`. It makes no sense to construct `X` and `const X` differently, either the type wants to use an allocator or it doesn't. I think `std::uses_allocator_construction_args<T>` should remove cv-qualifiers before checking `uses_allocator`, so that it works consistently.

We could consider changing `std::make_obj_using_allocator` to also strip cv-qualifiers, but it's not necessary as C++17 guaranteed elision works even for prvalues of `const` types. We only need to make the construction args ignore cv-qualifiers. We don't want to make cv-qualified types ill-formed, because that would require users of uses-allocator construction to strip cv-qualifiers before using these functions, e.g. in cases like `std::tuple<const int> t(allocator_arg, alloc, 1);`

[2019-03-15 Priority set to 3 after reflector discussion]

Previous resolution [SUPERSEDED]:

> This wording is relative to N4800.

> 1. Change 20.10.7.2 [allocator.uses.construction] as indicated:

>    >     template <class T, class Alloc, class... Args>
>    >       auto uses_allocator_construction_args(const Alloc& alloc, Args&&... args) -> see below;

>    > > -4- Constraints: `T` is not a specialization of `pair`.

>    > > -5- Returns: A `tuple` value determined as follows, where `U` denotes the type `remove_cv_t<T>`:

>    > > 1. (5.1) — If `uses_allocator_v<TU, Alloc>` is `false` and `is_constructible_v<T, Args...>` is `true`, return `forward_as_tuple(std::forward<Args>(args)...)`.

>    > > 2. (5.2) — Otherwise, if `uses_allocator_v<TU, Alloc>` is `true` and `is_constructible_v<T, allocator_arg_t, Alloc, Args...>` is `true`, return

>    > >    >     tuple<allocator_arg_t, const Alloc&, Args&&...>(
>    > >    >       allocator_arg, alloc, std::forward<Args>(args)...)

>    > > 3. (5.3) — Otherwise, if `uses_allocator_v<TU, Alloc>` is `true` and `is_constructible_v<T, Args..., Alloc>` is `true`, return `forward_as_tuple(std::forward<Args>(args)..., alloc)`.

>    > > 4. (5.4) — Otherwise, the program is ill-formed.

>    > […]

>    >     template <class T, class Alloc, class Tuple1, class Tuple2>
>    >       auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t,
>    >                                             Tuple1&& x, Tuple2&& y) -> see below;

>    > > -6- Constraints: `T` is a specialization of `pair`.

>    > > -7- Effects: For `T` specified as (possibly `const`) `pair<T1, T2>`, equivalent to:

>    > > […]

>    >     template <class T, class Alloc, class... Args>
>    >       T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc, Args&&... args);

>    > > -17- Effects: Equivalent to:

>    > > >     return ::new(static_cast<void*>voidify(*p))
>    > > >       T(make_obj_using_allocator<T>(alloc, std::forward<Args>(args)...));

[2020-05-01; Daniel syncs wording with recent working draft]

The previously needed change for `uninitialized_construct_using_allocator` is no longer required, because the reworded call to `construct_at` does do the right thing now.

Proposed resolution:

This wording is relative to N4861.

1. Change 20.10.7.2 [allocator.uses.construction] as indicated:

   >     template <class T, class Alloc, class... Args>
   >       constexpr auto uses_allocator_construction_args(const Alloc& alloc,
   >                                             Args&&... args) noexcept -> see below;

   > > -4- Constraints: `T` is not a specialization of `pair`.

   > > -5- Returns: A `tuple` value determined as follows, where `U` denotes the type `remove_cv_t<T>`:

   > > 1. (5.1) — If `uses_allocator_v<TU, Alloc>` is `false` and `is_constructible_v<T, Args...>` is `true`, return `forward_as_tuple(std::forward<Args>(args)...)`.

   > > 2. (5.2) — Otherwise, if `uses_allocator_v<TU, Alloc>` is `true` and `is_constructible_v<T, allocator_arg_t, const Alloc&, Args...>` is `true`, return

   > >    >     tuple<allocator_arg_t, const Alloc&, Args&&...>(
   > >    >       allocator_arg, alloc, std::forward<Args>(args)...)

   > > 3. (5.3) — Otherwise, if `uses_allocator_v<TU, Alloc>` is `true` and `is_constructible_v<T, Args..., const Alloc&>` is `true`, return `forward_as_tuple(std::forward<Args>(args)..., alloc)`.

   > > 4. (5.4) — Otherwise, the program is ill-formed.

   > […]

   >     template <class T, class Alloc, class Tuple1, class Tuple2>
   >       constexpr auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t,
   >                                             Tuple1&& x, Tuple2&& y)
   >                                             noexcept -> see below;

   > > -6- Constraints: `T` is a specialization of `pair`.

   > > -7- Effects: For `T` specified as (possibly `const`) `pair<T1, T2>`, equivalent to:

   > > […]

### 3193(i). Mandates: and Expects: elements are not defined for types

Section: 16.3.2.4 [structure.specifications] Status: New Submitter: Daniel Krügler Opened: 2019-03-04 Last modified: 2020-06-11

Priority: 3

View other active issues in [structure.specifications].

View all other issues in [structure.specifications].

View all issues with New status.

Discussion:

The working paper uses the special elements Mandates:, Expects: as well as Requires: to types, albeit 16.3.2.4 [structure.specifications] defines them only for functions, for example 16.3.2.4 [structure.specifications] sub-bullet (3.4):

> Expects: the conditions (sometimes termed preconditions) that the function assumes to hold whenever it is called.

Examples for such usages on types are (from N4800):

- 21.2.3 [char.traits.typedefs] for types `int_type` and `state_type`

- 20.4.4 [pair.astuple] for `tuple_element<I, pair<T1, T2>>::type`

- 20.5.6 [tuple.helper] for `tuple_element<I, tuple<Types...>>::type`

- 20.5.9 [tuple.traits] for `uses_allocator<tuple<Types...>, Alloc>`

- Table 62 — "Container requirements" for type `XX::value_type`

- Table 65 — "Allocator-aware container requirements" for type `allocator_type`

- Table 69 — "Associative container requirements" for types `X::value_type` and `X::key_compare`

- Table 70 — "Unordered associative container requirements" for types `X::value_type` and `X::key_equal`

Instead of replacing these elements usages for these places by extra wording to reach the same effects I recommend to update instead 16.3.2.4 [structure.specifications] to ensure that requirement-expressing elements are defined in a way that it also allows to express requirements imposed on types by these elements to standardize "existing practice".

Considering details, it seems obvious that Mandates:, Expects: as well as Requires: are "suitable" to be defined for types (With the acceptance of P1463R1 there are now also Mandates: for types such as Table 65 — "Allocator-aware container requirements" for type `allocator_type`).

For Constraints: the meaning would not be so clear: Should it mean that there is conditionally a type defined or not? According to the submitters knowledge there are currently no known examples for Constraints: to specify constraint on types, therefore I'm suggesting to restrict this extension to Mandates:, Expects:, and Requires: alone.

[2019-03-15 Priority set to 3 after reflector discussion]

[2019-03-15; Daniel comments and provides wording]

During the preparation of the wording for this issue it was found that we should allow Remarks: elements to be used for other things than functions. One example of imposed restrictions can be found in 17.11.3 [cmp.common]:

>     template<class... Ts>
>     struct common_comparison_category {
>       using type = see below;
>     };

> -2- Remarks: The member typedef-name `type` denotes the common comparison type (11.10.3 [class.spaceship]) of `Ts...`, the expanded parameter pack. […]

The discussion of this issue speaks of "type" restrictions (versus the specified restrictions on functions), because even the non-type template argument restrictions of 20.4.4 [pair.astuple] appear in the context of a member type specification, but there are examples where not really a single (member) type is involved, e.g. in the 20.5.6 [tuple.helper] example mentioned above.

Another example is when such elements are used for the specification of template specializations, e.g. in 20.5.6 [tuple.helper]:

>     template<class T> struct tuple_size;

> > -1- Remarks: All specializations of `tuple_size` shall satisfy the Cpp17UnaryTypeTrait requirements (20.15.2 [meta.rqmts]) with a base characteristic of `integral_constant<size_t, N>` for some `N`.

Besides class template specializations, a second relevant use-case is the specification of member types (Which are not necessarily part of a template), typically within the requirement tables, e.g. in Table 62 — "Container requirements"'s entry `X::value_type`:

> Requires: `T` is Cpp17Erasable from `X`

The suggested wording tries to cover the generalization by means of the term "non-function entities" in addition to the existing functions to prevent being enforced to enumerate all entities to which the extended rules apply.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4810.

> 1. Change 16.3.2.4 [structure.specifications], as indicated:

>    > -3- Descriptions of function semantics contain the following elements (as appropriate); some of these elements may also appear in the description of non-function entities as denoted below: (footnote […])

>    > 1. (3.1) — Requires: the preconditions imposed on a non-function entity, or for calling the function.

>    > 2. (3.2) — Constraints: […]

>    > 3. (3.3) — Mandates: the conditions that, if not met, render the program ill-formed. [Example: An implementation might express such a condition via the constant-expression in a static_assert-declaration (Clause 9). If the diagnostic is to be emitted only after the function has been selected by overload resolution, an implementation might express such a condition via a constraint-expression (13.5.3 [temp.constr.decl]) and also define the function as deleted. — end example]

>    > 4. (3.4) — Expects: the conditions (sometimes termed preconditions) imposed on a non-function entity, or that the function assumes to hold whenever it is called. [Example: An implementation might express such conditions via an attribute such as `[[expects]]` ( [dcl.attr.contract]) on a function declaration. However, some such conditions might not lend themselves to expression via code. — end example]

>    > 5. […]

>    > 6. (3.11) — Remarks: additional semantic constraints on the function.

>    > 7. […]

> 2. Change 99 [res.on.required], as indicated:

>    > -1- Violation of any preconditions specified in a function's Requires: element results in undefined behavior unless the function's Throws: element specifies throwing an exception when the a function's precondition is violated.

>    > -2- Violation of any preconditions specified in an function's Expects: element results in undefined behavior.

[2020-05-01; Daniel comments and adjusts wording to recent working draft]

It should be pointed out that the originally referred to Expects: element has since then be renamed to Preconditions: and that the Requires: element does now only occur in annex D.

[2020-06-11; Jonathan comments]

This issue also affects some type traits such as `alignment_of` and `make_signed`/`make_unsigned`. In addition to clarifying what Mandates: means on a non-function we need to decide exactly what is being mandated in the type traits. Is instantiating the class template ill-formed, or just odr-using the nested `type` or `value` member?

Proposed resolution:

This wording is relative to N4861.

1. Change 16.3.2.4 [structure.specifications], as indicated:

   > -3- Descriptions of function semantics contain the following elements (as appropriate); some of these elements may also appear in the description of non-function entities as denoted below: (footnote […])

   > 1. (3.1) — Constraints: […]

   > 2. (3.2) — Mandates: the conditions that, if not met, render the program ill-formed. [Example: An implementation might express such a condition via the constant-expression in a static_assert-declaration (9.1 [dcl.pre]). If the diagnostic is to be emitted only after the function has been selected by overload resolution, an implementation might express such a condition via a constraint-expression (13.5.3 [temp.constr.decl]) and also define the function as deleted. — end example]

   > 3. (3.3) — Preconditions: the conditions imposed on a non-function entity, or that the function assumes to hold whenever it is called.

   > 4. […]

   > 5. (3.10) — Remarks: additional semantic constraints on the function.

   > 6. […]

2. Change [res.on.expects], as indicated:

   > -1- Violation of any preconditions specified in a function's Preconditions: element results in undefined behavior.

3. Change D.10 [depr.res.on.required], as indicated:

   > [Drafting note: Interestingly, albey the Requires: element has nearly vanished, the issue is still relevant, see D.15 [depr.meta.types]]

   > -1- Violation of any preconditions specified in a function's Requires: element results in undefined behavior unless the function's Throws: element specifies throwing an exception when the a function's precondition is violated.

### 3197(i). `std::prev` should not require `BidirectionalIterator`

Section: 23.4.3 [iterator.operations] Status: New Submitter: Billy O'Neal III Opened: 2019-04-03 Last modified: 2020-09-06

Priority: 3

View other active issues in [iterator.operations].

View all other issues in [iterator.operations].

View all issues with New status.

Discussion:

MSVC++ (and apparently libc++) have asserts that `std::prev` only accepts `BidirectionalIterator`s, because it's declared in the standard as accepting only `BidirectionalIterator`. libc++ changed their tests (in this commit), apparently from a bug report from Ville and Jonathan, saying that one could theoretically call `std::prev` with a negative number.

The standardese in [iterator.operations] strongly indicates that `prev` requires a `BidirectionalIterator`, but I don't see the usual wording that connects template type parameters of that name to the `<algorithm>` requirements or similar. So perhaps one could argue that the name `Bidirectional` there has no meaning. Even if that is the case, that's a defect in the other direction.

[2019-06-12 Priority set to 3 after reflector discussion]

Proposed resolution:

This wording is relative to N4810.

> [Drafting Note: Three mutually exclusive options are prepared, depicted below by Option A, Option B, and Option C, respectively.]

Option A

1. NAD, the name `BidirectionalIterator` actually means that `prev` requires bidirectional iterators, in which case this change to libcxx is incorrect.

Option B

1. Modify 23.2 [iterator.synopsis], header `<iterator>` synopsis, as indicated:

   >     // 23.4.3 [iterator.operations], iterator operations
   >     […]
   >     template<class BidirectionalInputIterator>
   >       constexpr BidirectionalInputIterator prev(BidirectionalInputIterator x,
   >         typename iterator_traits<BidirectionalInputIterator>::difference_type n = 1);

2. Modify 23.4.3 [iterator.operations] as indicated:

   >     template<class BidirectionalInputIterator>
   >       constexpr BidirectionalInputIterator prev(BidirectionalInputIterator x,
   >         typename iterator_traits<BidirectionalInputIterator>::difference_type n = 1);

   > > -7- Effects: Equivalent to: `advance(x, -n); return x;`

Option C

1. The intent of the wording is that the template parameters apply requirements, and the defect is that they do not. We should add a requirement in 23.4.3 [iterator.operations]/1 to the effect that the template parameter names impose said requirements.

### 3203(i). `span` element access invalidation

Section: 22.7.3.1 [span.overview] Status: New Submitter: Johel Ernesto Guerrero Peña Opened: 2019-05-04 Last modified: 2020-09-06

Priority: 2

View all other issues in [span.overview].

View all issues with New status.

Discussion:

`span` doesn't explicitly point out when its accessed elements are invalidated like `string_view` does in 21.4.3.3 [string.view.iterators] p2.

[2019-06-12 Priority set to 2 after reflector discussion]

Proposed resolution:

This wording is relative to N4810.

1. Modify 22.7.3.1 [span.overview] as indicated:

   > -4- `ElementType` is required to be a complete object type that is not an abstract class type.

   > -?- For a `span s`, any operation that invalidates a pointer in the range `[s.data(), s.data() + s.size())` invalidates pointers, iterators, and references other than `*this` returned from `s`'s member functions.

### 3204(i). `sub_match::swap` only swaps the base class

Section: 30.8 [re.submatch] Status: New Submitter: Jonathan Wakely Opened: 2019-05-07 Last modified: 2020-09-06

Priority: 3

View other active issues in [re.submatch].

View all other issues in [re.submatch].

View all issues with New status.

Discussion:

`sub_match<I>` derives publicly from `pair<I,I>`, and so inherits `pair::swap(pair&)`. This means that the following program fails:

>     #include <regex>
>     #include <cassert>

>     int main()
>     {
>       std::sub_match<const char*> a, b;
>       a.matched = true;
>       a.swap(b);
>       assert(b.matched);
>     }

The `pair::swap(pair&)` member should be hidden by a `sub_match::swap(sub_match&)` member that does the right thing.

[2019-06-12 Priority set to 3 after reflector discussion]

[2020-05-01; Daniel adjusts wording to recent working draft]

Proposed resolution:

This wording is relative to N4861.

1. Modify 30.8 [re.submatch], class template `sub_match` synopsis, as indicated:

   >     template<class BidirectionalIterator>
   >     class sub_match : public pair<BidirectionalIterator, BidirectionalIterator> {
   >     public:
   >       […]
   >       int compare(const sub_match& s) const;
   >       int compare(const string_type& s) const;
   >       int compare(const value_type* s) const;

   >       void swap(sub_match& s) noexcept(see below);
   >     };

2. Modify 30.8.2 [re.submatch.members] as indicated:

   >     int compare(const value_type* s) const;

   > > […]

   >     void swap(sub_match& s) noexcept(see below);

   > > [Drafting note: The swappable requirement should really be unnecessary because Cpp17Iterator requires it, but there is no wording that requires `BidirectionalIterator` to satisfy the bidirectional iterator requirements. — end drafting note]

   > > -?- Preconditions: Lvalues of type `BidirectionalIterator` are swappable (16.4.4.3 [swappable.requirements]).

   > > -?- Effects: Equivalent to:

   > > >     this->pair<BidirectionalIterator, BidirectionalIterator>::swap(s);
   > > >     std::swap(matched, s.matched);

   > > -?- Remarks: The expression inside `noexcept` is equivalent to `is_nothrow_swappable_v<BidirectionalIterator>`.

### 3205(i). `decay_t` in the new `common_type` fallback should be `remove_cvref_t`

Section: 20.15.8.7 [meta.trans.other] Status: New Submitter: Casey Carter Opened: 2019-05-12 Last modified: 2020-09-06

Priority: 3

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

View all issues with New status.

Discussion:

P0898R4 "The One Ranges Proposal" added a new fallback case to the definition of `common_type` in 20.15.8.7 [meta.trans.other], bullet 3.3.4:

> Otherwise, if `COND_RES(CREF(D1), CREF(D2))` denotes a type, let `C` denote the type `decay_t<COND_RES(CREF(D1), CREF(D2))>`.

Per para 3.3, `D1` and `D2` are decayed types. If both are `void`, bullet 3.3.4 is not reached. If either is an abominable function type or `void`, the `COND_RES` type expression above is ill-formed and bullet 3.3.4 does not apply. In all cases in which the `COND_RES` expression is well-formed, `D1` and `D2` denote cv-unqualified non-array object types. Given that fact, (1) `CREF(D1)` and `CREF(D2)` are equivalent to `const D1&` and `const D2&`, respectively, and (2) the `COND_RES` expression is equivalent to `decltype(false ? declval<const D1&>() : declval<const D1&>())`, i.e., the second and third operands of the conditional operator are lvalues of type `const D1` and `const D2`, respectively.

[expr.cond]/3 cannot apply since the operands are not glvalue bit-fields.

If `D1` and `D2` are the same type, [expr.cond]/4 does not apply. If `D1` and `D2` are different types, there are a few cases to consider:

1. If [expr.cond]/4.1 applies, one operand is converted into an lvalue reference to the type of the other, i.e., both resulting operands are lvalues of type either `const D1` or `const D2`.

2. [expr.cond]/4.2 cannot apply since neither operand is an xvalue.

3. [expr.cond]/4.3.1 cannot apply since it would imply that the operands have the same type.

4. If [expr.cond]/4.3.2 applies — if either `D1` or `D2` is a base class of the other — again the resulting operands are lvalues of type either `const D1` or `const D2`.

5. If [expr.cond]/4.3.3 applies, the either the `const D1&` operand converts to `const D2` or the `const D2&` operand converts to `const D1`.

6. If none of the sub-bullets in [expr.cond]/4 applies, the operands are left unchanged.

[expr.cond]/5 applies if the operands initially had the same type, or in cases 1 and 4 above. The conditional expression is an lvalue of type `const D1` or `const D2`, and the `COND_RES` expression yields `const D1&` or `const D2&`.

Only cases 5 and 6 reach [expr.cond]/6. This paragraph performs overload resolution, which may result in converting both operands to the same non-class type to invoke a builtin conditional operator "overload".

[expr.cond]/7 applies standard conversions including array-to-pointer and function-to-pointer conversion to the operands. Consequently, the operands are once more "decayed" if [expr.cond]/6 converted them to an array or function type. Again case-by-case:

1. [expr.cond]/7.1 applies if the operands now have the same type, which is the type of the conditional expression.

2. [expr.cond]/7.2 applies if the operands have arithmetic or enumeration type; the conditional expression yields the result of applying the usual arithmetic conversions.

3. [expr.cond]/7.3 applies if the operands have pointer type; the conditional expression yields their composite pointer type.

4. [expr.cond]/7.4 applies if the operands have pointer-to-member type; the conditional expression applies some more standard conversions and yields their composite pointer type.

5. [expr.cond]/7.5 applies if one operand has type `nullptr_t` and the other is either a null pointer constant or has type `nullptr_t`; the conditional expression yields `nullptr_t`.

In every case above, the conditional expression is either ill-formed, an lvalue of type `const D1` or `const D2`, or a prvalue of a non-array non-function type. Consequently the `COND_RES` type expression always yields a non-array non-function type, for which `decay_t` and `remove_cvref_t` are equivalent. We can therefore replace `COND_RES(CREF(D1), CREF(D2))` in [meta.trans.other]/3.3.4 with `decltype(false ? declval<const D1&>() : declval<const D2&>())`, and replace the usage of `decay_t` with `remove_cvref_t`.

Furthermore, there are now quite a few different cases describing the behavior of `common_type`. It's not clear that `common_type<T...>::type` is always a decayed type without in-depth analysis. We should non-normatively clarify that fact.

[2019-06-12 Priority set to 3 after reflector discussion]

[2020-05-01; Daniel adjusts wording to recent working draft]

Proposed resolution:

This wording is relative to N4861.

1. Modify 20.15.8.7 [meta.trans.other] as indicated:

   > -3- Let:

   > 1. (3.1) — `CREF(A)` be `add_lvalue_reference_t<const remove_reference_t<A>>`,

   > 2. (3.2) — […]

   > 3. […]

   > 4. (3.9) — […]

   > If any of the types computed above is ill-formed, then `COMMON-REF(A, B)` is ill-formed.

   > -4- Note A: For the `common_type` trait applied to a template parameter pack `T` of types, the member `type` shall be either defined or not present as follows:

   > 1. (4.1) — […]

   > 2. (4.2) — […]

   > 3. (4.3) — If `sizeof...(T)` is two, let the first and second types constituting `T` be denoted by `T1` and `T2`, respectively, and let `D1` and `D2` denote the same types as `decay_t<T1>` and `decay_t<T2>`, respectively.

   >    1. (4.3.1) — […]

   >    2. (4.3.2) — […]

   >    3. (4.3.3) — Otherwise, if

   >       >     decay_t<decltype(false ? declval<D1>() : declval<D2>())>

   >       denotes a valid type, let `C` denote that type.

   >    4. (4.3.4) — Otherwise, if `COND-RES(CREF(D1), CREF(D2))`

   >       >     remove_cvref_t<decltype(false ? declval<const D1&>() : declval<const D2&>())>

   >       denotes a type, let `C` denote the at type `decay_t<COND-RES(CREF(D1), CREF(D2))>`.

   > 4. (4.4) — […]

   > [Note: Whenever the qualified-id `common_type<T...>::type` is valid, it denotes the same type as `decay_t<common_type<T...>::type>`. — end note]

   > -5- Note B: […]

### 3210(i). `allocate_shared` is inconsistent about removing `const` from the pointer passed to allocator `construct` and `destroy`

Section: 20.11.3.7 [util.smartptr.shared.create] Status: New Submitter: Billy O'Neal III Opened: 2019-05-29 Last modified: 2020-09-06

Priority: 3

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

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

View all issues with New status.

Discussion:

I implemented the fix for LWG 3008 and Stephan pointed out there's an inconsistency here for `allocate_shared<const T>`.

20.11.3.7 [util.smartptr.shared.create] p3 says that the allocator construct call is done without removing cv qualifiers, but 20.11.3.7 [util.smartptr.shared.create] p7.12 says that the `destroy` call is done with removed cv qualifiers.

The fallback for `allocator_traits::construct` rejects `const T*` (since it `static_casts` to `void*`), so the most likely outcome of attempting to do this today is to fail to compile, which is a break with C++17.

Our options are:

1. Fix the allocator model to deal with `const` elements somehow, which breaks compatibility with existing allocators unprepared for `const` elements here. We would need to extend the allocator requirements to allow `const T*` to be passed here, and fix our default to `const_cast`.

2. Fix `allocate_shared` to remove `const` before calling `construct`, which changes the experience for C++17 customers because `allocate_shared` constructs a `T` instead of a `const T`, but not in a way substantially different to edits P0674 already made here.

3. Back out `allocate_shared`'s interaction with this part of the allocator model (reverting this part of P0674 and reopening LWG 3008).

4. Go around the problem by prohibiting `allocate_shared<const T>`, which breaks existing C++17 customers.

Billy O'Neal argues that only (2) preserves the design intent P0674 while maintaining compatibility for most allocators and most C++17 customers.

Peter Dimov argues that (1) isn't likely to break enough to matter.

[2019-06-16 Priority set to 3 based on reflector discussion]

Proposed resolution:

This wording is relative to N4810.

> [Drafting note: As the issue submitter prefers option (2), this is wording for that.]

1. Modify 20.11.3.7 [util.smartptr.shared.create] as indicated:

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

   > > -2- Requires: […]

   > > […]

   > > -7- Remarks:

   > > 1. (7.1) — […]

   > > 2. […]

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

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

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

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

### 3214(i). §[facet.num.get.virtuals] doesn't say what it means for digit grouping to be consistent

Section: 28.4.3.2.3 [facet.num.get.virtuals] Status: New Submitter: Jonathan Wakely Opened: 2019-06-03 Last modified: 2019-08-23

Priority: 4

View all other issues in [facet.num.get.virtuals].

View all issues with New status.

Discussion:

28.4.3.2.3 [facet.num.get.virtuals] paragraph 4 says:

> "Digit grouping is checked. That is, the positions of discarded separators is examined for consistency with `use_facet<numpunct<charT>>(loc).grouping()`. If they are not consistent then `ios_base::failbit` is assigned to `err`."

It's unclear what is considered consistent or not.

Obviously if the expected grouping is "1,234,567" then an input of "1,234,567" is consistent. Libstdc++, MSVC and Boost all consider "1234567" to be consistent with an expected grouping "1,234,567" (and it looks like libc++ is going to agree soon). That can be justified by saying that there are no discarded separators to examine, so no inconsistency. But what about "1234,567"? There is only one discarded separator here, and its position is consistent with the expected format.

The wording should clarify that if there are no separators at all, that is OK. If there are one or more separators then they must be at the expected positions, and there must not be any missing.

[2019-07 Issue Prioritization]

Priority to 4 after discussion on the reflector.

Proposed resolution:

### 3215(i). `variant` default constructor has vague `constexpr` requirements

Section: 20.7.3.2 [variant.ctor] Status: New Submitter: Louis Dionne Opened: 2019-06-04 Last modified: 2020-09-06

Priority: 2

View other active issues in [variant.ctor].

View all other issues in [variant.ctor].

View all issues with New status.

Discussion:

In 20.7.3.2 [variant.ctor] p5, we say:

> Remarks: This function shall be `constexpr` if and only if the value-initialization of the alternative type `T0` would satisfy the requirements for a constexpr function. […]

First of all, I find it confusing that we say "This function shall be `constexpr` if […]", when the declaration of the function clearly has the `constexpr` keyword on it unconditionally. Instead, I would use the wording "This function shall be usable in a constexpr context if […]".

Secondly, I think we shouldn't be using if-and-only-if since it restricts whether implementations can be `constexpr`-friendly as an extension. Instead, it seems better to just say "if".

Finally, I think the condition under which the function must be `constexpr`-friendly is not something we can test for because it says "value-initialization of the alternative type `T0` would satisfy the requirements for a constexpr function", which doesn't imply the value initialization can actually be be performed inside a constexpr context (for example the default constructor could be `constexpr` friendly but not marked with the `constexpr` keyword).

[2017-06-17, Tim Song comments]

This issue is related to LWG 2833.

[2019-07 Issue Prioritization]

Priority to 2 after discussion on the reflector.

Previous resolution from Daniel [SUPERSEDED]:

> This wording is relative to N4810.

> 1. Modify 20.7.3.2 [variant.ctor] as indicated:

>    >     constexpr variant() noexcept(see below);

>    > > -2- Effects: […]

>    > > -3- Ensures: […]

>    > > -4- Throws: […]

>    > > -5- Remarks: This function shall be usable in a context that requires constant evaluation if the alternative type `T0` can be value-initialized in a context that requires constant evaluation `constexpr` if and only if the value-initialization of the alternative type `T0` would satisfy the requirements for a constexpr function. […]

[2020-06-08 Nina Dinka Ranns comments]

The revised wording provided by LWG 2833 should resolve this issue as well.

Proposed resolution:

### 3216(i). Rebinding the allocator before calling `construct`/`destroy` in `allocate_shared`

Section: 20.11.3.7 [util.smartptr.shared.create] Status: New Submitter: Billy O'Neal III Opened: 2019-06-11 Last modified: 2020-09-06

Priority: 3

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

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

View all issues with New status.

Discussion:

The new `allocate_shared` wording says we need to rebind the allocator back to `T`'s type before we can call `construct` or `destroy`, but this is suboptimal (might make extra unnecessary allocator copies), and is inconsistent with the containers' behavior, which call allocator `construct` on whatever `T` they want. (For example, `std::list<T, alloc<T>>` rebinds to `alloc<_ListNode<T>>`, but calls `construct(T*)` without rebinding back)

It seems like we should be consistent with the containers and not require a rebind here. PR would look something like this, relative to N4810; I'm still not super happy with this wording because it looks like it might be saying a copy of the allocator must be made we would like to avoid…

[2019-07 Issue Prioritization]

Priority to 3 after discussion on the reflector.

Proposed resolution:

This wording is relative to N4810.

1. Modify 20.11.3.7 [util.smartptr.shared.create] as indicated:

   > [Drafting note: The edits to change `pv` to `pu` were suggested by Jonathan Wakely (thanks!). This wording also has the `remove_cv_t` fixes specified by LWG 3210 — if that change is rejected some of those have to be stripped here.]

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

   > > -2- Requires: […]

   > > […]

   > > -7- Remarks:

   > > 1. (7.1) — […]

   > > 2. […]

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

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

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

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

   > > 4. (7.6) — […]

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

   > > 6. […]

   > > 7. (7.12) — When a (sub)object of non-array type `U` that was initialized by `allocate_shared` is to be destroyed, it is destroyed via the expression `allocator_traits<A2>::destroy(a2, pvu)` where `pvu` is a pointer of type `remove_cv_t<U>*` points ing to that object of type `remove_cv_t<U>` and `a2` of type `A2` is a potentially rebound copy of the allocator `a` passed to `allocate_shared` such that its `value_type` is `remove_cv_t<U>`.

### 3217(i). `<memory>` and `<execution>` should define `__cpp_lib_parallel_algorithm`

Section: 17.3.1 [support.limits.general] Status: New Submitter: Jonathan Wakely Opened: 2019-06-12 Last modified: 2020-09-06

Priority: 3

View all other issues in [support.limits.general].

View all issues with New status.

Discussion:

There are parallel overloads of algorithms in `<memory>`, so it should define the macro. Also, `<execution>` defines the exec policies for use with the algos, so that should define the macro too.

[2019-07 Issue Prioritization]

Priority to 3 after discussion on the reflector.

Proposed resolution:

This wording is relative to N4810.

1. Modify 17.3.1 [support.limits.general], Table 36 — "Standard library feature-test macros", as indicated:

   > Table 36 — Standard library feature-test macros
   > Macro name | Value | Header(s)
   > --- | --- | ---
   > `[…]`
   > `__cpp_lib_parallel_algorithm` | `201603L` | `<algorithm> <execution> <memory> <numeric>`
   > `[…]`

### 3219(i). `std::array` overview container requirements are incorrect

Section: 22.3.7.1 [array.overview], 22.2.1 [container.requirements.general] Status: New Submitter: Nevin Liber & Christian Trott Opened: 2019-06-13 Last modified: 2020-09-06

Priority: 3

View other active issues in [array.overview].

View all other issues in [array.overview].

View all issues with New status.

Discussion:

The requirements specified in 22.3.7.1 [array.overview] p3 are incorrect; namely:

- A default constructed `array<T, N>` where `0 < N` has linear, not constant complexity.

- A default constructed `array<T, 0>` is empty and has constant complexity.

[2019-07 Issue Prioritization]

Priority to 3 after discussion on the reflector.

Proposed resolution:

This wording is relative to N4810.

1. Modify 22.2.1 [container.requirements.general], Table 62 — "Container requirements", as indicated (This table can be identified by the "section" identifier [tab:container.req] in the next working draft):

   > Table 62 — Container requirements
   > Expression | Return type | Operational semantics | Assertion/note pre/post-condition | Complexity
   > --- | --- | --- | --- | ---
   > `[…]`
   > `X u;` | `` |  | Ensures: `!u.empty()` for `array<T, N>` where `0 < N`, and Ensures: `u.empty()` for all other standard containers. | constant(Note A)
   > `X()` | `` |  | Ensures: `!X().empty()` for `array<T, N>` where `0 < N`, and Ensures: `X().empty()` for all other standard containers. | constant(Note A)
   > `[…]`

   > Those entries marked "(Note A)" or "(Note B)" have linear complexity for `array<T, N>` where `0 < N` and have constant complexity for all other standard containers.

2. Modify 22.3.7.1 [array.overview] as indicated:

   > -2- An `array` is an aggregate (9.4.2 [dcl.init.aggr]) that can be list-initialized with up to `N` elements whose types are convertible to `T`.

   > -3- An `array<T, 0>` satisfies all of the requirements of a container and of a reversible container (22.2 [container.requirements]). An `array<T, N>` where `0 < N` satisfies all of the requirements of a container and of a reversible container (22.2 [container.requirements]), except that a default constructed `array<T, N>` object is not empty and that both default construction and `swap` does not have constant linear complexity. An `array` satisfies some of the requirements of a sequence container (22.2.3 [sequence.reqmts]). Descriptions are provided here only for operations on `array` that are not described in one of these tables and for operations where there is additional semantic information.

### 3220(i). P0558 broke conforming C++14 uses of atomic `shared_ptr`

Section: 31.2 [atomics.syn] Status: New Submitter: Casey Carter Opened: 2019-06-11 Last modified: 2020-09-06

Priority: 3

View other active issues in [atomics.syn].

View all other issues in [atomics.syn].

View all issues with New status.

Discussion:

This well-formed C++14 program:

>     #include <atomic>
>     #include <memory>

>     struct Abstract { virtual void test() = 0; };
>     struct Concrete : Abstract { virtual void test() override {} };

>     int main() {
>       std::shared_ptr<Abstract> ptr;
>       std::atomic_store<Abstract>(&ptr, std::make_shared<Concrete>());
>     }

is ill-formed in C++17. P0558 changed the non-member non-`shared_ptr` atomic functions to avoid deducing from their second argument, e.g. C++14 `atomic_store`:

>     template<class T> void atomic_store(atomic<T>*, T); // #1

became C++17 `atomic_store`:

>     template<class T> void atomic_store(atomic<T>*, typename atomic<T>::value_type); // #2

The program intends to call the "other" `atomic_store` from D.20 [depr.util.smartptr.shared.atomic]:

>     template<class T> void atomic_store(shared_ptr<T>*, shared_ptr<T>); // #3

In C++14, the call expression in the sample program — `std::atomic_store<Abstract>(&ptr, std::make_shared<Concrete>())` — selects overload `#3`; overload `#1` fails to be viable due to the lack of conversions from `shared_ptr<Abstract>*` to `atomic<Abstract>*` and from `shared_ptr<Concrete>` to `Abstract`. In C++17, overload `#2` doesn't get to the point of considering argument conversions: when we try to generate the declaration of the specialization for `T = Abstract` we must instantiate `atomic<Abstract>` in order to substitute `typename atomic<Abstract>::value_type`, but doing so violates the requirement in [atomics.types.generic] p1 that "The type of the template argument `T` shall be trivially copyable"

The fix is fairly straightforward since `atomic<T>::value_type` is always an alias for `T`: for those non-member atomic functions with overloads defined in D.20 [depr.util.smartptr.shared.atomic], use a different form to require that `T` in the type of the second parameter is non-deduced.

[2019-07 Issue Prioritization]

Priority to 3 after discussion on the reflector.

Proposed resolution:

This wording is relative to N4810.

1. Modify 31.2 [atomics.syn], header `<atomic>` synopsis, as indicated:

   >     […]
   >     // 31.9 [atomics.nonmembers], non-member functions
   >     […]
   >     template<class T>
   >       void atomic_store(volatile atomic<T>*, typename atomic<T>::value_typetype_identity_t<T>) noexcept;
   >     template<class T>
   >       void atomic_store(atomic<T>*, typename atomic<T>::value_typetype_identity_t<T>) noexcept;
   >     template<class T>
   >       void atomic_store_explicit(volatile atomic<T>*, typename atomic<T>::value_typetype_identity_t<T>,
   >                                  memory_order) noexcept;
   >     template<class T>
   >       void atomic_store_explicit(atomic<T>*, typename atomic<T>::value_typetype_identity_t<T>,
   >                                  memory_order) noexcept;
   >     […]
   >     template<class T>
   >       T atomic_exchange(volatile atomic<T>*, typename atomic<T>::value_typetype_identity_t<T>) noexcept;
   >     template<class T>
   >       T atomic_exchange(atomic<T>*, typename atomic<T>::value_typetype_identity_t<T>) noexcept;
   >     template<class T>
   >       T atomic_exchange_explicit(volatile atomic<T>*, typename atomic<T>::value_typetype_identity_t<T>,
   >                                  memory_order) noexcept;
   >     template<class T>
   >       T atomic_exchange_explicit(atomic<T>*, typename atomic<T>::value_typetype_identity_t<T>,
   >                                  memory_order) noexcept;
   >     template<class T>
   >       bool atomic_compare_exchange_weak(volatile atomic<T>*,
   >                                         typename atomic<T>::value_typetype_identity_t<T>*,
   >                                         typename atomic<T>::value_typetype_identity_t<T>) noexcept;
   >     template<class T>
   >       bool atomic_compare_exchange_weak(atomic<T>*,
   >                                         typename atomic<T>::value_typetype_identity_t<T>*,
   >                                         typename atomic<T>::value_typetype_identity_t<T>) noexcept;
   >     template<class T>
   >       bool atomic_compare_exchange_strong(volatile atomic<T>*,
   >                                           typename atomic<T>::value_typetype_identity_t<T>*,
   >                                           typename atomic<T>::value_typetype_identity_t<T>) noexcept;
   >     template<class T>
   >       bool atomic_compare_exchange_strong(atomic<T>*,
   >                                           typename atomic<T>::value_typetype_identity_t<T>*,
   >                                           typename atomic<T>::value_typetype_identity_t<T>) noexcept;
   >     template<class T>
   >       bool atomic_compare_exchange_weak_explicit(volatile atomic<T>*,
   >                                                  typename atomic<T>::value_typetype_identity_t<T>*,
   >                                                  typename atomic<T>::value_typetype_identity_t<T>,
   >                                                  memory_order, memory_order) noexcept;
   >     template<class T>
   >       bool atomic_compare_exchange_weak_explicit(atomic<T>*,
   >                                                  typename atomic<T>::value_typetype_identity_t<T>*,
   >                                                  typename atomic<T>::value_typetype_identity_t<T>,
   >                                                  memory_order, memory_order) noexcept;
   >     template<class T>
   >       bool atomic_compare_exchange_strong_explicit(volatile atomic<T>*,
   >                                                    typename atomic<T>::value_typetype_identity_t<T>*,
   >                                                    typename atomic<T>::value_typetype_identity_t<T>,
   >                                                    memory_order, memory_order) noexcept;
   >     template<class T>
   >       bool atomic_compare_exchange_strong_explicit(atomic<T>*,
   >                                                    typename atomic<T>::value_typetype_identity_t<T>*,
   >                                                    typename atomic<T>::value_typetype_identity_t<T>,
   >                                                    memory_order, memory_order) noexcept;

2. Modify 31.9 [atomics.nonmembers] as indicated:

   > -1- A non-member function template whose name matches the pattern `atomic_f` or the pattern `atomic_f_explicit` invokes the member function `f`, with the value of the first parameter as the object expression and the values of the remaining parameters (if any) as the arguments of the member function call, in order. An argument for a parameter of type `atomic<T>::value_type*` or `type_identity_t<T>*` is dereferenced when passed to the member function call. If no such member function exists, the program is ill-formed.

### 3223(i). `lerp` should not add the "sufficient additional overloads"

Section: 26.8.1 [cmath.syn] Status: New Submitter: Billy O'Neal III Opened: 2019-06-20 Last modified: 2019-08-23

Priority: 2

View other active issues in [cmath.syn].

View all other issues in [cmath.syn].

View all issues with New status.

Discussion:

It seems that `lerp` can't give a sensible answer for integer inputs. It's new machinery, not the legacy C stuff extended with extra overloads.

I would prefer to fix this by explicitly annotating the functions that are supposed to get additional overloads because we keep getting this wrong, but we could also exempt `lerp` in 26.8.1 [cmath.syn] p2.

[2019-07 Issue Prioritization]

Priority to 2 after discussion on the reflector.

Proposed resolution:

### 3227(i). Ambiguity issue for `extract` in ordered and unordered associative containers

Section: 22.2.6 [associative.reqmts], 22.2.7 [unord.req] Status: New Submitter: Konstantin Boyarinov Opened: 2019-06-25 Last modified: 2020-09-06

Priority: 3

View other active issues in [associative.reqmts].

View all other issues in [associative.reqmts].

View all issues with New status.

Discussion:

Ordered and unordered associative containers in C++14 contained an issue, which caused an ambiguity while invoking `std::map::erase` when `key_type` of the map can be constructed from the iterator. In this case both overloads `erase(const key_type&)` and `erase(const_iterator)` could be chosen.

The issue LWG 2059 was reported and resolved in C++17 by adding an extra overload for `erase` in ordered and unordered associative containers which accepts `iterator` as an argument.

C++17 also introduced new functionality for splicing ordered and unordered maps and sets. One of the extensions allows to extract a node from the container by passing either `key_type&` or `const_iterator` to the `extract()` member function:

>     node_type extract(const key_type& x);
>     node_type extract(const_iterator position);

Providing these two `extract` overloads causes the same problem as for `erase`. Consider the following example:

>     #include <map>
>     #include <string>

>     struct Key
>     {
>       template <typename T>
>       Key(const T&) {}
>     };

>     bool operator<(const Key&, const Key&) { return false; }

>     int main()
>     {
>       using map_type = std::map<Key, std::string>;

>       map_type m({ {Key(1), "a"}, {Key(2), "b"} });
>       map_type::iterator it = m.begin();
>       auto nh = m.extract(it);
>     }

In this case, call to `extract()` is ambiguous, because the overloads which accept `const_iterator` and `key_type` are equally good matches for the argument `it`.

Consequently, this issue can be resolved in the same way as for `std::map::erase` by adding an overload for `extract` which accepts `iterator` as an argument.

[2019-07 Issue Prioritization]

Priority to 3 after discussion on the reflector.

Proposed resolution:

This wording is relative to N4820.

1. Modify [tab:container.assoc.req], Table 69 — "Associative container requirements", as indicated:

   > Table 69 — Associative container requirements (in addition to container) [tab:container.assoc.req]
   > Expression | Return type | Assertion/note pre-/post-condition | Complexity
   > --- | --- | --- | ---
   > `…`
   > `a.extract(q)` | `node_type` | Effects: Removes the element pointed to by `q`. Returns: A `node_type` owning that element. | amortized constant
   > `a.extract(r)` | `node_type` | Effects: Removes the element pointed to by `r`. Returns: A `node_type` owning that element. | amortized constant
   > `…`

2. Modify [tab:container.assoc.req], Table 70 — "Unordered associative container requirements", as indicated:

   > Table 70 — Unordered associative container requirements (in addition to container) [tab:container.hash.req]
   > Expression | Return type | Assertion/note pre-/post-condition | Complexity
   > --- | --- | --- | ---
   > `…`
   > `a.extract(q)` | `node_type` | Effects: Removes the element pointed to by `q`. Returns: A `node_type` owning that element. | Average case `𝒪(1)`, worst case `𝒪(a.size())`.
   > `a.extract(r)` | `node_type` | Effects: Removes the element pointed to by `r`. Returns: A `node_type` owning that element. | Average case `𝒪(1)`, worst case `𝒪(a.size())`.
   > `…`

3. Modify 22.4.4.1 [map.overview], class template `map` synopsis, as indicated:

   >     […]
   >     node_type extract(iterator position);
   >     node_type extract(const_iterator position);
   >     node_type extract(const key_type& x);
   >     […]

4. Modify 22.4.5.1 [multimap.overview], class template `multimap` synopsis, as indicated:

   >     […]
   >     node_type extract(iterator position);
   >     node_type extract(const_iterator position);
   >     node_type extract(const key_type& x);
   >     […]

5. Modify 22.4.6.1 [set.overview], class template `set` synopsis, as indicated:

   >     […]
   >     node_type extract(iterator position);
   >     node_type extract(const_iterator position);
   >     node_type extract(const key_type& x);
   >     […]

6. Modify 22.4.7.1 [multiset.overview], class template `multiset` synopsis, as indicated:

   >     […]
   >     node_type extract(iterator position);
   >     node_type extract(const_iterator position);
   >     node_type extract(const key_type& x);
   >     […]

7. Modify 22.5.4.1 [unord.map.overview], class template `unordered_map` synopsis, as indicated:

   >     […]
   >     node_type extract(iterator position);
   >     node_type extract(const_iterator position);
   >     node_type extract(const key_type& x);
   >     […]

8. Modify 22.5.5.1 [unord.multimap.overview], class template `unordered_multimap` synopsis, as indicated:

   >     […]
   >     node_type extract(iterator position);
   >     node_type extract(const_iterator position);
   >     node_type extract(const key_type& x);
   >     […]

9. Modify 22.5.6.1 [unord.set.overview], class template `unordered_set` synopsis, as indicated:

   >     […]
   >     node_type extract(iterator position);
   >     node_type extract(const_iterator position);
   >     node_type extract(const key_type& x);
   >     […]

10. Modify 22.5.7.1 [unord.multiset.overview], class template `unordered_multiset` synopsis, as indicated:

    >     […]
    >     node_type extract(iterator position);
    >     node_type extract(const_iterator position);
    >     node_type extract(const key_type& x);
    >     […]

### 3229(i). §[res.on.exception.handling]#3 cannot apply to types with implicitly declared destructors

Section: 16.4.6.13 [res.on.exception.handling] Status: New Submitter: Nevin Liber Opened: 2019-06-28 Last modified: 2020-09-06

Priority: 3

View all other issues in [res.on.exception.handling].

View all issues with New status.

Discussion:

16.4.6.13 [res.on.exception.handling]#3 says:

> Destructor operations defined in the C++ standard library shall not throw exceptions. Every destructor in the C++ standard library shall behave as if it had a non-throwing exception specification.

However, types like `pair` and `array` have implicitly declared destructors, where 14.5 [except.spec]#8 applies:

> The exception specification for an implicitly-declared destructor, or a destructor without a noexcept-specifier, is potentially-throwing if and only if any of the destructors for any of its potentially constructed subobjects is potentially-throwing or the destructor is virtual and the destructor of any virtual base class is potentially throwing.

We can relax 16.4.6.13 [res.on.exception.handling] to only cover explicitly declared destructors because if they hold a user type where the destructor throws then we get UB from 16.4.5.8 [res.on.functions]#2:

> In particular, the effects are undefined in the following cases: […]

> 1. […]

> 2. (2.4) — if any replacement function or handler function or destructor operation exits via an exception, unless specifically allowed in the applicable Required behavior: paragraph.

> 3. […]

and the referred to UB happens before [res.on.exception.handling] could apply.

[2019-07 Issue Prioritization]

Priority to 3 after discussion on the reflector.

Proposed resolution:

This wording is relative to N4820.

1. Modify 16.4.6.13 [res.on.exception.handling] as indicated:

   > -3- Destructor operations defined in the C++ standard library shall not throw exceptions. Every explicitly declared destructor in the C++ standard library shall behave as if it had a non-throwing exception specification.

### 3234(i). Sufficient Additional Special Math Overloads

Section: 26.8.1 [cmath.syn] Status: New Submitter: Casey Carter Opened: 2019-07-11 Last modified: 2020-04-07

Priority: 3

View other active issues in [cmath.syn].

View all other issues in [cmath.syn].

View all issues with New status.

Discussion:

The "sufficient additional overloads" wording in 26.8.1 [cmath.syn] paragraph 2 does not apply to the special math functions, since they are not "overloaded functions". The lack of "sufficient additional overloads" doesn't agree with N3060 (the final draft of ISO/IEC 29124 which standardized the mathematical special functions) [sf.cmath] paragraphs 3 and 4:

> -3- Each of the functions specified above that has one or more `double` parameters (the `double` version) shall have two additional overloads:

> 1. a version with each `double` parameter replaced with a `float` parameter (the `float` version), and

> 2. a version with each `double` parameter replaced with a `long double` parameter (the `long double` version).

> The return type of each such `float` version shall be `float`, and the return type of each such `long double` version shall be `long double`.

> -4- Moreover, each `double` version shall have sufficient additional overloads to determine which of the above three versions to actually call, by the following ordered set of rules:

> 1. First, if any argument corresponding to a `double` parameter in the `double` version has type `long double`, the `long double` version is called.

> 2. Otherwise, if any argument corresponding to a `double` parameter in the `double` version has type `double` or has an integer type, the `double` version is called.

> 3. Otherwise, the `float` version is called.

P226R1 "Mathematical Special Functions for C++17" notably states: "At the level of and following [c.math], create a new subclause with heading and initial content the same as IS 29124:2010's clause [sf.cmath], 'Additions to header `<cmath>`,' renumbering as appropriate to the new context." which suggests the change between 29124 and C++17 was an oversight and not intentional.

Notably there is implementation divergence: MSVC implements precisely the wording in C++17, whereas libstdc++ provides additional overloads as specified in 29124, so they disagree e.g. on whether `std::sph_neumann({}, {})` is well-formed.

[2020-04-07 Issue Prioritization]

Priority to 3 after reflector discussion.

Proposed resolution:

### 3240(i). Headers declare more than entities

Section: 16.4.3.2 [using.headers] Status: New Submitter: Alisdair Meredith Opened: 2019-07-24 Last modified: 2020-04-07

Priority: 3

View all other issues in [using.headers].

View all issues with New status.

Discussion:

Quoting 16.4.3.2 [using.headers] p3:

> "[…] and shall include the header lexically before the first reference in that translation unit to any of the entities declared in that header."

This suggests we may be able to use macros and typedefs (like `size_t`) declared in standard headers without the corresponding `#include`. Clearly that is not the intended behavior!

I thought about replacing 'entity' with 'name', but the same name may occur with different contexts throughout the standard library. I thought about "contents of that header", but run afoul of the same function overloads (`std::begin` etc.) being declared in multiple headers.

It may be simpler to turn this sentence around, along the lines of:

> "No part of the standard library shall be used in a translation unit prior to a including or importing a header that provides that feature."

Even here, 'used' may be a problematic term of art. Perhaps "named"?

[2020-04-07 Issue Prioritization]

Priority to 3 after reflector discussion.

Proposed resolution:

### 3261(i). `regex` components' `noexcept` annotations appear broken for POCMA or throwing `BidirectionalIterator`

Section: 30.7 [re.regex], 30.9 [re.results] Status: New Submitter: Billy O'Neal III Opened: 2019-08-17 Last modified: 2019-10-07

Priority: 3

View all other issues in [re.regex].

View all issues with New status.

Discussion:

`std::basic_regex` and `std::match_results` have `noexcept` move construction, and `std::basic_regex` has `noexcept` move assignment, but both of them have throwing swaps. We probably need an Expects: or something to say that `BidirectionalIterator` doesn't throw through these operations. We probably also need `match_results::operator=` to respect `propagate_on_container_move_assignment` (and maybe the copy ctor respect `propagate_on_container_copy_assignment`).

[2019-09-02; Tim Song comments]

The issue is related to LWG 2490.

[2019-10 Priority set to 3 after reflector discussion]

Proposed resolution:

### 3263(i). Atomic waiting function calls should only be unblocked once

Section: 31.6 [atomics.wait] Status: New Submitter: Geoffrey Romer Opened: 2019-08-19 Last modified: 2020-09-06

Priority: 3

View other active issues in [atomics.wait].

View all other issues in [atomics.wait].

View all issues with New status.

Discussion:

It appears that in a conforming implementation, all but one `wait()` call on a given atomic object may block forever, regardless of any `notify_one()` calls, because in principle every `notify_one()` call could be considered to unblock the same single `wait()` call. Common sense suggests (and David Olsen confirms) that the intent is for each waiting function call to be (non-spuriously) unblocked by at most one notifying function call, but as far as I can tell the words never say that.

[2019-09-14 Priority set to 3 based on reflector discussion]

Proposed resolution:

This wording is relative to N4830.

1. Modify 31.6 [atomics.wait] as indicated:

   > -?- All blocking and unblocking events on a single atomic object occur in a single total order that is consistent with the "happens before" partial order.

   > -4- A call to an atomic waiting operation on an atomic object `M` is eligible to be unblocked by a call to an atomic notifying operation on `M` if it has not been unblocked, and there exist side effects `X` and `Y` on `M` such that:

   > 1. (4.1) — the atomic waiting operation has blocked after observing the result of `X`,

   > 2. (4.2) — `X` precedes `Y` in the modification order of `M`, and

   > 3. (4.3) — `Y` happens before the call to the atomic notifying operation.

### 3267(i). Rebound allocators and `is_always_equal`

Section: 16.4.4.6 [allocator.requirements] Status: New Submitter: FrankHB1989 Opened: 2019-08-27 Last modified: 2020-09-06

Priority: 4

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with New status.

Discussion:

[allocator.requirements] does not mention the interaction between `is_always_equal` and allocator rebinding. As the result, a rebound allocator may have different `is_always_equal::value` to the original allocator.

Further, for an allocator type `X` satisfying `std::allocator_type<X>::is_always_equal::value == true`, rebound allocators of `X` with same type are not guaranteed equal.

Consider:

1. `X` is used as an allocator for `value_type` used in a node-based container;

2. `Y` is the rebound allocator type for the node type used in the implementation;

3. `b1` and `b2` are values of `Y` from different allocator objects.

Then, `std::allocator_type<X>::is_always_equal::value == true` does not necessarily imply `b1 == b2`.

Since some of containers in the standard have already explicitly relied on `is_always_equal` of allocators for their `value_type` (notably, in the exception specification of the move assignment), this can cause subtle problems.

In general, the implementation of the move assignment operator of such a container can not avoid allocation for new nodes when `!std::allocator_traits<Y>::propagate_on_container_move_assignment::value && b1 != b2`. This can throw, and it can clash with the required exception specification based on `std::allocator_traits<value_type>::is_always_equal`:

>     #include <utility>
>     #include <memory>
>     #include <new>
>     #include <map>
>     #include <functional>
>     #include <type_traits>

>     using K = int;
>     using V = int;
>     using P = std::pair<const K, V>;

>     bool stop_alloc;

>     template<typename T>
>     struct AT
>     {
>       using value_type = T;

>       std::shared_ptr<void> sp = {};

>       template<typename U>
>       struct rebind
>       {
>         using other = AT<U>;
>       };

>       using is_always_equal = std::is_same<T, P>;

>       AT() : sp(is_always_equal::value ? nullptr : new T*()) {}

>       AT(const AT& a) = default;

>       template<typename U>
>       AT(const AT<U>& a) noexcept : sp(a.sp) {}

>       T* allocate(std::size_t size)
>       {
>         if (stop_alloc)
>           throw std::bad_alloc();
>         return static_cast<T*>(::operator new(size * sizeof(T)));
>       }

>       void deallocate(T* p, std::size_t)
>       {
>         ::operator delete(p);
>       }

>       friend bool operator==(const AT& x, const AT& y) noexcept
>       {
>         return !x.sp.owner_before(y.sp) && !y.sp.owner_before(x.sp);
>       }

>       friend bool operator!=(const AT& x, const AT& y) noexcept
>       {
>         return !(x == y);
>       }

>     };

>     using A = AT<P>;

>     int main()
>     {
>       // Some sanity checks:
>       static_assert(std::is_same_v<A::template rebind<A::value_type>::other, A>);
>       // For any U:
>       using U = int;
>       static_assert(std::is_same_v<A::template rebind<U>::other::template rebind<A::value_type>::other, A>);

>       using C = std::less<>;
>       using M = std::map<K, V, C, A>;

>       // As required by the current wording of the container move operator:
>       using always_equal = std::allocator_traits<A>::is_always_equal;
>       constexpr bool std_nothrow = always_equal::value && std::is_nothrow_move_assignable_v<C>;
>       static_assert(std_nothrow);

>       // For conforming implementations:
>       // static_assert(!(std_nothrow && !std::is_nothrow_move_assignable<M>::value));

>       M m{{K(), V()}}, m2;
>       auto a = m.get_allocator();

>       a.sp = std::make_shared<int>(42);
>       stop_alloc = true;

>       try
>       {
>         // Call terminate with conforming implementations. This does not work on libstdc++.
>         m2 = std::move(m);
>         // For libstdc++, terminate on allocator-extended move constructor call.
>         //    M m3(std::move(m), a);
>       }
>       catch(...)
>       {}
>     }

[2019-10 Priority set to 4 after reflector discussion]

Proposed resolution:

This wording is relative to N4830.

> [Drafting note: Additional questions: Is it necessary to ensure that
> `XX::propagate_on_container_copy_assignment::value == YY::propagate_on_container_copy_assignment::value` is `true` as well?]

1. Modify 16.4.4.6 [allocator.requirements], Table [tab:cpp17.allocator] "`Cpp17Allocator` requirements" as indicated:

   > Table 34 — `Cpp17Allocator` requirements [tab:cpp17.allocator]
   > Expression | Return type | Assertion/note pre-/post-condition | Default
   > --- | --- | --- | ---
   > `…`
   > `typename X::template rebind<U>::other` | `Y` | For all `U` (including `T`), `Y::template rebind<T>::other` is `X`. `XX::is_always_equal::value == YY::is_always_equal::value` is `true`. | See Note A, below.
   > `…`

### 3268(i). `memory_order::memory_order_foo` broken in C++20

Section: 31.4 [atomics.order] Status: New Submitter: Eric Fiselier Opened: 2019-08-31 Last modified: 2020-09-06

Priority: 4

View other active issues in [atomics.order].

View all other issues in [atomics.order].

View all issues with New status.

Discussion:

P0439R0 renamed the `std::memory_order` enumerators when making it a scoped enumeration. The paper makes the old unscoped names available in the global namespace, but not within the scope of the enumeration.

For example:

`std::memory_order::memory_order_consume` is no longer well-formed but `std::memory_order::consume` and `std::memory_order_consume` are.

In order to prevent unnecessary breakage, we should re-add the `memory_order_foo` names to the enumeration.

[2019-10 Priority set to 4 after reflector discussion]

Proposed resolution:

This wording is relative to N4830.

1. Add a new sub-clause at the end of Clause D [depr] as indicated:

   > D.?? Deprecated `memory_order` enumerators

   > -?- The following enumerators are declared in addition to those specified in 31.4 [atomics.order]:

   > >     namespace std {
   > >       enum class memory_order : unspecified {
   > >         memory_order_relaxed = relaxed, memory_order_consume = consume, memory_order_acquire = acquire,
   > >         memory_order_release = release, memory_order_acq_rel = acq_rel, memory_order_seq_cst = seq_cst
   > >       };
   > >     }

### 3275(i). Why does `time_get::do_get` require a valid pointer when none of the others do?

Section: 28.4.6.2.3 [locale.time.get.virtuals] Status: New Submitter: Marshall Clow Opened: 2019-09-09 Last modified: 2020-09-06

Priority: 3

View other active issues in [locale.time.get.virtuals].

View all other issues in [locale.time.get.virtuals].

View all issues with New status.

Discussion:

According to 28.4.6.2.3 [locale.time.get.virtuals] p11:

> Requires: `t` shall point to an object

[Note: In my "Mandates" paper, I changed this to "Expects: `t` points to an object"]

Nevertheless, it's odd, and inconsistent. `time_get::get` does not have any such stated requirement, and it calls `do_get`. None of the other "time" calls in `time_get` have such a (stated) requirement.

I believe that this requirement is redundant, that it is implied by the wording in P12 and P14.

P12: "or until it has extracted and assigned those `struct tm` members"

P14: "It is unspecified whether multiple calls to `do_get()` with the address of the same `struct tm` object will update the current contents of the object or simply overwrite its members."

If the pointer is invalid (null, or points to unmapped memory, say), you've got UB anyway.

All the other calls in [locale.time.get.virtuals] were from C++98. `do_get_time` was added in C++11, and p11 originally said "`t` shall be dereferenceable".

This was changed to "`t` shall point to an object" as part of the resolution of CWG issue 342

[2019-10 Priority set to 3 after reflector discussion]

Proposed resolution:

This wording is relative to N4830.

1. Modify 28.4.6.2.3 [locale.time.get.virtuals] as indicated:

   >     iter_type do_get(iter_type s, iter_type end, ios_base& f,
   >                      ios_base::iostate& err, tm* t, char format, char modifier) const;

   > > -11- Requires: `t` shall point to an object.

   > > -12- Effects: […]

### 3287(i). Exposition-only `cpp17-input-iterator` concept is needlessly complex

Section: 23.3.2.3 [iterator.traits] Status: New Submitter: Eric Niebler Opened: 2019-09-10 Last modified: 2020-09-06

Priority: 3

View all other issues in [iterator.traits].

View all issues with New status.

Discussion:

The new C++20 iterator concepts use `common_reference` to constrain the value, reference, and rvalue_reference associated types in order to support proxy references (see 23.3.4.2 [iterator.concept.readable]).

However, the C++17 iterators did not support proxy references, so the use of `common_reference` in 23.3.2.3 [iterator.traits]/p2 is needlessly complex. The `common_reference` constraints can be replaced with simple convertibility requirements to a `const` lvalue reference to the value type.

This fix has been implemented in range-v3.

[2019-10-14 Issue Prioritization]

Priority to 3 after reflector discussion.

Proposed resolution:

This wording is relative to N4830.

1. Modify 23.3.2.3 [iterator.traits] as indicated:

   > -2- The definitions in this subclause make use of the following exposition-only concepts:

   > >     template<class I>
   > >     concept cpp17-iterator =
   > >       copyable<I> && requires(I i) {
   > >         {   *i } -> can-reference;
   > >         {  ++i } -> same_as<I&>;
   > >         { *i++ } -> can-reference;
   > >       };

   > >     template<class I>
   > >     concept cpp17-input-iterator =
   > >       cpp17-iterator<I> && equality_comparable<I> && requires(I i) {
   > >         typename incrementable_traits<I>::difference_type;
   > >         typename readable_traits<I>::value_type;
   > >         typename common_reference_t<iter_reference_t<I>&&,
   > >                                     typename readable_traits<I>::value_type&>;
   > >         typename common_reference_t<decltype(*i++)&&,
   > >                                     typename readable_traits<I>::value_type&>;
   > >         { *i } -> convertible_to<const typename readable_traits<I>::value_type&>;
   > >         { *i++ } -> convertible_to<const typename readable_traits<I>::value_type&>;
   > >         requires signed_integral<typename incrementable_traits<I>::difference_type>;
   > >       };

   > >     […]

### 3288(i). `atomic<T>::notify_one` is unimplementable

Section: 31.6 [atomics.wait] Status: New Submitter: Anthony Williams Opened: 2019-09-11 Last modified: 2020-09-06

Priority: 2

View other active issues in [atomics.wait].

View all other issues in [atomics.wait].

View all issues with New status.

Discussion:

I am concerned by the wording around `atomic<T>::wait()/atomic<T>::notify_one()`.

31.6 [atomics.wait] p4 requires that the thread that calls `wait()` observed a value `X` prior to the value `Y` which results from a store that happens-before the notify in order to be eligible to be unlocked.

I am not sure how to implement that.

>     atomic<int> a = 0;

>     T1: int ra=a, read 0
>     T1: a.wait(0)
>     T2: a=42
>     T3: int ra=a, read 42
>     T3: a.wait(42)
>     T2: a.notify_one()

The wording requires that `T1` is eligible to be unlocked, but not `T3`, as there is not a write after the value read by `T3` that happens-before the notify.

However, both `T1` and `T3` are waiting, so `T3` may be woken by the OS. Waking `T3` is allowed (`wait()` says it may wake spuriously), but waking `T1` is currently required as it is the only thread "eligible to be unblocked".

This requires `notify_one()` to wake all waiters, which defeats the purpose.

I suspect we need to change 31.6 [atomics.wait] p4.

How about:

> "A call to an atomic waiting operation `W` on an atomic object `M` is eligible to be unlocked by a call to an atomic notifying operation `N` on `M` if

> - `N` does not happen-before `W`

> - There are no side effects `X` and `Y` in the modification order of `M` such that `N` happens-before `X`, `X` precedes `Y` in the modification order of `M` and an atomic operation that observes the effects of `Y` happens-before `W`.

> "

This would allow `T3` to be woken in the preceding example, but prevent it being woken in the following case:

>     T1: int ra=a, read 0
>     T1: a.wait(0)
>     T2: a=42
>     T2: a.notify_one()
>     T2: a=69
>     T3: int ra=a, read 69
>     T3: a.wait(69)

[2020-07-17; Priority set to 2 in telecon]

Proposed resolution:

This wording is relative to N4830.

1. Modify 31.6 [atomics.wait] as indicated:

   > -4- A call to an atomic waiting operation `W` on an atomic object `M` is eligible to be unblocked by a call to an atomic notifying operation `N` on `M` if there exist side effects `X` and `Y` on `M` such that:

   > 1. (4.1) — `N` does not happen before `W` the atomic waiting operation has blocked after observing the result of `X`,

   > 2. (4.2) — There are no side effects `X` and precedes `Y` in the modification order of `M`, and such that `N` happens before `X`, `X` precedes `Y` in the modification order of `M` and an atomic operation that observes the effects of `Y` happens before `W`.

   > 3. (4.3) — `Y` happens before the call to the atomic notifying operation.

### 3297(i). Useless sequence container requirement

Section: 22.2.3 [sequence.reqmts] Status: New Submitter: Casey Carter Opened: 2019-09-17 Last modified: 2020-09-06

Priority: 3

View other active issues in [sequence.reqmts].

View all other issues in [sequence.reqmts].

View all issues with New status.

Discussion:

22.2.3 [sequence.reqmts] paragraph 3 says that the names `i` and `j` denote "iterators that meet the Cpp17InputIterator requirements and refer to elements implicitly convertible to `value_type`". Ignoring for the moment that this is an occurrence of LWG 3105 — we really mean that `*i` and `*j` must be implicitly convertible to `value_type` — this requirement seems to be completely extraneous.

The names `i` and `j` are used in three places in the requirements table:

- The range constructors `X(i, j)` and `X u(i, j)`, which require that the container's value type is Cpp17EmplaceConstructible into the container from `*i`; implicit conversion is neither necessary nor sufficient.

- The range insert overload `a.insert(p, i, j)` which also requires Cpp17EmplaceConstructible, as well as the capability to move elements around for `vector` and `deque`; again, implicit conversion is neither necessary nor sufficient. It would be useful / performant here to require that the container's value type is assignable from `*i`, which may have been the intent of the implicit conversion requirement — would doing so be too breaking?

- The range assign overload `a.assign(i, j)` which requires both Cpp17EmplaceConstructible as above and that it can assign the result of dereferencing an iterator directly to the container's value type; again, implicit conversion is not useful here.

We should strike the implicit conversion requirement since it is not useful and only serves to confuse readers of the Standard (see e.g. here).

[2019-10-31 Issue Prioritization]

Priority to 3 after reflector discussion.

Proposed resolution:

This wording is relative to N4830.

1. Modify 22.2.3 [sequence.reqmts] as indicated:

   > -3- In Tables 76 and 77, `X` denotes a sequence container class, `a` denotes a value of type `X` containing elements of type `T`, `u` denotes the name of a variable being declared, `A` denotes `X::allocator_type` if the qualified-id `X::allocator_type` is valid and denotes a type (13.10.3 [temp.deduct]) and `allocator<T>` if it doesn't, `i` and `j` denote iterators that meet the Cpp17InputIterator requirements and refer to elements implicitly convertible to `value_type`, `[i, j)` denotes a valid range, […]

### 3305(i). `any_cast<void>`

Section: 20.8.5 [any.nonmembers] Status: Open Submitter: John Shaw Opened: 2019-10-16 Last modified: 2022-02-03

Priority: 2

View other active issues in [any.nonmembers].

View all other issues in [any.nonmembers].

View all issues with Open status.

Discussion:

>     any foo;
>     void* p = any_cast<void>(&foo);

Per 20.8.5 [any.nonmembers]/9, since the operand isn't `nullptr` and `operand->type() == typeid(T)` (because `T = void` in this case), we should return a pointer to the object contained by `operand`. But there is no such object.

We need to handle the `T = void` case, probably by just explicitly returning `nullptr`.

[2019-11 Priority to 2 during Monday issue prioritization in Belfast. There is implementation divergence here.]

[2020-02 LWG discussion in Prague did not reach consensus. Status to Open.]

There was discussion about whether or not `any_cast<void>(a)` should be ill-formed, or return `nullptr`.

Poll "should it return nullptr" was 0-4-5-5-1.

[2022-02 Currently ill-formed in MSVC ("error C2338: std::any cannot contain void") and returns null pointer in libstdc++ and libc++.]

Proposed resolution:

This wording is relative to N4835.

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

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

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

   > > […]

### 3308(i). `vector` and `deque` iterator `erase` invalidates elements even when no change occurs

Section: 22.3.8.4 [deque.modifiers], 22.3.11.5 [vector.modifiers] Status: New Submitter: Billy O'Neal III Opened: 2019-10-29 Last modified: 2019-11-04

Priority: 3

View all other issues in [deque.modifiers].

View all issues with New status.

Discussion:

It seems incorrect that a container would invalidate anything as a result of being asked to erase 0 elements. This came up in a recent customer bug report against Visual Studio, where given a `vector v`, `v.erase(v.begin(), v.begin())` triggered a self-assignment of all the elements in the vector.

`deque` has language enumerating erasures of the first and last element which invalidate fewer iterators, and a fallback that says all iterators are invalidated, which seems to intend to be talking about middle-of-container erasures. However, erasing 0 elements isn't really a middle of container erasure.

`vector` says that iterators and references are invalidated after the 'point of the erase', but when 0 elements are erased it's unclear what that even means.

We should say that erasures that erase 0 elements are no ops and be clearer about which elements are invalidated for `vector`.

[2019-11 Priority to 3 during Monday issue prioritization in Belfast]

Proposed resolution:

This wording is relative to N4835.

1. Modify 22.3.8.4 [deque.modifiers] as indicated:

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

   > > -4- Effects: Erases elements as indicated in Table 75 [tab:container.seq.req]. An erase operation that erases the last element of a deque invalidates only the past-the-end iterator and all iterators and references to the erased elements. An erase operation that erases the first element of a deque but not the last element invalidates only iterators and references to the erased elements. An erase operation that erases any elements, but neither the first element nor the last element of a deque invalidates the past-the-end iterator and all iterators and references to all the elements of the deque. [Note: `pop_front` and `pop_back` are erase operations. — end note]

   > > […]

2. Modify 22.3.11.5 [vector.modifiers] as indicated:

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

   > > -3- Effects: Erases elements as indicated in Table 75 [tab:container.seq.req]. Invalidates iterators and references at or after the point of the erase.first erased element. [Note: For the second overload of `erase`, if `first == last`, no elements are erased, and no iterators or references are invalidated. — end note]

   > > […]

### 3309(i). Is `<ios>` implicitly `#include`d by `<sstream>`, `<fstream>` etc.?

Section: 29.8 [string.streams], 29.10 [file.streams] Status: New Submitter: Jens Maurer Opened: 2019-11-01 Last modified: 2019-11-04

Priority: 3

View all other issues in [string.streams].

View all issues with New status.

Discussion:

It is unclear whether the streams headers implicitly `#include <ios>` and make (for example) the name `std::basic_ios` available after including `<sstream>`.

This question becomes more important as header units arrive with modules, where there is an explicit choice whether to re-export names from subordinate headers.

[2019-11 Priority to 3 during Monday issue prioritization in Belfast]

Proposed resolution:

### 3337(i). What is "is initialized" supposed to mean?

Section: 28.4.2.5.3 [locale.codecvt.virtuals] Status: New Submitter: Richard Smith Opened: 2019-11-15 Last modified: 2019-11-30

Priority: 3

View all other issues in [locale.codecvt.virtuals].

View all issues with New status.

Discussion:

In 28.4.2.5.3 [locale.codecvt.virtuals] paragraphs 6 and 11, we find:

> Preconditions: `(to <= to_end)` is well-defined and `true`; `state` is initialized, if at the beginning of a sequence, or else is equal to the result of converting the preceding characters in the sequence."

This doesn't make sense. What is the value of `state` if we're at the beginning of a sequence? Is the fact that we say that it's initialized in that case supposed to imply that it need not be initialized otherwise?

Perhaps this means "value-initialized" or "default-initialized" instead of merely "initialized"?

[2019-11-30 Issue Prioritization]

Priority to 3 after reflector discussion.

Proposed resolution:

### 3339(i). Move-constructed empty-container capacity

Section: 21.3.3 [basic.string], 22.3.11 [vector], 22.5.4 [unord.map], 22.5.6 [unord.set], 22.2.1 [container.requirements.general] Status: New Submitter: Nathan Myers Opened: 2019-11-17 Last modified: 2020-09-06

Priority: 3

View other active issues in [basic.string].

View all other issues in [basic.string].

View all issues with New status.

Discussion:

The Standard leaves unspecified the `capacity()` of a `string` or `vector`, and `bucket_count()` of an `unordered_(multi)set` or `unordered_(multi)map`, constructed by move from an empty `other`.

For a non-empty `other`, normative language in the Standard constrains the new object to use (mostly) the same storage as the other, by way of lifetime of iterators and pointers to elements.

For an empty `other`, there can be no such pointers or iterators. However, the empty container may have a non-zero `capacity()` or `bucket_count()`, and having reserved storage there, one naturally expects that storage to be delivered to the new object in the same way as if it had elements.

Existing implementations, in fact, do move storage to the new container, provided it can be deallocated using the new object's allocator. It is likely that existing programs have come to depend on this behavior.

The resolution proposed is to add language to the Standard specifying that, if the allocators of the existing and new container objects are compatible, the storage of the new object is the same as of the old, so that no allocations or deallocations are performed in the process, as existing implementations in fact do.

This appears to affect only `string`, `vector`, `unordered_set`, `unordered_multiset`, `unordered_map`, and `unordered_multimap`, but any new container types may also need similar attention.

Note that in the case of the hashed containers, the array of buckets appears not to be required to be moved, even when elements contained are. This seems to be a similar oversight; extant implementations do move the bucket array. The resolution should cover this case as well.

It is expected and intended that the proposed resolution does not require changes to the behavior of implementations.

See also LWG 2321 and P0966R1.

[2019-11-30 Issue Prioritization]

Priority to 3 after reflector discussion.

Proposed resolution:

### 3341(i). `basic_regex` range constructor: Missing requirements for iterator types

Section: 30.7.2 [re.regex.construct] Status: New Submitter: Денис Захаров Opened: 2019-11-17 Last modified: 2021-10-04

Priority: 3

View other active issues in [re.regex.construct].

View all other issues in [re.regex.construct].

View all issues with New status.

Discussion:

This is description of a `basic_regex` range constructor from N4835, 30.7.2 [re.regex.construct]:

>     template<class ForwardIterator>
>       basic_regex(ForwardIterator first, ForwardIterator last,
>                   flag_type f = regex_constants::ECMAScript);

> > -17- Throws: `regex_error` if the sequence `[first, last)` is not a valid regular expression.

> > -18- Effects: Constructs an object of class `basic_regex`; the object's internal finite state machine is constructed from the regular expression contained in the sequence of characters `[first, last)`, and interpreted according to the flags specified in `f`.

> > -19- Ensures: `flags()` returns `f. mark_count()` returns the number of marked sub-expressions within the expression.

It seems that there are no requirements about dereferenced iterator's element type, that, apparently, must be implicitly convertible to the `basic_regex::value_type`. For example, containers having range constructor satisfy a SequenceContainer requirements, where implicit converting to its elements is specified.

[2019-11-30 Issue Prioritization]

Priority to 3 after reflector discussion.

[2021-10-04; Jonathan adds a comment]

There isn't even a requirement that the arguments are iterators. And `assign(InputIterator, InputIterator, flag_type)` is not constrained to only accept iterators either, meaning you can call it with two integers and call the `basic_string(size_type, char_type)` constructor.

Proposed resolution:

### 3342(i). Library wording uses "initializes `x` with `y`", which is underspecified

Section: 20.4.2 [pairs.pair], 20.5.3.1 [tuple.cnstr], 20.7.3.2 [variant.ctor], 31.8.7.2 [util.smartptr.atomic.shared], 20.13.3 [allocator.adaptor.cnstr], 20.20.6.3 [format.parse.ctx], 20.20.7.1 [format.arg], 22.6 [container.adaptors], 23.5 [predef.iterators], 24.5.4.2 [range.subrange.ctor], 24.6 [range.factories], 24.7 [range.adaptors], 25.10 [numeric.ops], 27.9 [time.hms], 30.11 [re.iter], 31.8 [atomics.types.generic], 31.9 [atomics.nonmembers], 32.3 [thread.stoptoken], 32.4 [thread.threads], 32.5 [thread.mutex], 32.7 [thread.sema], 32.8 [thread.coord], 32.9 [futures] Status: New Submitter: Richard Smith Opened: 2019-11-21 Last modified: 2019-12-08

Priority: 3

View other active issues in [pairs.pair].

View all other issues in [pairs.pair].

View all issues with New status.

Discussion:

The problem was discussed here:

> It seems to me that this is just one instance of a systemic problem in the library wording. This phrasing "initializes `x` with `y`" is common, but underspecified (and formally meaningless) — the library wording either needs to say what kind of initialization is performed, or specify an initializer (not an expression) with which to initialize. We should ask LWG to think about this; for each "initializes `x` with `y`" utterance, the reader should know what kind of initialization we mean.

> Looking at random through the library wording, the first case I found: 22.6.4.2 [queue.cons]/1:

> > Effects: Initializes `c` with `cont`.

> The meaning of this depends on whether this is direct- or copy-initialization. (It's obscure, but if `T` is not Cpp17CopyInsertable into the container, it could be the case that one form of initialization works and the other does not, or that they both work and do different things.)

> Another random sample: 25.10.7 [partial.sum]/2:

> > Effects: For a non-empty range, the function creates an accumulator `acc` whose type is `InputIterator`'s value type, initializes it with `*first`, and assigns the result to `*result`.

> Again the difference between direct- and copy-initialization is observable here.

> Perhaps the library should have blanket wording that when it says "initializes", it means by direct- or copy-initialization, and that it's unspecified which one you get (or something like that) — and someone should go through all the instances and check if any of them mean something else (I doubt this is the only case that does).

Suggestion: either

- add blanket wording defining what you mean when you say "initializes `x` with `y`" (e.g., it's unspecified whether copy-initialization or direct-initialization is performed) and make sure that that's what's intended for all uses, or

- stop using the "initializes `x` with `y`" formulation entirely, and specify the kind of initialization on each use, or

- for each such use, ensure that `y` is an initializer (that is, of the form "`= expr`" or "`(expr, expr, …)`" or "`= { … }`" or "`{ … }`", and not merely an expression)

[2019-12-08 Issue Prioritization]

Priority to 3 after reflector discussion.

Proposed resolution:

### 3343(i). Ordering of calls to `unlock()` and `notify_all()` in Effects element of `notify_all_at_thread_exit()` should be reversed

Section: 32.6.3 [thread.condition.nonmember] Status: New Submitter: Lewis Baker Opened: 2019-11-21 Last modified: 2020-02-24

Priority: 3

View all issues with New status.

Discussion:

32.6.3 [thread.condition.nonmember] p2 states:

> Effects: Transfers ownership of the lock associated with `lk` into internal storage and schedules `cond` to be notified when the current thread exits, after all objects of thread storage duration associated with the current thread have been destroyed. This notification shall be as if:

> >     lk.unlock();
> >     cond.notify_all();

One common use-cases for the `notify_all_at_thread_exit()` is in conjunction with `thread::detach()` to allow detached threads to signal when they complete and to allow another thread to wait for them to complete using the `condition_variable/mutex` pair.

However, the current wording for `notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk)` makes it impossible to know when it is safe to destroy the `condition_variable` in the presence of spurious wake-ups and detached threads.

For example: Consider the following code-snippet:

>     #include <condition_variable>
>     #include <mutex>
>     #include <thread>

>     int main() {
>       std::condition_variable cv;
>       std::mutex mut;
>       bool complete = false;

>       std::thread{[&] {
>         // do work here

>         // Signal thread completion
>         std::unique_lock lk{mut};
>         complete = true;
>         std::notify_all_at_thread_exit(cv, std::move(lk));
>       }}.detach();

>       // Wait until thread completes
>       std::unique_lock lk{mut};
>       cv.wait(lk, [&] { return complete; });

>       // condition_variable destroyed on scope exit
>       return 0;
>     }

This seems to an intended usage of `thread::detach()` and `std::notify_all_at_thread_exit()` and yet this code contains a race involving the call to `cv.notify_all()` on the created thread, and the destructor of the `condition_variable`.

To highlight the issue, consider the following case:

Let `T0` be the thread that executes `main()` and `T1` be the thread created by the `std::thread` construction.

> `T0`: creates thread `T1`
> `T0`: context-switched out by OS
> `T1`: starts running

> `T1`: acquires mutex lock
> `T1`: sets `complete = true`

> `T1`: calls `notify_all_at_thread_exit()`
> `T1`: returns from thread-main function and runs all thread-local destructors
> `T1`: calls `lk.unlock()`
> `T1`: context-switched out by OS
> `T0`: resumes execution
> `T0`: acquires mutex lock
> `T0`: calls `cv.wait()` which returns immediately as `complete` is `true`

> `T0`: returns from `main()`, destroying `condition_variable`
> `T1`: resumes execution

> `T1`: calls `cv.notify_all()` on a dangling `cv` reference (undefined behaviour)

Other sequencings are possible involving spurious wake-ups of the `cv.wait()` call.

A proof-of-concept showing this issue can be found here.

The current wording requires releasing the mutex lock before calling `cv.notify_all()`. In the presence of spurious wake-ups of a `condition_variable::wait()`, there is no way to know whether or not a detached thread that called `std::notify_all_at_thread_exit()` has finished calling `cv.notify_all()`. This means there is no portable way to know when it will be safe for the waiting thread to destroy that `condition_variable`.

However, if we were to reverse the order of the calls to `lk.unlock()` and `cond.notify_all()` then the thread waiting for the detached thread to exit would not be able to observe the completion of the thread (in the above case, this would be observing the assignment of `true` to the `complete` variable) until the mutex lock was released by that thread and subsequently acquired by the waiting thread which would only happen after the completion of the call to `cv.notify_all()`. This would allow the above code example to eliminate the race between a subsequent destruction of the condition-variable and the call to `cv.notify_all()`.

[2019-12-08 Issue Prioritization]

Priority to 3 after reflector discussion.

[2019-12-15; Daniel synchronizes wording with N4842]

[2020-02, Prague]

Response from SG1: "We discussed it in Prague. We agree it’s an error and SG1 agreed with the PR."

Proposed resolution:

This wording is relative to N4842.

1. Change 32.6.3 [thread.condition.nonmember] as indicated:

   >     void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);

   > > […]

   > > -2- Effects: Transfers ownership of the lock associated with `lk` into internal storage and schedules `cond` to be notified when the current thread exits, after all objects of thread storage duration associated with the current thread have been destroyed. This notification is equivalent to:

   > > >     lk.unlock();
   > > >     cond.notify_all();
   > > >     lk.unlock();

### 3344(i). `advance(i, most-negative)` and `prev(i, most-negative)`

Section: 23.4.3 [iterator.operations], 23.4.4.2 [range.iter.op.advance] Status: New Submitter: Casey Carter Opened: 2019-11-22 Last modified: 2019-12-07

Priority: 3

View other active issues in [iterator.operations].

View all other issues in [iterator.operations].

View all issues with New status.

Discussion:

`ranges::advance` (23.4.4.2 [range.iter.op.advance]) and `std::advance` (23.4.3 [iterator.operations]) can be called with a negative count `n` when the iterator argument `i` models `bidirectional_iterator` (respectively, meets the Cpp17BidirectionalIterator requirements). In this case, they are specified to "decrement `i` by `-n`". If `n` is the most-negative value of a signed integral type, the expression `-n` has undefined behavior. This UB is unfortunate given that typical implementations never actually form the expression `-n`. It's nonsensical to describe the effects of a function in terms of an expression with undefined behavior, so we should either define the behavior or exclude this case via precondition.

`ranges::prev()` and `std::prev` (23.4.3 [iterator.operations]) have a similar problem: `prev(i, n)` is equivalent to:

>     advance(i, -n);
>     return i;

which has undefined behavior when `n` is `numeric_limits<T>::min()` where `T` is `iter_difference_t<decltype(i)>` (for `ranges::prev`) or some signed integral type (for `std::prev`). There is an implicit precondition here thanks to "Effects: Equivalent to" since the equivalent code has a precondition that `n` is not a most-negative value, so this wording is not defective. We could, however, define behavior for `prev` regardless of the value of `n` by duplicating the specification of advance and inverting the "direction" of the operations. We should consider doing so.

[2019-12-07 Issue Prioritization]

Priority to 3 after reflector discussion.

Proposed resolution:

This wording is relative to N4835.

> [Drafting note: I've chosen to provide wording for the conservative "define behavior for `advance` and leave `prev` as status quo" middle ground.

> The occurrences of "|" in the below are math-font vertical bars (indicating absolute value). I've changed both positive and negative cases for consistency of presentation. ]

1. Modify 23.4.3 [iterator.operations] as indicated:

   >     template<class InputIterator, class Distance>
   >       constexpr void advance(InputIterator& i, Distance n);

   > > -2- Expects: `n` is negative only for bidirectional iterators.

   > > -3- Effects: Increments `i` by `|n|` if `n` is non-negative, and decrements `i` by `-|n|` otherwise.

2. Modify 23.4.4.2 [range.iter.op.advance] as indicated:

   >     template<input_or_output_iterator I>
   >       constexpr void ranges::advance(I& i, iter_difference_t<I> n);

   > > -1- Expects: If `I` does not model `bidirectional_iterator`, `n` is not negative.

   > > -2- Effects:

   > > 1. (2.1) — If `I` models `random_access_iterator`, equivalent to `i += n`.

   > > 2. (2.2) — Otherwise, if `n` is non-negative, increments `i` by `|n|`.

   > > 3. (2.3) — Otherwise, decrements `i` by `-|n|`.

   > […]

   >     template<input_or_output_iterator I, sentinel_for<I> S>
   >       constexpr iter_difference_t<I> ranges::advance(I& i, iter_difference_t<I> n, S bound);

   > > -5- Expects: […]

   > > -6- Effects:

   > > 1. (6.1) — If `S` and `I` model `sized_sentinel_for<S, I>`:

   > >    1. (6.1.1) — If `|n| ≥ |bound - i|`, equivalent to `ranges::advance(i, bound)`.:

   > >    2. (6.1.2) — Otherwise, equivalent to `ranges::advance(i, n)`.

   > > 2. (6.2) — Otherwise,

   > >    1. (6.2.1) — if `n` is non-negative, while `bool(i != bound)` is `true`, increments `i` but at most `|n|` times.:

   > >    2. (6.2.2) — Otherwise, while `bool(i != bound)` is `true`, decrements `i` but at most `-|n|` times.

### 3353(i). `locale`'s copy assignment operator should return `locale&`

Section: 28.3.1 [locale] Status: New Submitter: Stephan T. Lavavej Opened: 2019-12-06 Last modified: 2019-12-21

Priority: 3

View all other issues in [locale].

View all issues with New status.

Discussion:

Curiously, `locale`'s copy assignment operator currently returns `const locale&`. As Casey Carter noted in microsoft/STL#268, this is:

- Weird!

- The only occurrence in the entire Standard Library.

- Preventing `locale` from satisfying `std::copyable`.

We aren't aware of any reason for this to be `const`. (I observe that this hasn't changed since N1804 on 2005-04-27 and probably goes back to C++98; I suspect that when this was originally specified, copy assignment operators were relatively new, and conventions for them weren't rigorously followed.)

[2019-12-21 Issue Prioritization]

Priority to 3 after reflector discussion based on the observation that we have implementation divergence.

Proposed resolution:

This wording is relative to N4842.

1. Modify 28.3.1 [locale] as indicated:

   >     […]
   >     ~locale(); // not virtual
   >     const locale& operator=(const locale& other) noexcept;
   >     template<class Facet> locale combine(const locale& other) const;
   >     […]

2. Modify 28.3.1.3 [locale.cons] as indicated:

   >     const locale& operator=(const locale& other) noexcept;

   > > -14- Effects: Creates a copy of `other`, replacing the current value.

   > > -15- Returns: `*this`.

### 3357(i). [fund.ts.v3] `default_random_engine` is overspecified for per-thread engine

Section: 99 [fund.ts.v3::rand.util.randint] Status: Open Submitter: Zhihao Yuan Opened: 2019-12-10 Last modified: 2020-05-31

Priority: 3

View all issues with Open status.

Discussion:

Addresses: fund.ts.v3

Although "implementation may select this type on the basis of performance, size, quality, or any combination of such factors," but changing this typedef is an ABI-break for implementations. Specifying per-thread engine to use this typedef results in losses of performance, size, and/or quality.

Since this type is not involved in `randint` facilities' interface (other than its member typedef), the current specification should be relaxed.

[2020-01 Priority set to 3 and assigned to LEWG after review on the reflector.]

[2020-05-28; LEWG issue reviewing]

LEWG issue processing voted to reject 3357 as NAD. Status change to Open.

>     Reject LWG3357 as NAD

>     SF  F N A SA
>     1  10 4 2 1

Proposed resolution:

This wording is relative to N4840.

1. Modify 9.1.1 [fund.ts.v3::rand.syn], header `<experimental/random>` synopsis, as indicated:

   >     #include <random>

   >     namespace std::experimental {
   >     inline namespace fundamentals_v3 {

   >       // 10.1.2.1, Function template randint
   >       template <class IntType>
   >       IntType randint(IntType a, IntType b);
   >       void reseed();
   >       void reseed(default_random_engine::result_typeuint_fast32_t value);

   >     } // inline namespace fundamentals_v3
   >     } // namespace std::experimental

2. Modify 99 [fund.ts.v3::rand.util.randint] as indicated:

   > -1- A separate per-thread engine of type `default_random_engine` (C++17 §29.6.5)unspecified type that meets the requirements of random number engine (C++17 [rand.req.eng]), initialized to an unpredictable state, shall be maintained for each thread. [Note: The implementation may choose the engine type on the basis of performance, size, quality, or any combination of such factors, so as to provide at least acceptable engine behavior for relatively casual, inexpert, and/or lightweight use. — end note]

   > […]

   >     void reseed();
   >     void reseed(default_random_engine::result_typeuint_fast32_t value);

   > > -7- Effects: Let `g` be the per-thread engine. The first form sets `g` to an unpredictable state. The second form invokes `g.seed(value)`.

   > > -8- Postconditions: Subsequent calls to `randint` do not depend on values produced by `g` before calling reseed. [Note: `reseed` also resets any instances of `uniform_int_distribution` used by `randint`. — end note]

### 3370(i). §[cstdint.syn]p2 and §[headers]p5 are not sufficiently clear

Section: 17.4.2 [cstdint.syn], 16.4.2.3 [headers] Status: New Submitter: Dawid Pilarski Opened: 2020-01-14 Last modified: 2020-01-25

Priority: 3

View all other issues in [cstdint.syn].

View all issues with New status.

Discussion:

This issue has been submitted, because the editorial change requests c++-draft-issue 3521 and c++-draft-pull request 3528 has been rejected as not being editorial changes:

Currently given wording of 17.4.2 [cstdint.syn]p2:

> The header defines all types and macros the same as the C standard library header `<stdint.h>`.

might be understood as intended: typedefs inside `stdint.h` and inside `cstdint` in namespace `std::` refer to the same types, but another interpretation could be, that it's understood as:

Definitions in both files are done the same way (`cstdint` provides typedefs not in namespace `std`, because it would be a different definition than one in `stdint.h`).

Also 16.4.2.3 [headers]p5 is non sufficiently clear:

> […] the contents of each header `cname` is the same as that of the corresponding header `name.h` […]

As it doesn't say what does "same content" mean. For example is an implementation allowed to do following:

>     // __impl.h
>     typedef int __my_int;
>     namespace std { typedef long __my_int; }

>     // cname header
>     #include "__impl.h"

>     namespace std {
>       typedef __my_int uint32_t;
>     }

>     // name.h header
>     #include "__impl.h"
>     typedef __my_int uint32_t;

?

In this case typedef from namespace `std` and from global namespace refer to different types?

Proposed change:

Apply wording, that will unambiguously make typedefs from namespace `std` refer to the same types as typedefs from global namespace for all headers `name.h` and their corresponding headers `cname`.

[2020-01-25 Issue Prioritization]

Priority to 3 after reflector discussion.

Proposed resolution:

### 3378(i). `tuple_size_v/tuple_element_t` should be available when `tuple_size/tuple_element` are

Section: 20.5.2 [tuple.syn], 20.5.6 [tuple.helper] Status: New Submitter: Casey Carter Opened: 2020-01-17 Last modified: 2021-11-04

Priority: 3

View all issues with New status.

Discussion:

20.5.6 [tuple.helper]/6 makes the `const`/`volatile`/`const volatile` partial specializations of `tuple_size` available when any of `<array>`, `<ranges>`, `<span>`, or `<utility>` is included. 20.5.6 [tuple.helper]/8 makes the `const`/`volatile`/`const volatile` partial specializations of `tuple_element` available when any of those same headers is included. This leads to a couple of problems:

1. For users of the Standard Library, it's not helpful to have these partial specializations of class templates available when the preferred interface — the variable template `tuple_size_v` and alias template `tuple_element_t` — are not.

2. For specifiers of the Standard Library, we must update two distinct yet identical lists of headers that make this same set of templates available when adding another header.

We could solve both of these problems by coalescing the two paragraphs into one and including the variable and alias template in the set of declarations made available by the pertinent (now single) list of headers.

[2020-02-08 Issue Prioritization]

Priority to 3 after reflector discussion. Tim Song said: It’s not clear that entities only mentioned in the synopsis are "defined in this subclause".

[2021-11-04; Jonathan Wakely adds note]

The `__cpp_lib_tuple_element_t` macro in 17.3.2 [version.syn] should be updated too.

Proposed resolution:

This wording is relative to N4842.

1. Modify 20.5.2 [tuple.syn], header `<tuple>` synopsis, as indicated:

   >     namespace std {
   >       […]

   >       // 20.5.6 [tuple.helper], tuple helper classes
   >       template<class T> struct tuple_size; // not defined
   >       template<class T> struct tuple_size<const T>;
   >       template<class T> struct tuple_size<volatile T>;
   >       template<class T> struct tuple_size<const volatile T>;

   >       template<class T>
   >         inline constexpr size_t tuple_size_v = tuple_size<T>::value;
   >       template<class... Types> struct tuple_size<tuple<Types...>>;

   >       template<size_t I, class T> struct tuple_element; // not defined
   >       template<size_t I, class T> struct tuple_element<I, const T>;
   >       template<size_t I, class T> struct tuple_element<I, volatile T>;
   >       template<size_t I, class T> struct tuple_element<I, const volatile T>;

   >       template<size_t I, class... Types>
   >         struct tuple_element<I, tuple<Types...>>;

   >       template<size_t I, class T>
   >         using tuple_element_t = typename tuple_element<I, T>::type;

   >       // 20.5.7 [tuple.elem], element access
   >       template<class... Types> struct tuple_size<tuple<Types...>>;

   >       template<size_t I, class... Types>
   >         struct tuple_element<I, tuple<Types...>>;

   >       template<size_t I, class... Types>
   >         constexpr tuple_element_t<I, tuple<Types...>>& get(tuple<Types...>&) noexcept;
   >       template<size_t I, class... Types>
   >         constexpr tuple_element_t<I, tuple<Types...>>&& get(tuple<Types...>&&) noexcept;
   >       […]

   >       // 20.5.6 [tuple.helper], tuple helper classes
   >       template<class T>
   >         inline constexpr size_t tuple_size_v = tuple_size<T>::value;
   >     }

2. Modify 20.5.6 [tuple.helper] as indicated:

   > 20.5.6 Tuple helper classes [tuple.helper]

   > -?- In addition to being available via inclusion of the `<tuple>` header, the entities defined in this subclause [tuple.helper] are available when any of the headers `<array>` (22.3.2 [array.syn]), `<ranges>` (24.2 [ranges.syn]), `<span>` (22.7.2 [span.syn]), or `<utility>` (20.2.1 [utility.syn]) are included.

   >     template<class T> struct tuple_size;

   > > -1- Remarks: All specializations of `tuple_size` shall meet the Cpp17UnaryTypeTrait requirements (20.15.2 [meta.rqmts]) with a base characteristic of `integral_constant<size_t, N>` for some `N`.

   >     template<class... Types>
   >       struct tuple_size<tuple<Types...>> : public integral_constant<size_t, sizeof...(Types)> { };

   >     template<size_t I, class... Types>
   >       struct tuple_element<I, tuple<Types...>> {
   >         using type = TI;
   >       };

   > > -2- Requires: `I < sizeof...(Types)`. The program is ill-formed if `I` is out of bounds.

   > > -3- Type: `TI` is the type of the `Ith` element of `Types`, where indexing is zero-based.

   >     template<class T> struct tuple_size<const T>;
   >     template<class T> struct tuple_size<volatile T>;
   >     template<class T> struct tuple_size<const volatile T>;

   > > -4- Let `TS` denote `tuple_size<T>` of the cv-unqualified type `T`. If the expression `TS::value` is well-formed when treated as an unevaluated operand, then each of the three templates shall meet the Cpp17UnaryTypeTrait requirements (20.15.2 [meta.rqmts]) with a base characteristic of

   > > >     integral_constant<size_t, TS::value>

   > > Otherwise, they shall have no member value.

   > > -5- Access checking is performed as if in a context unrelated to `TS` and `T`. Only the validity of the immediate context of the expression is considered. [Note: The compilation of the expression can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note]

   > > -6- In addition to being available via inclusion of the `<tuple>` header, the three templates are available when any of the headers `<array>` (22.3.2 [array.syn]), `<ranges>` (24.2 [ranges.syn]), `<span>` (22.7.2 [span.syn]), or `<utility>` (20.2.1 [utility.syn]) are included.

   >     template<size_t I, class T> struct tuple_element<I, const T>;
   >     template<size_t I, class T> struct tuple_element<I, volatile T>;
   >     template<size_t I, class T> struct tuple_element<I, const volatile T>;

   > > -7- Let `TE` denote `tuple_element_t<I, T>` of the cv-unqualified type `T`. Then each of the three templates shall meet the Cpp17TransformationTrait requirements (20.15.2 [meta.rqmts]) with a member typedef type that names the following type:

   > > 1. (7.1) — for the first specialization, `add_const_t<TE>`,

   > > 2. (7.2) — for the second specialization, `add_volatile_t<TE>`, and

   > > 3. (7.3) — for the third specialization, `add_cv_t<TE>`.

   > > -8- In addition to being available via inclusion of the `<tuple>` header, the three templates are available when any of the headers `<array>` (22.3.2 [array.syn]), `<ranges>` (24.2 [ranges.syn]), `<span>` (22.7.2 [span.syn]), or `<utility>` (20.2.1 [utility.syn]) are included.

3. Modify 20.5.7 [tuple.elem] as indicated:

   > [Drafting note: Since this issue performs colliding text changes with P1460R0, we perform similar wording changes as suggested on page 19 [tuple.helper] p2.]

   > 20.5.7 Element access [tuple.elem]

   >     template<class... Types>
   >       struct tuple_size<tuple<Types...>> : public integral_constant<size_t, sizeof...(Types)> { };

   >     template<size_t I, class... Types>
   >       struct tuple_element<I, tuple<Types...>> {
   >         using type = TI;
   >       };

   > > -?- Mandates: `I < sizeof...(Types)`.

   > > -?- Type: `TI` is the type of the `Ith` element of `Types`, where indexing is zero-based.

   >     template<size_t I, class... Types>
   >       constexpr tuple_element_t<I, tuple<Types...>>&
   >         get(tuple<Types...>& t) noexcept;
   >     […]

   > > […]

### 3400(i). Does `is_nothrow_convertible` consider destruction of the destination type?

Section: 20.15.7 [meta.rel] Status: New Submitter: Jiang An Opened: 2020-02-10 Last modified: 2020-09-06

Priority: 3

View other active issues in [meta.rel].

View all other issues in [meta.rel].

View all issues with New status.

Discussion:

This issue was submitted after a previous editorial change request had been rejected by the project editors.

I find that all known implementations (at least msvcstl, libc++, libstdc++ and the sample in P0758R1) of `std::is_nothrow_convertible` may be not clear enough to indicate that whether destruction of the destination type is considered (or not).

For example, given a type `Weird` defined as

>     struct Weird
>     {
>       Weird(int) noexcept {}
>       ~Weird() noexcept(false) {}
>     };

Then `std::is_nothrow_convertible_v<int, Weird>` is `false` in every known implementation. However, it seems that the conversion itself is `noexcept`.

[2020-02-22, Daniel comments]

This seems to be quite related to the existing issue LWG 2116.

[2020-03-11 Issue Prioritization]

Priority to 3 after reflector discussion.

Proposed resolution:

### 3401(i). Is "as if by" equivalent to "equivalent to"?

Section: 16.3.2.4 [structure.specifications] Status: New Submitter: Casey Carter Opened: 2020-02-14 Last modified: 2020-03-11

Priority: 3

View other active issues in [structure.specifications].

View all other issues in [structure.specifications].

View all issues with New status.

Discussion:

We have quite a few occurrences of the phrase "as if by" in Effects: elements in the library specification. Is the meaning of this phrase the same as "equivalent to"? If so, we should replace occurrences of "as if by" with "equivalent to" to make it clear that the magic "Effects: Equivalent to" wording in 16.3.2.4 [structure.specifications] para 4 is intended to apply.

[2020-03-11 Issue Prioritization]

Priority to 3 after reflector discussion.

Proposed resolution:

### 3402(i). Wording for `negative_binomial_distribution` is unclear as a consequence of LWG 2406 resolution

Section: 26.6.9.3.4 [rand.dist.bern.negbin] Status: New Submitter: Ahti Leppänen Opened: 2020-02-17 Last modified: 2020-03-11

Priority: 3

View all other issues in [rand.dist.bern.negbin].

View all issues with New status.

Discussion:

This issue has been created because a corresponding editorial change request had been rejected.

The resolution of LWG 2406 added a note to the definition of `negative_binomial_distribution`:

> [Note: This implies that P(i|k,p) is undefined when `p == 1`. — end note]

This issue argues that the note is invalid as are the premises on which LWG 2406 was based on. It's also argued that current normative standard text allowing `p == 1` is valid both conceptually and mathematically, and that it follows existing conventions in other software.

Problems with the added note:

- Why does `p == 1` imply that P(i|k,p) is undefined? The only questionable factor in the definition of P(i| k,p) seems to be that in case of `p == 1`, the factor `(1 - p)i` leads to `00` when `i == 0`. While it is true that there's no generally accepted convention what this means, `std::binomial_distribution` already uses the common convention `00 == 1` (e.g. with `p == 1 && t == i`, P(i|k,p) leads to `00`)

- Even if the term was undefined mathematically, does a non-normative note of mathematical term being undefined mean that the behaviour of the program is undefined (instead of e.g. resulting to NaN) even when no preconditions are violated?

- The note has lead to unclear situation of being able to construct a distribution object, but calling `operator()` might lead to undefined behaviour even though no preconditions are violated: for example the cppreference.com notes that

  > If `p == 1`, subsequent calls to the `operator()` overload that does not accept a `param_type` object will cause undefined behavior.

Invalidity of premises of LWG 2406:

- > For `p == 1`, this is "`* 1^k * 0^i`", so every integer `i >= 0` is produced with zero probability. (Let's avoid thinking about `0^0`.)

  - This is contradictory: first assuming that `0^i == 0` for all `i >= 0` (implying that `0^0 == 0`), but then comments not to think about `0^0`. The very essence of the issue is interpretation of `0^0` and given the definition of `binomial_distribution`, where `0^0 == 1`, the claim "so every integer `i >= 0` is produced with zero probability" can be considered faulty.

- > Wikipedia states that `p` must be within `(0, 1)`, exclusive on both sides.

  - I cannot find any mention of this in the Wikipedia's version as of 2014-06-02 (i.e. around the time when LWG 2406 was opened). Note that the Wikipedia's version is not the same as in C++ standard; in Wikipedia, `p` parameter is the same — i.e. the probability of success — but the integer parameter (`> 0`) is number of failures, while in C++ it is the number of successes. In the failure formulation `p == 1` is indeed invalid for essentially the same reason why `p == 0` is invalid for the C++ definition (i.e. leads to P(i|k,p) `== 0` for all `i`).

Validity of `p == 1`:

- > […] distribution of the number of failures in a sequence of trials with success probability `p` before `n` successes occur.

  (from Wolfram documentation). When `p == 1`, this means that trial always succeeds, so it's obvious that the probability to get 0 failures is 1, and the probability for `i > 0` failures is 0. This is exactly what the mathematical definition in 26.6.9.3.4 [rand.dist.bern.negbin] gives with convention `00 = 1` when `p == 1`.

- Software such as Mathematica, Matlab and R all accept `p == 1` for negative binomial distribution and they use the integer parameter as number of successes like the C++ standard.

What comes to the reasons why `p == 1` could have been considered invalid, it seems that major implementations — namely libstd++, libc++ and MSVC standard library — are using `std::gamma_distribution` in `std::negative_binomial_distribution` and passing `(1 - p)/p` as the second argument of `std::gamma_distribution`. Case `p == 1` is not checked leading to violation of precondition of `std::gamma_distribution`, which requires argument to be `> 0`.

For these reasons the note added by resolution of LWG 2406 seems invalid and could be considered for removal. However given the current status and history regarding handling of case `p == 1`, removing the note might not be the only option to consider.

[2020-03-11 Issue Prioritization]

Priority to 3 and hand over to SG6 after reflector discussion.

Proposed resolution:

### 3409(i). Too lax description of `atomic_ref<T>::required_alignment`

Section: 31.7.2 [atomics.ref.ops] Status: New Submitter: Andrey Semashev Opened: 2020-02-27 Last modified: 2020-09-06

Priority: 3

View all issues with New status.

Discussion:

N4849 31.7.2 [atomics.ref.ops]/1 describes `atomic_ref<T>::required_alignment` constant as follows:

> The alignment required for an object to be referenced by an atomic reference, which is at least `alignof(T)`.

This wording allows for an implementation to always define `required_alignment` to be equal to `alignof(T)` and implement atomic operations using locking, even if a lock-free implementation is possible at a higher alignment. For example, on x86-64, `atomic_ref<complex<double>>` could be lock-free only when the referred object is aligned to 16 bytes, but the above definition allows an implementation to define `required_alignment` to 8 and use locking.

The note in 31.7.2 [atomics.ref.ops]/2 does mention that lock-free operations may require higher alignment, but it does not provide guidance to the implementations so that `required_alignment` reflects alignment required for lock-free operations, if possible, and not just minimum alignment required for any kind of implementation.

The suggested resolution is to change the wording so that it is clear that `required_alignment` indicates the alignment required for lock-free implementation, if one is possible, or `alignof(T)` otherwise.

Further, the note in 31.7.2 [atomics.ref.ops]/2 contains this sentence:

> Further, whether operations on an `atomic_ref` are lock-free could depend on the alignment of the referenced object.

This sentence is misleading, because according to `is_lock_free()` definition in 31.7.2 [atomics.ref.ops]/4, the lock-free property is not allowed to depend on the alignment of a particular referenced object (`is_lock_free()` must return `true` or `false` if operations on all objects of the given type `T` are lock-free or not). In other words, `atomic_ref` can only refer to an object aligned at least to `required_alignment` and its lock-free capability cannot depend on the actual runtime alignment of the object.

To avoid the confusion, I propose to remove the sentence. The rest of the note can stay intact. However, this second edit is less important than the first one and can be omitted in case of disagreement.

[2020-04-04 Issue Prioritization]

Priority to 3 after reflector discussion.

Proposed resolution:

This wording is relative to N4849.

1. Modify 31.7.2 [atomics.ref.ops] as indicated:

   >     static constexpr size_t required_alignment;

   > > -1- Let `A` be t The alignment required for an object to be referenced by an atomic reference, which is at least `alignof(T)`so that `is_always_lock_free` is `true`. If there is no such alignment or `A` is less than `alignof(T)`, `required_alignment` equals `alignof(T)`. Otherwise, `required_alignment` equals `A`.

   > > -2- [Note: Hardware could require an object referenced by an `atomic_ref` to have stricter alignment (6.7.6 [basic.align]) than other objects of type `T`. Further, whether operations on an `atomic_ref` are lock-free could depend on the alignment of the referenced object. For example, lock-free operations on `std::complex<double>` could be supported only if aligned to `2*alignof(double)`. — end note]

### 3411(i). [fund.ts.v3] Contradictory namespace rules in the Library Fundamentals TS

Section: 5.4 [fund.ts.v3::memory.resource.syn] Status: New Submitter: Thomas Köppe Opened: 2020-02-28 Last modified: 2021-12-02

Priority: 3

View all issues with New status.

Discussion:

Addresses: fund.ts.v3

The Library Fundamentals TS, N4840, contains a rule about the use of namespaces (paragraph 1), with the consequence:

> "This TS does not define `std::experimental::fundamentals_v3::pmr`"

However, the TS then goes on to define exactly that namespace.

At the time when the subclause memory.resource.syn was added, the IS didn't use to contain a namespace `pmr`. When the IS adopted that namespace and the TS was rebased, the namespace rule started conflicting with the material in the TS.

I do not have a workable proposed resolution at this point.

[2020-04-07 Issue Prioritization]

Priority to 3 after reflector discussion.

[2021-11-17; Jiang An comments and provides wording]

Given namespaces `std::chrono::experimental::fundamentals_v2` and `std::experimental::fundamentals_v2::pmr` are used in LFTS v2, I think that the intent is that

- the prefix `experimental::fundamentals_vN` is only added to a namespace specified by the standard, and

- every name specified by the standard in the outer namespace of that of the related component in the TS.

If we follow the convention, perhaps we should relocate `resource_adaptor` from `std::experimental::fundamentals_v3::pmr` to `std::pmr::experimental::fundamentals_v3` in LFTS v3. If it's decided that `resource_adaptor` shouldn't be relocated, I suppose that LWG 3411 can be by striking the wrong wording in 1.3 [fund.ts.v3::general.namespaces] and using qualified `std::pmr::memory_resource` when needed.

Proposed resolution:

This wording is relative to N4853.

> [Drafting Note: Two mutually exclusive options are prepared, depicted below by Option A and Option B, respectively.]

Option A:

1. Modify 1.3 [fund.ts.v3::general.namespaces] as indicated:

   > -2- Each header described in this technical specification shall import the contents of `outer-namespacestd::experimental::fundamentals_v3` into `outer-namespacestd::experimental` as if by

   > >     namespace outer-namespacestd::experimental::inline fundamentals_v3 {}

   > where `outer-namespace` is a namespace defined in the C++ Standard Library.

2. Modify 5.3 [fund.ts.v3::memory.type.erased.allocator], Table 5, as indicated:

   > Table 5 — Computed `memory_resource` for type-erased allocator
   > If the type of `alloc` is | then the value of `rptr` is
   > --- | ---
   > `[…]`
   > any other type meeting the requirements (C++20 ¶16.5.3.5) | a pointer to a value of type `pmr::experimental::resource_adaptor<A>` where `A` is the type of `alloc`. `rptr` remains valid only for the lifetime of `X`.
   > `[…]`

3. Modify 5.4 [fund.ts.v3::memory.resource.syn], header `<experimental/memory_resource>` synopsis, as indicated:

   >     namespace std::pmr::experimental::inline fundamentals_v3::pmr {
   >     […]
   >     } // namespace std::pmr::experimental::inline fundamentals_v3::pmr

Option B:

1. Modify 1.3 [fund.ts.v3::general.namespaces] as indicated:

   > -1- Since the extensions described in this technical specification are experimental and not part of the C++ standard library, they should not be declared directly within namespace `std`. Unless otherwise specified, all components described in this technical specification either:

   > 1. — modify an existing interface in the C++ Standard Library in-place,

   > 2. — are declared in a namespace whose name appends `::experimental::fundamentals_v3` to a namespace defined in the C++ Standard Library, such as `std` or `std::chrono`, or

   > 3. — are declared in a subnamespace of a namespace described in the previous bullet, whose name is not the same as an existing subnamespace of namespace `std`.

   > [Example: This TS does not define `std::experimental::fundamentals_v3::pmr` because the C++ Standard Library defines `std::pmr`. — end example]

2. Modify 4.2 [fund.ts.v3::func.wrap.func], class template `function` synopsis, as indicated:

   >     namespace std {
   >       namespace experimental::inline fundamentals_v3 {

   >         template<class> class function; // undefined

   >         template<class R, class... ArgTypes>
   >         class function<R(ArgTypes...)> {
   >         public:
   >           […]
   >           std::pmr::memory_resource* get_memory_resource() const noexcept;
   >         };
   >     […]
   >     } // namespace experimental::inline fundamentals_v3
   >     […]
   >     } // namespace std

3. Modify 5.3 [fund.ts.v3::memory.type.erased.allocator], Table 5, as indicated:

   > Table 5 — Computed `memory_resource` for type-erased allocator
   > If the type of `alloc` is | then the value of `rptr` is
   > --- | ---
   > `[…]`
   > any other type meeting the requirements (C++20 ¶16.5.3.5) | a pointer to a value of type `experimental::pmr::resource_adaptor<A>` where `A` is the type of `alloc`. `rptr` remains valid only for the lifetime of `X`.
   > `[…]`

4. Modify 5.5.1 [fund.ts.v3::memory.resource.adaptor.overview] as indicated:

   > -1- An instance of `resource_adaptor<Allocator>` is an adaptor that wraps a `std::pmr::memory_resource` interface around `Allocator`. […]

   > >     // The name resource_adaptor_imp is for exposition only.
   > >     template<class Allocator>
   > >     class resource_adaptor_imp : public std::pmr::memory_resource {
   > >     public:
   > >       […]

   > >       virtual bool do_is_equal(const std::pmr::memory_resource& other) const noexcept;
   > >     };

5. Modify 5.5.3 [fund.ts.v3::memory.resource.adaptor.mem] as indicated:

   >     -6- bool do_is_equal(const std::pmr::memory_resource& other) const noexcept;

   > > […]

6. Modify 7.2 [fund.ts.v3::futures.promise], class template `promise` synopsis, as indicated:

   >     namespace std {
   >       namespace experimental::inline fundamentals_v3 {

   >         template<class R>
   >         class promise {
   >         public:
   >           […]
   >           std::pmr::memory_resource* get_memory_resource() const noexcept;
   >         };
   >     […]
   >     } // namespace experimental::inline fundamentals_v3
   >     […]
   >     } // namespace std

7. Modify 7.3 [fund.ts.v3::futures.task], class template `packaged_task` synopsis, as indicated:

   >     namespace std {
   >       namespace experimental::inline fundamentals_v3 {

   >         template<class R, class... ArgTypes>
   >         class packaged_task<R(ArgTypes...)> {
   >         public:
   >           […]
   >           std::pmr::memory_resource* get_memory_resource() const noexcept;
   >         };
   >     […]
   >     } // namespace experimental::inline fundamentals_v3
   >     […]
   >     } // namespace std

### 3412(i). §[format.string.std] references to "Unicode encoding" unclear

Section: 20.20.2.2 [format.string.std] Status: New Submitter: Hubert Tong Opened: 2020-02-29 Last modified: 2020-09-06

Priority: 3

View other active issues in [format.string.std].

View all other issues in [format.string.std].

View all issues with New status.

Discussion:

In 20.20.2.2 [format.string.std], the meaning of "Unicode encoding" in the text added by P1868R2 (the "Unicorn width" paper) is unclear.

One interpretation of what is meant by "Unicode encoding" is "UCS encoding scheme" (as defined by ISO/IEC 10646). Another interpretation is an encoding scheme capable of encoding all UCS code points that have been assigned to characters. Yet another interpretation is an encoding scheme capable of encoding all UCS scalar values.

SG16 reflector discussion (with the LWG reflector on CC) indicates that the third option above is the closest to the intent of the study group. The situation of the current wording, which readers can easily read as indicating the first option above, is undesirable.

[2020-07-17; Priority set to 3 in telecon]

Proposed resolution:

### 3416(i). The Throws: specification of `std::any` does not mention allocation

Section: 20.8.4 [any.class] Status: New Submitter: Thomas Köppe Opened: 2020-03-04 Last modified: 2020-04-04

Priority: 3

View all other issues in [any.class].

View all issues with New status.

Discussion:

Several of the function specifications in 20.8.4 [any.class] have Throws: elements, but those only mention "exceptions thrown by a constructor". It seems necessary for `std::any` to perform dynamic allocation in general, and so in general there should be a possibility of an exception raised by such dynamic allocation. (This may come from a user-provided `T::operator new`, as far as I can tell.)

We should revise the specifications to add relevant sources of exceptions.

The functions that should probably mention allocations are:

- `any(const any& other)`

- `template<class T> any(T&& value)`

- both `any(in_place_t<T>, …)` overloads

- `any& operator=(const any& rhs)`

- `template<class T> any& operator=(T&& rhs)`

- all `emplace` overloads

Proposed wording: None yet. Maybe insert something like "thrown by unspecified, internal bookkeeping logic" into each Throws: element, but perhaps something more specific is necessary.

[2020-04-04 Issue Prioritization]

Priority to 3 after reflector discussion.

Proposed resolution:

### 3417(i). Missing `volatile` atomic deprecations

Section: 31.8.2 [atomics.types.operations] Status: SG1 Submitter: Alisdair Meredith Opened: 2020-03-19 Last modified: 2020-09-06

Priority: 3

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

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

View all issues with SG1 status.

Discussion:

Paper P1831R1 aimed to deprecate all the atomic overloads for `volatile` qualified member function of `std::atomic` unless `is_always_lock_free` is `true`. There are a few omissions in the wording.

First, `operator++` and `operator--` are correctly constrained, but the deprecated overloads are not restored in Annex D, unlike the other member functions. I confirmed with the paper author this is an accidental oversight, and not an intended change of behavior for C++20.

Secondly, the wait/notify APIs were added after the initial wording For this paper was drafted, and the paper did not catch up. Again, I confirmed with the paper author that these functions should be similarly constrained and deprecated.

[2020-04-04 Issue Prioritization]

Priority to 3 after reflector discussion. The suggested wording was generally accepted, but there were considerable doubts that it is necessary to add deprecated functions of the new `wait/notify` functions instead of declaring only the non-volatile overloads. The wish was expressed that both SG1 and LEWG should express their opinion here.

Proposed resolution:

This wording is relative to N4861.

1. Modify 31.8.2 [atomics.types.operations] as indicated:

   >     void wait(T old, memory_order order = memory_order::seq_cst) const volatile noexcept;
   >     void wait(T old, memory_order order = memory_order::seq_cst) const noexcept;

   > > Constraints: For the `volatile` overload of this function, `is_always_lock_free` is `true`.

   > > -29- Preconditions: […]

   > > […]

   >     void notify_one() volatile noexcept;
   >     void notify_one() noexcept;

   > > Constraints: For the `volatile` overload of this function, `is_always_lock_free` is `true`.

   > > -32- Effects: […]

   > > […]

   >     void notify_all() volatile noexcept;
   >     void notify_all() noexcept;

   > > Constraints: For the `volatile` overload of this function, `is_always_lock_free` is `true`.

   > > -34- Effects: […]

   > > […]

2. Modify D.26.2 [depr.atomics.volatile], annex D, as indicated:

   > If an atomic specialization has one of the following overloads, then that overload participates in overload resolution even if `atomic<T>::is_always_lock_free` is `false`:

   > >     void store(T desired, memory_order order = memory_order::seq_cst) volatile noexcept;
   > >     […]
   > >     T* fetch_key(ptrdiff_t operand, memory_order order = memory_order::seq_cst) volatile noexcept;
   > >     value_type operator++(int) volatile noexcept;
   > >     value_type operator--(int) volatile noexcept;
   > >     value_type operator++() volatile noexcept;
   > >     value_type operator--() volatile noexcept;
   > >     void wait(T old, memory_order order = memory_order::seq_cst) const volatile noexcept;
   > >     void notify_one() volatile noexcept;
   > >     void notify_all() volatile noexcept;

### 3418(i). Deprecated free functions in `<atomic>`

Section: 31.9 [atomics.nonmembers] Status: New Submitter: Alisdair Meredith Opened: 2020-03-19 Last modified: 2020-09-06

Priority: 3

View all issues with New status.

Discussion:

Paper P1831R1 deprecated the `volatile`-qualified member functions of `std::atomic` unless `is_always_lock_free` is `true`. 31.9 [atomics.nonmembers] maps free functions calls, declared in the `<atomic>` header, to those member functions, but does not deprecate them under the same circumstances.

I have confirmed with the paper author that the intended design was to deprecate these too, but currently we have no wording.

[2020-03-29; Daniel provides wording]

The suggested wording changes for 31.9 [atomics.nonmembers] attempts to make clear that any of the specification elements of the member function (including but not restricted to Constraints: elements) are also imposed on the corresponding non-member function template. According to 16.3.2.4 [structure.specifications], the wording "the semantics of the code sequence are determined by the Constraints,[…], and Error conditions specified for the function invocations contained in the code sequence." should realize the wanted effect. The advantage of this more general wording form is that we don't need to to worry in case that in the future Constraints: elements of the member functions are modified.

[2020-03-30; Tim improves wording]

[2020-04-25 Issue Prioritization]

Priority to 3 after reflector discussion.

Proposed resolution:

This wording is relative to N4861.

1. Modify 31.9 [atomics.nonmembers] as indicated:

   > -1- A non-member function template whose name matches the pattern `atomic_f` or the pattern `atomic_f_explicit` invokes the member function `f`, with the value of the first parameter as the object expression and the values of the remaining parameters (if any) as the arguments of the member function call, in order. An argument for a parameter of type `atomic<T>::value_type*` is dereferenced when passed to the member function call. If no such member function exists, the program is ill-formed. Otherwise, a call to such a function template has effects equivalent to (16.3.2.4 [structure.specifications]) the effective code sequence containing the `f` invocation specified in this subclause.

2. Modify D.26.2 [depr.atomics.volatile], annex D, as indicated:

   > If an atomic specialization has one of the following overloads, then that overload participates in overload resolution even if `atomic<T>::is_always_lock_free` is `false`:

   > >     void store(T desired, memory_order order = memory_order::seq_cst) volatile noexcept;
   > >     […]
   > >     T* fetch_key(ptrdiff_t operand, memory_order order = memory_order::seq_cst) volatile noexcept;

   > In addition, the following non-member function templates participate in overload resolution even if `atomic<T>::is_always_lock_free` is `false`:

   > >     template<class T>
   > >       void atomic_store(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
   > >     template<class T>
   > >       T atomic_load(const volatile atomic<T>*) noexcept;
   > >     template<class T>
   > >       T atomic_load_explicit(const volatile atomic<T>*, memory_order) noexcept;
   > >     template<class T>
   > >       T atomic_exchange(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
   > >     template<class T>
   > >     T atomic_exchange_explicit(volatile atomic<T>*, typename atomic<T>::value_type,
   > >       memory_order) noexcept;
   > >     template<class T>
   > >       bool atomic_compare_exchange_weak(volatile atomic<T>*,
   > >                                         typename atomic<T>::value_type*,
   > >                                         typename atomic<T>::value_type) noexcept;
   > >     template<class T>
   > >       bool atomic_compare_exchange_strong(volatile atomic<T>*,
   > >                                           typename atomic<T>::value_type*,
   > >                                           typename atomic<T>::value_type) noexcept;
   > >     template<class T>
   > >       bool atomic_compare_exchange_weak_explicit(volatile atomic<T>*,
   > >                                                  typename atomic<T>::value_type*,
   > >                                                  typename atomic<T>::value_type,
   > >                                                  memory_order, memory_order) noexcept;
   > >     template<class T>
   > >       bool atomic_compare_exchange_strong_explicit(volatile atomic<T>*,
   > >                                                    typename atomic<T>::value_type*,
   > >                                                    typename atomic<T>::value_type,
   > >                                                    memory_order, memory_order) noexcept;
   > >     template<class T>
   > >       T atomic_fetch_key(volatile atomic<T>*, typename atomic<T>::difference_type) noexcept;
   > >     template<class T>
   > >       T atomic_fetch_key_explicit(volatile atomic<T>*, typename atomic<T>::difference_type,
   > >                                   memory_order) noexcept;
   > >     template<class T>
   > >       T atomic_fetch_key(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
   > >     template<class T>
   > >       T atomic_fetch_key_explicit(volatile atomic<T>*, typename atomic<T>::value_type,
   > >                                   memory_order) noexcept;
   > >     template<class T>
   > >       void atomic_wait(const volatile atomic<T>*, typename atomic<T>::value_type);
   > >     template<class T>
   > >       void atomic_wait_explicit(const volatile atomic<T>*, typename atomic<T>::value_type,
   > >                                 memory_order);
   > >     template<class T>
   > >       void atomic_notify_one(volatile atomic<T>*);
   > >     template<class T>
   > >       void atomic_notify_all(volatile atomic<T>*);

### 3423(i). `std::any_cast` should never return a cv-qualified type

Section: 20.8.5 [any.nonmembers] Status: New Submitter: Casey Carter Opened: 2020-04-02 Last modified: 2020-09-06

Priority: 3

View other active issues in [any.nonmembers].

View all other issues in [any.nonmembers].

View all issues with New status.

Discussion:

The return type of the non-pointer overloads of `std::any_cast<T>` is `T`. This is silly when `T` is cv-qualified (and, since merging P1152 "Deprecating volatile" into the working draft, deprecated when `T` is `volatile`-qualified). We should strip cv-qualifiers to determine the type returned.

[2020-04-18 Issue Prioritization]

Priority to 3 after reflector discussion.

Proposed resolution:

This wording is relative to N4861.

1. Modify 20.8.2 [any.synop] as indicated:

   >     […]
   >     template<class T>
   >       remove_cv_t<T> any_cast(const any& operand);
   >     template<class T>
   >       remove_cv_t<T> any_cast(any& operand);
   >     template<class T>
   >       remove_cv_t<T> any_cast(any&& operand);
   >     […]

2. Modify 20.8.5 [any.nonmembers] as indicated:

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

   > > -4- Let `R` be the type `remove_cv_t<T>`, and `U` be the type `remove_cvref_t<T>`.

   > > -5- Mandates: For the first overload, `is_constructible_v<TR, const U&>` is `true`. For the second overload, `is_constructible_v<TR, U&>` is `true`. For the third overload, `is_constructible_v<TR, U>` is `true`.

   > > -6- Returns: For the first and second overload, `static_cast<TR>(*any_cast<U>(&operand))`. For the third overload, `static_cast<TR>(std::move(*any_cast<U>(&operand)))`.

   > > -7- Throws: `bad_any_cast` if `operand.type() != typeid(remove_reference_t<T>)`.

### 3424(i). `optional::value_or` should never return a cv-qualified type

Section: 20.6.3.6 [optional.observe] Status: New Submitter: Casey Carter Opened: 2020-04-02 Last modified: 2020-09-06

Priority: 3

View other active issues in [optional.observe].

View all other issues in [optional.observe].

View all issues with New status.

Discussion:

The `optional<T>::value_or` overloads are specified to return `T`. This seems silly when `T` is `const` or `volatile` qualified — return types should never be cv-qualified. (In the `volatile` case, it is even deprecated since merging P1152R4 "Deprecating volatile" into the working draft.) We should strip cv-qualifiers from these return types.

[2020-04-18 Issue Prioritization]

Priority to 3 after reflector discussion.

Proposed resolution:

This wording is relative to N4861.

1. Modify 20.6.3 [optional.optional] as indicated:

   >     […]
   >     template<class U> constexpr remove_cv_t<T> value_or(U&&) const&;
   >     template<class U> constexpr remove_cv_t<T> value_or(U&&) &&;
   >     […]

2. Modify 20.6.3.6 [optional.observe] as indicated:

   > [Drafting note: The two removals of the `&&` in `is_convertible_v<U&&, T>` below is just a drive-by simplification]

   >     template<class U> constexpr remove_cv_t<T> value_or(U&& v) const&;

   > > -?- Let `R` be `remove_cv_t<T>`.

   > > -17- Mandates: `is_copy_constructible_v<T>is_convertible_v<const T&, R> && is_convertible_v<U&&, T>` is `true`.

   > > -18- Effects: Equivalent to:

   > > >     return bool(*this) ? **this : static_cast<TR>(std::forward<U>(v));

   >     template<class U> constexpr remove_cv_t<T> value_or(U&& v) &&;

   > > -?- Let `R` be `remove_cv_t<T>`.

   > > -19- Mandates: `is_move_constructible_v<T>is_convertible_v<T, R> && is_convertible_v<U&&, T>` is `true`.

   > > -20- Effects: Equivalent to:

   > > >     return bool(*this) ? std::move(**this) : static_cast<TR>(std::forward<U>(v));

### 3429(i). "models" should subsume like "satisfies"

Section: 16.4.5.11 [res.on.requirements] Status: New Submitter: Tim Song Opened: 2020-04-07 Last modified: 2020-09-06

Priority: 3

View all issues with New status.

Discussion:

It has been pointed out both on the LWG reflector and as editorial issue 3912 that the definition of "models" added in P2101R0 is not a model of clarity when a concept is defined in terms of other concepts.

[2020-04-25 Issue Prioritization]

Priority to 3 after reflector discussion. There was a temptation to resolve this as P0, but concerns were expressed that the "satisfied as part of the satisfaction" part was a bit confusing.

Proposed resolution:

This wording is relative to N4861.

1. Modify 16.4.5.11 [res.on.requirements] as indicated:

   > -1- A sequence `Args` of template arguments is said to model a concept `C` if:

   > 1. (1.1) — `Args` satisfies `C` (13.5.3 [temp.constr.decl]);

   > 2. (1.2) — and `Args` meets all semantic requirements (if any) given in the specification of `C`; and

   > 3. (1.3) — every concept found to be satisfied as part of the satisfaction determination above is also modeled.

### 3431(i). `<=>` for containers should require `three_way_comparable<T>` instead of `<=>`

Section: 22.2.1 [container.requirements.general] Status: New Submitter: Jonathan Wakely Opened: 2020-04-17 Last modified: 2020-09-06

Priority: 2

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

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

View all issues with New status.

Discussion:

The precondition for `<=>` on containers is:

"Either `<=>` is defined for values of type (possibly `const`) `T`, or `<` is defined for values of type (possibly `const`) `T` and `<` is a total ordering relationship."

I don't think `<=>` is sufficient, because `synth-three-way` won't use `<=>` unless `three_way_comparable<T>` is satisfied, which requires `weakly-equality-comparable-with<T, T>` as well as `<=>`.

So to use `<=>` I think the type also requires `==`, or more precisely, it must satisfy `three_way_comparable`.

The problem becomes clearer with the following example:

>     #include <compare>
>     #include <vector>

>     struct X
>     {
>       friend std::strong_ordering operator<=>(X, X) { return std::strong_ordering::equal; }
>     };

>     std::vector<X> v(1);
>     std::strong_ordering c = v <=> v;

This doesn't compile, because despite `X` meeting the preconditions for `<=>` in [tab:container.opt], `synth-three-way` will return `std::weak_ordering`.

Here is another example:

>     #include <compare>
>     #include <vector>

>     struct X
>     {
>       friend bool operator<(X, X) { return true; } // The return value is intentional, see below
>       friend std::strong_ordering operator<=>(X, X) { return std::strong_ordering::equal; }
>     };

>     std::vector<X> v(1);
>     std::weak_ordering c = v <=> v;

This meets the precondition because it defines `<=>`, but the result of `<=>` on `vector<X>` will be nonsense, because `synth-three-way` will use `operator<` not `operator<=>` and that defines a broken ordering.

So we're stating a precondition which implies "if you do this, you don't get garbage results" and then we give garbage results anyway.

The proposed resolution is one way to fix that, by tightening the precondition so that it matches what `synth-three-way` actually does.

[2020-04-25 Issue Prioritization]

Priority to 2 after reflector discussion.

Proposed resolution:

This wording is relative to N4861.

1. Modify 22.2.1 [container.requirements.general], Table [tab:container.opt], as indicated:

   > Table 75: Optional container operations [tab:container.opt]
   > Expression | Return type | Operational semantics | Assertion/note pre-/post-condition | Complexity
   > --- | --- | --- | --- | ---
   > `…`
   > `a <=> b` | `synth-three-way-result<value_type>` | `lexicographical_compare_three_way( a.begin(), a.end(), b.begin(), b.end(), synth-three-way)` | Preconditions: Either `<=>` is defined for values of type (possibly `const`) `T` satisfies `three_way_comparable`, or `<` is defined for values of type (possibly `const`) `T` and `<` is a total ordering relationship. | linear
   > `…`

### 3436(i). `std::construct_at` should support arrays

Section: 25.11.8 [specialized.construct] Status: New Submitter: Jonathan Wakely Opened: 2020-04-29 Last modified: 2021-12-11

Priority: 2

View all issues with New status.

Discussion:

`std::construct_at` is ill-formed for array types, because the type of the `new`-expression is `T` not `T*` so it cannot be converted to the return type.

In C++17 `allocator_traits::construct` did work for arrays, because it returns `void` so there is no ill-formed conversion. On the other hand, in C++17 `allocator_traits::destroy` didn't work for arrays, because `p->~T()` isn't valid.

In C++20 `allocator_traits::destroy` does work, because `std::destroy_at` treats arrays specially, but `allocator_traits::construct` no longer works because it uses `std::construct_at`.

It seems unnecessary and/or confusing to remove support for arrays in `construct` when we're adding it in `destroy`.

I suggest that `std::construct_at` should also handle arrays. It might be reasonable to restrict that support to the case where `sizeof...(Args) == 0`, if supporting parenthesized aggregate-initialization is not desirable in `std::construct_at`.

[2020-05-09; Reflector prioritization]

Set priority to 2 after reflector discussions.

[2021-01-16; Zhihao Yuan provides wording]

Previous resolution [SUPERSEDED]:

> This wording is relative to N4878.

> 1. Modify 25.11.8 [specialized.construct] as indicated:

>    >     template<class T, class... Args>
>    >       constexpr T* construct_at(T* location, Args&&... args);

>    >     namespace ranges {
>    >       template<class T, class... Args>
>    >         constexpr T* construct_at(T* location, Args&&... args);
>    >     }

>    > > -1- Constraints: The expression `::new (declval<void*>()) T(declval<Args>()...)` is well-formed when treated as an unevaluated operand.

>    > > -2- Effects: Equivalent to:

>    > > >     returnauto ptr = ::new (voidify(*location)) T(std::forward<Args>(args)...);
>    > > >     if constexpr (is_array_v<T>)
>    > > >       return launder(location);
>    > > >     else
>    > > >       return ptr;

[2021-12-07; Zhihao Yuan comments and provides improved wording]

The previous PR allows constructing arbitrary number of elements when `T` is an array of unknown bound:

>     extern int a[];
>     std::construct_at(&a, 0, 1, 2);

and leads to a UB.

Proposed resolution:

This wording is relative to N4901.

1. Modify 25.11.8 [specialized.construct] as indicated:

   >     template<class T, class... Args>
   >       constexpr T* construct_at(T* location, Args&&... args);

   >     namespace ranges {
   >       template<class T, class... Args>
   >         constexpr T* construct_at(T* location, Args&&... args);
   >     }

   > > -1- Constraints: The expression `::new (declval<void*>()) T(declval<Args>()...)` is well-formed when treated as an unevaluated operand (7.2.3 [expr.context]) and `is_unbounded_array_v<T>` is `false`.

   > > -2- Effects: Equivalent to:

   > > >     returnauto ptr = ::new (voidify(*location)) T(std::forward<Args>(args)...);
   > > >     if constexpr (is_array_v<T>)
   > > >       return launder(location);
   > > >     else
   > > >       return ptr;

### 3438(i). §[container.node.overview] missing `multiset`/`map` cases

Section: 22.2.4.1 [container.node.overview] Status: New Submitter: Jens Maurer Opened: 2020-04-30 Last modified: 2020-05-09

Priority: 3

View all other issues in [container.node.overview].

View all issues with New status.

Discussion:

This issue resulted out of this editorial change request.

In 22.2.4.1 [container.node.overview], there is Table 79 [tab:container.node.compat] which indicates which containers have compatible nodes.

It appears that rows along

>     multimap<K, T, C1, A>     multimap<K, T, C2, A>

(i.e. multimaps with differing `Compare` functions) are missing from the table.

(Same for `multiset` and `unordered_multiset/map`.)

However, the introductory sentences in 22.2.4.1 [container.node.overview] do not relate "compatible nodes" with Table 79 and do not clearly state transitivity:

> A node handle is an object that accepts ownership of a single element from an associative container (22.2.6 [associative.reqmts]) or an unordered associative container (22.2.7 [unord.req]). It may be used to transfer that ownership to another container with compatible nodes. Containers with compatible nodes have the same node handle type. Elements may be transferred in either direction between container types in the same row of Table 79 [tab:container.node.compat].

[2020-05-09; Reflector prioritization]

Set priority to 3 after reflector discussions.

Proposed resolution:

### 3439(i). "`Distance`" template parameter is underspecified

Section: 23.4.3 [iterator.operations], 25.7.12 [alg.random.sample] Status: New Submitter: Jens Maurer Opened: 2020-05-01 Last modified: 2020-05-09

Priority: 3

View other active issues in [iterator.operations].

View all other issues in [iterator.operations].

View all issues with New status.

Discussion:

The library specification conveys pre-concept requirements on template parameters by naming, e.g. "`InputIterator`".

There is no general specification for template parameters named "`Distance`", as used by `std::advance` (see 23.4.3 [iterator.operations]). When addressing this omission, the local restriction in 25.7.12 [alg.random.sample] could possibly be removed.

See the related issue 3213 for the `Size` template parameter.

[2020-05-09; Reflector prioritization]

Set priority to 3 after reflector discussions.

Proposed resolution:

### 3441(i). Misleading note about calls to customization points

Section: 16.4.5.2.1 [namespace.std] Status: Open Submitter: Michael Park Opened: 2020-05-08 Last modified: 2020-10-02

Priority: 1

View other active issues in [namespace.std].

View all other issues in [namespace.std].

View all issues with Open status.

Discussion:

P0551 (Thou Shalt Not Specialize `std` Function Templates!) added a clause in [namespace.std]/7:

> Other than in namespace `std` or in a namespace within namespace `std`, a program may provide an overload for any library function template designated as a customization point, provided that (a) the overload's declaration depends on at least one user-defined type and (b) the overload meets the standard library requirements for the customization point. (footnote 174) [Note: This permits a (qualified or unqualified) call to the customization point to invoke the most appropriate overload for the given arguments. — end note]

Given that `std::swap` is a designated customization point, the note seems to suggest the following:

>     namespace N {
>       struct X {};
>       void swap(X&, X&) {}
>     }

>     N::X a, b;
>     std::swap(a, b); // qualified call to customization point finds N::swap?

This is not what happens, as the call to `std::swap` does not find `N::swap`.

[2020-07-17; Priority set to 1 in telecon]

Related to 3442.

[2020-09-11; discussed during telecon]

The note is simply bogus, not backed up by anything normative. The normative part of the paragraph is an unacceptable landgrab on those identifiers. We have no right telling users they can't use the names `data` and `size` unless they do exactly what we say `std::data` and `std::size` do. The library only ever uses `swap` unqualified, so the effect of declaring the others as designated customization points is unclear.

The rule only needs to apply to such overloads when actually found by overload resolution in a context that expects the semantics of the customization point.

Frank: do we need to designate `operator<<` as a customization point? Users overload that in their own namespaces all the time.

Walter: This clearly needs a paper.

[2020-10-02; status to Open]

Proposed resolution:

This wording is relative to N4861.

1. Modify 16.4.5.2.1 [namespace.std] as indicated:

   > -7- Other than in namespace `std` or in a namespace within namespace `std`, a program may provide an overload for any library function template designated as a customization point, provided that (a) the overload's declaration depends on at least one user-defined type and (b) the overload meets the standard library requirements for the customization point. (footnote 173) [Note: This permits a (qualified or unqualified) call to the customization point to invoke the most appropriate overload for the given arguments. — end note]

### 3442(i). Unsatisfiable suggested implementation of customization points

Section: 16.4.5.2.1 [namespace.std] Status: Open Submitter: Michael Park Opened: 2020-05-08 Last modified: 2020-10-02

Priority: 1

View other active issues in [namespace.std].

View all other issues in [namespace.std].

View all issues with Open status.

Discussion:

Footnote 173 under [namespace.std]/7 reads (emphasis mine):

> Any library customization point must be prepared to work adequately with any user-defined overload that meets the minimum requirements of this document. Therefore an implementation may elect, under the as-if rule (6.9.1 [intro.execution]), to provide any customization point in the form of an instantiated function object (20.14 [function.objects]) even though the customization point's specification is in the form of a function template. The template parameters of each such function object and the function parameters and return type of the object's `operator()` must match those of the corresponding customization point's specification.

This implementation suggestion doesn't seem to be satisfiable with the as-if rule.

1. In order to maintain as-if rule for qualified calls to `std::swap`, `std::swap` cannot perform ADL look-up like `std::ranges::swap` does.

2. But then we cannot maintain as-if rule for two-step calls to `std::swap`, since ADL is turned off when function objects are involved.

   >     #include <iostream>

   >     namespace S {
   >     #ifdef CPO
   >       static constexpr auto swap = [](auto&, auto&) { std::cout << "std"; };
   >     #else
   >       template<typename T> swap(T&, T&) { std::cout << "std"; }
   >     #endif
   >     }

   >     namespace N {
   >       struct X {};
   >       void swap(X&, X&) { std::cout << "mine"; }
   >     }

   >     int main() {
   >       N::X a, b;
   >       S::swap(a, b);  // (1) prints `std` in both cases
   >       using S::swap;
   >       swap(a, b);     // (2) prints `std` with `-DCPO`, and `mine` without.
   >     }

3. We can try to satisfy the as-if rule for (2) by having `std::swap` perform ADL like `std::ranges::swap`, but then that would break (1) since qualified calls to `std::swap` would also ADL when it did not do so before.

[2020-07-17; Priority set to 1 in telecon]

Related to 3441.

[2020-10-02; status to Open]

Proposed resolution:

This wording is relative to N4861.

1. Modify 16.4.5.2.1 [namespace.std], footnote 173, as indicated:

   > footnote 173) Any library customization point must be prepared to work adequately with any user-defined overload that meets the minimum requirements of this document. Therefore an implementation may elect, under the as-if rule (6.9.1 [intro.execution]), to provide any customization point in the form of an instantiated function object (20.14 [function.objects]) even though the customization point's specification is in the form of a function template. The template parameters of each such function object and the function parameters and return type of the object's `operator()` must match those of the corresponding customization point's specification.

### 3444(i). [networking.ts] `net::basic_socket_streambuf::connect(Args&&...)` effects are wrong

Section: 19.1.2 [networking.ts::socket.streambuf.members] Status: New Submitter: Jonathan Wakely Opened: 2020-05-14 Last modified: 2020-07-17

Priority: 2

View all issues with New status.

Discussion:

Addresses: networking.ts

The effects in 19.1.2 [networking.ts::socket.streambuf.members] p3 say that the function loops through every endpoint in the sequence, attempting to establish a connection. It needs to say that as soon as a connection is successfully established it returns. Otherwise even if a connection is made, it closes the socket and tries the next endpoint in the sequence. That means it will always be left in whatever state resulted from trying the last endpoint in the sequence (or from timing out if the expiry time was reached before iterating through all endpoints).

[2020-07-17; Priority set to 2 in telecon]

Jonathan to provide wording.

Proposed resolution:

### 3445(i). [networking.ts] `net::basic_socket_istream::connect` should be constrained

Section: 19.2.1 [networking.ts::socket.iostream.cons], 19.2.2 [networking.ts::socket.iostream.members] Status: LEWG Submitter: Jonathan Wakely Opened: 2020-05-14 Last modified: 2021-05-10

Priority: 3

View all other issues in [networking.ts::socket.iostream.cons].

View all issues with LEWG status.

Discussion:

Addresses: networking.ts

`basic_socket_streambuf<P, C, W>::connect(Args&&...)` is constrained to only exist when `P` meets the `InternetProtocol` requirements, but `basic_socket_iostream<P, C, W>::connect(Args&&...)` is not constrained. Since it just passes those arguments straight to the `streambuf`, the outer `connect(Args&&...)` should be constrained too.

In addition to that, the `basic_socket_iostream(Args&&...)` constructor should be constrained, so that `is_constructible` gives the right answer.

[2020-07-17; Priority set to 3 in telecon]

Proposed resolution:

This wording is relative to N4771.

1. Modify 19.2.1 [networking.ts::socket.iostream.cons] as indicated:

   > [Drafting note: As a drive-by fix, a missing `std::` qualification in front of `forward` has been added]

   >     template<class... Args>
   >       explicit basic_socket_iostream(Args&&... args);

   > > -4- Effects: Initializes the base class as `basic_iostream<char>(&sb_))`, value-initializes `sb_`, and performs `setf(std::ios_base::unitbuf)`. Then calls `rdbuf()->connect(std::forward<Args>(args)...)`. If that function returns a null pointer, calls `setstate(failbit)`.

   > > -?- Remarks: This function shall not participate in overload resolution unless the expression `rdbuf()->connect(std::forward<Args>(args)...)` is well-formed.

2. Modify 19.2.2 [networking.ts::socket.iostream.members] as indicated:

   > [Drafting note: As a drive-by fix, a missing `std::` qualification in front of `forward` has been added]

   >     template<class... Args>
   >       void connect(Args&&... args);

   > > -1- Effects: Calls `rdbuf()->connect(std::forward<Args>(args)...)`. If that function returns a null pointer, calls `setstate(failbit)` (which may throw `ios_base::failure`).

   > > -?- Remarks: This function shall not participate in overload resolution unless the expression `rdbuf()->connect(std::forward<Args>(args)...)` is well-formed.

### 3451(i). Inconsistently explicit deduction guides

Section: 21.3.3 [basic.string], 24.7.12.2 [range.join.view] Status: New Submitter: Johel Ernesto Guerrero Peña Opened: 2020-06-11 Last modified: 2020-07-17

Priority: 3

View other active issues in [basic.string].

View all other issues in [basic.string].

View all issues with New status.

Discussion:

The library inconsistently marks deduction guides as `explicit`. `join_view` and `basic_string` account for the only two occurrences of unconditionally explicit deduction guides. All other deduction guides have no `explicit`-specifier. Following is a list of unconditionally explicit constructors with their deduction guides.

>     template<class Y>
>       explicit shared_ptr(const weak_ptr<Y>& r);

>     template<class T>
>       shared_ptr(weak_ptr<T>) -> shared_ptr<T>;

>     template<class T>
>       constexpr explicit basic_string(const T& t, const Allocator& a = Allocator());

>     template<class charT,
>              class traits,
>              class Allocator = allocator<charT>>
>       explicit basic_string(basic_string_view<charT, traits>, const Allocator& = Allocator())
>         -> basic_string<charT, traits, Allocator>;

>     explicit queue(const Container&);
>     explicit queue(Container&&);

>     template<class Container>
>       queue(Container) -> queue<typename Container::value_type, Container>;

>     explicit stack(const Container&);
>     explicit stack(Container&&);

>     template<class Container>
>       stack(Container) -> stack<typename Container::value_type, Container>;

>     constexpr explicit join_view(V base);

>     template<class R>
>       explicit join_view(R&&) -> join_view<views::all_t<R>>;

>     constexpr explicit common_view(V r);

>     template<class R>
>       common_view(R&&) -> common_view<views::all_t<R>>;

>     constexpr explicit reverse_view(V r);

>     template<class R>
>       reverse_view(R&&) -> reverse_view<views::all_t<R>>;

>     explicit zoned_time(TimeZonePtr z);
>     explicit zoned_time(string_view name);

>     template<class TimeZonePtrOrName>
>       zoned_time(TimeZonePtrOrName&&)
>         -> zoned_time<seconds, time-zone-representation<TimeZonePtrOrName>>;

>     template<class C>
>     explicit stop_callback(const stop_token& st, C&& cb)
>         noexcept(is_nothrow_constructible_v<Callback, C>);
>     template<class C>
>     explicit stop_callback(stop_token&& st, C&& cb)
>         noexcept(is_nothrow_constructible_v<Callback, C>);

>     template<class Callback>
>       stop_callback(stop_token, Callback) -> stop_callback<Callback>;

[2020-07-17; Priority set to 3 in telecon]

Proposed resolution:

This wording is relative to N4861.

1. Modify 21.3.3 [basic.string], class template `basic_string` synopsis, as indicated:

   >     […]
   >     template<class charT,
   >              class traits,
   >              class Allocator = allocator<charT>>
   >       explicit basic_string(basic_string_view<charT, traits>, const Allocator& = Allocator())
   >         -> basic_string<charT, traits, Allocator>;
   >     […]

2. Modify 21.3.3.3 [string.cons] as indicated:

   >     […]
   >     template<class charT,
   >              class traits,
   >              class Allocator = allocator<charT>>
   >       explicit basic_string(basic_string_view<charT, traits>, const Allocator& = Allocator())
   >         -> basic_string<charT, traits, Allocator>;
   >     […]

   > > -22- Constraints: `Allocator` is a type that qualifies as an allocator (22.2.1 [container.requirements.general]).

3. Modify 24.7.12.2 [range.join.view], class template `join_view` synopsis, as indicated:

   >     […]
   >     template<class R>
   >       explicit join_view(R&&) -> join_view<views::all_t<R>>;
   >     […]

### 3454(i). `pointer_traits::pointer_to` should be `constexpr`

Section: 20.10.3 [pointer.traits] Status: LEWG Submitter: Alisdair Meredith Opened: 2020-06-21 Last modified: 2020-09-06

Priority: Not Prioritized

View other active issues in [pointer.traits].

View all other issues in [pointer.traits].

View all issues with LEWG status.

Discussion:

Trying to implement a `constexpr std::list` (inspired by Tim Song's note on using variant members in the node) as part of evaluating the `constexpr` container and adapters proposals, I hit problems I could not code around in `pointer_traits`, as only the specialization for native pointers has a `constexpr pointer_to` function.

This means that containers of my custom allocator, that delegates all allocation behavior to `std::allocator<T>` but adds extra telemetry and uses a fancy pointer, does not work with the approach I tried for implementing `list` (common link type, shared between nodes, and stored as `end` sentinel directly in the `list` object).

[2020-07-17; Forwarded to LEWG after review in telecon]

Proposed resolution:

This wording is relative to N4861.

1. Modify 20.10.3 [pointer.traits] as indicated:

   > -1- The class template `pointer_traits` supplies a uniform interface to certain attributes of pointer-like types.

   > >     namespace std {
   > >       template<class Ptr> struct pointer_traits {
   > >         using pointer         = Ptr;
   > >         using element_type    = see below;
   > >         using difference_type = see below;

   > >         template<class U> using rebind = see below;

   > >         static constexpr pointer pointer_to(see below r);
   > >       };
   > >       […]
   > >     }

2. Modify 20.10.3.3 [pointer.traits.functions] as indicated:

   >     static constexpr pointer pointer_traits::pointer_to(see below r);
   >     static constexpr pointer pointer_traits<T*>::pointer_to(see below r) noexcept;

   > > -1- Mandates: For the first member function, `Ptr::pointer_to(r)` is well-formed.

   > > -2- Preconditions: For the first member function, `Ptr::pointer_to(r)` returns a pointer to `r` through which indirection is valid.

   > > -3- Returns: The first member function returns `Ptr::pointer_to(r)`. The second member function returns `addressof(r)`.

   > > -4- Remarks: If `element_type` is cv `void`, the type of `r` is unspecified; otherwise, it is `element_type&`.

### 3456(i). Pattern used by `std::from_chars` is underspecified

Section: 20.19.3 [charconv.from.chars] Status: New Submitter: Jonathan Wakely Opened: 2020-06-23 Last modified: 2020-09-06

Priority: 3

View other active issues in [charconv.from.chars].

View all other issues in [charconv.from.chars].

View all issues with New status.

Discussion:

The intention of 20.19.3 [charconv.from.chars] p7 is that the `fmt` argument modifies the expected pattern, so that only a specific subset of valid `strtod` patterns are recognized for each format. This is not clear from the wording.

When `fmt == chars_format::fixed` no exponent is to be used, so any trailing characters that match the form of a `strtod` exponent are ignored. For example, `"1.23e4"` should produce the result `1.23` for the fixed format. The current wording says "the optional exponent part shall not appear" which can be interpreted to mean that `"1.23e4"` violates a precondition and so has undefined behaviour!

When `fmt != chars_format::hex` only decimal numbers should be recognized. This means that for any format except scientific, `"0x123"` produces `0.0` (it's invalid when `fmt == chars_format::scientific` because there's no exponent). The current wording only says that when `hex` is used the string has an assumed `"0x"` prefix, so is interpreted as a hexadecimal float, it doesn't say that when `fmt != hex` that the string is not interpreted as a hexadecimal float.

Two alternative resolutions are provided, one is a minimal fix and the other attempts to make it clearer by not referring to a modified version of the C rules.

[2020-07-14; Jonathan fixes the `strtod` call in Option B]

[2020-07-17; Priority set to 3 in telecon]

Proposed resolution:

This wording is relative to N4861.

Option A:

1. Modify 20.19.3 [charconv.from.chars] as indicated:

   >     from_chars_result from_chars(const char* first, const char* last, float& value,
   >                                  chars_format fmt = chars_format::general);
   >     from_chars_result from_chars(const char* first, const char* last, double& value,
   >                                  chars_format fmt = chars_format::general);
   >     from_chars_result from_chars(const char* first, const char* last, long double& value,
   >                                  chars_format fmt = chars_format::general);

   > > -6- Preconditions: `fmt` has the value of one of the enumerators of `chars_format`.

   > > -7- Effects: The pattern is the expected form of the subject sequence in the "C" locale, as described for `strtod`, except that

   > > 1. (7.1) — the sign `'+'` may only appear in the exponent part;

   > > 2. (7.2) — if `fmt` has `chars_format::scientific` set but not `chars_format::fixed`, the otherwise optional exponent part shall appear exponent part is not optional;

   > > 3. (7.3) — if `fmt` has `chars_format::fixed` set but not `chars_format::scientific`, the optional exponent part shall not appear; and there is no exponent part;

   > > 4. (?.?) — if `fmt` is not `chars_format::hex`, only decimal digits and an optional `'.'` appear before the exponent part (if any); and

   > > 5. (7.4) — if `fmt` is `chars_format::hex`, the prefix `"0x"` or `"0X"` is assumed. [Example: The string `0x123` is parsed to have the value `0` with remaining characters `x123`. — end example]

   > > In any case, the resulting `value` is one of at most two floating-point values closest to the value of the string matching the pattern.

Option B:

1. Modify 20.19.3 [charconv.from.chars] as indicated:

   >     from_chars_result from_chars(const char* first, const char* last, float& value,
   >                                  chars_format fmt = chars_format::general);
   >     from_chars_result from_chars(const char* first, const char* last, double& value,
   >                                  chars_format fmt = chars_format::general);
   >     from_chars_result from_chars(const char* first, const char* last, long double& value,
   >                                  chars_format fmt = chars_format::general);

   > > -6- Preconditions: `fmt` has the value of one of the enumerators of `chars_format`.

   > > -7- Effects: The pattern is the expected form of the subject sequence in the "C" locale, as described for `strtod`, except that The pattern is an optional `'-'` sign followed by one of:

   > > 1. (7.1) — the sign `'+'` may only appear in the exponent part `INF` or `INFINITY`, ignoring case;

   > > 2. (7.2) — if `fmt` has `chars_format::scientific` set but not `chars_format::fixed`, the otherwise optional exponent part shall appear if `numeric_limits<T>::has_quiet_NaN` is `true`, `NAN` or `NAN(`n-char-sequenceopt`)`, ignoring case in the `NAN` part, where:

   > >    >     n-char-sequence:
   > >    >            digit
   > >    >            nondigit
   > >    >            n-char-sequence digit
   > >    >            n-char-sequence nondigit

   > >    ;

   > > 3. (7.3) — if `fmt` has `chars_format::fixed` set but not `chars_format::scientific`, the optional exponent part shall not appear; and if `fmt` is equal to `chars_format::scientific`, a sequence of characters matching chars-format-dec exponent-part, where:

   > >    >     chars-format-dec:
   > >    >              fractional-constant
   > >    >              digit-sequence

   > >    ;

   > > 4. (7.4) — if `fmt` is `chars_format::hex`, the prefix `"0x"` or `"0X"` is assumed. [Example: The string `0x123` is parsed to have the value `0` with remaining characters `x123`. — end example]if `fmt` is equal to `chars_format::fixed`, a sequence of characters matching chars-format-dec;

   > > 5. (?.?) — if `fmt` is equal to `chars_format::general`, a sequence of characters matching chars-format-dec exponent-partopt; or

   > > 6. (?.?) — if `fmt` is equal to `chars_format::hex`, a sequence of characters matching chars-format-hex binary-exponent-partopt, where:

   > >    >     chars-format-hex:
   > >    >              hexadecimal-fractional-constant
   > >    >              hexadecimal-digit-sequence

   > >    [Note: The pattern is derived from the subject sequence in the `"C"` locale for `strtod`, with the value of `fmt` limiting which forms of the subject sequence are recognized, and with no `0x` or `0X` prefix recognized. — end note]

   > > For a character sequence `INF`, `INFINITY`, `NAN`, or `NAN(`n-char-sequenceopt`)` the resulting value is obtained as if by evaluating `strtod(string(first, last).c_str(), nullptr)` in the `"C"` locale. In all other cases In any case, the resulting `value` is one of at most two floating-point values closest to the value of the string matching the pattern.

### 3457(i). `*this` is not invalidated

Section: 21.4.3 [string.view.template] Status: New Submitter: Johel Ernesto Guerrero Peña Opened: 2020-06-26 Last modified: 2020-09-06

Priority: 3

View other active issues in [string.view.template].

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

View all issues with New status.

Discussion:

21.4.3 [string.view.template] states:

> 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 member functions.

The assignment operators return a reference to `*this`, but `*this` is not invalidated.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4861.

> 1. Modify 21.4.3 [string.view.template] as indicated:

>    > -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 to the elements in that range and its past-the-end iterator returned from `str`'s member functions.

[2020-06-29; Casey comments and provides alternative proposed wording]

I think we should additionally strike "returned from `str`'s member functions" from the end of the sentence. Provenance shouldn't affect invalidation; `ranges::next(some_string_view.begin(), 42)`, for example, returns an iterator that denotes an element of `some_string_view`, but is not a member function of `basic_string_view`.

[2020-07-05; Reflector prioritization]

Set priority to 3 after reflector discussions.

Proposed resolution:

This wording is relative to N4861.

1. Modify 21.4.3 [string.view.template] as indicated:

   > -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 to the elements in that range and its past-the-end iterator returned from `str`'s member functions.

### 3459(i). Why doesn't `std::convertible_to` have semantic requirement when `To` is reference-to-function type?

Section: 18.4.4 [concept.convertible] Status: New Submitter: S. B. Tam Opened: 2020-06-30 Last modified: 2020-07-12

Priority: 3

View other active issues in [concept.convertible].

View all other issues in [concept.convertible].

View all issues with New status.

Discussion:

18.4.4 [concept.convertible] p2:

> Types `From` and `To` model `convertible_to<From, To>` only if:

> 1. (2.1) — `To` is not an object or reference-to-object type, or `static_cast<To>(f())` is equal to `test(f)`.

> 2. […]

This requires the implicit and explicit conversions to produce equal results.

However, it seems that when `To` is a reference-to-function type, this restriction does not apply. This makes it possible to create a class that models `convertible_to`, but produces different results depending on the kind of conversion:

>     #include <concepts>

>     int foo() { return 0; }
>     int bar() { return 42; }

>     using FT = int();
>     struct A
>     {
>       operator FT&() const { return foo; }
>       explicit operator FT&() { return bar; }
>     };

>     static_assert(std::convertible_to<A, FT&>);

>     A a;
>     FT& x = a;                    // x == foo
>     auto y = static_cast<FT&>(a); // y == bar

[2020-07-12; Reflector prioritization]

Set priority to 3 after reflector discussions.

Proposed resolution:

### 3463(i). Incorrect requirements for `transform_inclusive_scan` without initial value

Section: 25.10.11 [transform.inclusive.scan] Status: New Submitter: Agustín K-ballo Bergé Opened: 2020-07-07 Last modified: 2020-09-06

Priority: 3

View all issues with New status.

Discussion:

The requirements for the overloads of `std::transform_inclusive_scan` without an initial value incorrectly assume that the internal accumulator uses the iterator's value type, as it does for `std::inclusive_scan`, rather than the transformed type of the iterator's value type, as it was intended.

According to the standard, the following program is ill-formed as it requires `std::string` to be convertible to `int`:

>     auto vs = {0, 1, 2};
>     std::transform_inclusive_scan(
>        vs.begin(), vs.end(),
>        std::ostream_iterator<std::string>(std::cout, ";"),
>        [](std::string x, std::string y) { return x + y; },
>        [](int x) { return std::to_string(x); });

libstdc++ and Microsoft's STL accept the snippet, producing `0;01;012;` as expected, libc++ strictly conforms to the standard and rejects it.

These constrains were introduced by P0574R1.

[2020-07-17; Priority set to 3 in telecon]

Proposed resolution:

This wording is relative to N4861.

> [Drafting note: Current implementations that accept the code, do some form of `auto acc = unary_op(*first);`, therefore the following proposed wording uses `decay_t` instead of e.g. `remove_cvref_t`.]

1. Modify 25.10.11 [transform.inclusive.scan] as indicated:

   >     template<class InputIterator, class OutputIterator,
   >              class BinaryOperation, class UnaryOperation>
   >       constexpr OutputIterator
   >         transform_inclusive_scan(InputIterator first, InputIterator last,
   >                                  OutputIterator result,
   >                                  BinaryOperation binary_op, UnaryOperation unary_op);
   >     template<class ExecutionPolicy,
   >              class ForwardIterator1, class ForwardIterator2,
   >              class BinaryOperation, class UnaryOperation>
   >       ForwardIterator2
   >         transform_inclusive_scan(ExecutionPolicy&& exec,
   >                                  ForwardIterator1 first, ForwardIterator1 last,
   >                                  ForwardIterator2 result,
   >                                  BinaryOperation binary_op, UnaryOperation unary_op);
   >     template<class InputIterator, class OutputIterator,
   >              class BinaryOperation, class UnaryOperation, class T>
   >       constexpr OutputIterator
   >         transform_inclusive_scan(InputIterator first, InputIterator last,
   >                                  OutputIterator result,
   >                                  BinaryOperation binary_op, UnaryOperation unary_op,
   >                                  T init);
   >     template<class ExecutionPolicy,
   >              class ForwardIterator1, class ForwardIterator2,
   >              class BinaryOperation, class UnaryOperation, class T>
   >       ForwardIterator2
   >         transform_inclusive_scan(ExecutionPolicy&& exec,
   >                                  ForwardIterator1 first, ForwardIterator1 last,
   >                                  ForwardIterator2 result,
   >                                  BinaryOperation binary_op, UnaryOperation unary_op,
   >                                  T init);

   > > -1- Let `U` be the value type of `decltype(first)``decay_t<decltype(unary_op(*first))>`.

   > > -2- […]

### 3475(i). `std::thread`'s constructor needs to be able to report general memory allocation failures

Section: 32.4.3.3 [thread.thread.constr], 32.4.4.2 [thread.jthread.cons] Status: New Submitter: Billy O'Neal III Opened: 2020-08-14 Last modified: 2020-09-06

Priority: 3

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

View all issues with New status.

Discussion:

`(j)thread`'s constructor needs to `decay-copy` the supplied parameters and callable over to the started thread through an operating system API that generally only accepts a single `void*`. The MSVC++ and libc++ implementations do this by putting the parameters in a `std::tuple` allocated from the heap, passing a pointer to that tuple through the operating system API, and leaving ownership of the parameters to the other thread.

It might be theoretically possible to introduce an additional copy and synchronization where the starting thread blocks for the started thread to make a move constructed copy of that tuple from the parameters, but that would introduce unreasonable synchronization overhead since the starting thread would have to block for all TLS initializers and similar in the started thread.

It is technically possible to implement the current design by transforming this allocation failure into `resource_unavailable_try_again`, but the description for this error in the standard is that some thread-based limitation has been reached, not a general memory limit, so that doesn't seem to meet the spirit of the requirement.

[2020-08-21; Issue processing telecon: set priority to 3]

Jonathan: I prefer Option A, but I think we need something like: "any exceptions thrown by the `decay-copy` calls, or ...".

Proposed resolution:

This wording is relative to N4861.

> [Drafting Note: Two mutually exclusive options are prepared, depicted below by Option A and Option B, respectively.]

Option A: The memory allocation failure results in `bad_alloc`.

1. Modify 32.4.3.3 [thread.thread.constr] as indicated:

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

   > > -3- Constraints: […]

   > > […]

   > > -8- Postconditions: `get_id() != id()`. `*this` represents the newly started thread.

   > > -9- Throws: `bad_alloc` if memory to transfer parameters to the new thread cannot be obtained. `system_error` if unable to start the new thread.

   > > -10- Error conditions:

   > > 1. (10.1) — `resource_unavailable_try_again` — the system lacked the necessary resources to create another thread, or the system-imposed limit on the number of threads in a process would be exceeded.

2. Modify 32.4.4.2 [thread.jthread.cons] as indicated:

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

   > > -3- Constraints: […]

   > > […]

   > > -8- Postconditions: `get_id() != id()` is `true` and `ssource.stop_possible()` is `true` and `*this` represents the newly started thread. [Note: The calling thread can make a stop request only once, because it cannot replace this stop token. — end note]

   > > -9- Throws: `bad_alloc` if memory to transfer parameters to the new thread cannot be obtained. `system_error` if unable to start the new thread.

   > > -10- Error conditions:

   > > 1. (10.1) — `resource_unavailable_try_again` — the system lacked the necessary resources to create another thread, or the system-imposed limit on the number of threads in a process would be exceeded.

Option B: The memory allocation failure results in a `system_error` with the error condition `out_of_memory`.

1. Modify 32.4.3.3 [thread.thread.constr] as indicated:

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

   > > -3- Constraints: […]

   > > […]

   > > -8- Postconditions: `get_id() != id()`. `*this` represents the newly started thread.

   > > -9- Throws: `system_error` if unable to start the new thread.

   > > -10- Error conditions:

   > > 1. (10.?) — `not_enough_memory` — the system lacked memory resources to transfer parameters to the new thread.

   > > 2. (10.1) — `resource_unavailable_try_again` — the system lacked the necessary resources to create another thread, or the system-imposed limit on the number of threads in a process would be exceeded.

2. Modify 32.4.4.2 [thread.jthread.cons] as indicated:

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

   > > -3- Constraints: […]

   > > […]

   > > -8- Postconditions: `get_id() != id()` is `true` and `ssource.stop_possible()` is `true` and `*this` represents the newly started thread. [Note: The calling thread can make a stop request only once, because it cannot replace this stop token. — end note]

   > > -9- Throws: `system_error` if unable to start the new thread.

   > > -10- Error conditions:

   > > 1. (10.?) — `not_enough_memory` — the system lacked memory resources to transfer parameters to the new thread.

   > > 2. (10.1) — `resource_unavailable_try_again` — the system lacked the necessary resources to create another thread, or the system-imposed limit on the number of threads in a process would be exceeded.

### 3484(i). Should `<stddef.h>` declare `::nullptr_t`?

Section: 99 [depr.c.headers.other] Status: New Submitter: Thomas Köppe Opened: 2020-09-06 Last modified: 2020-09-29

Priority: 3

View all issues with New status.

Discussion:

From this editorial issue request:

The header `<stddef.h>` is currently specified in 99 [depr.c.headers.other] to not declare a global name corresponding to `std::byte`, but no similar exclusion exists for `std::nullptr_t`.

Is an oversight or intentional? There does not seem to be an interoperability reason to provide a global namespace name `::nullptr_t`, since this construction would be meaningless in C and thus the name would not be encountered in code that is both valid C and C++.

For lack of justification, I would like to propose to require normatively that no name `::nullptr_t` be declared by `<stddef.h>`.

Additional notes: The proposing paper N2431 mentions only an addition of "`nullptr_t`" to `<cstddef>` and does not discuss the impact on `<stddef.h>`. By omission this means the default rules for `<stddef.h>` apply and the global name should exist, but this does not provide us with a positive signal of intention.

I also realize that this is a rather obscure point, and that vendors are already shipping `::nullptr_t`, so I am also happy to drop this issue as not being worth the churn and the increase in implementation complexity (since removals don't generally simplify implementations). I would welcome a bit of discussion, though.

[2020-09-29; Priority to P3 after reflector discussions]

Proposed resolution:

This wording is relative to N4861.

1. Modify 99 [depr.c.headers.other] as indicated:

   > -1- Every C header other than `<complex.h>` ( [depr.complex.h.syn]), `<iso646.h>` ( [depr.iso646.h.syn]), `<stdalign.h>` ( [depr.stdalign.h.syn]), `<stdbool.h>` ( [depr.stdbool.h.syn]), and `<tgmath.h>` ( [depr.tgmath.h.syn]), each of which has a name of the form `<name.h>`, behaves as if each name placed in the standard library namespace by the corresponding `<cname>` header is placed within the global namespace scope, except for the functions described in 26.8.6 [sf.cmath], the declaration of `std::byte` and `std::nullptr_t` (17.2.1 [cstddef.syn]), and the functions and function templates described in 17.2.5 [support.types.byteops]. It is unspecified whether these names are first declared or defined within namespace scope (6.4.5 [basic.scope.namespace]) of the namespace `std` and are then injected into the global namespace scope by explicit using-declarations (9.9 [namespace.udecl]).

2. In [diff.cpp??] [Editorial note: new compatibility section to be created for C++20], add a new entry:

   > Affected subclause: 99 [depr.c.headers.other]
   > Change: Removal of name `::nullptr_t` from header `<stddef.h>`.
   > Rationale: `std::nullptr_t` is a C++-only feature that is not useful for interoperability with ISO C.
   > Effect on original feature: Valid C++20 code may fail to compile in this International Standard. Occurrences of `#include <stddef.h>` and `nullptr_t` should be replaced with `#include <cstddef>` and `std::nullptr_t`.

### 3485(i). `atomic_ref` safety should be based on operations that "potentially conflict" rather than lifetime

Section: 31.7 [atomics.ref.generic] Status: SG1 Submitter: Billy O'Neal III Opened: 2020-09-12 Last modified: 2020-09-29

Priority: 3

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

View all issues with SG1 status.

Discussion:

Consider the following program:

>     #include <atomic>
>     #include <iostream>
>     #include <thread>

>     using namespace std;

>     int main() {
>       int i{500};
>       atomic_ref atom{i};
>       i += 500;
>       thread t1{[&atom] { for (int val{0}, x{0}; x < 70;) {
>         if (atom.compare_exchange_weak(val, val + 10)) { ++x; }}}};
>       thread t2{[&atom] { for (int val{0}, y{0}; y < 29;) {
>         if (atom.compare_exchange_weak(val, val + 1)) { ++y; }}}};
>       t1.join(); t2.join();
>       cout << i << endl; // 1729
>     }

Technically this program has undefined behavior. 31.7 [atomics.ref.generic] p3 says that, during the lifetime of any `atomic_ref` referring to an object, that the object may only be accessed through the `atomic_ref` instances. However, in this example the `atomic_ref` is constructed before the `i+=500` and is not destroyed before the print, even though we have a happens-before relationship between the atomic and non-atomic 'phases' of access of the value.

The user would instead have to write:

>     #include <atomic>
>     #include <iostream>
>     #include <thread>

>     using namespace std;

>     int main() {
>       int i{500};
>       i += 500;
>       {
>         atomic_ref atom{i};
>         thread t1{[&atom] { for (int val{0}, x{0}; x < 70;) {
>           if (atom.compare_exchange_weak(val, val + 10)) { ++x; }}}};
>         thread t2{[&atom] { for (int val{0}, y{0}; y < 29;) {
>           if (atom.compare_exchange_weak(val, val + 1)) { ++y; }}}};
>         t1.join(); t2.join();
>       } // destroy atom
>       cout << i << endl; // 1729
>     }

We should probably get SG1 on record clarifying whether they intend the first program to be acceptable. I can think of a reason to for `atomic_ref`'s ctor to do something (zeroing out padding), but in our implementation it does nothing. I can't think of any reason for `atomic_ref`'s dtor to do anything.

[2020-09-29; Priority to P3 after reflector discussions; Status set to "SG1"]

Proposed resolution:

### 3486(i). `is_constructible<T[], T...>` may be misleading in C++20

Section: 20.15.5.4 [meta.unary.prop] Status: LEWG Submitter: Jonathan Wakely Opened: 2020-10-01 Last modified: 2020-10-01

Priority: Not Prioritized

View other active issues in [meta.unary.prop].

View all other issues in [meta.unary.prop].

View all issues with LEWG status.

Discussion:

According to the current wording, `std::is_constructible<int[], int>` should be true, because the preconditions are met (all types are complete types or unbounded arrays) and the variable definition is well-formed since C++20:

>     using T = int[];
>     T t(declval<int>()); // equiv. to int t[] = {1};

However, this doesn't construct an object of type `int[]` because it deduces the array bound from the initializers, and so constructs `int[1]`, which is not the type being asked about. It seems more logical for the trait to give a false result for an unbounded array, because it's an incomplete type, and no `int[]` can ever be constructed.

On the reflector Tim Song noted:

> On the other hand, the result is something to which an `int(&)[]` can be bound directly thanks to another C++20 change, so a lot of things might Just Work (for some definition of "Work") despite the type difference.

This seems to me a reasonable rationale for `is_constructible<int(&&)[], int>` to be true (which it is today), but not for `int[]`.

Peter Dimov replied:

> Placement new, which is often the way to construct we're interested in, is not going to work even for `T[2]`.

For example:

>     using T2 = int[2];
>     T2 x;
>     new(x) T2(1, 2); // ill-formed

We need to decide what behaviour we want here. Do we just want `is_constructible` to reflect the `T(declval<Args...>);` construct as currently specified in 20.15.5.4 [meta.unary.prop] p8, or do we want to give a more useful/meaningful answer here?

Should we revisit 20.15.5.4 [meta.unary.prop] p8 in the light of parenthesized aggregate init, so that `is_constructible<T[], T>` and `is_constructible<T[1], T>` are false?

There may be some interaction with LWG 3436.

Proposed resolution:

### 3487(i). Missing precondition on input and output aliasing of [numeric.ops]

Section: 25.10 [numeric.ops] Status: New Submitter: Matthias Kretz Opened: 2020-10-01 Last modified: 2020-10-02

Priority: 3

View all other issues in [numeric.ops].

View all issues with New status.

Discussion:

The algorithms `partial_sum`, `exclusive_scan`, `inclusive_scan`, `transform_exclusive_scan`, `transform_inclusive_scan`, and `adjacent_difference` with no `ExecutionPolicy` do not have a precondition "`result` is not in the range [`first`, `last`)". But they explicitly allow "`result` may be equal to `first`". This suggests the precondition got lost, because otherwise the permission is redundant.

Suggested fix: Add "`result` is not in the range [`first + 1`, `last`)." to the Preconditions paragraphs of the affected generalized numeric operations.

[2020-10-02; Issue processing telecon: Priority set to P3.]

Proposed resolution:

### 3488(i). Is `array<const int, 0>` swappable or not?

Section: 22.3.7.4 [array.special] Status: Open Submitter: Casey Carter Opened: 2020-10-01 Last modified: 2020-10-04

Priority: 3

View all issues with Open status.

Discussion:

Per 22.3.7.4 [array.special]/1, `std::array`'s non-member swap participates in overload resolution when the array has size 0 or swappable elements. The effects of non-member swap are "As if by [member swap]", but member swap's effects are simply "Equivalent to swap_ranges(begin(), end(), y.begin())" per 22.3.7.3 [array.members]/4. In effect, we've gone out of our way to ensure that `is_swappable_v<array<T, 0>>` and `swappable<array<T, 0>>` are always true despite that actually swapping such an array may be ill-formed.

It seems that the wording stops half-way to making `array<T, 0>` swappable regardless of `T`. I personally find that design distasteful - it seems a gratuitous difference between `array<T, N>` and `array<T, 0>` - but I'd prefer a consistent design over the status quo even if it's the "wrong" design.

[2020-10-02; Issue processing telecon]

Preference for Option B, and successful vote to move to Tentatively Ready. But on the reflector Tim Song pointed out a conflict with 2157 and question the decision. Status to Open instead. Priority set to P3 in line with 2157.

Proposed resolution:

Wording relative to N4861.

This resolution proposes two wording alternatives: Option A makes `array<T, 0>` swappable regardless of `T`, and the clearly superior Option B makes `array<T, N>` swappable only if `T` is swappable (i.e., regardless of `N`) removing gratuitous special-case behavior for the `N == 0` case.

Option A:

1. Change 22.3.7.3 [array.members] as follows:

   >     constexpr void swap(array& y) noexcept(N == 0 || is_nothrow_swappable_v<T>);

   -4- Effects: If `N == 0`, no effects. Otherwise, equivalent Equivalent to `swap_ranges(begin(), end(), y.begin())`.

   -5- […]

2. Also remove the now-redundant paragraph four from 22.3.7.5 [array.zero] as follows:

   > -4- Member function `swap()` shall have a non-throwing exception specification.

Option B:

1. Change 22.3.7.4 [array.special] as follows:

   >     template<class T, size_t N>
   >     constexpr void swap(array<T, N>& x, array<T, N>& y) noexcept(noexcept(x.swap(y)));

   -1- Constraints: `N == 0` or `is_swappable_v<T>` is `true`.

2. Also remove paragraph four from 22.3.7.5 [array.zero] as follows:

   > -4- Member function `swap()` shall have a non-throwing exception specification.

### 3489(i). Improve `istream_view` wording

Section: 24.6.5.3 [range.istream.iterator] Status: New Submitter: Michael Schellenberger Costa Opened: 2020-10-09 Last modified: 2021-09-02

Priority: 3

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

View all issues with New status.

Discussion:

While implementing `iranges::stream_view` we found some issues with the Preconditions on the member functions of `istream_view::iterator`, which are superfluous or incorrect.

1. 24.6.5.3 [range.istream.iterator] p2 reads as:

   > Preconditions: `parent_->stream_ != nullptr` is `true`.

   However in the Effects element 24.6.5.3 [range.istream.iterator] p3 it reads:

   > Effects: Equivalent to:

   > >     *parent_->stream_ >> parent_->object_;
   > >     return *this;

   For the Effects element to be valid, we implicitly require that `parent_ != nullptr`, `parent_->stream_ != nullptr` and — because we are reading from the underlying stream — `!*x.parent_->stream_`.

   Given that the Preconditions element only mentions one of the three preconditions and essentially means that we are not at the end of the stream, we should replace 24.6.5.3 [range.istream.iterator] p2 by:

   > Preconditions: `*this != default_sentinel`.

2. We should use the same precondition for 24.6.5.3 [range.istream.iterator] p4, even if it is implicit via the Effects element in 24.6.5.3 [range.istream.iterator] p5, as that requires experts knowledge of the standard.

3. The Precondition in 24.6.5.3 [range.istream.iterator] p6 is completely bogus, as accessing the cached object has no dependency on the stream. We assume it is meant that we are not at the end of the stream. Again we should change this to:

   > Preconditions: `*this != default_sentinel`.

[2020-10-14; Priority to P3 after reflector discusssion]

[2021-09-02; Jonathan comments:]

The preconditions were removed by P2325R3 approved in June 2021. Although the pointers now cannot be null, it's unclear if we want to require `fail()` to be false for the stream.

Proposed resolution:

This wording is relative to N4861.

1. Modify 24.6.5.3 [range.istream.iterator] as indicated:

   >     iterator& operator++();

   > > -2- Preconditions: `parent_->stream_ != nullptr*this != default_sentinel` is `true`.

   > > -3- Effects: Equivalent to:

   > > >     *parent_->stream_ >> parent_->object_;
   > > >     return *this;

   >     void operator++(int);

   > > -4- Preconditions: `parent_->stream_ != nullptr*this != default_sentinel` is `true`.

   > > -5- Effects: Equivalent to `++*this`.

   >     Val& operator*() const;

   > > -6- Preconditions: `parent_->stream_ != nullptr*this != default_sentinel` is `true`.

   > > -7- Effects: Equivalent to: `return parent_->object_;`

   >     friend bool operator==(const iterator& x, default_sentinel_t);

   > > -8- Effects: Equivalent to: `return x.parent_ == nullptr || !*x.parent_->stream_;`

### 3491(i). What is a "decayed type"?

Section: 17.11.6 [cmp.alg], 24.7.5.1 [range.all.general], 17.11.6 [cmp.alg] Status: New Submitter: Alisdair Meredith Opened: 2020-10-27 Last modified: 2021-10-30

Priority: 3

View all other issues in [cmp.alg].

View all issues with New status.

Discussion:

Some of our newer wording for C++20 uses the term "decayed type" as if it were a defined term of art. While I have intuition for what may be intended in these cases, it turns out the "function to function pointer decay" and "array to array pointer decay" were never actually Core terms of art — having searched all standards going back as far as C++03.

We should either define this term for library use, or find a way to state our intent using existing well-defined terms of art.

Affected clauses:

- 17.11.6 [cmp.alg]: Most heavily used here.

- 24.7.5.1 [range.all.general]

- 17.11.6 [cmp.alg]

[2021-01-15; Telecon prioritization]

Set priority to 3 following reflector and telecon discussions.

Proposed resolution:

### 3493(i). The constructor of `std::function` taking an `F` is missing a constraint

Section: 20.14.17.3.2 [func.wrap.func.con] Status: New Submitter: Ville Voutilainen Opened: 2020-10-31 Last modified: 2021-08-20

Priority: 3

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

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

View all issues with New status.

Discussion:

In P0288, `any_invocable` is (correctly) constraining its constructor that takes an `F`:

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

> > Let `VT` be `decay_t<F>`.

> > Constraints:

> > 1. — […]

> > 2. — `is_constructible_v<VT, F>` is `true`, and

> > 3. — […]

`std::function` doesn't do that. According to N4868, 20.14.17.3.2 [func.wrap.func.con] p8 has a constraint for Lvalue-Callable, but not for copy-constructibility. There is a precondition in p9, but that's not enough for portable well/ill-formedness.

Since this is a constructor, and we want to give the right answer to `is_constructible`/`constructible_from` queries, we should add the relevant constraint.

[2020-11-01; Daniel comments]

This issue has some overlap with LWG 2774.

[2021-01-15; Telecon prioritization]

Set priority to 3 following reflector and telecon discussions.

[2021-05-17; Tim comments]

The new constraint causes constraint recursion in an example like:

>     struct C {
>         explicit C(std::function<void()>); // #1
>         void operator()() {}
>     };
>     static_assert(std::is_constructible_v<C, const C&>);

Here, to determine whether a `C` can be constructed from a `const C` lvalue, the overload resolution will attempt to determine whether the constructor marked `#1` is a viable candidate, which involves a determination of whether that lvalue can be implicitly converted to a `std::function<void()>`, which, with the new constraint, requires a determination whether `C` is copy-constructible — in other words, whether it can be constructed from a `C` lvalue.

This is similar to LWG 3420: in both cases we have a class (`filesystem::path` there, `function` here) that is convertible from every type that are, inter alia, copy constructible, and this then results in constraint recursion when we ask whether a different type that is constructible from such a class is copy constructible.

The `C` above is reduced from an internal helper type in libstdc++. Given the ubiquity of call wrappers — types that are callable in their own right and therefore may not be able to be ruled out by the Lvalue-Callable constraint, and can also naturally have a constructor that take the wrapped function object as the argument, triggering the recursion scenario — it is not clear that there is a good way to add this constraint without causing undue breakage.

[2021-08-20; LWG telecon]

LWG requested that the constraint cited above for `move_only_function` (né `any_invocable`) be moved to a Mandates: element instead, to avoid the same constraint recursion.

Proposed resolution:

This wording is relative to N4868.

1. Modify 20.14.17.3.2 [func.wrap.func.con] as indicated:

   >     template<class F> function(F f);

   > > -8- Constraints: `F` is Lvalue-Callable (20.14.17.3.1 [func.wrap.func.general]) for argument types `ArgTypes...` and return type `R`, and `is_copy_constructible_v<F>` is `true`.

   > > -9- Preconditions: `F` meets the Cpp17CopyConstructible requirements.

   > > […]

### 3496(i). What does "uniquely associated" mean for `basic_syncbuf::emit()`?

Section: 29.11.2.4 [syncstream.syncbuf.members] Status: New Submitter: Jonathan Wakely Opened: 2020-11-10 Last modified: 2020-11-21

Priority: 3

View other active issues in [syncstream.syncbuf.members].

View all other issues in [syncstream.syncbuf.members].

View all issues with New status.

Discussion:

29.11.2.4 [syncstream.syncbuf.members] p5 says "May call member functions of `wrapped` while holding a lock uniquely associated with `wrapped`."

It's unclear what "uniquely associated" means. Is it required to be a one-to-one mapping, so that every `streambuf*` that is wrapped is associated with a different lock?

I believe the intention is only that for a given `streambuf*` every `syncbuf` that wraps it uses the same lock. The intention was that it's a valid implementation for the same lock to be used for more than one `streambuf*` (e.g. using a table of `N` locks which are indexed by a hash of the `streambuf* value)`. The current wording can be interpreted to forbid that implementation.

[2020-11-21; Reflector prioritization]

Set priority to 3 during reflector discussions.

Proposed resolution:

### 3497(i). Postconditions for `basic_syncbuf::emit()`

Section: 29.11.2.4 [syncstream.syncbuf.members] Status: New Submitter: Jonathan Wakely Opened: 2020-11-10 Last modified: 2020-11-21

Priority: 3

View other active issues in [syncstream.syncbuf.members].

View all other issues in [syncstream.syncbuf.members].

View all issues with New status.

Discussion:

29.11.2.4 [syncstream.syncbuf.members] p2 says:

> Postconditions: On success, the associated output is empty.

Are there any postconditions on failure? If part of the associated output was written, is that part still in the associated output? Will another call to `emit()` duplicate that part?

[2020-11-21; Reflector prioritization]

Set priority to 3 during reflector discussions.

Proposed resolution:

### 3499(i). Timed lockable and mutex requirements are imprecise about `duration` and `time_point`

Section: 32.2.5.4 [thread.req.lockable.timed], 32.5.4.3 [thread.timedmutex.requirements] Status: New Submitter: Tim Song Opened: 2020-11-14 Last modified: 2020-11-21

Priority: 3

View all issues with New status.

Discussion:

The timed lockable and mutex requirements currently use "`rel_time` denotes an object of an instantiation of duration, and `abs_time` denotes an object of an instantiation of `time_point`" to define the variables used to specify the timed lock functions. During LWG review of P2160R0, it was noted that this definition is deficient in two aspects:

- It doesn't allow for cv-qualification of `rel_time` and `abs_time`

- For `time_point`s, it should require that the clock is a real Cpp17Clock. We impose that requirement via 32.2.1 [thread.req.paramname], but there are no template parameters named `Clock` here.

[2020-11-21; Reflector prioritization]

Set priority to 3 during reflector discussions.

Proposed resolution:

### 3501(i). `basic_syncbuf`-related manipulators refer to some `Allocator` without defining it

Section: 29.7.5.5 [ostream.manip] Status: New Submitter: Jonathan Wakely Opened: 2020-11-15 Last modified: 2020-11-21

Priority: 3

View all other issues in [ostream.manip].

View all issues with New status.

Discussion:

From this editorial issue request:

The three `basic_syncbuf`-related manipulators `emit_on_flush`, `noemit_on_flush`, and `flush_emit` use in their Effects: elements the following wording:

> "If `os.rdbuf()` is a `basic_syncbuf<charT, traits, Allocator>*`, called `buf` for the purpose of exposition, calls […]

There are two problems with that wording (even when considering the helpful note following p8): First, the type `Allocator` is not defined elsewhere (e.g. it is not part of the function signature) and second, `os.rdbuf()` has type `basic_streambuf<charT, traits>*` and not any other type.

By introducing an expository `SYNCBUF` to detect `basic_syncbuf` during the work on the above mentioned editorial issue to solve these problems it turned out that the suggested wording fix would introduce an apparently normative change that the `syncbuf` type must not use a program-defined specialization.

[2020-11-21; Reflector prioritization]

Set priority to 3 during reflector discussions.

Proposed resolution:

This wording is relative to N4868.

> This proposed wording is known to be incorrect, but is nonetheless depicted to present the overall idea.

1. Modify 29.7.5.5 [ostream.manip] as indicated:

   > -1- Each instantiation of any of the function templates specified in this subclause is a designated addressable function (16.4.5.2.1 [namespace.std]).

   > -?- In this subclause, `SYNCBUF(p)` for a pointer `p` of type `B*` is determined as follows. If `*p` is a base class subobject of an object of type `S`, where `S` is a specialization generated from the `basic_syncbuf` primary template, and `is_convertible_v<S*, B*>` is `true`, then `SYNCBUF(p)` is `dynamic_cast<S*>(p)`. Otherwise, `SYNCBUF(p)` is `static_cast<void*>(nullptr)`. [Note ?: To work around the issue that the `Allocator` template argument of `S` cannot be deduced, implementations can introduce an intermediate base class to `basic_syncbuf` that manages its `emit_on_sync` flag. — end note]

   > […]

   >     template<class charT, class traits>
   >       basic_ostream<charT, traits>& emit_on_flush(basic_ostream<charT, traits>& os);

   > > Let `p` be `SYNCBUF(os.rdbuf())`.

   > > -8- Effects: If `pos.rdbuf()` is not null a `basic_syncbuf<charT, traits, Allocator>*`, called `buf` for the purpose of exposition, calls `pbuf->set_emit_on_sync(true)`. Otherwise this manipulator has no effect. [Note 1: To work around the issue that the Allocator template argument cannot be deduced, implementations can introduce an intermediate base class to `basic_syncbuf` that manages its `emit_on_sync` flag. — end note]

   > > -9- Returns: `os`.

   >     template<class charT, class traits>
   >       basic_ostream<charT, traits>& noemit_on_flush(basic_ostream<charT, traits>& os);

   > > Let `p` be `SYNCBUF(os.rdbuf())`.

   > > -10- Effects: If `pos.rdbuf()` is not null a `basic_syncbuf<charT, traits, Allocator>*`, called `buf` for the purpose of exposition, calls `pbuf->set_emit_on_sync(false)`. Otherwise this manipulator has no effect.

   > > -11- Returns: `os`.

   >     template<class charT, class traits>
   >       basic_ostream<charT, traits>& flush_emit(basic_ostream<charT, traits>& os);

   > > Let `p` be `SYNCBUF(os.rdbuf())`.

   > > -12- Effects: Calls `os.flush()`. Then, if `pos.rdbuf()` is not null a `basic_syncbuf<charT, traits, Allocator>*`, called `buf` for the purpose of exposition, calls `pbuf->emit()`.

   > > -13- Returns: `os`.

### 3503(i). `chrono::ceil` has surprising requirement

Section: 27.5.8 [time.duration.cast] Status: New Submitter: Jonathan Wakely Opened: 2020-11-18 Last modified: 2020-11-29

Priority: 3

View all other issues in [time.duration.cast].

View all issues with New status.

Discussion:

27.5.8 [time.duration.cast] p7 requires that the return value is "The least result `t` representable in `ToDuration` for which `t >= d`".

This means that `chrono::ceil<chrono::microseconds>(chrono::duration<float, milli>(m)).count()` is required to be the smallest integer `n` such that `(float)n == m*1000.0f`, which might be less than the mathematically correct value of `m x 1000`.

(The specific values below assume `float` uses the IEEE binary32 format and default rounding, but similar problems will exist for other formats, even if the specific values are different.)

For example, if `m == 13421772.0f` then the naively expected result is `n == 13421772000`, but the standard requires `n == 13421771265`, a significantly lower value. This surprising result is a consequence of how the `chrono::ceil` spec interacts with floating-point arithmetic, due to the fact that for the integers in the range `[13421770753, 13421772799]`, only one can be exactly represented as 32-bit `float`. All but that one will be rounded to a different value when converted to `float`.

A straightforward implementation of `chrono::ceil` will produce `(long long)(13421772.0f * 1000)` which is `13421771776`, which is less than the expected result, but compares equal using the `t >= d` expression. That expression converts both operands to their `common_type`, which is `chrono::duration<float, micro>`. That means we compare `(float)13421771776 >= (13421772.0f * 1000)` which is `true`. But the spec requires an even worse result. All integers in `[13421771265, 13421771776)` are also rounded to that value when converted to `float`. That means `chrono::microseconds(13421771265)` is "the least result representable in `ToDuration` for which `t >= d`".

Meeting the "least result" requirement is impractical, and unhelpful. The straightforward result `13421771776` is already lower than the naively expected result (which is surprising for a "ceil" function). To meet the standard's requirements the implementation would have to do extra work, just to produce an even lower (and even more surprising) result.

It might be impractical to require the naively expected value to be returned (the additional work might have unacceptable performance implications), but the standard should at least permit the straightforward result instead of requiring an even worse one.

The same problem almost certainly exists for `chrono::floor` in reverse.

[2020-11-29; Reflector prioritization]

Set priority to 3 during reflector discussions.

Proposed resolution:

### 3504(i). `condition_variable::wait_for` is overspecified

Section: 32.6.4 [thread.condition.condvar] Status: New Submitter: Jonathan Wakely Opened: 2020-11-18 Last modified: 2020-11-29

Priority: 3

View all other issues in [thread.condition.condvar].

View all issues with New status.

Discussion:

32.6.4 [thread.condition.condvar] p24 says:

> Effects: Equivalent to: `return wait_until(lock, chrono::steady_clock::now() + rel_time);`

This is overspecification, removing implementer freedom to make `cv.wait_for(duration<float>(1))` work accurately.

The type of `steady_clock::now() + duration<float>(n)` is `time_point<steady_clock, duration<float, steady_clock::period>>`. If the steady clock's period is `std::nano` and its epoch is the time the system booted, then in under a second a 32-bit `float` becomes unable to exactly represent those `time_points`! Every second after boot makes `duration<float, nano>` less precise.

This means that adding a `duration<float>` to a `time_point` (or `duration`) measured in nanoseconds is unlikely to produce an accurate value. Either it will round down to a value less than `now()`, or round up to one greater than `now() + 1s`. Either way, the `wait_for(rel_time)` doesn't wait for the specified time, and users think the implementation is faulty.

A possible solution is to use `steady_clock::now() + ceil<steady_clock::duration>(rel_time)` instead. This converts the relative time to a suitably large integer, and then the addition is not affected by floating-point rounding errors due to the limited precision of 32-bit `float`. Libstdc++ has been doing this for nearly three years. Alternatively, the standard could just say that the relative timeout is converted to an absolute timeout measured against the steady clock, and leave the details to the implementation. Some implementations might not be affected by the problem (e.g. if the steady clock measures milliseconds, or processes only run for a few seconds and use the process start as the steady clock's epoch).

This also affects the other overload of `condition_variable::wait_for`, and both overloads of `condition_variable_any::wait_for`.

[2020-11-29; Reflector prioritization]

Set priority to 3 during reflector discussions.

Proposed resolution:

### 3507(i). P0881R7 ("stacktrace") does not define "actual file name", "actual line number"

Section: 20.21.3.4 [stacktrace.entry.query] Status: New Submitter: Thomas Köppe Opened: 2020-12-02 Last modified: 2021-01-15

Priority: 2

View all issues with New status.

Discussion:

The specification of 20.21.3.4 [stacktrace.entry.query] uses the terms "presumed or actual name of the source file" and "actual line number". It makes reference to 15.11 [cpp.predefined], which introduces the term "presumed". It does not clearly define the term, but it describes how the presumed values can be modified with preprocessor directives. However, there is no definition whatsoever of "actual".

The term should either be defined, or we should strike the "actual" parts of the stacktrace wording. We should consult implementers about this.

I don't have a proposed resolution, but if we want to keep "actual", then perhaps we should define both "presumed" and "actual" in 15.11 [cpp.predefined].

[2021-01-15; Telecon prioritization]

Set priority to 2 following reflector and telecon discussions.

Proposed resolution:

### 3508(i). `atomic_ref<cv T>` is not well-specified

Section: 31.7.1 [atomics.ref.generic.general] Status: New Submitter: Casey Carter Opened: 2020-12-02 Last modified: 2020-12-19

Priority: 2

View all issues with New status.

Discussion:

`atomic_ref<T>` requires only that its template parameter `T` is trivially copyable, which is not sufficient to implement many of the class template's member functions. Consider, for example:

>     int main() {
>       static const int x = 42;
>       std::atomic_ref<const int> meow{x};
>       meow.store(0);
>       return meow.load();
>     }

Since `const int` is trivially copyable, this is a well-formed C++20 program that returns `0`. That said, the `store` call that mutates the value of a constant object is (a) not implementable with library technology, and (b) pure madness that violates the language semantics. `atomic_ref::store` should presumably require `is_copy_assignable_v<T>`, and other operations need to have their requirements audited as well. (Related: LWG 3012 made similar changes to `atomic`.)

As a related issue, `volatile atomic<T>` recently had its member functions deprecated when they are not lock-free. Presumably `atomic_ref<volatile T>` should require that atomic operations on `T` be lock-free for consistency.

Jonathan:

The last point is related to LWG 3417 (another case where we screwed up the `volatile` deprecations).

[2020-12-19; Reflector prioritization]

Set priority to 2 during reflector discussions.

Proposed resolution:

### 3511(i). Clarify global permission to move

Section: 16.4.5.9 [res.on.arguments] Status: New Submitter: Gonzalo Brito Gadeschi Opened: 2020-12-08 Last modified: 2021-01-15

Priority: 3

View all other issues in [res.on.arguments].

View all issues with New status.

Discussion:

The intent of LWG 1204 is to allow standard library APIs accepting rvalue arguments:

- to move from their arguments, e.g., without having to specify that they might do this as part of their Effects clause, and

- to assume that rvalue arguments do not alias any pointer in the scope of the standard library API, e.g., to allow `vector`'s `push_back(T&& t)` to assume that `t` is not an element of the `vector`.

The current wording in 16.4.5.9 [res.on.arguments]/1.3 states:

> If a function argument binds to an rvalue reference parameter, the implementation may assume that this parameter is a unique reference to this argument.

This sentence is not clear about the scope in which the reference can be assumed to be unique, and it does not explicitly state that the function can modify the argument, e.g., to move from it.

If the scope of the "unique reference" is "whole program scope", this example:

>     void example(vector<int>& a, int* b)
>     {
>       int* c = b;            // reference to object pointed at by b
>       a.push_back(move(*b)); // UB: rvalue reference aliases c: not unique in whole-program scope
>       assert(c == b);        // FAILS: if rvalue reference to *b is unique, b is unique, and c == b is false
>     }

exhibits UB because the implementation may assume that the reference to `b` is unique, which does not hold since `c` is also a reference to `b`.

If the scope of the "unique reference" is the "function scope" of the standard library API, then the semantics of the rvalue reference argument are very similar to those of C's `restrict`. This allows aliasing optimizations, for example:

>     void std_api(int&& a, int&& b); // allowed to assume that a and b do not alias
>     int a, b, c;
>     std_api(move(a), move(b)); // OK: two unique references in std_api
>     std_api(move(c), move(c)); // UB: a and b alias

See llvm Bug 48238 for a bug tracking the implementation of these optimizations in clang.

This also allows optimizing `vector::push_back(T&& t)` since if `t` does not alias any pointer in `vector::push_back`'s scope, it also does not alias `this`, `this->data()`, `(*this)[0]`, etc.

[2021-01-15; Telecon prioritization]

Set priority to 3 following reflector and telecon discussions.

Proposed resolution:

This wording is relative to N4868.

1. Modify 16.4.5.9 [res.on.arguments] as indicated:

   > -1- Each of the following applies to all arguments to functions defined in the C++ standard library, unless explicitly stated otherwise.

   > 1. (1.1) — If an argument to a function has an invalid value (such as a value outside the domain of the function or a pointer invalid for its intended use), the behavior is undefined.

   > 2. (1.2) — If a function argument is described as being an array, the pointer actually passed to the function shall have a value such that all address computations and accesses to objects (that would be valid if the pointer did point to the first element of such an array) are in fact valid.

   > 3. (1.3) — If a function argument binds to an rvalue reference parameter, the implementation may assume that this parameter is a unique reference to this argument the value within the function's scope and may move from it.

   >    [Example ?:

   >    >     void std_api(int&& a);
   >    >     int a;
   >    >     std_api(move(a));
   >    >     // a is in an unspecified but valid state

   >    — end example]

   >    [Example ?:

   >    >     void std_api(int&& a, int&& b);
   >    >     int a, b, c;
   >    >     std_api(move(a), move(b)); // OK: int&& a and int&& b do not alias
   >    >     std_api(move(c), move(c)); // UB: int&& a and int&& b alias

   >    — end example]

   >    [Example ?:

   >    >     std::vector<int> a = {...};
   >    >     a.push_back(move(42)); // OK: unique reference
   >    >     a.push_back(move(a[0])); // UB: (*this)[0] and rvalue argument alias

   >    — end example]

   >    [Note 1: If the parameter is a generic parameter of the form `T&&` and an lvalue of type `A` is bound, the argument binds to an lvalue reference (13.10.3.2 [temp.deduct.call]) and thus is not covered by the previous sentence this item. — end note] [Note 2: If a program casts an lvalue to an xvalue while passing that lvalue to a library function (e.g., by calling the function with the argument `std::move(x))`, the program is effectively asking that function to treat that lvalue as a temporary object. The implementation is free to optimize away aliasing checks which might be needed if the argument was an lvalue. — end note]

### 3512(i). Incorrect exception safety guarantee for unordered containers

Section: 20.14.19 [unord.hash] Status: New Submitter: Jonathan Wakely Opened: 2020-12-28 Last modified: 2021-01-29

Priority: 3

View all other issues in [unord.hash].

View all issues with New status.

Discussion:

See this editorial issue.

20.14.19 [unord.hash] p5.4 ends with "shall not throw an exception unless `hash<Key>` is a program-defined specialization that depends on at least one program-defined type."

This seems wrong, because `hash<optional<T>>` is not a program-defined specialization, but it might throw if `hash<T>` can throw. There are also other partial specializations of `std::hash` defined in the standard library but that depend on program-defined specializations and so can throw.

[2021-01-29; reflector prioritization]

Set priority to 3 following reflector discussions. It was pointed out that this wording could be simplified if 3513 changes the definition of program-defined type.

Proposed resolution:

### 3513(i). Fix definition of program-defined based on its uses

Section: 3.43 [defns.prog.def.type] Status: New Submitter: Johel Ernesto Guerrero Peña Opened: 2020-12-29 Last modified: 2021-01-30

Priority: 3

View all issues with New status.

Discussion:

Consider the following definitions:

> 3.42 [defns.prog.def.spec]
> program-defined specialization
> <library> explicit template specialization or partial specialization that is not part of the C++ standard library and not defined by the implementation

and

> 3.43 [defns.prog.def.type]
> program-defined type
> <library> non-closure class type or enumeration type that is not part of the C++ standard library and not defined by the implementation, or a closure type of a non-implementation-provided lambda expression, or an instantiation of a program-defined specialization [Note 1 to entry: Types defined by the implementation include extensions (4.1) and internal types used by the library. — end note]

A program-defined type is either a type or an instantiation. "program-defined type" is used in 16.4.5.2.1 [namespace.std] p2 to give permission to specialize standard class templates:

> Unless explicitly prohibited, a program may add a template specialization for any standard library class template to namespace `std` provided that (a) the added declaration depends on at least one program-defined type and (b) the specialization meets the standard library requirements for the original template.

ISO requires that the terms in Clause 3 be substitutable with their definitions. If this were done for "program-defined type", we'd end up with "or an instantiation of a program-defined specialization". It's fine to depend on a type, but not an instantiated type, because all you need is the name of its specialization (its type) as a template argument to explicitly or partially specialize a template.

[2021-01-29; reflector prioritization]

Set priority to 3 following reflector discussions. It was pointed out that it might be easier to resolve 3512 if this issue changes the definition of program-defined type.

Proposed resolution:

This wording is relative to N4878.

1. Modify 3.43 [defns.prog.def.type] as indicated:

   > 3.43 [defns.prog.def.type]
   > program-defined type
   > <library> non-closure class type or enumeration type that is not part of the C++ standard library and not defined by the implementation, or a closure type of a non-implementation-provided lambda expression, or an instantiation a name of a program-defined specialization or instantiation thereof [Note 1 to entry: Types defined by the implementation include extensions (4.1 [intro.compliance]) and internal types used by the library. — end note]

### 3515(i). §[stacktrace.basic.nonmem]: `operator<<` should be less templatized

Section: 20.21.2 [stacktrace.syn], 20.21.4.6 [stacktrace.basic.nonmem] Status: LEWG Submitter: Jiang An Opened: 2021-01-25 Last modified: 2021-03-12

Priority: 2

View other active issues in [stacktrace.syn].

View all other issues in [stacktrace.syn].

View all issues with LEWG status.

Discussion:

According to 21.3.4.4 [string.io], the `operator<<` overloads in 20.21.4.6 [stacktrace.basic.nonmem] are well-formed only if the template parameters `charT` and `traits` are `char` and `std::char_traits<char>` (that of `std::string`) respectively, because it is required in Effects: that these overloads behave as-if insert a `std::string`.

I think the declarations of these overloads should be changed to:

>     ostream& operator<<(ostream& os, const stacktrace_entry& f);

>     template<class Allocator>
>     ostream& operator<<(ostream& os, const basic_stacktrace<Allocator>& st);

[2021-03-12; Reflector poll]

Set priority to 2 and status to LEWG following reflector poll.

Proposed resolution:

This wording is relative to N4878.

1. Modify 20.21.2 [stacktrace.syn], header `<stacktrace>` synopsis, as indicated:

   >     namespace std {
   >       // 20.21.3 [stacktrace.entry], class stacktrace_entry
   >       class stacktrace_entry;

   >       // 20.21.4 [stacktrace.basic], class template basic_stacktrace
   >       template<class Allocator>
   >       class basic_stacktrace;

   >       […]

   >       // 20.21.4.6 [stacktrace.basic.nonmem], non-member functions
   >       […]

   >       string to_string(const stacktrace_entry& f);

   >       template<class Allocator>
   >         string to_string(const basic_stacktrace<Allocator>& st);

   >       template<class charT, class traits>
   >         basic_ostream<charT, traits>&
   >           operator<<(basic_ostream<charT, traits>& os, const stacktrace_entry& f);

   >       template<class charT, class traits, class Allocator>
   >         basic_ostream<charT, traits>&
   >           operator<<(basic_ostream<charT, traits>& os, const basic_stacktrace<Allocator>& st);

   >       […]
   >     }

2. Modify 20.21.4.6 [stacktrace.basic.nonmem] as indicated:

   >     template<class charT, class traits>
   >     basic_ostream<charT, traits>&
   >       operator<<(basic_ostream<charT, traits>& os, const stacktrace_entry& f);

   > > -4- Effects: Equivalent to: `return os << to_string(f);`

   >     template<class charT, class traits, class Allocator>
   >     basic_ostream<charT, traits>&
   >       operator<<(basic_ostream<charT, traits>& os, const basic_stacktrace<Allocator>& st);

   > > -5- Effects: Equivalent to: `return os << to_string(st);`

### 3516(i). `thread::id` spaceship may be inconsistent with equality

Section: 32.4.3.2 [thread.thread.id] Status: New Submitter: Casey Carter Opened: 2021-01-26 Last modified: 2021-03-12

Priority: 3

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

View all issues with New status.

Discussion:

32.4.3.2 [thread.thread.id]/5-7 specify the behavior of `==` and `<=>` for `std::thread::id`:

>     bool operator==(thread::id x, thread::id y) noexcept;

> > -5- Returns: `true` only if `x` and `y` represent the same thread of execution or neither `x` nor `y` represents a thread of execution.

>     strong_ordering operator<=>(thread::id x, thread::id y) noexcept;

> > -6- Let `P(x, y)` be an unspecified total ordering over `thread::id` as described in 25.8.

> > -7- Returns: `strong_ordering::less` if `P(x, y)` is `true`. Otherwise, `strong_ordering::greater` if `P(y, x)` is `true`. Otherwise, `strong_ordering::equal`.

"Unspecified total ordering" provides too much freedom, since it does not require that `!P(x, y)` holds when `x` and `y` both represent the same thread of execution or both represent no thread of execution. A conforming implementation could return `strong_ordering::equal` from `<=>` for a pair of `thread::id` values for which `==` returns `false`. We should guarantee consistency of `==` and `<=>` for `thread::id` to preserve sanity of the programming model.

[2021-03-12; Reflector poll]

Set priority to 3 following reflector poll.

Proposed resolution:

This wording is relative to N4878.

1. Modify 32.4.3.2 [thread.thread.id] as indicated:

   >     strong_ordering operator<=>(thread::id x, thread::id y) noexcept;

   > > -6- Let `P(x, y)` be an unspecified a total ordering over `thread::id` as described in 25.8 [alg.sorting], unspecified except that `P(x, y)` is `false` when `x` and `y` both represent the same thread of execution, or when neither represents a thread of execution.

   > > -7- Returns: `strong_ordering::less` if `P(x, y)` is `true`. Otherwise, `strong_ordering::greater` if `P(y, x)` is `true`. Otherwise, `strong_ordering::equal`.

### 3531(i). LWG 3025 broke previous valid code

Section: 22.4.4.1 [map.overview], 22.4.5.1 [multimap.overview], 22.5.4.1 [unord.map.overview], 22.5.5.1 [unord.multimap.overview] Status: New Submitter: Mike Spertus Opened: 2021-03-09 Last modified: 2021-04-20

Priority: 3

View all other issues in [map.overview].

View all issues with New status.

Discussion:

The resolution for LWG 3025 enabled code like the following to be accepted:

>     map m1{{pair{1, 2}, {3, 4}}, less<int>()};

but breaks code that had been previously working like the following

>     using value_type = pair<const int, int>;

>     map m2{{value_type{1, 2}, {3, 4}}, less<int>()};

as shown on godbolt.

[Acknowledgment to Tim Song and Arthur O'Dwyer for independently pointing out this case on the LWG mailing list]

[2021-04-20; Reflector poll]

Priority set to 3. Three preferences expressed for Option B, none for A.

Proposed resolution:

This wording is relative to N4878.

> We present two partial wording options for `std::map`, denoted by (A) and (B) below. If the committee accepts one of them, we will complete them to all key-value containers.

1. (A) Wording option 1: In this option, we restore the deduction guide that was removed in LWG 3025 while maintaining the one that was added, demonstrates this working.

   1. Modify 22.4.4.1 [map.overview] as indicated:

      >     […]
      >     template<class Key, class T, class Compare = less<Key>,
      >              class Allocator = allocator<pair<const Key, T>>>
      >       map(initializer_list<pair<Key, T>>, Compare = Compare(), Allocator = Allocator())
      >         -> map<Key, T, Compare, Allocator>;

      >     template<class Key, class T, class Compare = less<Key>,
      >              class Allocator = allocator<pair<const Key, T>>>
      >       map(initializer_list<pair<const Key, T>>, Compare = Compare(), Allocator = Allocator())
      >         -> map<Key, T, Compare, Allocator>;

      >     template<class InputIterator, class Allocator>
      >       map(InputIterator, InputIterator, Allocator)
      >         -> map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>,
      >                less<iter-key-type<InputIterator>>, Allocator>;

      >     template<class Key, class T, class Allocator>
      >       map(initializer_list<pair<Key, T>>, Allocator) -> map<Key, T, less<Key>, Allocator>;

      >     template<class Key, class T, class Allocator>
      >       map(initializer_list<pair<const Key, T>>, Allocator) -> map<Key, T, less<Key>, Allocator>;
      >     […]

2. (B) Wording option 2: This one follows Tim Song's suggestion: "It seems that the cleanest fix is to 1) disallow the `initializer_list<value_type>` constructors from being used for CTAD, and 2) change the guides to use `remove_const_t<Key>`." This change has been tested locally with g++ similar to the above godbolt.

   1. Modify 22.4.4.1 [map.overview] as indicated:

      >     […]
      >     // types
      >     using key_type = Key;
      >     using mapped_type = T;
      >     using value_type = type_identity_t<pair<const Key, T>>;
      >     […]

      >     template<class Key, class T, class Compare = less<remove_const_t<Key>>,
      >              class Allocator = allocator<pair<const Key, T>>>
      >       map(initializer_list<pair<Key, T>>, Compare = Compare(), Allocator = Allocator())
      >         -> map<remove_const_t<Key>, T, Compare, Allocator>;

      >     template<class InputIterator, class Allocator>
      >       map(InputIterator, InputIterator, Allocator)
      >         -> map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>,
      >                less<iter-key-type<InputIterator>>, Allocator>;

      >     template<class Key, class T, class Allocator>
      >       map(initializer_list<pair<Key, T>>, Allocator)
      >         -> map<remove_const_t<Key>, T, less<remove_const_t<Key>>, Allocator>;

      >     […]

### 3534(i). `ranges::set_intersection` and `ranges::set_difference` algorithm requirements are too strict

Section: 25.8.7.4 [set.intersection], 25.8.7.5 [set.difference] Status: LEWG Submitter: Alexander Bessonov Opened: 2021-03-16 Last modified: 2021-04-20

Priority: 3

View all issues with LEWG status.

Discussion:

The `std::mergeable` concept requires elements of both source ranges to be copyable to the output iterator, while the standard specifically tells that both algorithms `ranges::set_intersection` and `ranges::set_difference` only use the first range as the source of elements to be copied into output. The following code snippet illustrates the problem:

>     #include <vector>
>     #include <ranges>
>     #include <algorithm>
>     #include <cassert>

>     int main()
>     {
>       std::vector<std::pair<int, int>> v1;
>       std::vector<int> v2;

>       assert(std::ranges::is_sorted(v1));
>       assert(std::ranges::is_sorted(v2));

>       std::vector<std::pair<int, int>> v3;

>       // Compilation error on the following line:
>       std::ranges::set_intersection(v1, v2, std::back_inserter(v3),
>         std::less{}, [](const auto& p) { return p.first; });
>     }

The proposed solution is to introduce a new concept. It could be declared "exposition-only" and is worded `half-mergeable` below:

>     template<class I1, class I2, class Out, class R = ranges::less,
>     	     class P1 = identity, class P2 = identity>
>       concept half-mergeable =
>         input_iterator<I1> &&
>         input_iterator<I2> &&
>         weakly_incrementable<Out> &&
>         indirectly_copyable<I1, Out> &&
>         // indirectly_copyable<I2, Out> && <— this line removed
>         indirect_strict_weak_order<R, projected<I1, P1>, projected<I2, P2>>;

After such template is introduced, `std::mergeable` may be defined based on it:

>     template<class I1, class I2, class Out, class R = ranges::less,
>     	     class P1 = identity, class P2 = identity>
>       concept mergeable = half-mergeable<I1, I2, Out, R, P1, P2> &&
>         indirectly_copyable<I2, Out>;

See also the related discussion on reddit.

[2021-04-20; Reflector poll]

Priority set to 3. Send to LEWG.

Proposed resolution:

This wording is relative to N4878.

1. Modify 23.2 [iterator.synopsis], header `<iterator>` synopsis, as indicated:

   >       […]

   >       // 23.3.7.7 [alg.req.mergeable], concept mergeable
   >       template<class I1, class I2, class Out,
   >           class R = ranges::less, class P1 = identity, class P2 = identity>
   >         concept half-mergeable = see below; // exposition only

   >       template<class I1, class I2, class Out,
   >           class R = ranges::less, class P1 = identity, class P2 = identity>
   >         concept mergeable = see below;

   >      […]

2. Modify 23.3.7.7 [alg.req.mergeable] as indicated:

   > 23.3.7.7 Concept `mergeable` [alg.req.mergeable]

   > -1- The `mergeable` concept specifies the requirements of algorithms that merge sorted sequences into an output sequence by copying elements.

   > >     template<class I1, class I2, class Out, class R = ranges::less,
   > >              class P1 = identity, class P2 = identity>
   > >       concept half-mergeable = // exposition only
   > >         input_iterator<I1> &&
   > >         input_iterator<I2> &&
   > >         weakly_incrementable<Out> &&
   > >         indirectly_copyable<I1, Out> &&
   > >         indirect_strict_weak_order<R, projected<I1, P1>, projected<I2, P2>>;

   > >     template<class I1, class I2, class Out, class R = ranges::less,
   > >              class P1 = identity, class P2 = identity>
   > >       concept mergeable =
   > >         half-mergeable<I1, I2, Out, R, P1, P2> &&
   > >         input_iterator<I1> &&
   > >         input_iterator<I2> &&
   > >         weakly_incrementable<Out> &&
   > >         indirectly_copyable<I1, Out> &&
   > >         indirectly_copyable<I2, Out> &&
   > >         indirect_strict_weak_order<R, projected<I1, P1>, projected<I2, P2>>;

3. Modify 25.8.7.4 [set.intersection] as indicated:

   >     […]
   >     template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
   >              weakly_incrementable O, class Comp = ranges::less,
   >              class Proj1 = identity, class Proj2 = identity>
   >       requires half-mergeablemergeable<I1, I2, O, Comp, Proj1, Proj2>
   >       constexpr ranges::set_intersection_result<I1, I2, O>
   >         ranges::set_intersection(I1 first1, S1 last1, I2 first2, S2 last2, O result,
   >                                  Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
   >     template<input_range R1, input_range R2, weakly_incrementable O,
   >              class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
   >       requires half-mergeablemergeable<iterator_t<R1>>,
   >         iterator_t<R2>, O, Comp, Proj1, Proj2>
   >       constexpr ranges::set_intersection_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
   >         ranges::set_intersection(R1&& r1, R2&& r2, O result,
   >                                  Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

   > > […]

   > > -6- Remarks: Stable (16.4.6.8 [algorithm.stable]). If `[first1, last1)` contains `m` elements that are equivalent to each other and `[first2, last2)` contains `n` elements that are equivalent to them, the first `min(m, n)` elements are copied from the first range to the output range, in order.

4. Modify 25.8.7.5 [set.difference] as indicated:

   >     […]
   >     template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
   >              weakly_incrementable O, class Comp = ranges::less,
   >              class Proj1 = identity, class Proj2 = identity>
   >       requires half-mergeablemergeable<I1, I2, O, Comp, Proj1, Proj2>
   >       constexpr ranges::set_difference_result<I1, O>
   >         ranges::set_difference(I1 first1, S1 last1, I2 first2, S2 last2, O result,
   >                                Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
   >     template<input_range R1, input_range R2, weakly_incrementable O,
   >              class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
   >       requires half-mergeablemergeable<iterator_t<R1>>, iterator_t<R2>, O, Comp, Proj1, Proj2>
   >       constexpr ranges::set_difference_result<borrowed_iterator_t<R1>, O>
   >         ranges::set_difference(R1&& r1, R2&& r2, O result,
   >                                Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

   > > […]

   > > -6- Remarks: If `[first1, last1)` contains `m` elements that are equivalent to each other and `[first2, last2)` contains `n` elements that are equivalent to them, the last `max(m - n, 0)` elements from `[first1, last1)` is copied to the output range, in order.

### 3537(i). §[iterator.range] Missing `noexcept` for `std::rbegin`/`rend` for arrays and `initializer_list`

Section: 23.7 [iterator.range] Status: New Submitter: Jiang An Opened: 2021-03-21 Last modified: 2021-04-20

Priority: 3

View other active issues in [iterator.range].

View all other issues in [iterator.range].

View all issues with New status.

Discussion:

Overloads for `std::rbegin`/`rend` for built-in arrays and `std::initializer_list`'s has no preconditions and never throw exceptions, thus should be `noexcept`. LWG 2280 addressed a similar issue for `std::begin/end`.

Suggestion: change these declarations in 23.7 [iterator.range] (p10, 11, 12, 13) as indicated:

>     template<class T, size_t N> constexpr reverse_iterator<T*> rbegin(T (&array)[N]) noexcept;

>     template<class T, size_t N> constexpr reverse_iterator<T*> rend(T (&array)[N]) noexcept;

>     template<class E> constexpr reverse_iterator<const E*> rbegin(initializer_list<E> il) noexcept;

>     template<class E> constexpr reverse_iterator<const E*> rend(initializer_list<E> il) noexcept;

If this change is accepted, we may also specify conditional `noexcept` for `std::crbegin/crend` (in 23.7 [iterator.range] p14, 15), by adding `noexcept(noexcept(std::rbegin/crend(c)))`, like in LWG 2280.

Conditional noexcept for other functions in 23.7 [iterator.range] (p2, 3, 7, 8, 16, 18, 20 22) may also be added for consistency.

[2021-03-21; Daniel comments]

There is intentionally no P/R provided at this point, but I'm volunteering to provide it if we got feedback whether adding conditional `noexcept` specifiers similar to those provided by LWG 2280 would be preferred or not.

[2021-04-20; Reflector poll]

Priority set to 3.

Jonathan: This would create a strange situation where `std::rbegin` and `std::crbegin` on an `initializer_list` are noexcept but `std::begin` and `std::cbegin` aren't guaranteed to be (because an `initializer_list` uses the generic `std::begin` and `std::cbegin` overloads, which have no conditional noexcept).

Casey: I don't think we should mark these rbegin/rend overloads noexcept without making the pertinent `reverse_iterator` constructors conditionally noexcept.

Proposed resolution:

### 3538(i). §[library.c] C library functions are not addressable

Section: 16.2 [library.c] Status: New Submitter: Jiang An Opened: 2021-03-29 Last modified: 2021-04-20

Priority: 2

View all issues with New status.

Discussion:

P0551R3 has made almost all standard library functions non-addressable, including all functions from the C standard library. However, C17 (and the latest C23 working draft) explicitly allows taking address of a C standard library function in 7.1.4/1.

Should we require something like "every function from the C standard library is addressable unless it is overloaded", in order to minimize the incompatibility with C? Or explicitly say something in C.7 [diff.library] if such requirement is not wanted?

[2021-04-20; Reflector poll]

Priority set to 2.

Proposed resolution:

### 3545(i). `std::pointer_traits` should be SFINAE-friendly

Section: 20.10.3 [pointer.traits] Status: Open Submitter: Glen Joseph Fernandes Opened: 2021-04-20 Last modified: 2022-02-23

Priority: 2

View other active issues in [pointer.traits].

View all other issues in [pointer.traits].

View all issues with Open status.

Discussion:

P1474R1 chose to use `std::to_address` (a mechanism of converting pointer-like types to raw pointers) for contiguous iterators. `std::to_address` provides an optional customization point via an optional member in `std::pointer_traits`. However all iterators are not pointers, and the primary template of `std::pointer_traits<Ptr>` requires that either `Ptr::element_type` is valid or `Ptr` is of the form `template<T, Args...>` or the `pointer_traits` specialization is ill-formed. This requires specializing `pointer_traits` for those contiguous iterator types which is inconvenient for users. P1474 should have also made `pointer_traits` SFINAE friendly.

[2021-05-10; Reflector poll]

Priority set to 2. Send to LEWG. Daniel: "there is no similar treatment for the `rebind` member template and I think it should be clarified whether `pointer_to`'s signature should exist and in which form in the offending case."

[2022-01-29; Daniel comments]

This issue has some overlap with LWG 3665 in regard to the question how we should handle the `rebind_alloc` member template of the `allocator_traits` template as specified by 20.10.8.2 [allocator.traits.types]/11. It would seem preferable to decide for the same approach in both cases.

[2022-02-22 LEWG telecon; Status changed: LEWG → Open]

No objection to unanimous consent for Jonathan's suggestion to make `pointer_traits` an empty class when there is no `element_type`. Jonathan to provide a paper.

Proposed resolution:

This wording is relative to N4885.

1. Modify 20.10.3.2 [pointer.traits.types] as indicated:

   > As additional drive-by fix the improper usage of the term "instantiation" has been corrected.

   >     using element_type = see below;

   > > -1- Type: `Ptr::element_type` if the qualified-id `Ptr::element_type` is valid and denotes a type (13.10.3 [temp.deduct]); otherwise, `T` if `Ptr` is a class template instantiation specialization of the form `SomePointer<T, Args>`, where `Args` is zero or more type arguments; otherwise, the specialization is ill-formed `pointer_traits` has no member `element_type`.

### 3550(i). Names reserved by C for standard library not reserved by C++

Section: 16.4.5.3 [reserved.names] Status: New Submitter: Hubert Tong Opened: 2021-05-10 Last modified: 2021-05-20

Priority: 3

View all other issues in [reserved.names].

View all issues with New status.

Discussion:

The C standard has a section called "Future library directions". This is subclause 7.31 in C17, which is the version that the C++ working draft references. C reserves the names described in that subclause for its standard library, allowing C library vendors to introduce some names from future standards as conforming, "orthogonal" extensions. ISO C++ does not appear to reserve these names in a clear way. In particular, 16.4.5.3 [reserved.names] has wording about names and function signatures "from the C standard library declared with external linkage", but C's "Future library directions" describes names that "may be added to the declarations in [some] header[s]".

Extra clarity regarding whether these names are actually intended to be reserved by C++ would be appreciated.

[2021-05-20; Reflector poll]

Priority set to 3.

Proposed resolution:

### 3556(i). Specification of when semantic constraints are imposed by use of concepts is unclear

Section: 16.3.2.3 [structure.requirements] Status: New Submitter: Tim Song Opened: 2021-05-23 Last modified: 2021-05-26

Priority: 3

View all other issues in [structure.requirements].

View all issues with New status.

Discussion:

16.3.2.3 [structure.requirements] p9 says:

> A declaration may explicitly impose requirements through its associated constraints (13.5.3 [temp.constr.decl]). When the associated constraints refer to a concept (13.7.9 [temp.concept]), the semantic constraints specified for that concept are additionally imposed on the use of the declaration.

There are at least two issues with this wording:

1. First, "associated constraints" is a Core term that refers to the constraints on a declaration after normalization, at which point direct uses of concepts have been decomposed into the constituent atomic constraints and are no longer visible.

2. Second, "refers to" is too vague. Does `!C<T>` "refer to" `C` and impose its semantic constraints? Does `C1<T> || C2<T>` "refer to" both `C1` and `C2` and therefore impose the semantic constraints of both?

[2021-05-26; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

### 3564(i). `transform_view::iterator<true>::value_type` and `iterator_category` should use `const F&`

Section: 24.7.7.3 [range.transform.iterator] Status: SG9 Submitter: Tim Song Opened: 2021-06-06 Last modified: 2021-06-14

Priority: 2

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

Discussion:

Iterators obtained from a `const transform_view` invoke the transformation function as `const`, but the `value_type` and `iterator_category` determination uses plain `F&`, i.e., non-`const`.

[2021-06-14; Reflector poll]

Set priority to 2 after reflector poll, send to SG9 for design clarification. Should `r` and `as_const(r)` guarantee same elements?

Proposed resolution:

This wording is relative to N4885.

1. Modify 24.7.7.3 [range.transform.iterator] as indicated:

   > >     namespace std::ranges {
   > >       template<input_range V, copy_constructible F>
   > >         requires view<V> && is_object_v<F> &&
   > >                  regular_invocable<F&, range_reference_t<V>> &&
   > >                  can-reference<invoke_result_t<F&, range_reference_t<V>>>
   > >       template<bool Const>
   > >       class transform_view<V, F>::iterator {
   > >       private:
   > >         […]
   > >       public:
   > >         using iterator_concept = see below;
   > >         using iterator_category = see below; // not always present
   > >         using value_type =
   > >           remove_cvref_t<invoke_result_t<maybe-const<Const, F>&,
   > >           range_reference_t<Base>>>;
   > >         using difference_type = range_difference_t<Base>;
   > >         […]
   > >       };
   > >     }

   > -1- […]

   > -2- The member typedef-name `iterator_category` is defined if and only if `Base` models `forward_range`. In that case, `iterator::iterator_category` is defined as follows: Let `C` denote the type `iterator_traits<iterator_t<Base>>::iterator_category`.

   > 1. (2.1) — If `is_lvalue_reference_v<invoke_result_t<maybe-const<Const, F>&, range_reference_t<Base>>>` is `true`, then

   >    1. (2.1.1) — […]

   >    2. (2.1.2) — […]

   > 2. (2.2) — Otherwise, `iterator_category` denotes `input_iterator_tag`.

### 3565(i). Handling of encodings in localized formatting of `chrono` types is underspecified

Section: 27.12 [time.format] Status: SG16 Submitter: Victor Zverovich Opened: 2021-05-31 Last modified: 2021-06-14

Priority: 2

View all other issues in [time.format].

View all issues with SG16 status.

Discussion:

When formatting chrono types using a locale the result is underspecified, possibly a mix of the literal and locale encodings. For example:

>     std::locale::global(std::locale("Russian.1251"));
>     auto s = std::format("День недели: {}", std::chrono::Monday);

(Note that "`{}`" should be replaced with "`{:L}`" if P2372 is adopted but that's non-essential.)

If the literal encoding is UTF-8 and the `"Russian.1251"` locale exists we have a mismatch between encodings. As far as I can see the standard doesn't specify what happens in this case.

One possible and undesirable result is

>     "День недели: \xcf\xed"

where `"\xcf\xed"` is `"Пн"` (Mon in Russian) in CP1251 and is not valid UTF-8.

Another possible and desirable result is

>     "День недели: Пн"

where everything is in one encoding (UTF-8).

This issue is not resolved by LWG 3547 / P2372 but the resolution proposed here is compatible with P2372 and can be rebased onto its wording if the paper is adopted.

[2021-06-14; Reflector poll]

Set priority to 2 after reflector poll. Send to SG16.

Proposed resolution:

This wording is relative to N4885.

1. Modify 27.12 [time.format] as indicated:

   > -2- Each conversion specifier conversion-spec is replaced by appropriate characters as described in Table [tab:time.format.spec]; the formats specified in ISO 8601:2004 shall be used where so described. Some of the conversion specifiers depend on the locale that is passed to the formatting function if the latter takes one, or the global locale otherwise. If the string literal encoding is UTF-8 the replacement of a conversion specifier that depends on the locale is transcoded to UTF-8 for narrow strings, otherwise the replacement is taken as is. If the formatted object does not contain the information the conversion specifier refers to, an exception of type `format_error` is thrown.

### 3569(i). `join_view` fails to support ranges of ranges with non-`default_initializable` iterators

Section: 24.7.12.3 [range.join.iterator] Status: New Submitter: Casey Carter Opened: 2021-06-16 Last modified: 2021-08-27

Priority: 3

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

View all issues with New status.

Discussion:

`join_view::iterator` has exposition-only members `outer_` — which holds an iterator into the adapted range — and `inner_` — which holds an iterator into the range denoted by `outer_`. After application of P2325R3 "Views should not be required to be default constructible" to the working draft, single-pass iterators can be `non-default_initializable`. P2325R3 constrains `join_view::iterator`'s default constructor to require that the types of both `outer_` and `inner_` are `default_initializable`, indicating an intent to support such iterator types. However, the effect of the non-default constructor specified in 24.7.12.3 [range.join.iterator] paragraph 6 is to default-initialize `inner_`, which is ill-formed if its type is not `default_initializable`.

[2021-06-23; Reflector poll]

Set priority to 3 after reflector poll.

Previous resolution [SUPERSEDED]:

> Wording relative to the post 2021-06 virtual plenary working draft. This PR is currently being implemented in MSVC.

> 1. Modify 24.7.12.3 [range.join.iterator] as indicated:

>    > >     namespace std::ranges {
>    > >       template<input_range V>
>    > >         requires view<V> && input_range<range_reference_t<V>> &&
>    > >                  (is_reference_v<range_reference_t<V>> ||
>    > >                   view<range_value_t<V>>)
>    > >       template<bool Const>
>    > >       struct join_view<V>::iterator {
>    > >         […]
>    > >         optional<InnerIter> inner_ = InnerIter();
>    > >         […]
>    > >         constexpr decltype(auto) operator*() const { return **inner_; }
>    > >         […]
>    > >         friend constexpr decltype(auto) iter_move(const iterator& i)
>    > >         noexcept(noexcept(ranges::iter_move(*i.inner_))) {
>    > >           return ranges::iter_move(*i.inner_);
>    > >         }

>    > >         friend constexpr void iter_swap(const iterator& x, const iterator& y)
>    > >           noexcept(noexcept(ranges::iter_swap(*x.inner_, *y.inner_)))
>    > >           requires indirectly_swappable<InnerIter>;
>    > >       };
>    > >     }

>    > […]

>    >     constexpr void satisfy();       // exposition only

>    > > -5- Effects: Equivalent to:

>    > > >     auto update_inner = [this](const iterator_t<Base>& x) -> auto&& {
>    > > >     […]
>    > > >     };
>    > > >     for (; outer_ != ranges::end(parent_->base_); ++outer_) {
>    > > >       auto&& inner = update_inner(*outer_);
>    > > >       inner_ = ranges::begin(inner);
>    > > >       if (*inner_ != ranges::end(inner))
>    > > >         return;
>    > > >     }
>    > > >     if constexpr (ref-is-glvalue)
>    > > >       inner_.reset() = InnerIter();

>    > […]

>    >     constexpr InnerIter operator->() const
>    >       requires has-arrow<InnerIter> && copyable<InnerIter>;

>    > > -8- Effects: Equivalent to: `return *inner_;`

>    >     constexpr iterator& operator++();

>    > > -9- Let inner-range be:

>    > > […]

>    > > -10- Effects: Equivalent to:

>    > > >     auto&& inner_rng = inner-range;
>    > > >     if (++*inner_ == ranges::end(inner_rng)) {
>    > > >       ++outer_;
>    > > >       satisfy();
>    > > >     }
>    > > >     return *this;

>    > […]

>    >     constexpr iterator& operator--()
>    >       requires ref-is-glvalue && bidirectional_range<Base> &&
>    >                bidirectional_range<range_reference_t<Base>> &&
>    >                common_range<range_reference_t<Base>>;

>    > > -13- Effects: Equivalent to:

>    > > >     if (outer_ == ranges::end(parent_->base_))
>    > > >       inner_ = ranges::end(*--outer_);
>    > > >     while (*inner_ == ranges::begin(*outer_))
>    > > >       *inner_ = ranges::end(*--outer_);
>    > > >     --*inner_;
>    > > >     return *this;

>    > […]

>    >     friend constexpr void iter_swap(const iterator& x, const iterator& y)
>    >       noexcept(noexcept(ranges::iter_swap(*x.inner_, *y.inner_)))
>    >       requires indirectly_swappable<InnerIter>;

>    > > -16- Effects: Equivalent to: return `ranges::iter_swap(*x.inner_, *y.inner_);`

[2021-08-23; Louis Dionne comments and provides improved wording]

I believe the currently proposed resolution is missing the removal of the `default_initializable<InnerIter>` constraint on `join_view::iterator`'s default constructor in 24.7.12.3 [range.join.iterator]. Indeed, after the currently-proposed resolution, `join_view::iterator` reads like:

>     template<input_range V>
>       requires […]
>     struct join_view<V>::iterator {
>     private:
>       optional<InnerIter> inner_; // exposition only
>       […]
>     public:
>       iterator() requires default_initializable<OuterIter> &&
>                           default_initializable<InnerIter> = default;
>         […]
>     };

I believe we should drop the `default_initializable<InnerIter>` constraint from the default constructor (that seems like an oversight unless I missed something):

>     template<input_range V>
>       requires […]
>     struct join_view<V>::iterator {
>     private:
>       optional<InnerIter> inner_; // exposition only
>       […]
>     public:
>       iterator() requires default_initializable<OuterIter> = default;
>       […]
>     };

Proposed resolution:

This wording is relative to N4892.

1. Modify 24.7.12.3 [range.join.iterator] as indicated:

   > >     namespace std::ranges {
   > >       template<input_range V>
   > >         requires view<V> && input_range<range_reference_t<V>> &&
   > >                  (is_reference_v<range_reference_t<V>> ||
   > >                   view<range_value_t<V>>)
   > >       template<bool Const>
   > >       struct join_view<V>::iterator {
   > >         […]
   > >         optional<InnerIter> inner_ = InnerIter();
   > >         […]
   > >         iterator() requires default_initializable<OuterIter> &&
   > >                             default_initializable<InnerIter> = default;
   > >         […]
   > >         constexpr decltype(auto) operator*() const { return **inner_; }
   > >         […]
   > >         friend constexpr decltype(auto) iter_move(const iterator& i)
   > >         noexcept(noexcept(ranges::iter_move(*i.inner_))) {
   > >           return ranges::iter_move(*i.inner_);
   > >         }

   > >         friend constexpr void iter_swap(const iterator& x, const iterator& y)
   > >           noexcept(noexcept(ranges::iter_swap(*x.inner_, *y.inner_)))
   > >           requires indirectly_swappable<InnerIter>;
   > >       };
   > >     }

   > […]

   >     constexpr void satisfy();       // exposition only

   > > -5- Effects: Equivalent to:

   > > >     auto update_inner = [this](const iterator_t<Base>& x) -> auto&& {
   > > >     […]
   > > >     };
   > > >     for (; outer_ != ranges::end(parent_->base_); ++outer_) {
   > > >       auto&& inner = update_inner(*outer_);
   > > >       inner_ = ranges::begin(inner);
   > > >       if (*inner_ != ranges::end(inner))
   > > >         return;
   > > >     }
   > > >     if constexpr (ref-is-glvalue)
   > > >       inner_.reset() = InnerIter();

   > […]

   >     constexpr InnerIter operator->() const
   >       requires has-arrow<InnerIter> && copyable<InnerIter>;

   > > -8- Effects: Equivalent to: `return *inner_;`

   >     constexpr iterator& operator++();

   > > -9- Let inner-range be:

   > > […]

   > > -10- Effects: Equivalent to:

   > > >     auto&& inner_rng = inner-range;
   > > >     if (++*inner_ == ranges::end(inner_rng)) {
   > > >       ++outer_;
   > > >       satisfy();
   > > >     }
   > > >     return *this;

   > […]

   >     constexpr iterator& operator--()
   >       requires ref-is-glvalue && bidirectional_range<Base> &&
   >                bidirectional_range<range_reference_t<Base>> &&
   >                common_range<range_reference_t<Base>>;

   > > -13- Effects: Equivalent to:

   > > >     if (outer_ == ranges::end(parent_->base_))
   > > >       inner_ = ranges::end(*--outer_);
   > > >     while (*inner_ == ranges::begin(*outer_))
   > > >       *inner_ = ranges::end(*--outer_);
   > > >     --*inner_;
   > > >     return *this;

   > […]

   >     friend constexpr void iter_swap(const iterator& x, const iterator& y)
   >       noexcept(noexcept(ranges::iter_swap(*x.inner_, *y.inner_)))
   >       requires indirectly_swappable<InnerIter>;

   > > -16- Effects: Equivalent to: return `ranges::iter_swap(*x.inner_, *y.inner_);`

### 3576(i). Clarifying fill character in `std::format`

Section: 20.20.2.2 [format.string.std] Status: SG16 Submitter: Mark de Wever Opened: 2021-08-01 Last modified: 2021-08-27

Priority: 2

View other active issues in [format.string.std].

View all other issues in [format.string.std].

View all issues with SG16 status.

Discussion:

The paper P1868 "width: clarifying units of width and precision in `std::format`" added optional Unicode support to the `format` header. This paper didn't update the definition of the fill character, which is defined as

> "The fill character can be any character other than `{` or `}`."

This wording means the fill is a character and not a Unicode grapheme cluster. Based on the current wording the range of available fill characters depends on the `char_type` of the format string. After P1868 the determination of the required padding size is Unicode aware, but it's not possible to use a Unicode grapheme clusters as padding. This looks odd from a user's perspective and already lead to implementation divergence between libc++ and MSVC STL:

- The WIP libc++ implementation stores one `char_type`, strictly adhering to the wording of the Standard.

- MSVC STL stores one code point, regardless of the `char_type` used. This is already better from a user's perspective; all 1 code point grapheme clusters are properly handled.

For the width calculation the width of a Unicode grapheme cluster is estimated to be 1 or 2. Since padding with a 2 column width can't properly pad an odd number of columns the grapheme cluster used should always have a column width of 1.

The responsibility for precondition can be either be validated in the library or by the user. It would be possible to do the validation compile time and make the code ill-formed when the precondition is violated. For the following reason I think it's better to not validate the width:

- P1868 14. Implementation

  > "More importantly, our approach permits refining the definition in the future if there is interest in doing so. It will mostly require researching the status of Unicode support on terminals and minimal or no changes to the implementation."

  When an estimated width of 1 is required it means that improving the Standard may make previously valid code ill-formed after the improvement.

- P1868 13. Examples

  The example of the family grapheme cluster is only rendered properly on the MacOS terminal. So even when the library does a proper validation it's not certain the output will be rendered properly.

Changing the fill type changes the size of the `std::formatter` and thus will be an ABI break.

The proposed resolution probably needs some additional changes since the Unicode and output width are specified later in the standard, specifically 20.20.2.2 [format.string.std]/9 - 12.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4892.

> 1. Modify 20.20.2.2 [format.string.std] as indicated:

>    > -2- [Note 2: The fill character can be any character other than `{` or `}`. For a string in a Unicode encoding, the fill character can be any Unicode grapheme cluster other than `{` or `}`. For a string in a non-Unicode encoding, the fill character can be any character other than `{` or `}`. The output width of the fill character is always assumed to be one column. The presence of a fill character is signaled by the character following it, which must be one of the alignment options. If the second character of std-format-spec is not a valid alignment option, then it is assumed that both the fill character and the alignment option are absent. — end note]

[2021-08-09; Mark de Wever provides improved wording]

[2021-08-20; Reflector poll]

Set priority to 2 and status to "SG16" after reflector poll.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4892.

> 1. Modify 20.20.2.2 [format.string.std] as indicated:

>    > -1- […] The syntax of format specifications is as follows:

>    > >     […]
>    > >     fill:
>    > >                  any Unicode grapheme cluster or character other than { or }
>    > >     […]

>    > -2- [Note 2: The fill character can be any character other than `{` or `}`. For a string in a Unicode encoding, the fill character can be any Unicode grapheme cluster other than `{` or `}`. For a string in a non-Unicode encoding, the fill character can be any character other than `{` or `}`. The output width of the fill character is always assumed to be one column.

>    > [Note 2: The presence of a fill character is signaled by the character following it, which must be one of the alignment options. If the second character of std-format-spec is not a valid alignment option, then it is assumed that both the fill character and the alignment option are absent. — end note]

[2021-08-26; SG16 reviewed and provides alternative wording]

Proposed resolution:

This wording is relative to N4892.

1. Modify 20.20.2.2 [format.string.std] as indicated:

   > -1- […] The syntax of format specifications is as follows:

   > >     […]
   > >     fill:
   > >                  any charactercodepoint of the literal encoding other than { or }
   > >     […]

   > -2- [Note 2: The fill character can be any character codepoint other than `{` or `}`. The presence of a fill character is signaled by the character following it, which must be one of the alignment options. If the second character of std-format-spec is not a valid alignment option, then it is assumed that both the fill character and the alignment option are absent. — end note]

### 3577(i). Merging an (unordered) associative container with itself

Section: 22.2.6.1 [associative.reqmts.general], 22.2.7.1 [unord.req.general] Status: New Submitter: Joaquín M López Muñoz Opened: 2021-08-04 Last modified: 2021-08-20

Priority: 3

View other active issues in [associative.reqmts.general].

View all other issues in [associative.reqmts.general].

View all issues with New status.

Discussion:

For the expression `a.merge(a2)`, it is not explicitly stated whether `a2` can be the same object as `a`. libstdc++-v3 and libc++ seemingly assume this is not allowed, as the following code produces an infinite loop with both standard library implementations:

>     #include <set>

>     int main()
>     {
>       std::multiset<int> c={0, 0};
>       c.merge(c);
>     }

A strict reading of postconditions seems to ban the case where `a` and `a2` are the same:

- 22.2.6.1 [associative.reqmts.general]: "Iterators referring to the transferred elements […] now behave as iterators into `a`, not into `a2`": if `a` and `a2` are the same, a transferred iterator can't be both an iterator to `a` and not an iterator to `a2`.

- 22.2.7.1 [unord.req.general]: "Iterators referring to the transferred elements and all iterators referring to `a` will be invalidated, but iterators to elements remaining in `a2` will remain valid": if `a` and `a2` are the same, an iterator can't both be invalidated and remain valid.

Even if a provision is made that, when `a` and `a2` are the same, no elements are transferred by convention, 22.2.7.1 [unord.req.general] would still implicitly ban the case, as all iterators would be invalidated but the iterators to the remaining elements (again, all iterators) would remain valid, which is contradictory.

For context, analogous operations for `std::list` take inconsistent approaches:

- `splice(const_iterator position, list& x)` requires that source and destination be not the same.

- `splice(const_iterator position, list& x, const_iterator i)` implicitly allows `addressof(x) == this`, as the case `position == i` is taken care of.

- `std::list::merge` explicitly allows the case `addressof(x) == this` (resulting in a no-op).

[2021-08-20; Reflector poll]

Set priority to 3 after reflector poll. Tim Song commented: "I think the current PR of LWG2414 bans this code, but we might want to have consistency with `list::merge` instead."

Proposed resolution:

### 3578(i). Iterator SCARYness in the context of associative container merging

Section: 22.2.6.1 [associative.reqmts.general] Status: New Submitter: Joaquín M López Muñoz Opened: 2021-08-04 Last modified: 2021-08-20

Priority: 3

View other active issues in [associative.reqmts.general].

View all other issues in [associative.reqmts.general].

View all issues with New status.

Discussion:

For the expression `a.merge(a2)`, postconditions say that "iterators referring to the transferred elements […] now behave as iterators into `a` […]". When `a` and `a2` are of different types, this seems to imply, under the widest interpretation for "behaving as", that `a`-iterators and `a2`-iterators are actually of the same type, that is, that associative containers have SCARY iterators, which is, to the best of my knowledge, not currently mandated by the standard.

There are (at least) three possible resolutions to this ambiguity, ordered by intrusiveness:

- Indicate that "behaving as" only applies to the case where `a` and `a2` are of the same type.

- Clarify what "behaving as" means. A non-SCARY interpretation is that an `a2`-iterator to a transferred element can still be dereferenced, incremented (if not past the last element of `a`) and decremented (if not pointing to the first element of `a`), while comparison with `a`-iterators and use in the interface of `a` is not guaranteed.

- Mandate SCARY iterators by, for instance, requiring that associative containers with compatible nodes (22.2.4.1 [container.node.overview]/1) have the same iterator types.

Note that this issue does not extend to unordered associative containers, as there (22.2.7.1 [unord.req.general]) iterators to transferred elements are invalidated, which makes the point of SCARYness irrelevant. That said, if SCARY iterators are finally required for associative containers, it makes much sense to extend the requirement to unordered associative containers as well.

[2021-08-20; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

### 3582(i). Unclear where `std::async` exceptions are handled

Section: 32.9.9 [futures.async] Status: New Submitter: Jonathan Wakely Opened: 2021-08-23 Last modified: 2021-09-30

Priority: 3

View other active issues in [futures.async].

View all other issues in [futures.async].

View all issues with New status.

Discussion:

32.9.9 [futures.async] (3.1) says:

> Any exception propagated from the execution of `invoke(decay-copy(std::forward<F>(f)), decay-copy(std::forward<Args>(args))...)` is stored as the exceptional result in the shared state.

It's not clear whether this includes the evaluation of the `decay-copy` calls in the calling thread, or only the invocation of invoke with the results of those `decay-copy` calls.

A literal reading suggests that any exceptions from any part of that expression should be stored in the shared state. All of libstdc++, libc++ and MSVC only store exceptions from the call to `invoke`, not the calls to `decay-copy`. Exceptions from the `decay-copy` calls are propagated to the caller of `std::async`. We should clarify that that's what the standard means.

[2021-09-20; Reflector poll]

Set priority to 3 after reflector poll.

[2021-09-20; Jonathan updates wording to change the Throws: and attempt to align the Effects: with the deferred function case. ]

Previous resolution [SUPERSEDED]:

> This wording is relative to N4892.

> 1. Modify 32.9.9 [futures.async] as indicated:

>    >     template<class F, class... Args>
>    >       [[nodiscard]] future<invoke_result_t<decay_t<F>, decay_t<Args>...>>
>    >         async(F&& f, Args&&... args);
>    >     template<class F, class... Args>
>    >       [[nodiscard]] future<invoke_result_t<decay_t<F>, decay_t<Args>...>>
>    >         async(launch policy, F&& f, Args&&... args);

>    > > -2- Mandates: […]

>    > > -3- Effects: The first function behaves the same as a call to the second function with a `policy` argument of `launch::async | launch::deferred` and the same arguments for `F` and `Args`. The second function creates a shared state that is associated with the returned `future` object. The further behavior of the second function depends on the `policy` argument as follows (if more than one of these conditions applies, the implementation may choose any of the corresponding policies):

>    > > 1. (3.1) — If `launch::async` is set in `policy`, calls `invoke(decay-copy(std::forward<F>(f)), decay-copy(std::forward<Args>(args))...)` (20.14.4 [func.require], 32.4.3.3 [thread.thread.constr]) as if in a new thread of execution represented by a `thread` object with the calls to `decay-copy` being evaluated in the thread that called `async`. Any return value is stored as the result in the shared state. Any exception propagated from the execution of `invoke(decay-copy(std::forward<F>(f)), decay-copy(std::forward<Args>(args))...)`call to `invoke` is stored as the exceptional result in the shared state. [Note ?: Exceptions from the `decay-copy` calls are propagated to the caller. — end note] The `thread` object is stored in the shared state and affects the behavior of any asynchronous return objects that reference that state.

>    > > 2. […]

Proposed resolution:

This wording is relative to N4892.

1. Modify 32.9.9 [futures.async] as indicated:

   >     template<class F, class... Args>
   >       [[nodiscard]] future<invoke_result_t<decay_t<F>, decay_t<Args>...>>
   >         async(F&& f, Args&&... args);
   >     template<class F, class... Args>
   >       [[nodiscard]] future<invoke_result_t<decay_t<F>, decay_t<Args>...>>
   >         async(launch policy, F&& f, Args&&... args);

   > > -2- Mandates: […]

   > > -3- Effects: The first function behaves the same as a call to the second function with a `policy` argument of `launch::async | launch::deferred` and the same arguments for `F` and `Args`. The second function creates a shared state that is associated with the returned `future` object. The further behavior of the second function depends on the `policy` argument as follows (if more than one of these conditions applies, the implementation may choose any of the corresponding policies):

   > > 1. (3.1) — If `launch::async` is set in `policy`, calls `invoke(decay-copy(std::forward<F>(f)), decay-copy(std::forward<Args>(args))...)` (20.14.4 [func.require], 32.4.3.3 [thread.thread.constr]) as if in a new thread of execution represented by a `thread` object with the calls to `decay-copy` being evaluated in the thread that called `async`. Any return value is stored as the result in the shared state. Any exception propagated from the execution of `invoke(decay-copy(std::forward<F>(f)), decay-copy(std::forward<Args>(args)...)std::move(g), std::move(xyz))` is stored as the exceptional result in the shared state, where `g` is the result of `decay-copy(std::forward<F>(f))` and `xyz` is the result of `decay-copy(std::forward<Args>(args))...` . [Note ?: Exceptions from the `decay-copy` calls are propagated to the caller. — end note] The `thread` object is stored in the shared state and affects the behavior of any asynchronous return objects that reference that state.

   > > 2. […]

   > > […]

   > > -6- Throws: `system_error` if `policy == launch::async` and the implementation is unable to start a new thread; `std::bad_alloc` if memory for the internal data structures cannot be allocated; or any exception thrown by the initialization of the objects returned by the `decay-copy` calls.

### 3583(i). Clarify if/when short circuiting applies to conditions in Constraints: elements

Section: 20.5.3.1 [tuple.cnstr] Status: New Submitter: Jonathan Wakely Opened: 2021-08-23 Last modified: 2021-09-20

Priority: 3

View other active issues in [tuple.cnstr].

View all other issues in [tuple.cnstr].

View all issues with New status.

Discussion:

We do not specify whether or not short-circuiting is expected to happen for individual conditions stated in a Constraints: element. For example, 20.5.3.1 [tuple.cnstr] p12 says:

> Constraints: `sizeof...(Types)` equals `sizeof...(UTypes)` and `sizeof...(Types) ≤ 1` and `is_constructible_v<Ti , Ui>` is `true` for all `i`.

It's not even possible to test the `is_constructible` part unless the first part is true, so presumably it is expected that the `sizeof...` expressions are tested first, and so the `is_constructible` traits don't even need to be instantiated.

In some cases it might be user observable whether short circuiting happens, as whether later conditions are tested might affect whether errors outside the immediate context are permitted or not.

We should clarify what is intended, and refactor any Constraints: elements that are special cases where something different is required.

[2021-09-20; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

### 3584(i). Clarify common comparison category conversions

Section: 17.11.3 [cmp.common] Status: New Submitter: Peter Brett Opened: 2021-08-23 Last modified: 2021-09-20

Priority: 3

View all issues with New status.

Discussion:

17.11.3 [cmp.common]/1 says:

> The type `common_comparison_category` provides an alias for the strongest comparison category to which all of the template arguments can be converted.

A naive reader like me might interpret this as meaning that (1) you attempt to convert the template arguments to comparison categories and then (2) obtain the strongest among them.

However, the intent is in fact to realize the common comparison type notion from 11.10.3 [class.spaceship]/4. To obtain a non-`void` result, all the template arguments must be comparison categories, rather than convertible to comparison categories.

17.11.3 [cmp.common]/2 mildly contradicts the first paragraph:

> Remarks: The member typedef-name `type` denotes the common comparison type (11.10.3 [class.spaceship]) of `Ts...`, the expanded parameter pack, or `void` if any element of `Ts` is not a comparison category type.

It more precisely states the behaviour, cross-references 11.10.3 [class.spaceship], and uses the correct core terminology for the metafunction that the template represents.

Suggested resolution;

Delete 17.11.3 [cmp.common]/1, because it does not provide any information not already more precisely included in 17.11.3 [cmp.common]/2.

[2021-09-20; Reflector poll]

Set priority to 3 after reflector poll.

[2021-09-20; Reflector poll]

Jens suggests alternative wording.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4892.

> 1. Modify 17.11.3 [cmp.common] as indicated:

>    > -1- The type `common_comparison_category` provides an alias for the strongest comparison category to which all of the template arguments can be converted. [Note 1: A comparison category type is stronger than another if they are distinct types and an instance of the former can be converted to an instance of the latter. — end note]

>    >     template<class... Ts>
>    >     struct common_comparison_category {
>    >       using type = see below;
>    >     };

>    > -2- Remarks: The member typedef-name `type` denotes the common comparison type (11.10.3 [class.spaceship]) of `Ts...`, the expanded parameter pack, or `void` if any element of `Ts` is not a comparison category type.

Proposed resolution:

This wording is relative to N4892.

1. Modify 17.11.3 [cmp.common] as indicated:

   > -1- The type `common_comparison_category` provides an alias for the strongest comparison category to which all of the template arguments can be converted among all the template arguments. [Note 1: A comparison category type is stronger than another if they are distinct types and an instance of the former can be converted to an instance of the latter. — end note]

   >     template<class... Ts>
   >     struct common_comparison_category {
   >       using type = see below;
   >     };

   > -2- Remarks: The member typedef-name `type` denotes the common comparison type (11.10.3 [class.spaceship]) of `Ts...`, the expanded parameter pack, or `void` if any element of `Ts` is not a comparison category type.

### 3586(i). Formatting character alignment inconsistencies

Section: 20.20.2.2 [format.string.std] Status: New Submitter: Mark de Wever Opened: 2021-09-05 Last modified: 2021-12-04

Priority: 2

View other active issues in [format.string.std].

View all other issues in [format.string.std].

View all issues with New status.

Discussion:

The alignment options specified in 20.20.2.2 [format.string.std], Table [tab:format.align] causes an inconsistency when formatting characters. The output differs depending on whether an integer is formatted using a character presentation type or when using a character directly:

>     format("{:3}", '*'); -> "*  " // aligned at the start of the available space
>     format("{:3c}", 42); -> "  *" // aligned at the end of the available space

I expect both calls to return the same value: `"* "`. The current wording mixes the type and the presentation type. To me, it seems clearer to adjust to wording to only use the presentation type. Another approach would be adjusting the wording to add an exception when an integer type uses the character presentation.

[2021-09-20; Reflector poll]

Set priority to 2 after reflector poll.

Victor said "It mostly looks correct but I think the wording needs a bit more work because we don't mention arithmetic presentation types anywhere."

[2021-11-29; Daniel comments]

This issue touches the same wording area as LWG 3644 does.

Proposed resolution:

This wording is relative to N4892.

1. Modify 20.20.2.2 [format.string.std], Table [tab:format.align], as indicated:

   > Table 59 — Meaning of align options [tab:format.align]
   > Option | Meaning
   > --- | ---
   > `<` | Forces the field to be aligned to the start of the available space. This is the default when the presentation type is a non-arithmetic type for non-arithmetic types, `charT`, and `bool`, unless an integer presentation type is specified.
   > `>` | Forces the field to be aligned to the end of the available space. This is the default when the presentation type is an arithmetic type for arithmetic types other than `charT` and `bool` or when an integer presentation type is specified.
   > `[…]`

### 3587(i). `std::three_way_comparable_with<T, U, void>` can be satisfied but can't be modeled

Section: 17.11.4 [cmp.concept] Status: New Submitter: Jiang An Opened: 2021-09-06 Last modified: 2021-10-23

Priority: 3

View all other issues in [cmp.concept].

View all issues with New status.

Discussion:

Due to the current specification of `std::common_comparison_category`, `compare-as<void, void>` is satisfied. And thus given two types `T` and `U` with regular `==`, `!=`, `<`, `>`, `<=`, and `>=` but irregular `<=>` that has return type `void`, `std::three_way_comparable_with<T, U, void>` is satisfied.

However, in this situation `std::three_way_comparable_with<T, U, void>` can't be modeled, because `Cat(t <=> u) == Cat(C(t) <=> C(u))` is ill-formed if `Cat` is `void` (see this godbolt link).

I don't think this issue has any impact on meaningful codes, but it seems to be a hole in the current specification.

It seems that `compares-as<void, void>` should be changed to `false`. `compares-as<NonComparisonCategoryType, void>` might need refinement.

(Note: The same problem does not exists for `std::three_way_comparable`, because `std::three_way_comparable<T, void>` can be modeled if the `<=>` on `T` has "regular" definition or its return type is not a comparison category type, but the return value has "regular" semantics)

[2021-09-20; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

### 3594(i). `inout_ptr` — inconsistent `release()` in destructor

Section: 20.11.10 [inout.ptr.t] Status: New Submitter: JeanHeyd Meneide Opened: 2021-09-16 Last modified: 2021-10-30

Priority: 1

View all issues with New status.

Discussion:

More succinctly, the model for `std::out_ptr_t` and `std::inout_ptr_t` both have a conditional release in their destructors as part of their specification (20.11.8 [out.ptr.t] p8) (Option #2 below). But, if the wording is followed, they have an unconditional release in their constructor (Option #1 below). This is not exactly correct and can cause issues with double-free in `inout_ptr` in particular.

Consider a function `MyFunc` that sets `rawPtr` to `nullptr` when freeing an old value and deciding not to produce a new value, as shown below:

>     // Option #1:
>     auto uptr = std::make_unique<BYTE[]>(25);
>     auto rawPtr = uptr.get();
>     uptr.release(); // UNCONDITIONAL
>     MyFunc(&rawPtr);
>     If (rawPtr)
>     {
>       uptr.reset(rawPtr);
>     }

>     // Option #2:
>     auto uptr = std::make_unique<BYTE[]>(25);
>     auto rawPtr = uptr.get();
>     MyFunc(&rawPtr);
>     If (rawPtr)
>     {
>       uptr.release(); // CONDITIONAL
>       uptr.reset(rawPtr);
>     }

This is no problem if the implementation selected Option #1 (release in the constructor), but results in double-free if the implementation selected option #2 (release in the destructor).

As the paper author and after conferring with others, the intent was that the behavior was identical and whether a choice between the constructor or destructor is made. The reset should be unconditional, at least for `inout_ptr_t`. Suggested change for the `~inout_ptr_t` destructor text is to remove the "`if (p) { ... }`" wrapper from around the code in 20.11.10 [inout.ptr.t] p11.

[2021-09-24; Reflector poll]

Set priority to 1 after reflector poll.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4892.

> 1. Modify 20.11.10 [inout.ptr.t] as indicated:

>    >     ~inout_ptr_t();

>    > > -9- Let `SP` be `POINTER_OF_OR(Smart, Pointer)` (20.10.1 [memory.general]).

>    > > -10- Let `release-statement` be `s.release()`; if an implementation does not call `s.release()` in the constructor. Otherwise, it is empty.

>    > > -11- Effects: Equivalent to:

>    > > 1. (11.1) —

>    > >    >     if (p) {
>    > >    >       apply([&](auto&&... args) {
>    > >    >       s = Smart( static_cast<SP>(p), std::forward<Args>(args)...); }, std::move(a));
>    > >    >     }

>    > >    if `is_pointer_v<Smart>` is `true`;

>    > > 2. (11.2) — otherwise,

>    > >    >     if (p) {
>    > >    >       apply([&](auto&&... args) {
>    > >    >       release-statement;
>    > >    >       s.reset(static_cast<SP>(p), std::forward<Args>(args)...); }, std::move(a));
>    > >    >     }

>    > >    if the expression `s.reset(static_cast<SP>(p), std::forward<Args>(args)...)` is well-formed;

>    > > 3. (11.3) — otherwise,

>    > >    >     if (p) {
>    > >    >       apply([&](auto&&... args) {
>    > >    >       release-statement;
>    > >    >       s = Smart(static_cast<SP>(p), std::forward<Args>(args)...); }, std::move(a));
>    > >    >     }

>    > >    if `is_constructible_v<Smart, SP, Args...>` is `true`;

>    > > 4. (11.4) — otherwise, the program is ill-formed.

[2021-10-28; JeanHeyd Meneide provides improved wording]

Proposed resolution:

This wording is relative to N4901.

1. Modify 20.11.10 [inout.ptr.t] as indicated:

   >     ~inout_ptr_t();

   > > -9- Let `SP` be `POINTER_OF_OR(Smart, Pointer)` (20.10.1 [memory.general]).

   > > -10- Let `release-statement` be `s.release()`; if an implementation does not call `s.release()` in the constructor. Otherwise, it is empty.

   > > -11- Effects: Equivalent to:

   > > 1. (11.1) —

   > >    >     if (p) {
   > >    >       apply([&](auto&&... args) {
   > >    >       s = Smart( static_cast<SP>(p), std::forward<Args>(args)...); }, std::move(a));
   > >    >     }

   > >    if `is_pointer_v<Smart>` is `true`;

   > > 2. (11.2) — otherwise,

   > >    >     release-statement;
   > >    >     if (p) {
   > >    >       apply([&](auto&&... args) {
   > >    >       release-statement;
   > >    >       s.reset(static_cast<SP>(p), std::forward<Args>(args)...); }, std::move(a));
   > >    >     }

   > >    if the expression `s.reset(static_cast<SP>(p), std::forward<Args>(args)...)` is well-formed;

   > > 3. (11.3) — otherwise,

   > >    >     release-statement;
   > >    >     if (p) {
   > >    >       apply([&](auto&&... args) {
   > >    >       release-statement;
   > >    >       s = Smart(static_cast<SP>(p), std::forward<Args>(args)...); }, std::move(a));
   > >    >     }

   > >    if `is_constructible_v<Smart, SP, Args...>` is `true`;

   > > 4. (11.4) — otherwise, the program is ill-formed.

### 3597(i). Unsigned integer types don't model `advanceable`

Section: 24.6.4.2 [range.iota.view] Status: New Submitter: Jiang An Opened: 2021-09-23 Last modified: 2021-10-14

Priority: 3

View other active issues in [range.iota.view].

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

View all issues with New status.

Discussion:

Unsigned integer types satisfy `advanceable`, but don't model it, since

> every two values of an unsigned integer type are reachable from each other, and modular arithmetic is performed on unsigned integer types,

which makes the last three bullets of the semantic requirements of `advanceable` (24.6.4.2 [range.iota.view]/5) can't be satisfied, and some (if not all) uses of `iota_view`s of unsigned integer types ill-formed, no diagnostic required.

Some operations that are likely to expect the semantic requirements of `advanceable` behave incorrectly for unsigned integer types. E.g. according to 24.6.4.2 [range.iota.view]/6 and 24.6.4.2 [range.iota.view]/16, `std::ranges::iota_view<std::uint8_t, std::uint8_t>(std::uint8_t(1)).size()` is well-defined IMO, because

> `Bound()` is `std::uint8_t(0)`, which is reachable from `std::uint8_t(1)`, and not modeling `advanceable` shouldn't affect the validity, as both `W` and `Bound` are integer types.

However, it returns `unsigned(-1)` on common implementations (where `sizeof(int) > sizeof(std::uint8_t))`, which is wrong.

Perhaps the semantic requirements of `advanceable` should be adjusted, and a refined definition of reachability in 24.6.4 [range.iota] is needed to avoid reaching `a` from `b` when `a > b` (the iterator type is also affected).

[2021-10-14; Reflector poll]

Set priority to 3 after reflector poll.

[Tim Song commented:]

The advanceable part of the issue is NAD. This is no different from NaN and `totally_ordered`, see 16.3.2.3 [structure.requirements]/8.

The part about `iota_view<uint8_t, uint8_t>(1)` is simply this: when we added "When `W` and `Bound` model ..." to 24.6.4.2 [range.iota.view]/8, we forgot to add its equivalent to the single-argument constructor. We should do that.

Proposed resolution:

### 3599(i). The `const` overload of `lazy_split_view::begin` should be constrained by `const Pattern`

Section: 24.7.13.2 [range.lazy.split.view] Status: New Submitter: Hewill Kang Opened: 2021-09-23 Last modified: 2021-10-14

Priority: 3

View all other issues in [range.lazy.split.view].

View all issues with New status.

Discussion:

Consider the following code snippet:

>     #include <ranges>

>     int main() {
>       auto p = std::views::iota(0)
>              | std::views::take(1)
>              | std::views::reverse;
>       auto r = std::views::single(42)
>              | std::views::lazy_split(p);
>       auto f = r.front();
>     }

`r.front()` is ill-formed even if `r` is a `forward_range`.

This is because the `const` overload of `lazy_split_view::begin` is not constrained by the `const Pattern`, which makes it still well-formed in such cases. When the `const` overload of `view_interface<lazy_split_view<V, Pattern>>::front` is instantiated, the `subrange{parent_->pattern_}` inside `lazy_split_view::outer-iterator<true>::operator++()` will cause a hard error since `const Pattern` is not a `range`.

[2021-09-24; Daniel comments]

This issue is related to LWG 3592.

[2021-10-14; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

This wording is relative to N4892.

1. Modify 24.7.13.2 [range.lazy.split.view], class template `lazy_split_view` synopsis, as indicated:

   > >     namespace std::ranges {

   > >       […]

   > >       template<input_range V, forward_range Pattern>
   > >         requires view<V> && view<Pattern> &&
   > >                  indirectly_comparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&
   > >                 (forward_range<V> || tiny-range<Pattern>)
   > >       class lazy_split_view : public view_interface<lazy_split_view<V, Pattern>> {
   > >       private:
   > >         […]
   > >       public:
   > >         […]

   > >         constexpr auto begin() {
   > >           […]
   > >         }

   > >         constexpr auto begin() const requires forward_range<V> && forward_range<const V> &&
   > >                                               forward_range<const Pattern>{
   > >           return outer-iterator<true>{*this, ranges::begin(base_)};
   > >         }

   > >         constexpr auto end() requires forward_range<V> && common_range<V> {
   > >           […]
   > >         }

   > >         constexpr auto end() const {
   > >           if constexpr (forward_range<V> && forward_range<const V> && common_range<const V> &&
   > >                         forward_range<const Pattern>)
   > >             return outer-iterator<true>{*this, ranges::end(base_)};
   > >           else
   > >             return default_sentinel;
   > >         }
   > >       };

   > >       […]

   > >     }

### 3600(i). Making `istream_iterator` copy constructor trivial is an ABI break

Section: 23.6.2.2 [istream.iterator.cons] Status: New Submitter: Jonathan Wakely Opened: 2021-09-23 Last modified: 2021-10-14

Priority: 3

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

View all issues with New status.

Discussion:

Libstdc++ never implemented this change made between C++03 and C++11 (by N2994):

24.6.1.1 [istream.iterator.cons] p3:

>     istream_iterator(const istream_iterator<T,charT,traits,Distance>& x) = default;

> > -3- Effects: Constructs a copy of `x`. If `T` is a literal type, then this constructor shall be a trivial copy constructor.

This breaks our ABI, as it changes the argument passing convention for the type, meaning this function segfaults if compiled with today's libstdc++ and called from one that makes the triviality change:

>     #include <iterator>
>     #include <istream>

>     int f(std::istream_iterator<int> i)
>     {
>       return *i++;
>     }

As a result, it's likely that libstdc++ will never implement the change.

There is no reason to require this constructor to be trivial. It was required for C++0x at one point, so the type could be literal, but that is not true in the current language. We should strike the requirement, to reflect reality. MSVC and libc++ are free to continue to define it as defaulted (and so trivial when appropriate) but we should not require it from libstdc++. The cost of an ABI break is not worth the negligible benefit from making it trivial.

[2021-09-30; Jonathan revises wording after reflector discussion]

Previous resolution [SUPERSEDED]:

> This wording is relative to N4892.

> 1. Modify 23.6.2.2 [istream.iterator.cons] as indicated:

>    >     istream_iterator(const istream_iterator& x) = default;

>    > > -5- Postconditions: `in_stream == x.in_stream` is `true`.

>    > > -6- Remarks: If `is_trivially_copy_constructible_v<T>` is `true`, then this constructor is trivial.

[2021-10-14; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

This wording is relative to N4892.

1. Modify the class synopsis in 23.6.2.1 [istream.iterator.general] as indicated:

   >     constexpr istream_iterator();
   >     constexpr istream_iterator(default_sentinel_t);
   >     istream_iterator(istream_type& s);
   >     constexpr istream_iterator(const istream_iterator& x) = default;
   >     ~istream_iterator() = default;
   >     istream_iterator& operator=(const istream_iterator&) = default;

2. Modify 23.6.2.2 [istream.iterator.cons] as indicated:

   >       constexpr istream_iterator(const istream_iterator& x) = default;

   > > -5- Postconditions: `in_stream == x.in_stream` is `true`.

   > > -6- Remarks: If `is_trivially_copy_constructible_v<T>` is `true`, then this constructor is trivial. If the initializer `T(x.value)` in the declaration `auto val = T(x.value);` is a constant initializer ([expr.const]), then this constructor is a constexpr constructor.

### 3602(i). `reverse_iterator`'s converting assignment is overconstrained

Section: 23.5.1.4 [reverse.iter.cons], 23.5.3.4 [move.iter.cons] Status: New Submitter: Hewill Kang Opened: 2021-09-26 Last modified: 2021-10-14

Priority: 3

View all other issues in [reverse.iter.cons].

View all issues with New status.

Discussion:

In order to remove the incorrect bi-convertibility of `reverse_iterator<int*>` and `reverse_iterator<const int*>`, LWG 3435 adds two constraints to `reverse_iterator`'s converting assignment, namely `convertible_to<const U&, Iterator>` and `assignable_from<Iterator&, const U&>`, but since this function only assigns `u.current` to `current`, there is no need to require `convertible_to<const U&, Iterator>` — the latter is sufficient.

We should remove this constraint and be consistent with the `move_sentinel` and `counted_iterator`' converting assignment.

[2021-10-14; Reflector poll]

Set priority to 3 after reflector poll.

[Tim Song commented:]

This was intentional, but I think we missed the fact that `counted_iterator` did something else already. These should probably be made consistent one way or another.

[Tomasz Kamiński commented]

The `move_iterator`/`reverse_iterator` were present before C++20, and this change restores their compatibility with C++17 code, where only assignment was required. They are materially different from adapters introduced with C++20, and I believe we should put more weight into backward compatibility than consistency with newer iterator wrappers.

Proposed resolution:

This wording is relative to N4892.

1. Modify 23.5.1.4 [reverse.iter.cons] as indicated:

   >     template<class U>
   >       constexpr reverse_iterator&
   >         operator=(const reverse_iterator<U>& u);

   > > -5- Constraints: `is_same_v<U, Iterator>` is `false`, `const U&` models `convertible_to<Iterator>`, and `assignable_from<Iterator&, const U&>` is modeled.

   > > -6- Effects: Assigns `u.current` to `current`.

   > > -7- Returns: `*this`.

2. Modify 23.5.3.4 [move.iter.cons] as indicated:

   > [Drafting note: As drive-by fix a missing "Returns: `*this`" has been added as well.]

   >     template<class U> constexpr move_iterator& operator=(const move_iterator<U>& u);

   > > -5- Constraints: `is_same_v<U, Iterator>` is `false`, `const U&` models `convertible_to<Iterator>`, and `assignable_from<Iterator&, const U&>` is modeled.

   > > -6- Effects: Assigns `u.current` to `current`.

   > > -?- Returns: `*this`.

### 3603(i). Matching of null characters by regular expressions is underspecified

Section: 30.7.2 [re.regex.construct], 30.10 [re.alg] Status: New Submitter: Jonathan Wakely Opened: 2021-09-27 Last modified: 2021-10-14

Priority: 3

View other active issues in [re.regex.construct].

View all other issues in [re.regex.construct].

View all issues with New status.

Discussion:

ECMAScript says that `\0` is an ordinary character and can be matched. POSIX says the opposite:

"The interfaces specified in POSIX.1-2017 do not permit the inclusion of a NUL character in an RE or in the string to be matched. If during the operation of a standard utility a NUL is included in the text designated to be matched, that NUL may designate the end of the text string for the purposes of matching."

So does that mean `std::regex{"", 1, regex::basic}` should throw an exception?

And `std::regex_match(string{"a\0b", 3}, regex{"a.b", regex::basic})` should fail?

The POSIX rule is because those interfaces are specified with NTBS arguments, so there's no way to distinguish `"a\0b"` and `"a"`. The C++ interfaces could allow it, but we never specify any divergence from POSIX, so presumably the rule still applies. Is that what was intended and is it what we want?

[2021-10-14; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

### 3604(i). What is the effect of an invalid value of type `syntax_option_type`?

Section: 30.7.2 [re.regex.construct], 30.4.2 [re.synopt] Status: New Submitter: Jonathan Wakely Opened: 2021-09-27 Last modified: 2021-10-14

Priority: 3

View other active issues in [re.regex.construct].

View all other issues in [re.regex.construct].

View all issues with New status.

Discussion:

30.4.2 [re.synopt] says:

> A valid value of type `syntax_option_type` shall have at most one of the grammar elements `ECMAScript`, `basic`, `extended`, `awk`, `grep`, `egrep`, set.

But then we never say what happens if an invalid value is used.

What does `std::regex(".", std::regex::grep|std::regex::awk)` do? Is it undefined? Does it throw?

It seems reasonable for `basic_regex` constructors to throw if `f` is not a valid value, i.e. for each non-default constructor:

> Throws: `regex_error` if `f` is not a valid value, or if […] is not a valid regular expression according to the grammar specified by `f`.

However, there is no `regex_constants::error_code` value suitable for this error condition.

Also, the constructors say "Postconditions: `flags()` returns `f`." This prevents an implementation from storing `f|ECMAScript` in `flags()` if no grammar element is present in `f`. This seems like an unnecessary restriction, and forces implementations to do extra work to check if the `ECMAScript` grammar is in use. Arguably, it would even be better to require implementations to set `ECMAScript` in `flags()` if no grammar element was set in the flags passed to the constructor. This problem was introduced by LWG 2330.

[2021-10-14; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

### 3605(i). `regex_constants::match_prev_avail` is underspecified

Section: 30.4.3 [re.matchflag] Status: New Submitter: Jonathan Wakely Opened: 2021-09-27 Last modified: 2021-10-14

Priority: 3

View all other issues in [re.matchflag].

View all issues with New status.

Discussion:

The standard doesn't say what it means if `match_prev_avail` is set. Table [tab:re.matchflag] says:

> `--first` is a valid iterator position. When this flag is set the flags `match_not_bol` and `match_not_bow` shall be ignored by the regular expression algorithms (30.10 [re.alg]) and iterators (30.11 [re.iter]).

What difference does it make whether `--first` is a valid iterator position or not?

What behaviour is changed when it's a valid iterator position? The standard doesn't say anything else about that.

When do the regex algorithms care about `--first`?

Examples like `regex_match("xa"+1, regex("^a"), match_prev_avail)` and `regex_match("xa"+1, regex("\\ba"), match_prev_avail)` are presumably supposed to inspect the character at `--first` to determine if there is a match. The standard doesn't specify that `*--first` is ever inspected, only that it's a valid character (which is a useless guarantee if nothing looks at it).

[2021-10-14; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

### 3606(i). Missing `regex_traits::locale_type` requirements

Section: 30.2 [re.req] Status: New Submitter: Jonathan Wakely Opened: 2021-09-28 Last modified: 2021-10-14

Priority: 3

View other active issues in [re.req].

View all other issues in [re.req].

View all issues with New status.

Discussion:

Why is `locale_type` part of the regular expression traits requirements in 30.2 [re.req]? When would `locale_type` not be `std::locale`? What are the requirements on the type? Does it have to provide exactly the same interface as `std::locale`, or just some unspecified interface that a custom regex traits type needs from it? Why is none of this specified?

Currently the only requirement on `locale_type` in the standard is that it's copy constructible. Clearly it needs to be default constructible as well, otherwise you can't construct a `basic_regex`, since none of them allows passing in a locale, so they have to default construct it (see also LWG 2431).

The other requirements on `locale_type` are a mystery. Why do we allow custom locale types, but not say anything about what they should do? Can we just require `locale_type` to be `std::locale`? Is anybody really going to use `boost::locale` with `std::basic_regex`, when they could just use `boost::basic_regex` instead?

Why does the regular expression traits requirements table say that `imbue` and `getloc` talk about the locale used, "if any". How would there not be one already?

Why is imbuing a locale into a `basic_regex` a separate operation from compiling the regular expression pattern? Is the following supposed to change the compiled regex?

>     std::regex r("[a-z]");
>     r.imbue(std::locale("en_GB.UTF-8"));

Hasn't the regex constructor already made use of the locale to compile the `"[a-z]"` pattern, and so changing the locale is too late? So do we need to do the following to compile the regex with a specific locale?

>     std::regex r;
>     r.imbue(std::locale("en_GB.UTF-8"));
>     r.assign("[a-z]");

Why require two-stage initialization like this, is it just so that we appear consistent with the `imbue`/`getloc` API of `std::ios_base`? It works for `ios_base`, because the new locale is effective after imbuing it, but for `basic_regex` the pattern has already been compiled using the old locale and imbuing a new one can't change that. Is the `basic_regex` supposed to store the pattern and recompile it after `imbue`, or is this just an inappropriate API for `basic_regex`?

[2021-10-14; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

### 3608(i). `convertible_to` and temporary-bound references

Section: 18.4.4 [concept.convertible] Status: New Submitter: Tim Song Opened: 2021-09-28 Last modified: 2021-10-23

Priority: 3

View other active issues in [concept.convertible].

View all other issues in [concept.convertible].

View all issues with New status.

Discussion:

The semantic requirements of `convertible_to` express implicit conversion by means of a function:

>     To test(FromR (&f)()) {
>       return f();
>     }

and it requires that `static_cast<To>(f())` be equal to `test(f)` for some equality-preserving function `f`. However, when `To` is a reference type but `FromR` is such that the conversion binds the reference to a temporary, the `static_cast` is valid but `test(f)` would produce a dangling reference.

We should rephrase this requirement to just perform the implicit conversion in words. Using a function handles the convert-`void`-to-`void` case, but the semantic requirements wording already excluded that case anyway.

[2021-10-14; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

### 3609(i). `std::ranges::iota_view<int, long>` has non-subtractable `iterator` and `sentinel` types

Section: 24.6.4.4 [range.iota.sentinel] Status: New Submitter: Jiang An Opened: 2021-09-25 Last modified: 2021-10-14

Priority: 3

View all issues with New status.

Discussion:

Currently `std::ranges::iota_view<int, long>` uses its special `sentinel` type, as its `W` and `Bound` are different types and `Bound` is not `std::unreachable_sentinel_t`. However, as `W` (`int`) is not an iterator type, the iterator and sentinel types don't satisfy `std::sized_sentinel_for`, and thus not subtractable.

IMO we should handle `operator-` overloads for `iota_view::iterator` and `iota_view::sentinel` like `iota_view::size` and `operator-` for `iota_view::iterator`.

[2021-10-14; Reflector poll]

Set priority to 3 after reflector poll.

[Tim Song commented:]

We might be able to simplify the `(y_value > x.value_)` conditional since we know that we are working with an iterator and its sentinel.

Proposed resolution:

This wording is relative to N4892.

1. Modify 24.6.4.4 [range.iota.sentinel] as indicated:

   > >     namespace std::ranges {
   > >       template<weakly_incrementable W, semiregular Bound>
   > >         requires weakly-equality-comparable-with<W, Bound> && copyable<W>
   > >       struct iota_view<W, Bound>::sentinel {
   > >       private:
   > >         Bound bound_ = Bound(); // exposition only
   > >       public:
   > >         sentinel() = default;
   > >         constexpr explicit sentinel(Bound bound);

   > >         friend constexpr bool operator==(const iterator& x, const sentinel& y);

   > >         friend constexpr iter_difference_t<W>IOTA-DIFF-T(W) operator-(const iterator& x, const sentinel& y)
   > >           requires (is-integer-like<W> && is-integer-like<Bound>) || sized_sentinel_for<Bound, W>;

   > >         friend constexpr iter_difference_t<W>IOTA-DIFF-T(W) operator-(const sentinel& x, const iterator& y)
   > >           requires (is-integer-like<W> && is-integer-like<Bound>) || sized_sentinel_for<Bound, W>;
   > >       };
   > >     }

   > […]

   >     friend constexpr iter_difference_t<W>IOTA-DIFF-T(W) operator-(const iterator& x, const sentinel& y)
   >       requires (is-integer-like<W> && is-integer-like<Bound>) || sized_sentinel_for<Bound, W>;

   > > -3- Effects: Equivalent to: `return x.value_ - y.bound_;`

   > > >     using D = IOTA-DIFF-T(W);
   > > >     if constexpr (is-integer-like<W>) {
   > > >       auto y_value = W(y.bound_);
   > > >       if constexpr (is-signed-integer-like<W>) {
   > > >         return D(D(x.value_) - D(y_value));
   > > >       } else {
   > > >         return (y_value > x.value_)
   > > >           ? D(-D(y_value - x.value_))
   > > >           : D(x.value_ - y_value);
   > > >       }
   > > >     } else {
   > > >       return x.value_ - y.bound_;
   > > >     }

   >     friend constexpr iter_difference_t<W>IOTA-DIFF-T(W) operator-(const sentinel& x, const iterator& y)
   >       requires (is-integer-like<W> && is-integer-like<Bound>) || sized_sentinel_for<Bound, W>;

   > > -4- Effects: Equivalent to: `return -(y - x);`

### 3611(i). Should `compare_exchange` be allowed to modify the `expected` value on success?

Section: 31.8.2 [atomics.types.operations] Status: SG1 Submitter: Jonathan Wakely Opened: 2021-09-29 Last modified: 2021-10-23

Priority: 2

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

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

View all issues with SG1 status.

Discussion:

Currently a `compare_exchange` will only update the `expected` parameter if the `compare_exchange` fails. This precludes unconditionally clearing the padding bits of the `expected` object prior to doing the `compare_exchange`, which complicates the implementation by requiring additional work (e.g. making a copy of the `expected` value and clearing the copy's padding, then copying it back to expected only if the `compare_exchange` fails).

We should consider whether we want to allow modifications to `expected` in the success case, if such modifications only affect padding bits (i.e. do not alter the value). If we want to allow it, we need to say so explicitly. The current wording does not permit modifications in the success case, and any such modification could create a data race if another thread is reading the same memory location (if it knows a priori that a `compare_exchange_strong` would succeed and so not write to that location).

[2021-10-14; Reflector poll]

Set priority to 2 after reflector poll. Send to SG1.

This is 2426 again, but the new requirement to clear padding bits changes things.

Proposed resolution:

### 3613(i). Specify that `nullopt_t` is copyable

Section: 20.6.4 [optional.nullopt] Status: New Submitter: Frank Birbacher Opened: 2021-10-01 Last modified: 2021-10-14

Priority: 3

View all other issues in [optional.nullopt].

View all issues with New status.

Discussion:

The Standard defines a number of types that are used to create overload disambiguators for constructors, like `nullopt_t` and `allocator_tag_t`. Values of such types are passed by value to such constructors to give it particular meaning. For pass-by-value these types need to be copy-constructible and for consistency should also be copy-assignable. Of those types the specification of `nullopt_t` doesn't clearly state that the type is copyable, 20.6.4 [optional.nullopt].

The reason that `nullopt_t` is defined differently from other such types is to avoid ambiguity in expressions that assign an empty brace initializer to an `optional`. The meaning of such assignment should be to engage the `optional` instead of taking the braces to create a temporary `nullopt_t` for assignment and thus reset the `optional`. The RHS of such assignment should be a temporary empty `optional` instead of a temporary `nullopt_t`.

Types that aren't affected: `nullptr_t` (fundamental type), `allocator_tag_t`, `piecewise_construct_t`, `in_place_t`, `in_place_type_t`, `in_place_index_t` (all basically defined as a `class T { explicit T() = default; }` which works fine for pass-by-value)

[2021-10-14; Reflector poll]

Set priority to 3 after reflector poll.

[Daniel commented:]

I would prefer to see the wording use `is_trivially_copy_constructible_v` and `trivially_copy_assignable_v`, which is consistent with similar usage of trivial-requirements in `std::optional`.

[Tim commented:]

We need to say that it models copyable and is trivially copyable (not sure if we need the latter but might as well - does anyone do it differently?). "has a copy constructor" isn't enough - `T(T&)` is a copy constructor.

Proposed resolution:

This wording is relative to N4892.

1. Modify 20.6.4 [optional.nullopt] as indicated:

   >     struct nullopt_t{see below};
   >     inline constexpr nullopt_t nullopt(unspecified);

   > > -1- The struct `nullopt_t` is an empty class type used as a unique type to indicate the state of not containing a value for `optional` objects. In particular, `optional<T>` has a constructor with `nullopt_t` as a single argument; this indicates that an optional object not containing a value shall be constructed.

   > > -2- Type `nullopt_t` shall not have a default constructor or an initializer-list constructor, and shall not be an aggregate, and shall have a copy constructor and a copy assignment operator, both shall be public and trivial.

### 3614(i). `iota_view::size` and the most negative signed integer values

Section: 24.6.4.2 [range.iota.view] Status: New Submitter: Jiang An Opened: 2021-10-01 Last modified: 2021-10-14

Priority: 3

View other active issues in [range.iota.view].

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

View all issues with New status.

Discussion:

According to 24.6.4.2 [range.iota.view]/15, when both `W` and `Bound` are integer-like, the expression in the return statement uses `-value_` and `-bound_`. These operations result in undefined behavior when `-` is applied to the most negative integer value of a promoted type.

I believe that we can simply convert `value_` and `bound_` to the return type (`make-unsigned-like-t<common_type_t<W, Bound>>`) and then perform the subtraction. Such method should give the same results with UB eliminated.

Additionally, if we decide that `iota_view<uint8_t, uint8_t>(uint8_t(1)).size()` is well-defined (LWG 3597), it should give the correct result. We can truncate the result to fit the type `W`.

[2021-10-14; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

This wording is relative to N4892.

> [Drafting Note: Two mutually exclusive options are prepared, depicted below by Option A and Option B, respectively.]

Option A: Just fixes the most negative values

1. Modify 24.6.4.2 [range.iota.view] as indicated:

   >     constexpr auto size() const requires see below;

   > > -15- Effects: Equivalent to:

   > > >     if constexpr (is-integer-like<W> && is-integer-like<Bound>) {
   > > >       return (value_ < 0)
   > > >         ? ((bound_ < 0)
   > > >           ? to-unsigned-like(-value_) - to-unsigned-like(-bound_)
   > > >           : to-unsigned-like(bound_) + to-unsigned-like(-value_))
   > > >         : to-unsigned-like(bound_) - to-unsigned-like(value_);
   > > >       using UC = make-unsigned-like-t<common_type_t<W, Bound>>;
   > > >       return UC(bound_) - UC(value_);
   > > >     } else
   > > >       return to-unsigned-like(bound_ - value_);

   > > -16- Remarks: […]

Option B: Also fixes pathological cases involving unsigned-integer-like types

1. Modify 24.6.4.2 [range.iota.view] as indicated:

   >     constexpr auto size() const requires see below;

   > > -15- Effects: Equivalent to:

   > > >     if constexpr (is-integer-like<W> && is-integer-like<Bound>) {
   > > >       return (value_ < 0)
   > > >         ? ((bound_ < 0)
   > > >           ? to-unsigned-like(-value_) - to-unsigned-like(-bound_)
   > > >           : to-unsigned-like(bound_) + to-unsigned-like(-value_))
   > > >         : to-unsigned-like(bound_) - to-unsigned-like(value_);
   > > >       using UC = make-unsigned-like-t<common_type_t<W, Bound>>;
   > > >       if constexpr (is-signed-integer-like<W>)
   > > >         return UC(bound_) - UC(value_);
   > > >       else
   > > >         return UC(W(UC(bound_) - UC(value_)));
   > > >     } else
   > > >       return to-unsigned-like(bound_ - value_);

   > > -16- Remarks: […]

### 3615(i). The last specialization of `incrementable_traits` has wrong operand types

Section: 23.3.2.1 [incrementable.traits] Status: New Submitter: Hewill Kang Opened: 2021-09-30 Last modified: 2022-01-31

Priority: 3

View all issues with New status.

Discussion:

The last specialization of `incrementable_traits` requires `a - b` to be well-formed, where the types of both operands are `const` lvalue reference of type `T`. However inside the `struct`, it uses `decltype(declval<T>() - declval<T>())` to define the `difference_type`, that is, non-`const` rvalue reference of type `T`.

[2022-01-29; Reflector poll]

Set priority to 3 after reflector poll that failed to reach consensus. Some suggested NAD: "Implicit expression variations ([concepts.equality]/6) apply here."

Proposed resolution:

This wording is relative to N4892.

1. Modify 23.3.2.1 [incrementable.traits] as indicated:

   >     namespace std {
   >       […]
   >       template<class T>
   >         requires (!requires { typename T::difference_type; } &&
   >                   requires(const T& a, const T& b) { { a - b } -> integral; })
   >       struct incrementable_traits<T> {
   >         using difference_type = make_signed_t<decltype(declval<const T&>() - declval<const T&>())>;
   >       };
   >       […]
   >     }

### 3617(i). `function`/`packaged_task` deduction guides and deducing `this`

Section: 20.14.17.3.2 [func.wrap.func.con], 32.9.10.2 [futures.task.members] Status: New Submitter: Barry Revzin Opened: 2021-10-09 Last modified: 2021-10-17

Priority: 2

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

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

View all issues with New status.

Discussion:

With the adoption of deducing `this` (P0847), we can now create types whose call operator is an explicit object member function, which means that `decltype(&F::operator())` could have pointer-to-function type rather than pointer-to-member-function type. This means that the deduction guides for `std::function` (20.14.17.3.2 [func.wrap.func.con]) and `std::packaged_task` (32.9.10.2 [futures.task.members]) will simply fail:

>     struct F {
>       int operator()(this const F&) { return 42; }
>     };

>     std::function g = F{}; // error: decltype(&F::operator()) is not of the form R(G::*)(A...) cv &opt noexceptopt

We should update the deduction guides to keep them in line with the core language.

[2021-10-14; Reflector poll]

Set priority to 2 after reflector poll.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4892.

> 1. Modify 20.14.17.3.2 [func.wrap.func.con] as indicated:

>    >     template<class F> function(F) -> function<see below>;

>    > > -16- Constraints: `&F::operator()` is well-formed when treated as an unevaluated operand and `decltype(&F::operator())` is either of the form `R(G::*)(A...) cv &opt noexceptopt` or of the form `R(*)(G cv &opt, A...) noexceptopt` for a class type `G`.

>    > > -17- Remarks: The deduced type is `function<R(A...)>`.

> 2. Modify 32.9.10.2 [futures.task.members] as indicated:

>    >     template<class F> packaged_task(F) -> packaged_task<see below>;

>    > > -7- Constraints: `&F::operator()` is well-formed when treated as an unevaluated operand and `decltype(&F::operator())` is either of the form `R(G::*)(A...) cv &opt noexceptopt` or of the form `R(*)(G cv &opt, A...) noexceptopt` for a class type `G`.

>    > > -8- Remarks: The deduced type is `packaged_task<R(A...)>`.

[2021-10-17; Improved wording based on Tim Song's suggestion]

Proposed resolution:

This wording is relative to N4892.

1. Modify 20.14.17.3.2 [func.wrap.func.con] as indicated:

   >     template<class F> function(F) -> function<see below>;

   > > -16- Constraints: `&F::operator()` is well-formed when treated as an unevaluated operand and `decltype(&F::operator())` is either of the form `R(G::*)(A...) cv &opt noexceptopt` or of the form `R(*)(G, A...) noexceptopt` for a class type `G`.

   > > -17- Remarks: The deduced type is `function<R(A...)>`.

2. Modify 32.9.10.2 [futures.task.members] as indicated:

   >     template<class F> packaged_task(F) -> packaged_task<see below>;

   > > -7- Constraints: `&F::operator()` is well-formed when treated as an unevaluated operand and `decltype(&F::operator())` is either of the form `R(G::*)(A...) cv &opt noexceptopt` or of the form `R(*)(G, A...) noexceptopt` for a class type `G`.

   > > -8- Remarks: The deduced type is `packaged_task<R(A...)>`.

### 3620(i). What are execution character sets and execution wide-character sets (after P2314R4)?

Section: 16.3.3.3.5.1 [character.seq.general] Status: New Submitter: Dawn Perchik Opened: 2021-10-17 Last modified: 2022-01-29

Priority: 3

View all issues with New status.

Discussion:

The definitions for execution character set and execution wide-character set were reworded and moved to 16.3.3.3.5.1 [character.seq.general]/p1.2 after applying CWG motion 10 "P2314R4 Character sets and encodings", but I can't figure out what these terms mean from the wording, which now reads:

> "The execution character set and the execution wide-character set are supersets of the basic literal character set (5.3 [lex.charset]). The encodings of the execution character sets and the sets of additional elements (if any) are locale-specific."

Would it be possible to provide complete definitions for these and give examples of each?

[2022-01-29; Reflector poll]

Set priority to 3 after reflector poll. Should say something, even if just "unspecified". P1885R9 will expose the possible encoding programmatically, so could say it's implementationd-defined and implementations can document that you should ask `std::text_encoding`.

Proposed resolution:

### 3622(i). Misspecified transitivity of equivalence in §[unord.req.general]

Section: 22.2.7.1 [unord.req.general] Status: New Submitter: Thomas Köppe Opened: 2021-10-20 Last modified: 2021-10-24

Priority: 2

View all issues with New status.

Discussion:

The paper P2077R3 ("Heterogeneous erasure overloads for associative containers") adds a new variable `kx` with specific meaning for use in the Table of Unordered Associative Container Requirements, 22.2.7.1 [unord.req.general] p11, which is meant to stand for an equivalence class of heterogeneous values that can be compared with container keys.

One property required of `kx` is transitivity of equality/equivalence, but this is currently specified as:

> "`kx` is a value such that […] `(eq(r1, kx) && eq(r1, r2)) == eq(r2, kx)` […], where `r1` and `r2` are [any] keys".

But this doesn't seem right. Transitivity means that `eq(r1, kx) && eq(r1, r2)` being true implies `eq(r2, kx)` being true, but it does not imply that both sides are equal in general. In particular, `eq(r2, kx)` can be true even when `eq(r1, kx) && eq(r1, r2)` is false.

More abstractly, equality is transitive, but inequality is not.

The new wording appears to have been copied from the pre-existing wording for the variable "`ke`", which suffers from the same problem, and so we propose to fix both cases.

[2022-01-29; Reflector poll]

Set priority to 2 after reflector poll.

Proposed resolution:

This wording is relative to N4901.

1. Modify 22.2.7.1 [unord.req.general] as indicated:

   > 1. […]

   > 2. (11.19) — `ke` is a value such that

   >    1. (11.19.1) — `eq(r1, ke) == eq(ke, r1)`,

   >    2. (11.19.2) — `hf(r1) == hf(ke)` if `eq(r1, ke)` is `true`, and

   >    3. (11.19.3) — `(eq(r1, ke) && eq(r1, r2)) == eq(r2, ke)``eq(ke, r2)` is `true` if `eq(ke, r1) && eq(r1, r2)` is `true`,

   >    where `r1` and `r2` are keys of elements in `a_tran`,

   > 3. (11.20) — `kx` is a value such that

   >    1. (11.20.1) — `eq(r1, kx) == eq(kx, r1)`,

   >    2. (11.20.2) — `hf(r1) == hf(kx)` if `eq(r1, kx)` is `true`,

   >    3. (11.20.3) — `(eq(r1, kx) && eq(r1, r2)) == eq(r2, kx)``eq(kx, r2)` is `true` if `eq(kx, r1) && eq(r1, r2)` is `true`, and

   >    4. (11.20.4) — `kx` is not convertible to either `iterator` or `const_iterator`,

   >    where `r1` and `r2` are keys of elements in `a_tran`,

   > 4. […]

### 3623(i). Uses of `std::reverse_iterator` with containers should not require manually including `<iterator>`

Section: 23.5.1.1 [reverse.iterators.general] Status: New Submitter: Jiang An Opened: 2021-10-23 Last modified: 2021-10-24

Priority: 3

View all issues with New status.

Discussion:

Currently it is unspecified whether the definitions of `std::reverse_iterator` and its related operators are available in `<vector>`, `<array>`, etc. So, it's unspecified now whether the following program is well-formed because it's unspecified whether the equality operator is available:

>     #include <vector>

>     int main()
>     {
>       auto v = std::vector<int>(42);
>       for (auto it = v.rbegin(); it != v.rend(); ++it);
>       for (auto it = std::rbegin(v); it != std::rend(v); ++it);
>     }

Such underspecification also leaves the guarantee that `std::rbegin`, `std::rend`, `std::crbegin`, and `std::crend` are available in some other headers seems not so meaningful. In order to guarantee these function templates can be used meaningfully with containers, users are still required to include `<iterator>` manually.

I think the standard should guarantee that wherever the member `rbegin` (that returns `std::reverse_iterator`) or `std::rbegin` is provided, the definitions of `std::reverse_iterator` and its related operators are also provided. This strategy is already implemented by libc++, libstdc++, and MSVC STL, and thus I believe we should standardize it to reduce uncertainty for users.

Note that the situation for `std::reverse_iterator` is different from LWG 1361, because every operation on `std::size_t` is still valid when the typedef-name itself is absent, but `==` and `!=` on `std::reverse_iterator` fail if the corresponding declarations are unavailable.

[2022-01-29; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

This wording is relative to N4901.

1. Modify 23.5.1.1 [reverse.iterators.general] as indicated:

   > -1- Class template `reverse_iterator` is an iterator adaptor that iterates from the end of the sequence defined by its underlying iterator to the beginning of that sequence.

   > -?- In addition to being available via inclusion of the `<iterator>` header, class template `reverse_iterator` and function templates in 23.5.1.8 [reverse.iter.cmp] and 23.5.1.9 [reverse.iter.nonmember] are available when any of the following headers are included: `<array>` (22.3.2 [array.syn]), `<deque>` (22.3.3 [deque.syn]), `<forward_list>` (22.3.4 [forward.list.syn]), `<list>` (22.3.5 [list.syn]), `<map>` (22.4.2 [associative.map.syn]), `<regex>` (30.3 [re.syn]), `<set>` (22.4.3 [associative.set.syn]), `<span>` (22.7.2 [span.syn]), `<stacktrace>` (20.21.2 [stacktrace.syn]), `<string>` (21.3.2 [string.syn]), `<string_view>` (21.4.2 [string.view.synop]), `<unordered_map>` (22.5.2 [unord.map.syn]), `<unordered_set>` (22.5.3 [unord.set.syn]), and `<vector>` (22.3.6 [vector.syn]).

### 3624(i). Inconsistency of `<typeinfo>`, `<initializer_list>`, and `<compare>` in the standard library

Section: 17.7 [support.rtti], 17.10 [support.initlist], 17.11 [cmp] Status: New Submitter: Jiang An Opened: 2021-10-23 Last modified: 2021-10-24

Priority: 3

View all issues with New status.

Discussion:

Standard library headers `<typeinfo>`, `<initializer_list>`, and `<compare>` are required for some core language features, as specified in 7.6.1.8 [expr.typeid]/7, 9.4.5 [dcl.init.list]/2, and 7.6.8 [expr.spaceship]/8. In C++11 (via N2930), every header that has dependency on `std::initializer_list` is required to include `<initializer_list>`. The similar requirements are added for `operator<=>` and `<compare>` in C++20 (via LWG 3330).

As N2930 and LWG3330 have been adpoted, IMO there are some inconsistencies in the standard library now:

- No operation is done for `<typeinfo>`, although `<typeindex>` (`std::type_index`), `<functional>` (`std::function`, since C++11), and `<any>` (`std::any`) have dependency on `std::type_info`;

- `<iterator>` has dependency on `std::initializer_list` since C++14/LWG 2128 (the `std::rbegin` overload and its friends), but it is not required to include `<initializer_list>`;

- `<stacktrace>` is not required to include `<compare>` while it provides operator `<=>` overloads.

The situation may be quite serious for `std::type_index`. Perhaps no expected operation on `std::type_index` is guaranteed to work when only `<typeindex>` but not `<typeinfo>` is included.

libc++, libstdc++, and MSVC STL include `<typeinfo>` and `<initializer_list>` when the required standard interface depends on them. I think we should standardize the existing practice (except that `<stackstrace>` has not been implemented now) to reduce uncertainty for users.

[2021-10-24; Daniel comments]

This issue is related to and depending on LWG 3625.

[2022-01-29; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

This wording is relative to N4901.

> [Drafting note: The proposed wording below contains one conditional change, it is therefore depending upon LWG 3625.]

1. Add `#include <typeinfo>` to 20.8.2 [any.synop], 20.14.2 [functional.syn], and 20.17.1 [type.index.synopsis].

2. Add `#include <initializer_list>` to 23.2 [iterator.synopsis].

3. Add `#include <compare>` to 20.21.2 [stacktrace.syn].

4. If we decide to add range access function templates (23.7 [iterator.range]) to `<stacktrace>`, we should also add `#include <initializer_list>` to 20.21.2 [stacktrace.syn].

### 3625(i). Should `<stacktrace>` provide range access function templates?

Section: 20.21.2 [stacktrace.syn], 23.7 [iterator.range] Status: New Submitter: Jiang An Opened: 2021-10-23 Last modified: 2021-10-24

Priority: 3

View other active issues in [stacktrace.syn].

View all other issues in [stacktrace.syn].

View all issues with New status.

Discussion:

Range access function templates (23.7 [iterator.range]) are available in every standard header for containers. As `std::basic_stacktrace` provides some container-like interfaces (member functions `begin`, `end`, `size`, etc.), should we add these free function templates to `<stacktrace>` for consistency?

[2021-10-24; Daniel comments]

This issue is related to LWG 3624.

[2022-01-29; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

This wording is relative to N4901.

> [Drafting note: The proposed wording below contains one conditional change, it is therefore depending upon a decision]

1. Modify 23.7 [iterator.range] as indicated:

   > -1- In addition to being available via inclusion of the `<iterator>` header, the function templates in 23.7 [iterator.range] are available when any of the following headers are included: `<array>` (22.3.2 [array.syn]), `<deque>` (22.3.3 [deque.syn]), `<forward_list>` (22.3.4 [forward.list.syn]), `<list>` (22.3.5 [list.syn]), `<map>` (22.4.2 [associative.map.syn]), `<regex>` (30.3 [re.syn]), `<set>` (22.4.3 [associative.set.syn]), `<span>` (22.7.2 [span.syn]), `<stacktrace>` (20.21.2 [stacktrace.syn]), `<string>` (21.3.2 [string.syn]), `<string_view>` (21.4.2 [string.view.synop]), `<unordered_map>` (22.5.2 [unord.map.syn]), `<unordered_set>` (22.5.3 [unord.set.syn]), and `<vector>` (22.3.6 [vector.syn]). […]

2. If we decide that `<initializer_list>` should be included if the header has dependency on `std::initializer_list` (it may be introduce by `std::rbegin`, `std::data`, etc.), `#include <initializer_list>` should also be added to 20.21.2 [stacktrace.syn].

### 3626(i). Is `std::basic_stacktrace` required to use contiguous storage?

Section: 20.21.4.1 [stacktrace.basic.overview] Status: New Submitter: Jiang An Opened: 2021-10-23 Last modified: 2021-10-27

Priority: 3

View all issues with New status.

Discussion:

Currently `std::basic_stacktrace` has an exposition-only `std::vector` member for storing its elements. According to 16.3.3.5 [objects.within.classes]/3, it seems that it is effectively required that elements of a `std::basic_stacktrace` are contiguously stored. However, the implication seems not used otherwhere. The iterator type of a `std::basic_stacktrace` is only required to be random access iterator.

IMO if it is required that `std::basic_stacktrace` uses contiguous storage, we should explicitly strengthen some requirements, perhaps a the member function data should be added.

[2022-01-29; Reflector poll]

Set priority to 3 after reflector poll.
"The problem here is that a handful of member functions (`operator[]`, `at`, perhaps `begin`) expose references to the vector elements directly, which can be read to require contiguity. We should rephrase the members at issue to not do that."

Proposed resolution:

This wording is relative to N4901.

> [Drafting note: The proposed wording below contains also conditional changes, it is therefore depending upon a decision]

1. Modify 20.21.4.1 [stacktrace.basic.overview] as indicated:

   > -1- The class template `basic_stacktrace` satisfies the requirements of an allocator-aware container (Table 80 [tab:container.alloc.req]), a sequence container (22.2.3 [sequence.reqmts]), a contiguous container, and a reversible container (22.2.1 [container.requirements.general]) except that […]

2. Modify 20.21.4.3 [stacktrace.basic.obs] as indicated:

   >     using const_iterator = implementation-defined;

   > > -1- The type models `random_access_iteratorcontiguous_iterator` (23.3.4.13 [iterator.concept.random.access]23.3.4.14 [iterator.concept.contiguous]) and meets the Cpp17RandomAccessIterator requirements (23.3.5.7 [random.access.iterators]).

Optional additional changes (the following parts are proposed only if `data()` is wanted)

3. Modify 20.21.4.1 [stacktrace.basic.overview], class template `basic_stacktrace` synopsis, as indicated:

   >     […]
   >     const_reference operator[](size_type) const;
   >     const_reference at(size_type) const;

   >     const stacktrace_entry* data() const noexcept;

   >     // 20.21.4.4 [stacktrace.basic.cmp], comparisons
   >     […]

4. Modify 20.21.4.3 [stacktrace.basic.obs] as indicated:

   >     const_reference at(size_type frame_no) const;

   > > -13- […]

   > > -14- […]

   >     const stacktrace_entry* data() const noexcept;

   > > -?- Returns: `frames_.data()`.

### 3627(i). Inconsistent specifications for `std::make_optional` overloads

Section: 20.6.9 [optional.specalg] Status: New Submitter: Jiang An Opened: 2021-10-23 Last modified: 2021-10-24

Priority: 3

View all issues with New status.

Discussion:

Three `std::make_optional` overloads are specified in 20.6.9 [optional.specalg]. The first one is specified by "Returns:" and the other two are specified by "Effects: Equivalent to:". According to 16.3.2.4 [structure.specifications]/4, such uses of "Effects: Equivalent to:" propagate the Constraints specified for constructors. As the selected constructor for the first overload has "Constraints:" (20.6.3.2 [optional.ctor]/22), it seems that inconsistency is introduced here.

Existing implementations are inconsistent: libstdc++ constrains all three overloads, while libc++ and MSVC STL do not constrain any of them.

IMO all three overloads should be constrained.

[2022-01-29; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

This wording is relative to N4901.

1. Modify 20.6.9 [optional.specalg] as indicated:

   >     template<class T> constexpr optional<decay_t<T>> make_optional(T&& v);

   > > -3- Returns Effects: Equivalent to: `return optional<decay_t<T>>(std::forward<T>(v));`.

### 3628(i). "Effects: Equivalent to:" and uninitialized memory algorithms

Section: 25.11 [specialized.algorithms] Status: New Submitter: Jiang An Opened: 2021-10-23 Last modified: 2022-01-29

Priority: 3

View other active issues in [specialized.algorithms].

View all other issues in [specialized.algorithms].

View all issues with New status.

Discussion:

Most uninitialized memory algorithms (25.11 [specialized.algorithms]) are specified by plain "Effects: Equivalent to:". According to 16.3.2.4 [structure.specifications]/4, such wording requires propagation of "Constraints" of selected constructors. The first two overloads of `std::reduce` (25.10.4 [reduce]) are specified similarly.

I feel the wording for uninitialized memory algorithms is incorrect, because it means that the constraints, especially for algorithms in the `std`, depend on "`Constraints`" in the specifications of many standard library types (but not any user-defined type), which is implementable but brings serious inconsistency.

Perhaps we should add "Mandates:" to these algorithms (except for algorithms in `std::ranges`).

[2022-01-29; Reflector poll]

Set priority to 3 after reflector poll.
Tim: "P2. Not for this particular case (I'm pretty sure there'll be agreement that this shouldn't induce any constraint), but for the more general issue of "Effects: Equivalent to" propagating Constraints:; I'm not sure that's the right approach in general (unlike the other elements, Constraints: requires special handling beyond "use this code" and is pretty hard to work through if we have a lengthy code block) - and it certainly doesn't really make a lot of sense to propagate Constraints: but not actual core-language constraints."

Proposed resolution:

### 3629(i). `make_error_code` and `make_error_condition` are customization points

Section: 19.5 [syserr] Status: New Submitter: Jonathan Wakely Opened: 2021-10-31 Last modified: 2021-10-31

Priority: 2

View all other issues in [syserr].

View all issues with New status.

Discussion:

The rule in 16.4.2.2 [contents] means that the calls to `make_error_code` in 19.5.4.2 [syserr.errcode.constructors] and 19.5.4.3 [syserr.errcode.modifiers] are required to call `std::make_error_code`, which means program-defined error codes do not work. The same applies to the `make_error_condition` calls in 19.5.5.2 [syserr.errcondition.constructors] and 19.5.5.3 [syserr.errcondition.modifiers].

They need to use ADL. This is what all known implementations (including Boost.System) do.

[2022-01-29; Reflector poll]

Set priority to 2 after reflector poll.

Proposed resolution:

This wording is relative to N4901.

1. Modify 19.5.2 [system.error.syn] as indicated:

   > -1- The value of each `enum errc` constant shall be the same as the value of the `<cerrno>` macro shown in the above synopsis. Whether or not the `<system_error>` implementation exposes the `<cerrno>` macros is unspecified.

   > -?- Invocations of `make_error_code` and `make_error_condition` shown in subclause 19.5 [syserr] select a function to call via overload resolution (12.2 [over.match]) on a candidate set that includes the lookup set found by argument dependent lookup (6.5.4 [basic.lookup.argdep]).

   > -2- The `is_error_code_enum` and `is_error_condition_enum` templates may be specialized for program-defined types to indicate that such types are eligible for `class error_code` and `class error_condition` implicit conversions, respectively.

   > [Note 1: Conversions from such types are done by program-defined overloads of `make_error_code` and `make_error_condition`, found by ADL. —end note]

### 3630(i). Inconsistent `basic_regex` construction and assignment from iterator range

Section: 30.7.2 [re.regex.construct] Status: New Submitter: Jonathan Wakely Opened: 2021-10-31 Last modified: 2021-10-31

Priority: 4

View other active issues in [re.regex.construct].

View all other issues in [re.regex.construct].

View all issues with New status.

Discussion:

We have:

    template<class ForwardIterator>
      basic_regex(ForwardIterator first, ForwardIterator last,
                  flag_type f = regex_constants::ECMAScript);

and:

    template<class InputIterator>
      basic_regex& assign(InputIterator first, InputIterator last,
                              flag_type f = regex_constants::ECMAScript);

Ignoring the lack of proper requirements (which is LWG 3341), why does the constructor take forward iterators, but the assign function takes input iterators? Why could construction from input iterators not be implemented as simply `assign(first, last, f)`?

The current constructor signature is the result of N2409 which was resolving LWG 682. It looks like the `assign` function should have been changed at the same time, to keep them consistent. I see no reason why they can't both take input iterators. The meta-programming needed to avoid an additional string copy for the input iterator case is trivial with `if constexpr` and C++20 iterator concepts.

[2022-01-29; Reflector poll]

Set priority to 4 after reflector poll.

Proposed resolution:

### 3631(i). `basic_format_arg(T&&)` should use `remove_cvref_t<T>` throughout

Section: 20.20.7.1 [format.arg] Status: New Submitter: Tim Song Opened: 2021-11-03 Last modified: 2021-11-06

Priority: 3

View all other issues in [format.arg].

View all issues with New status.

Discussion:

P2418R2 changed `basic_format_arg`'s constructor to take a forwarding reference but didn't change 20.20.7.1 [format.arg]/5 which inspects various properties of `T`. Now that the deduced type can be cvref-qualified, they need to be removed before the checks.

[2022-01-29; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

This wording is relative to N4901.

1. Modify 20.20.7.1 [format.arg] as indicated:

   >     template<class T> explicit basic_format_arg(T&& v) noexcept;

   > > -?- Let `TD` be `remove_cvref_t<T>`.

   > > -4- Constraints: The template specialization

   > > >     typename Context::template formatter_type<remove_cvref_t<T>TD>

   > > meets the BasicFormatter requirements (20.20.6.1 [formatter.requirements]). The extent to which an implementation determines that the specialization meets the BasicFormatter requirements is unspecified, except that as a minimum the expression

   > > >     typename Context::template formatter_type<remove_cvref_t<T>TD>()
   > > >       .format(declval<T&>(), declval<Context&>())

   > > shall be well-formed when treated as an unevaluated operand (7.2.3 [expr.context]).

   > > -5- Effects:

   > > 1. (5.1) — if `TD` is `bool` or `char_type`, initializes `value` with `v`;

   > > 2. (5.2) — otherwise, if `TD` is `char` and `char_type` is `wchar_t`, initializes `value` with `static_cast<wchar_t>(v)`;

   > > 3. (5.3) — otherwise, if `TD` is a signed integer type (6.8.2 [basic.fundamental]) and `sizeof(TD) <= sizeof(int)`, initializes `value` with `static_cast<int>(v)`;

   > > 4. (5.4) — otherwise, if `TD` is an unsigned integer type and `sizeof(TD) <= sizeof(unsigned int)`, initializes `value` with `static_cast<unsigned int>(v)`;

   > > 5. (5.5) — otherwise, if `TD` is a signed integer type and `sizeof(TD) <= sizeof(long long int)`, initializes `value` with `static_cast<long long int>(v)`;

   > > 6. (5.6) — otherwise, if `TD` is an unsigned integer type and `sizeof(TD) <= sizeof(unsigned long long int)`, initializes `value` with `static_cast<unsigned long long int>(v)`;

   > > 7. (5.7) — otherwise, initializes `value` with `handle(v)`.

### 3633(i). Atomics are copy constructible and copy assignable from `volatile` atomics

Section: 31 [atomics] Status: New Submitter: Wesley Maxey Opened: 2021-11-05 Last modified: 2022-01-29

Priority: 3

View all other issues in [atomics].

View all issues with New status.

Discussion:

The specification of `atomic` and `atomic<T*>` (in 31.8.1 [atomics.types.generic.general] and 31.8.5 [atomics.types.pointer]) explicitly deletes the following functions:

>     atomic(const atomic&) = delete;
>     atomic& operator=(const atomic&) = delete;
>     atomic& operator=(const atomic&) volatile = delete;

The intent is to make atomic objects not copyable, so that initializing an atomic object from another atomic, or assigning an atomic object with a value from another atomic, must be an explicit operation.

We also explicitly support `volatile` objects of types that are specializations of `std::atomic`; some of the functions that are vital for the support of volatile atomics are the following conversion operators:

>     operator T() const volatile noexcept; // for non-pointers
>     operator T*() const volatile noexcept; // for pointers

The presence of this conversion operator means that all the statements in the following piece of code compile successfully today, despite the deleted functions mentioned earlier:

>     volatile std::atomic<int> a;
>     volatile std::atomic<int> b(a);
>     std::atomic<int> c(a);
>     b = a;
>     c = a;

However, if `a` is not a volatile object, none of the last four lines compile.

[2022-01-29; Reflector poll]

Set priority to 3 after reflector poll.
This PR would allow

    atomic<int> x, y = std::move(x);

because const volatile& doesn't bind to rvalues. It sounds like we'll need to delete both const volatile& and const volatile&&.

Proposed resolution:

This wording is relative to N4901.

1. Modify 31.8.1 [atomics.types.generic.general], class template `atomic` synopsis, as indicated:

   >     […]
   >     atomic(const volatile atomic&) = delete;
   >     atomic& operator=(const volatile atomic&) = delete;
   >     atomic& operator=(const volatile atomic&) volatile = delete;
   >     […]

2. Modify 31.8.3 [atomics.types.int], class template `atomic<integral>` specialization synopsis, as indicated:

   >     […]
   >     atomic(const volatile atomic&) = delete;
   >     atomic& operator=(const volatile atomic&) = delete;
   >     atomic& operator=(const volatile atomic&) volatile = delete;
   >     […]

3. Modify 31.8.4 [atomics.types.float], class template `atomic<floating-point>` specialization synopsis, as indicated:

   >     […]
   >     atomic(const volatile atomic&) = delete;
   >     atomic& operator=(const volatile atomic&) = delete;
   >     atomic& operator=(const volatile atomic&) volatile = delete;
   >     […]

4. Modify 31.8.5 [atomics.types.pointer], class template `atomic<T*>` partial specialization synopsis, as indicated:

   >     […]
   >     atomic(const volatile atomic&) = delete;
   >     atomic& operator=(const volatile atomic&) = delete;
   >     atomic& operator=(const volatile atomic&) volatile = delete;
   >     […]

### 3634(i). When are static-duration `memory_resource` objects destroyed?

Section: 20.12.4 [mem.res.global], 19.5.3.5 [syserr.errcat.objects] Status: New Submitter: Jiang An Opened: 2021-11-07 Last modified: 2022-01-29

Priority: 3

View all other issues in [mem.res.global].

View all issues with New status.

Discussion:

Both `std::pmr::new_delete_resource` and `std::pmr::null_memory_resource` return pointers to static-duration objects. It seems unspecified when the pointed-to objects are destroyed, so users can't reliably use these objects during destructions of their static-duration objects.

`std::generic_category` and `std::system_category` have the same issue, except that the referred-to objects may have different storage duration.

Should we specify in which case can these objects be used in the termination of a program?

[2022-01-29; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

### 3635(i). Add `__cpp_lib_deduction_guides` to feature test macros

Section: 17.3.2 [version.syn] Status: New Submitter: Konstantin Varlamov Opened: 2021-11-09 Last modified: 2021-11-21

Priority: 3

View all other issues in [version.syn].

View all issues with New status.

Discussion:

P0433R2, the proposal for adding deduction guides to the standard library, contained a recommendation to use `__cpp_lib_deduction_guides` as a feature test macro. However, it appears that this feature test macro has been accidentally omitted from the Standard when the paper was applied and probably needs to be added back.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4901.

> 1. Modify 17.3.2 [version.syn] as indicated:

>    >     […]
>    >     #define __cpp_lib_coroutine          201902L  // also in <coroutine>
>    >     #define __cpp_lib_deduction_guides   201703L
>    >       // also in <deque>, <forward_list>, <list>, <map>, <queue>, <set>, <stack>,
>    >       // <unordered_map>, <unordered_set>, <vector>
>    >     #define __cpp_lib_destroying_delete  201806L  // also in <new>
>    >     […]

[2021-11-16; Konstantin Varlamov comments and improves wording]

One potential topic of discussion is whether the new feature test macro needs to be defined in every library header that contains an explicit deduction guide. While this would be consistent with the current approach, no other macro is associated with such a large set of headers (20 headers in total, whereas the current record-holder is `__cpp_lib_nonmember_container_access` with 12 headers). For this reason, it should be considered whether perhaps the new macro should only be defined in `<version>` (which would, however, make it an outlier). The proposed wording currently contains an exhaustive list (note that the deduction guides for `<mutex>` were removed by LWG 2981).

[2022-01-30; Reflector poll]

Set priority to 3 after reflector poll. Several votes for NAD as it's too late to be useful, and code which needs to be portable to pre-CTAD compilers can just not use CTAD.

Proposed resolution:

This wording is relative to N4901.

1. Modify 17.3.2 [version.syn] as indicated:

   >     […]
   >     #define __cpp_lib_coroutine          201902L  // also in <coroutine>
   >     #define __cpp_lib_deduction_guides   201703L
   >       // also in <array>, <deque>, <forward_list>, <functional>, <list>, <map>,
   >       // <memory>, <optional>, <queue>, <regex>, <scoped_allocator>, <set>, <stack>,
   >       // <string>, <tuple>, <unordered_map>, <unordered_set>, <utility>, <valarray>,
   >       // <vector>
   >     #define __cpp_lib_destroying_delete  201806L  // also in <new>
   >     […]

### 3636(i). `formatter<T>::format` should be `const`-qualified

Section: 20.20.6.1 [formatter.requirements] Status: New Submitter: Arthur O'Dwyer Opened: 2021-11-11 Last modified: 2021-11-20

Priority: 1

View all other issues in [formatter.requirements].

View all issues with New status.

Discussion:

In libc++ review, we've noticed that we don't understand the implications of 20.20.6.1 [formatter.requirements] bullet 3.1 and Table [tab:formatter.basic]: (emphasize mine):

> (3.1) — `f` is a value of type `F`,

> […]

> Table 70: BasicFormatter requirements [tab:formatter.basic]

> […]

> `f.parse(pc)` [must compile] […]

> `f.format(u, fc)` [must compile] […]

According to Victor Zverovich, his intent was that `f.parse(pc)` should modify the state of `f`, but `f.format(u, fc)` should merely read `f`'s state to support format string compilation where formatter objects are immutable and therefore the `format` function must be `const`-qualified.

That is, a typical formatter should look something like this (modulo errors introduced by me):

>     struct WidgetFormatter {
>       auto parse(std::format_parse_context&) -> std::format_parse_context::iterator;
>       auto format(const Widget&, std::format_context&) const -> std::format_context::iterator;
>     };

However, this is not reflected in the wording, which treats `parse` and `format` symmetrically. Also, there is at least one example that shows a non-const `format` method:

>     template<> struct std::formatter<color> : std::formatter<const char*> {
>       auto format(color c, format_context& ctx) {
>         return formatter<const char*>::format(color_names[c], ctx);
>       }
>     };

Victor writes:

> Maybe we should […] open an LWG issue clarifying that all standard formatters have a `const` format function.

I'd like to be even more assertive: Let's open an LWG issue clarifying that all formatters must have a `const` format function!

[2022-01-30; Reflector poll]

Set priority to 1 after reflector poll.

Proposed resolution:

This wording is relative to N4901.

1. Modify 20.20.6.1 [formatter.requirements] as indicated:

   > [Drafting note: It might also be reasonable to do a drive-by clarification that when the Table 70 says "Stores the parsed format specifiers in `*this`," what it actually means is "Stores the parsed format specifiers in `g`." (But I don't think anyone's seriously confused by that wording.)

   > -3- Given character type `charT`, output iterator type `Out`, and formatting argument type `T`, in Table 70 and Table 71:

   > 1. (3.1) — `f` is a value of type (possibly `const`) `F`,

   > 2. (3.?) — `g` is an lvalue of type `F`,

   > 3. (3.2) — `u` is an lvalue of type `T`,

   > 4. (3.3) — `t` is a value of a type convertible to (possibly `const`) `T`,

   > 5. […]

   > […]

   > > Table 70: Formatter requirements [tab:formatter]
   > > Expression | Return type | Requirement
   > > --- | --- | ---
   > > `fg.parse(pc)` | `PC::iterator` | […] Stores the parsed format specifiers in `*this` and returns an iterator past the end of the parsed range.
   > > `…`

2. Modify 20.20.6.2 [format.formatter.spec] as indicated:

   > -6- An enabled specialization `formatter<T, charT>` meets the BasicFormatter requirements (20.20.6.1 [formatter.requirements]).

   > [Example 1:

   > >     #include <format>

   > >     enum color { red, green, blue };
   > >     const char* color_names[] = { "red", "green", "blue" };

   > >     template<> struct std::formatter<color> : std::formatter<const char*> {
   > >       auto format(color c, format_context& ctx) const {
   > >         return formatter<const char*>::format(color_names[c], ctx);
   > >       }
   > >     };

   > >     […]

   > — end example]

3. Modify 20.20.6.4 [format.context] as indicated:

   >     void advance_to(iterator it);

   > > -8- Effects: Equivalent to: `out_ = std::move(it);`

   > > [Example 1:

   > > >     struct S { int value; };

   > > >     template<> struct std::formatter<S> {
   > > >       size_t width_arg_id = 0;

   > > >       // Parses a width argument id in the format { digit }.
   > > >       constexpr auto parse(format_parse_context& ctx) {
   > > >         […]
   > > >       }

   > > >       // Formats an S with width given by the argument width_arg_id.
   > > >       auto format(S s, format_context& ctx) const {
   > > >         int width = visit_format_arg([](auto value) -> int {
   > > >           if constexpr (!is_integral_v<decltype(value)>)
   > > >             throw format_error("width is not integral");
   > > >           else if (value < 0 || value > numeric_limits<int>::max())
   > > >             throw format_error("invalid width");
   > > >           else
   > > >             return value;
   > > >           }, ctx.arg(width_arg_id));
   > > >         return format_to(ctx.out(), "{0:x<{1}}", s.value, width);
   > > >       }
   > > >     };

   > > >     […]

   > > — end example]

4. Modify 27.12 [time.format] as indicated:

   >     template<class Duration, class charT>
   >     struct formatter<chrono::local-time-format-t<Duration>, charT>;

   > > -15- Let `f` be […]

   > > -16- Remarks: […]

   > >     template<class Duration, class TimeZonePtr, class charT>
   > >     struct formatter<chrono::zoned_time<Duration, TimeZonePtr>, charT>
   > >       : formatter<chrono::local-time-format-t<Duration>, charT> {
   > >       template<class FormatContext>
   > >         typename FormatContext::iterator
   > >           format(const chrono::zoned_time<Duration, TimeZonePtr>& tp, FormatContext& ctx) const;
   > >     };

   >     template<class FormatContext>
   >       typename FormatContext::iterator
   >         format(const chrono::zoned_time<Duration, TimeZonePtr>& tp, FormatContext& ctx) const;

   > > -17- Effects: Equivalent to:

   > > >     sys_info info = tp.get_info();
   > > >     return formatter<chrono::local-time-format-t<Duration>, charT>::
   > > >              format({tp.get_local_time(), &info.abbrev, &info.offset}, ctx);

### 3637(i). `pmr::memory_resource::do_allocate` needs clarification

Section: 20.12.2 [mem.res.class] Status: New Submitter: Jonathan Wakely Opened: 2021-11-12 Last modified: 2021-11-14

Priority: 3

View all other issues in [mem.res.class].

View all issues with New status.

Discussion:

20.12.2.3 [mem.res.private] says that `pmr::memory_resource::do_allocate` returns "a pointer to allocated storage" and references 6.7.5.5.2 [basic.stc.dynamic.allocation]. But it's not really clear which parts of 6.7.5.5.2 [basic.stc.dynamic.allocation] define "allocated storage". `pmr::memory_resource::allocate` is not "an allocation function" and not a "replaceable allocation function", so "the value returned by a replaceable allocation function is a non-null pointer value" doesn't apply here, and neither does "different from any previously returned value".

Is `pmr::memory_resource::allocate` allowed to return a null pointer on success? Is it allowed to return the same address twice, without an intervening deallocation? What about if you call `pmr::monotonic_buffer_resource::release()`, is that a deallocation?

When discussed on the reflector the consensus was that returning null should not be allowed, it should throw an exception or return a valid dereferenceable pointer. The reference to 6.7.5.5.2 [basic.stc.dynamic.allocation] doesn't work to specify this though, so we should restate the requirements without directly using the core wording for `operator new`.

It was also suggested that returning the same value should not be allowed without an intervening deallocation, but that "deallocation" should not only mean a call to deallocate on the resource, but include things like `pmr::monotonic_buffer_resource::release()`, and when a memory resource's destructor returns memory to an upstream resource.

[2022-01-30; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

### 3638(i). `vector<bool>::swap(reference, reference)` is useless

Section: 22.3.12 [vector.bool] Status: New Submitter: Jonathan Wakely Opened: 2021-11-12 Last modified: 2022-01-22

Priority: 3

View other active issues in [vector.bool].

View all other issues in [vector.bool].

View all issues with New status.

Discussion:

`vector<bool>` provides a static member function that can be used to swap rvalues of type `vector<bool>::reference` like so:

>     vector<bool> v{true, false};
>     vector<bool>::swap(v[0], v[1]);

This is not useful. Nobody calls `swap` like that. This fails to make `v[0]` swappable with `v[1]` as per 16.4.4.3 [swappable.requirements]. The similar SGI STL `bit_vector` class that `vector<bool>` is partially inspired by has a "global function" with the same signature, described as:

> "Swaps the bits referred to by `x` and `y`. This is a global function, not a member function. It is necessary because the ordinary version of `swap` takes arguments of type `T&`, and `bit_vector::reference` is a class, not a built-in C++ reference."

For some reason this became a static member function of `vector<bool>` in the C++ standard.

We should restore the intended functionality, and deprecate the useless function.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4901.

> 1. Create a new subclause [vector.bool.general] below 22.3.12 [vector.bool] and move paragraphs p1-p3 (including the class template `vector<bool, Allocator>` partial specialization synopsis) into that subclause.

> 2. Add to the synopsis in [vector.bool.general] p1 (née 22.3.12 [vector.bool] p1):

>    >     […]
>    >     // bit reference
>    >     class reference {
>    >       friend class vector;
>    >       constexpr reference() noexcept;
>    >     public:
>    >       constexpr reference(const reference&) = default;
>    >       constexpr ~reference();
>    >       constexpr operator bool() const noexcept;
>    >       constexpr reference& operator=(bool x) noexcept;
>    >       constexpr reference& operator=(const reference& x) noexcept;
>    >       constexpr const reference& operator=(bool x) const noexcept;
>    >       constexpr void flip() noexcept; // flips the bit

>    >       friend constexpr void swap(reference x, reference y) noexcept;
>    >       friend constexpr void swap(reference x, bool& y) noexcept;
>    >       friend constexpr void swap(bool& x, reference y) noexcept;
>    >     };
>    >     […]

> 3. Remove the static `swap` function from the class template `vector<bool, Allocator>` partial specialization synopsis:

>    >     […]
>    >     constexpr void swap(vector&);
>    >     constexpr static void swap(reference x, reference y) noexcept;
>    >     constexpr void flip() noexcept; // flips all bits
>    >     […]

> 4. Create a new subclause [vector.bool.ref] after p3, with p4 as its first paragraph, and add after it:

>    > 22.3.12.? Class `vector<bool, Allocator>::reference` [vector.bool.ref]

>    > -1- `reference` is a class that simulates the behavior of references of a single bit in `vector<bool>`. The conversion function returns `true` when the bit is set, and `false` otherwise. The assignment operators set the bit when the argument is (convertible to) `true` and clear it otherwise. `flip` reverses the state of the bit.

>    >     constexpr void flip() noexcept;

>    > > -?- Effects: `*this = !*this;`

>    >      friend constexpr void swap(reference x, reference y) noexcept;
>    >      friend constexpr void swap(reference x, bool& y) noexcept;
>    >      friend constexpr void swap(bool& x, reference y) noexcept;

>    > > -?- Effects: Exchanges the contents of `x` and `y` as if by:

>    > > >     bool b = x;
>    > > >     x = y;
>    > > >     y = b;

> 5. Create a new subclause [vector.bool.mem] after that, containing the paragraphs describing `flip()` and the `hash` specialization:

>    > 22.3.12.? Class `vector<bool, Allocator>` members [vector.bool.mem]

>    >     constexpr void flip() noexcept;

>    > > -1- Effects: Replaces each element in the container with its complement.

>    >      constexpr static void swap(reference x, reference y) noexcept;

>    > > -6- Effects: Exchanges the contents of `x` and `y` as if by:

>    > > >     bool b = x;
>    > > >     x = y;
>    > > >     y = b;

>    >     template<class Allocator> struct hash<vector<bool, Allocator>>;

>    > > -7- The specialization is enabled (20.14.19 [unord.hash]).

> 6. Create a new subclause [depr.vector.bool.swap] after D.21 [depr.string.capacity]

>    > D.? Deprecated `vector<bool, Allocator>` swap [depr.vector.bool.swap]

>    > -?- The following member is declared in addition to those members specified in 22.3.12 [vector.bool]:

>    >     namespace std {
>    >       template<class Allocator> class vector<bool, Allocator> {
>    >       public:
>    >         constexpr static void swap(reference x, reference y) noexcept;
>    >       };
>    >     }

>    >     constexpr static void swap(reference x, reference y) noexcept;

>    > > -?- Effects: `swap(x, y)`.

[2022-01-22; Jonathan replaces `swap(x, y)` in the Annex D wording, following reflector discussion about lookup for `swap` finding itself in that context. ]

[2022-01-30; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

This wording is relative to N4901.

1. Create a new subclause [vector.bool.general] below 22.3.12 [vector.bool] and move paragraphs p1-p3 (including the class template `vector<bool, Allocator>` partial specialization synopsis) into that subclause.

2. Add to the synopsis in [vector.bool.general] p1 (née 22.3.12 [vector.bool] p1):

   >     […]
   >     // bit reference
   >     class reference {
   >       friend class vector;
   >       constexpr reference() noexcept;
   >     public:
   >       constexpr reference(const reference&) = default;
   >       constexpr ~reference();
   >       constexpr operator bool() const noexcept;
   >       constexpr reference& operator=(bool x) noexcept;
   >       constexpr reference& operator=(const reference& x) noexcept;
   >       constexpr const reference& operator=(bool x) const noexcept;
   >       constexpr void flip() noexcept; // flips the bit

   >       friend constexpr void swap(reference x, reference y) noexcept;
   >       friend constexpr void swap(reference x, bool& y) noexcept;
   >       friend constexpr void swap(bool& x, reference y) noexcept;
   >     };
   >     […]

3. Remove the static `swap` function from the class template `vector<bool, Allocator>` partial specialization synopsis:

   >     […]
   >     constexpr void swap(vector&);
   >     constexpr static void swap(reference x, reference y) noexcept;
   >     constexpr void flip() noexcept; // flips all bits
   >     […]

4. Create a new subclause [vector.bool.ref] after p3, with p4 as its first paragraph, and add after it:

   > 22.3.12.? Class `vector<bool, Allocator>::reference` [vector.bool.ref]

   > -1- `reference` is a class that simulates the behavior of references of a single bit in `vector<bool>`. The conversion function returns `true` when the bit is set, and `false` otherwise. The assignment operators set the bit when the argument is (convertible to) `true` and clear it otherwise. `flip` reverses the state of the bit.

   >     constexpr void flip() noexcept;

   > > -?- Effects: `*this = !*this;`

   >      friend constexpr void swap(reference x, reference y) noexcept;
   >      friend constexpr void swap(reference x, bool& y) noexcept;
   >      friend constexpr void swap(bool& x, reference y) noexcept;

   > > -?- Effects: Exchanges the contents of `x` and `y` as if by:

   > > >     bool b = x;
   > > >     x = y;
   > > >     y = b;

5. Create a new subclause [vector.bool.mem] after that, containing the paragraphs describing `flip()` and the `hash` specialization:

   > 22.3.12.? Class `vector<bool, Allocator>` members [vector.bool.mem]

   >     constexpr void flip() noexcept;

   > > -1- Effects: Replaces each element in the container with its complement.

   >      constexpr static void swap(reference x, reference y) noexcept;

   > > -6- Effects: Exchanges the contents of `x` and `y` as if by:

   > > >     bool b = x;
   > > >     x = y;
   > > >     y = b;

   >     template<class Allocator> struct hash<vector<bool, Allocator>>;

   > > -7- The specialization is enabled (20.14.19 [unord.hash]).

6. Create a new subclause [depr.vector.bool.swap] after D.21 [depr.string.capacity]

   > D.? Deprecated `vector<bool, Allocator>` swap [depr.vector.bool.swap]

   > -?- The following member is declared in addition to those members specified in 22.3.12 [vector.bool]:

   >     namespace std {
   >       template<class Allocator> class vector<bool, Allocator> {
   >       public:
   >         constexpr static void swap(reference x, reference y) noexcept;
   >       };
   >     }

   >     constexpr static void swap(reference x, reference y) noexcept;

   > > -?- Effects: Exchanges the contents of `x` and `y` as if by:

   > > >     bool b = x;
   > > >     x = y;
   > > >     y = b;

### 3639(i). Handling of fill character width is underspecified in `std::format`

Section: 20.20.2.2 [format.string.std] Status: SG16 Submitter: Victor Zverovich Opened: 2021-11-13 Last modified: 2021-11-14

Priority: 3

View other active issues in [format.string.std].

View all other issues in [format.string.std].

View all issues with SG16 status.

Discussion:

20.20.2.2 [format.string.std] doesn't specify if implementations should consider the estimated width of the fill character when substituting it into the formatted results.

For example:

>     auto s = std::format("{:🤡>10}", 42);

`"🤡"` (U+1F921) is a single code point but its estimated display width is two.

There are at least three possible resolutions:

1. `s == "🤡🤡🤡🤡42"`: use the estimated display width, correctly displayed on compatible terminals.

2. `s == "🤡🤡🤡🤡🤡🤡🤡🤡42"`: assume the display width of 1, incorrectly displayed.

3. Require the fill character to have the estimated width of 1.

[2021-11-14; Daniel comments]

Resolving this issue should be harmonized with resolving LWG 3576.

[2022-01-30; Reflector poll]

Set priority to 3 after reflector poll. Sent to SG16.

Proposed resolution:

### 3640(i). Clarify which exceptions are propagated

Section: 16.4.4 [utility.requirements] Status: New Submitter: Johel Ernesto Guerrero Peña Opened: 2021-11-01 Last modified: 2021-11-14

Priority: 3

View all issues with New status.

Discussion:

This originated from the editorial issues #4863 and #4869.

Some Throws: elements are specified to throw the exceptions an evaluation of `E` exits with. This wording excludes exceptions thrown involving the initialization and destruction of parameters of `E`, temporaries of `E`, and the destruction of the result of `E`.

The proposed wording below fixes this with front matter. As if affects more than just Throws: elements, it talks about requirements and guarantees when `E` exits via an exception.

As noted in the originating editorial issues, some LWG members prefer fixing each individual case of wording used to describe exception propagation rather than patching them up with front matter.

[2022-01-30; Reflector poll]

Set priority to 3 after reflector poll. "Any throwing destructor is library UB already, so there's no need to contort the wording to accommodate those."

Proposed resolution:

This wording is relative to N4901.

1. Add a new subclause [exception.propagation] at the end of 16.4.4 [utility.requirements] (after 16.4.4.6.2 [allocator.requirements.completeness]):

   > 16.4.4.? Exception propagation requirements [exception.propagation]

   > -?- Some functions defined in the C++ standard library impose requirements and guarantees R-G when a described evaluation `E` exits via an exception. Let `F` be an evaluation that is implied by evaluating `E` up to the complete evaluation of its enclosing full-expression. Unless stated otherwise, an execution of `F` that exits via an exception also has R-G imposed. [Note ?: This includes when initializing and destroying parameters, evaluating default arguments, and destroying temporaries (including discarded-value expressions) (7.6.1.3 [expr.call]) exit via an exception. — end note]

### 3641(i). Add `operator==` to `format_to_n_result`

Section: 20.20.1 [format.syn] Status: New Submitter: Mark de Wever Opened: 2021-11-14 Last modified: 2021-11-14

Priority: 3

View all issues with New status.

Discussion:

During the 2019 Cologne meeting the papers P1614R2 "The Mothership has Landed" and P0645R10 "Text Formatting" have been accepted. P1614R2 adds `operator==` to `to_chars_result` and `from_chars_result`. P0645R10 adds a similar type `format_to_n_result` without an `operator==`. LWG 3373 reaffirms these three types are similar by ensuring they can be used in structured bindings.

It seems due to accepting P1614R2 and P0645R10 during the same meeting the addition of `operator==` wasn't applied to `format_to_n_result`. I propose to add `operator==` to `format_to_n_result` to keep these types similar.

The `Out` template argument of `format_to_n_result` is unconstrained. Since it's returned from `format_to_n` it's indirectly constrained to an `output_iterator`. An `output_iterator` doesn't require `equality_comparable`, thus the defaulted `operator==` can be defined deleted.

[2022-01-30; Reflector poll]

Set priority to 3 after reflector poll. Several votes for NAD. Unclear why `to_chars_result` is equality comparable, but whatever the reason, this is unrelated to them and doesn't need to be.

Proposed resolution:

This wording is relative to N4901.

1. Modify 20.20.1 [format.syn], header `<format>` synopsis, as indicated:

   >     […]
   >     template<class Out> struct format_to_n_result {
   >       Out out;
   >       iter_difference_t<Out> size;
   >       friend bool operator==(const format_to_n_result&, const format_to_n_result&) = default;
   >     };
   >     […]

### 3642(i). `move_only_function` assignment operators seem to be defined suboptimal

Section: 20.14.17.4.3 [func.wrap.move.ctor] Status: New Submitter: Alexander Guteniev Opened: 2021-11-20 Last modified: 2021-11-20

Priority: 3

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

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

View all issues with New status.

Discussion:

20.14.17.4.3 [func.wrap.move.ctor]/22 and 20.14.17.4.3 [func.wrap.move.ctor]/25 define the effects of assignment as following:

>     move_only_function& operator=(move_only_function&& f);

> > Effects: Equivalent to: `move_only_function(std::move(f)).swap(*this);`

> […]

>     template<class F> move_only_function& operator=(F&& f);

> > Effects: Equivalent to: `move_only_function(std::forward<F>(f)).swap(*this);`

The assignment via `swap` with temporary makes the implementation to do the following:

- move out the previous target to a temporary location

- move in the new target

- finally destroy the previous target.

As everything is `noexcept` here, I think it can be short cut to just:

- destroy the previous target.

- move in the new target

Looks like the implementation cannot do such optimization in a generic case with small functor optimization enabled and non-trivial move constructor for the new target and with non-trivial destruction of the previous target, since the difference is observable.

Apparently the optimization is precluded for no reason.

[2022-01-30; Reflector poll]

Set priority to 3 after reflector poll. Some suggestions for NAD, but others disagreed.

Proposed resolution:

This wording is relative to N4901.

1. Modify 20.14.17.4.3 [func.wrap.move.ctor] as indicated:

   >     move_only_function& operator=(move_only_function&& f);

   > > -22- Effects: Sets the target object of `this` to the target object of `f` before the assignment and leaves `f` in a valid state with an unspecified value.Equivalent to: `move_only_function(std::move(f)).swap(*this);`

   > […]

   >     template<class F> move_only_function& operator=(F&& f);

   > > -25- Effects: Equivalent to: `*this = move_only_function(std::forward<F>(f)).swap(*this);`

### 3644(i). `std::format` does not define "integer presentation type"

Section: 20.20.2.2 [format.string.std] Status: New Submitter: Charlie Barto Opened: 2021-11-23 Last modified: 2021-11-29

Priority: 2

View other active issues in [format.string.std].

View all other issues in [format.string.std].

View all issues with New status.

Discussion:

20.20.2.2 [format.string.std] specifies the behavior of several format specifiers in terms of "integer presentation types"; for example 20.20.2.2 [format.string.std]/4 states:

> "The sign option is only valid for arithmetic types other than `charT` and `bool` or when an integer presentation type is specified".

Unfortunately nowhere does the standard actually define the term "integer presentation type". The closest it comes is in 20.20.2.2 [format.string.std]/19 and [tab:format.type.int], but that explicitly excludes `charT` and `bool`. [tab:format.type.char] and [tab:format.type.bool] then refer to [tab:format.type.int].

I can come up with many interpretations for what could happen when `'c'` is used with `charT` or `bool`, but the following table is what msvc does right now (throws is the same as does not compile after P2216 in all these cases, although not in general for `'c'`):

> Argument type | Specifiers | Throws?
> --- | --- | ---
> `bool` | `#` | Yes
> `bool` | `#c` | No
> `bool` | `:+` | Yes
> `bool` | `+c` | Yes
> `bool` | `^` | No
> `bool` | `^c` | No
> `bool` | `0` | Yes
> `bool` | `0c` | Yes
> `bool` | `c` | No
> `charT` | `#` | Yes
> `charT` | `#c` | Yes
> `charT` | `+` | Yes
> `charT` | `+c` | Yes
> `charT` | `^` | No
> `charT` | `^c` | No
> `charT` | `0` | Yes
> `charT` | `0c` | Yes

As you can see we don't interpret `'c'` as an "integer type specifier", except when explicitly specified for `bool` with `#`. I think this is because for `#` the standard states

> "This option is valid for arithmetic types other than `charT` and `bool` or when an integer presentation type is specified, and not otherwise",

and [tab:format.type.bool] puts `'c'` in the same category as all the other "integer type specifiers", whereas [tab:format.type.char] separates it out into the char-specific types. If this issue's proposed resolution is adopted our behavior would become non-conforming (arguably it already is) and `"#c"` with `bool`s would become invalid.

[2021-11-29; Tim comments]

This issue touches the same wording area as LWG 3586 does.

[2022-01-30; Reflector poll]

Set priority to 2 after reflector poll.

Proposed resolution:

This wording is relative to N4901.

1. Modify 20.20.2.2 [format.string.std] as indicated:

   > -6- The `#` option causes the alternate form to be used for the conversion. This option is only valid for arithmetic types other than `charT` and `bool` or when an integer presentation type is specified, and not otherwise. For integral types, the alternate form inserts the base prefix (if any) specified in Table 65 into the output after the sign character (possibly space) if there is one, or before the output of `to_chars` otherwise. For floating-point types, the alternate form causes the result of the conversion of finite values to always contain a decimal-point character, even if no digits follow it. Normally, a decimal-point character appears in the result of these conversions only if a digit follows it. In addition, for `g` and `G` conversions, trailing zeros are not removed from the result.

   > […]

   > > [Drafting note: This modification is a simple cleanup given the other changes further below, to bring the wording for `#` in line with the wording for the other modifiers, in the interest of preventing confusion.]

   > […]

   > -16- The type determines how the data should be presented.

   > -?- An integer presentation type is one of the following type specifiers in Table [tab:format.type.integer_presentation], or none, if none is defined to have the same behavior as one of the type specifiers in Table [tab:format.type.integer_presentation].

   > > Table ? — Meaning of type options for integer representations [tab:format.type.integer_presentation]
   > > Type | Meaning
   > > --- | ---
   > > `b` | `to_chars(first, last, value, 2);` the base prefix is `0b`.
   > > `B` | The same as `b`, except that the base prefix is `0B`.
   > > `d` | `to_chars(first, last, value)`.
   > > `o` | `to_chars(first, last, value, 8)`; the base prefix is `0` if `value` is nonzero and is empty otherwise.
   > > `x` | `to_chars(first, last, value, 16)`; the base prefix is `0x`.
   > > `X` | The same as `x`, except that it uses uppercase letters for digits above `9` and the base prefix is `0X`.

   > > [Drafting note: This is the same as [tab:format.type.int] with "none" and `'c'` removed]

   > -17- The available string presentation types are specified in Table 64 ([tab:format.type.string]).

   > […]

   > > Table 65 — Meaning of type options for integer types [tab:format.type.int]
   > > Type | Meaning
   > > --- | ---
   > > `b`, `B`, `d`, `o`, `x`, `X` | As specified in Table [tab:format.type.integer_presentation]`to_chars(first, last, value, 2);` the base prefix is `0b`.
   > > `B` | The same as `b`, except that the base prefix is `0B`.
   > > `c` | Copies the character `static_cast<charT>(value)` to the output. Throws `format_error` if `value` is not in the range of representable values for `charT`.
   > > `d` | `to_chars(first, last, value)`.
   > > `o` | `to_chars(first, last, value, 8)`; the base prefix is `0` if `value` is nonzero and is empty otherwise.
   > > `x` | `to_chars(first, last, value, 16)`; the base prefix is `0x`.
   > > `X` | The same as `x`, except that it uses uppercase letters for digits above `9` and the base prefix is `0X`.
   > > none | The same as `d`. [Note 8: If the formatting argument type is `charT` or `bool`, the default is instead `c` or `s`, respectively. — end note]

   > > Table 66 — Meaning of type options for `charT` [tab:format.type.char]
   > > Type | Meaning
   > > --- | ---
   > > none, `c` | Copies the character to the output.
   > > `b`, `B`, `d`, `o`, `x`, `X` | As specified in Table [tab:format.type.int][tab:format.type.integer_presentation].

   > > Table 67 — Meaning of type options for `bool` [tab:format.type.bool]
   > > Type | Meaning
   > > --- | ---
   > > none, `s` | Copies textual representation, either `true` or `false`, to the output.
   > > `b`, `B`, `c`, `d`, `o`, `x`, `X` | As specified in Table [tab:format.type.int][tab:format.type.integer_presentation] for the value `static_cast<unsigned char>(value)`.
   > > `c` | Copies the character `static_cast<unsigned char>(value)` to the output.

   > > [Drafting note: allowing the `'c'` specifier for `bool` is pretty bizarre behavior, but that's very clearly what the standard says now, so I'm preserving it. I would suggest keeping discussion of changing that behavior to a separate issue or defect report (the reworking of the tables in this issue makes addressing that easier anyway).

   > > The inconsistency with respect to using `static_cast<unsigned char>` here and `static_cast<charT>` in [tab:format.type.int] is pre-existing and should be addressed in a separate issue if needed. ]

### 3645(i). `resize_and_overwrite` is overspecified to call its callback with lvalues

Section: 21.3.3.5 [string.capacity] Status: New Submitter: Arthur O'Dwyer Opened: 2021-11-28 Last modified: 2021-12-04

Priority: 2

View other active issues in [string.capacity].

View all other issues in [string.capacity].

View all issues with New status.

Discussion:

21.3.3.5 [string.capacity] p7 says:

- [Let] `OP` be the expression `std::move(op)(p, n)`.

- [Precondition:] `OP` does not throw an exception or modify `p` or `n`.

Notice that `p` and `n` above are lvalue expressions.

Discussed with Mark Zeren, Casey Carter, Jonathan Wakely. We observe that:

A. This wording requires vendors to reject

>     s.resize_and_overwrite(100, [](char*&&, size_t&&){ return 0; });

which is surprising.

B. This wording requires vendors to accept

>     s.resize_and_overwrite(100, [](char*&, size_t&){ return 0; });

which is even more surprising, and also threatens to allow the user to corrupt the internal state (which is why we need to specify the Precondition above).

C. A user who writes

>     s.resize_and_overwrite(100, [](auto&&, auto&&){ return 0; });

can detect that they're being passed lvalues instead of rvalues. If we change the wording to permit implementations to pass either lvalues or rvalues (their choice), then this will be detectable by the user, so we don't want that if we can help it.

1. X. We want to enable implementations to say `move(op)(__p, __n)` and then use `__p` and `__n`.

2. Y. We have one implementation which wants to say `move(op)(data(), __n)`, which is not currently allowed, but arguably should be.

3. Z. We have to do or say something about disallowing writes to any internal state to which `Op` might get a reference.

Given all of this, Mark and Arthur think that the simplest way out is to say that the arguments are prvalues. It prevents X, but fixes the surprises in A, B, Y, Z. We could do this in the Let bullets. Either like so:

- [Let] `p` be a prvalue of type `charT*` …

- `m` be a prvalue of type `size_type` equal to `n`,

- `OP` be the expression `std::move(op)(p, m)`.

or (Arthur's preference) by specifying prvalues in the expression `OP` itself:

- [Let] `OP` be the expression `std::move(op)(auto(p), auto(n))`.

No matter which specification approach we adopt, we can also simplify the Preconditions bullet to:

- [Precondition:] `OP` does not throw an exception.

because once the user is receiving prvalue copies, it will no longer be physically possible for the user to modify the library's original variables `p` and `n`.

[2021-11-29; Arthur O'Dwyer provides wording]

[2022-01-30; Reflector poll]

Set priority to 2 after reflector poll.

Proposed resolution:

This wording is relative to N4901.

1. Modify 21.3.3.5 [string.capacity] as indicated:

   >     template<class Operation> constexpr void resize_and_overwrite(size_type n, Operation op);

   > > -7- Let

   > > 1. (7.1) — `o = size()` before the call to `resize_and_overwrite`.

   > > 2. (7.2) — `k` be `min(o, n)`.

   > > 3. (7.3) — `p` be a `charT*`, such that the range `[p, p + n]` is valid and `this->compare(0, k, p, k) == 0` is `true` before the call. The values in the range `[p + k, p + n]` may be indeterminate (6.7.4 [basic.indet]).

   > > 4. (7.4) — `OP` be the expression `std::move(op)(auto(p), auto(n))`.

   > > 5. (7.5) — `r = OP`.

   > > -8- Mandates: `OP` has an integer-like type (23.3.4.4 [iterator.concept.winc]).

   > > -9- Preconditions:

   > > 1. (9.1) — `OP` does not throw an exception or modify `p` or `n`.

   > > 2. (9.2) — `r ≥ 0`.

   > > 3. (9.3) — `r ≤ n`.

   > > 4. (9.4) — After evaluating `OP` there are no indeterminate values in the range `[p, p + r)`.

   > > -10- Effects: Evaluates `OP`, replaces the contents of `*this` with `[p, p + r)`, and invalidates all pointers and references to the range `[p, p + n]`.

   > > -11- Recommended practice: Implementations should avoid unnecessary copies and allocations by, for example, making `p` a pointer into internal storage and by restoring `*(p + r)` to `charT()` after evaluating `OP`.

### 3646(i). `std::ranges::view_interface::size` returns a signed type

Section: 24.5.3.1 [view.interface.general] Status: LEWG Submitter: Jiang An Opened: 2021-11-29 Last modified: 2021-12-04

Priority: 3

View all issues with LEWG status.

Discussion:

According to 24.5.3.1 [view.interface.general], `view_interface::size` returns the difference between the sentinel and the beginning iterator, which always has a signed-integer-like type. However, IIUC the decision that a `size` member function should return an unsigned type by default was made when adopting P1227R2, and the relative changes of the ranges library were done in P1523R1. I don't know why `view_interface::size` was unchanged, while `ranges::size` returns an unsigned type in similar situations (24.3.10 [range.prim.size] (2.5)).

If we want to change `views_interface::size` to return an unsigned type, the both overloads should be changed as below:

>     constexpr auto size() requires forward_range<D> &&
>       sized_sentinel_for<sentinel_t<D>, iterator_t<D>> {
>         return to-unsigned-like(ranges::end(derived()) - ranges::begin(derived()));
>       }
>     constexpr auto size() const requires forward_range<const D> &&
>       sized_sentinel_for<sentinel_t<const D>, iterator_t<const D>> {
>         return to-unsigned-like(ranges::end(derived()) - ranges::begin(derived()));
>       }

[2022-01-30; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

This wording is relative to N4901.

1. Modify 24.5.3.1 [view.interface.general], class template `view_interface` synopsis, as indicated:

   >     […]
   >     constexpr auto size() requires forward_range<D> &&
   >       sized_sentinel_for<sentinel_t<D>, iterator_t<D>> {
   >         return to-unsigned-like(ranges::end(derived()) - ranges::begin(derived()));
   >       }
   >     constexpr auto size() const requires forward_range<const D> &&
   >       sized_sentinel_for<sentinel_t<const D>, iterator_t<const D>> {
   >         return to-unsigned-like(ranges::end(derived()) - ranges::begin(derived()));
   >       }
   >     […]

### 3647(i). `nothrow-input-iterator` constraints should not mention copying

Section: 25.11.2 [special.mem.concepts] Status: New Submitter: Konstantin Varlamov Opened: 2021-11-30 Last modified: 2021-12-19

Priority: 3

View all issues with New status.

Discussion:

25.11.2 [special.mem.concepts] states that a type qualifies as a `nothrow-input-iterator` only if no exceptions are thrown from, among other things, copy construction and copy assignment. However, being copyable isn't part of the requirements for an `input_iterator` on which `nothrow-input-iterator` is based (indeed, one of the things `forward_iterator` adds to `input_iterator` is copyability), and the `nothrow-input-iterator` concept doesn't add any new constraints related to copyability.

[2021-12-19; Daniel comments]

During LWG discussion of the issue one argument brought forward against the proposed wording was that it might be incomplete, because it doesn't adjust the `nothrow-forward-iterator` concept, which adds among other things the `copyable` requirements. But `nothrow-forward-iterator` also requires `nothrow-sentinel-for<I, I>`, which already extends this necessary no-throw requirement for copy operations by p. 4:

> Types `S` and `I` model `nothrow-sentinel-for` only if no exceptions are thrown from copy construction, move construction, copy assignment, move assignment, or comparisons between valid values of type `I` and `S`.

It should also be emphasized that the definitions of move construction (3.34 [defns.move.constr]) and move assignment (3.33 [defns.move.assign]) are compatible even for copyable input iterator types, because these definitions refer just to expression conditions, and not to concrete operator overloads. So as long as an implementation applies these expression conditions, we are safe.

[2022-01-30; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

This wording is relative to N4901.

1. Modify 25.11.2 [special.mem.concepts] as indicated:

   >     template<class I>
   >     concept nothrow-input-iterator = // exposition only
   >       input_iterator<I> &&
   >       is_lvalue_reference_v<iter_reference_t<I>> &&
   >       same_as<remove_cvref_t<iter_reference_t<I>>, iter_value_t<I>>;

   > > -2- A type `I` models `nothrow-input-iterator` only if no exceptions are thrown from increment, copy construction, move construction, copy assignment, move assignment, or indirection through valid iterators.

### 3651(i). Unspecified lifetime guarantees for the format string

Section: 20.20 [format] Status: New Submitter: Barry Revzin Opened: 2021-12-08 Last modified: 2021-12-11

Priority: 3

View all issues with New status.

Discussion:

Is this program guaranteed to be valid:

>     #include <format>
>     #include <algorithm>

>     struct Thing { };

>     template <>
>     struct std::formatter<Thing> {
>       std::string_view spec;

>       constexpr auto parse(std::format_parse_context& ctx) {
>         auto end = std::find(ctx.begin(), ctx.end(), '}');
>         spec = std::string_view(ctx.begin(), end);
>         return end;
>       }

>       auto format(Thing, std::format_context& ctx) {
>         return std::ranges::copy(spec, ctx.out()).out;
>       }
>     };

>     int main() {
>       std::print("{:lwg issue}\n",  Thing{});
>     }

In `parse()`, the formatter for `Thing` holds onto a string view of its specifiers. And then in `format()`, it just prints them. I don't think we say anywhere that this works. Does this code print `"lwg issue"` because there's no issue or does it print some garbage memory somewhere because there is one?

libfmt's implementation internally stores `string_view`'s into the format string (for named argument support), which implies that it should work. But it'd be nice to come out and say that.

[2022-01-30; Reflector poll]

Set priority to 3 after reflector poll.
"Presumably we need to say in [formatter.requirements] that [`pc.begin()`, `pc.end()`) is guaranteed to be a valid range until the next call to `parse()` or `f` is destroyed, whichever comes first."

Proposed resolution:

### 3653(i). `<coroutine>` is freestanding, but uses `std::hash` which is not

Section: 17.12.2 [coroutine.syn] Status: New Submitter: Jonathan Wakely Opened: 2021-12-17 Last modified: 2021-12-18

Priority: 3

View all other issues in [coroutine.syn].

View all issues with New status.

Discussion:

The `<coroutine>` header is required for freestanding implementations, but it defines a specialization of `std::hash`, which is not required for freestanding implementations.

Presumably we should make the `std::hash` specialization conditionally present.

[2022-01-30; Reflector poll]

Set priority to 3 after reflector poll. Would be resolved by P1642 for C++23, but it's still a defect in C++20.

Proposed resolution:

### 3655(i). The `INVOKE` operation and `union` types

Section: 20.14.4 [func.require] Status: New Submitter: Jiang An Opened: 2021-12-29 Last modified: 2022-01-15

Priority: 3

View all other issues in [func.require].

View all issues with New status.

Discussion:

There are two cases of the `INVOKE` operation specified with `std::is_base_of_v` (20.14.4 [func.require] (1.1), (1,4)), which means the following code snippet is ill-formed, as `std::is_base_of_v<B, D>` is `false` when either `B` or `D` is a `union` type.

>     union Foo { int x; };
>     static_assert(std::is_invocable_v<int Foo::*, Foo&>);

Currently libstdc++ accepts this code, because it uses slightly different conditions that handle `union` types. libc++ and MSVC STL reject this code as specified in 20.14.4 [func.require].

Should we change the conditions in 20.14.4 [func.require] (1.1) and (1.4) to match libstdc++ and correctly handle `union` types?

[2022-01-30; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

### 3656(i). Inconsistent bit operations returning a count

Section: 26.5.5 [bit.pow.two] Status: Open Submitter: Nicolai Josuttis Opened: 2021-12-30 Last modified: 2022-02-23

Priority: 3

View all issues with Open status.

Discussion:

Among the bit operations returning a count, `bit_width()` is the only one not returning an `int`.

This has the following consequences:

>     std::uint64_t b64 = 1;
>     b64 = std::rotr(b64, 1);
>     int count1 = std::popcount(b64);     // OK
>     int count2 = std::countl_zero(b64);  // OK
>     int count3 = std::bit_width(b64);    // OOPS

The last line may result in a warning such as:

> Warning: conversion from `long long unsigned` to `int` may change value

You have to use a `static_cast` to avoid the warning.

Note that P0553R4 explicitly states the following design considerations, which I would also assume to apply to the later added functions from P0556R3:

> The counting operations return "`int`" quantities, consistent with the rule "use an `int` unless you need something else". This choice does not reflect, in the type, the fact that counts are always non-negative.

[2022-01-30; Reflector poll]

Set priority to 3 after reflector poll. Eight votes for P0, but request LEWG confirmation before setting it to Tentatively Ready.

[2022-02-22 LEWG telecon; Status changed: LEWG → Open]

No objection to unanimous consent to send the proposed resolution for LWG3656 to LWG for C++23. The changes in P1956 changed the functions to be more counting than mathematical.

Proposed resolution:

This wording is relative to N4901.

1. Modify 26.5.2 [bit.syn], header `<bit>` synopsis, as indicated:

   >     […]
   >     template<class T>
   >       constexpr Tint bit_width(T x) noexcept;
   >     […]

2. Modify 26.5.5 [bit.pow.two], as indicated:

   >     template<class T>
   >       constexpr Tint bit_width(T x) noexcept;

   > > -11- Constraints: `T` is an unsigned integer type (6.8.2 [basic.fundamental]).

   > > -12- Returns: If `x == 0`, `0`; otherwise one plus the base-2 logarithm of `x`, with any fractional part discarded.

### 3658(i). `basic_streambuf::sputn` is both overspecified and underspecified

Section: 29.6.3.3.5 [streambuf.pub.put] Status: New Submitter: Jonathan Wakely Opened: 2022-01-17 Last modified: 2022-01-23

Priority: 3

View all issues with New status.

Discussion:

The specification for `basic_streambuf::sputn` is:

> Returns: `xsputn(s, n)`.

One interpretation of this implies that `sputn` can't insert characters directly into the put area if there is space for them, it has to make a virtual call. That has significant overhead for repeated calls, such as inserting many small strings/string_views in a loop.

But another interpretation is that it doesn't use "Effects: Equivalent to" or anything like that, so doesn't say an actual call to `xsputn` happens. Strictly speaking, it only says it returns the value that `xsputn` would return, and doesn't even have to produce any of its effects!

We should describe the effects, not the return value, and we should do so in a way that does not overconstrain the implementation. It should not be necessary to make a virtual call to `xsputn` if the put area has capacity for the characters. On the other hand, if it doesn't have capacity, then calling `xsputn` is the best option; it allows the derived `streambuf` to decide how best to handle large writes.

The proposed resolution replaces the Returns: element with an Effects: element, so that we specify that those effects actually occur. A normative remark is added to give the implementation leeway to avoid the virtual call when it isn't needed.

[2022-01-30; Reflector poll]

Set priority to 3 after reflector poll. Jonathan to revise P/R to also cover `sgetn`.

Proposed resolution:

This wording is relative to N4901.

1. Modify 29.6.3.3.5 [streambuf.pub.put] as indicated:

   >     streamsize sputn(const char_type* s, streamsize n);

   > > -?- Preconditions: `[s, s+n)` is a valid range.

   > > -?- Effects: `return xsputn(s, n)`.

   > > -?- Remarks: When `(epptr() - pptr()) >= n`, it is unspecified whether the characters are written directly to the output sequence without calling `xsputn`.

   > > -2- Returns: `xsputn(s, n)`.

### 3659(i). Consider `ATOMIC_FLAG_INIT` undeprecation

Section: D.26.5 [depr.atomics.flag] Status: SG1 Submitter: Aaron Ballman Opened: 2022-01-18 Last modified: 2022-01-22

Priority: 3

View all issues with SG1 status.

Discussion:

P0883R2 deprecated `ATOMTIC_VAR_INIT` and `ATOMIC_FLAG_INIT` largely based on rationale from WG14. However, WG14 only deprecated `ATOMIC_VAR_INIT` because we were told by implementers that `ATOMIC_FLAG_INIT` is still necessary for some platforms (platforms for which "clear" is actually not all zero bits, which I guess exist).

I'd like to explore whether WG21 should undeprecate `ATOMIC_FLAG_INIT` as there was no motivation that I could find in the paper on the topic or in the discussion at P0883R0 [Jacksonville 2018].

One possible approach would be to undeprecate it from `<stdatomic.h>` only (C++ can still use the constructors from `<atomic>` and shared code can use the macros from `<stdatomic.h>`).

[2022-01-30; Reflector poll]

Set priority to 3 after reflector poll. Send to SG1.

Proposed resolution:

### 3662(i). `basic_string::append/assign(NTBS, pos, n)` suboptimal

Section: 21.3.3.7.2 [string.append], 21.3.3.7.3 [string.assign] Status: New Submitter: Jonathan Wakely Opened: 2022-01-21 Last modified: 2022-01-30

Priority: 3

View all other issues in [string.append].

View all issues with New status.

Discussion:

This will allocate temporary string, then copy one byte from it:

>     std::string s;
>     s.append("a very very long string that doesn't fit in SSO buffer", 13, 1);

The problem is that there is no overload accepting an NTBS there, so it converts to a temporary string using:

>     append(const basic_string&, size_t, size_t = npos);

C++17 added a new overload for a `string_view`:

>     append(const T&, size_t, size_t = npos);

But that overload is constrained to not allow `const char*` arguments, so we still create a temporary string.

If we're going to accept those arguments, we should do so efficiently, without forcing an unnecessary allocation.

We could do better if we split the `append(const T&, ...)` overload into:

>     append(const T&, size_t);
>     append(const T&, size_t, size_t);

and then remove the `!is_convertible_v<const T&, const charT*>` constraint from the second overload (Option A in the proposed resolution).

Alternatively, we can leave the `append(const T&, size_t, size_t)` overload alone and just add one taking exactly the arguments used above. That seems simpler to me, and I prefer that (Option B in the Proposed Resolution).

The same problem applies to `assign("...", pos, n)`.

[2022-01-30; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

This wording is relative to N4901.

> [Drafting Note: Two mutually exclusive options are prepared, depicted below by Option A and Option B, respectively.]

Option A:

1. Modify 21.3.3.1 [basic.string.general], class template `basic_string` synopsis, as indicated:

   >     […]
   >     // 21.3.3.7 [string.modifiers], modifiers
   >     […]
   >     template<class T>
   >       constexpr basic_string& append(const T& t);
   >     template<class T>
   >       constexpr basic_string& append(const T& t, size_type pos);
   >     template<class T>
   >       constexpr basic_string& append(const T& t, size_type pos, size_type n = npos);
   >     constexpr basic_string& append(const charT* s, size_type n);
   >     […]
   >     template<class T>
   >       constexpr basic_string& assign(const T& t);
   >     template<class T>
   >       constexpr basic_string& assign(const T& t, size_type pos);
   >     template<class T>
   >       constexpr basic_string& assign(const T& t, size_type pos, size_type n = npos);
   >     constexpr basic_string& assign(const charT* s, size_type n);
   >     […]

2. Modify 21.3.3.7.2 [string.append] as indicated:

   >     template<class T>
   >       constexpr basic_string& append(const T& t);

   > > -3- Constraints:

   > > 1. (3.1) — `is_convertible_v<const T&, basic_string_view<charT, traits>>` is `true` and

   > > 2. (3.2) — `is_convertible_v<const T&, const charT*>` is `false`.

   > > -4- Effects: Equivalent to:

   > > >     basic_string_view<charT, traits> sv = t;
   > > >     return append(sv.data(), sv.size());

   >     template<class T>
   >       constexpr basic_string& append(const T& t, size_type pos);

   > > -?- Constraints:

   > > 1. (?.1) — `is_convertible_v<const T&, basic_string_view<charT, traits>>` is `true` and

   > > 2. (?.2) — `is_convertible_v<const T&, const charT*>` is `false`.

   > > -?- Effects: Equivalent to:

   > > >     basic_string_view<charT, traits> sv = t;
   > > >     return append(sv.substr(pos));

   >     template<class T>
   >       constexpr basic_string& append(const T& t, size_type pos, size_type n = npos);

   > > -5- Constraints:

   > > 1. (5.1) — `is_convertible_v<const T&, basic_string_view<charT, traits>>` is `true` and

   > > 2. (5.2) — `is_convertible_v<const T&, const charT*>` is `false`.

   > > -6- Effects: Equivalent to:

   > > >     basic_string_view<charT, traits> sv = t;
   > > >     return append(sv.substr(pos, n));

3. Modify 21.3.3.7.3 [string.assign] as indicated:

   >     template<class T>
   >       constexpr basic_string& assign(const T& t);

   > > -4- Constraints:

   > > 1. (4.1) — `is_convertible_v<const T&, basic_string_view<charT, traits>>` is `true` and

   > > 2. (4.2) — `is_convertible_v<const T&, const charT*>` is `false`.

   > > -5- Effects: Equivalent to:

   > > >     basic_string_view<charT, traits> sv = t;
   > > >     return assign(sv.data(), sv.size());

   >     template<class T>
   >       constexpr basic_string& assign(const T& t, size_type pos);

   > > -?- Constraints:

   > > 1. (?.1) — `is_convertible_v<const T&, basic_string_view<charT, traits>>` is `true` and

   > > 2. (?.2) — `is_convertible_v<const T&, const charT*>` is `false`.

   > > -?- Effects: Equivalent to:

   > > >     basic_string_view<charT, traits> sv = t;
   > > >     return assign(sv.substr(pos));

   >     template<class T>
   >       constexpr basic_string& assign(const T& t, size_type pos, size_type n = npos);

   > > -6- Constraints:

   > > 1. (6.1) — `is_convertible_v<const T&, basic_string_view<charT, traits>>` is `true` and

   > > 2. (6.2) — `is_convertible_v<const T&, const charT*>` is `false`.

   > > -7- Effects: Equivalent to:

   > > >     basic_string_view<charT, traits> sv = t;
   > > >     return assign(sv.substr(pos, n));

Option B:

1. Modify 21.3.3.1 [basic.string.general], class template `basic_string` synopsis, as indicated:

   >     […]
   >     // 21.3.3.7 [string.modifiers], modifiers
   >     […]
   >     constexpr basic_string& append(const charT* s, size_type n);
   >     constexpr basic_string& append(const charT* s);
   >     constexpr basic_string& append(const charT* s, size_type pos, size_type n);
   >     constexpr basic_string& append(size_type n, charT c);
   >     […]
   >     constexpr basic_string& assign(const charT* s, size_type n);
   >     constexpr basic_string& assign(const charT* s);
   >     constexpr basic_string& assign(const charT* s, size_type pos, size_type n);
   >     constexpr basic_string& assign(size_type n, charT c);
   >     […]

2. Modify 21.3.3.7.2 [string.append] as indicated:

   >     constexpr basic_string& append(const charT* s, size_type n);

   > > -7- Preconditions: `[s, s + n)` is a valid range.

   > > -8- Effects: Appends a copy of the range `[s, s + n)` to the string.

   > > -9- Returns: `*this`.

   >     constexpr basic_string& append(const charT* s);

   > > -10- Effects: Equivalent to: `return append(s, traits::length(s));`

   >     constexpr basic_string& append(const charT* s, size_type pos, size_type n);

   > > -?- Effects: Equivalent to: `return append(basic_string_view<charT, traits>(s).substr(pos, n));`

3. Modify 21.3.3.7.3 [string.assign] as indicated:

   >     constexpr basic_string& assign(const charT* s, size_type n);

   > > -8- Preconditions: `[s, s + n)` is a valid range.

   > > -9- Effects: Replaces the string controlled by `*this` with a copy of the range `[s, s + n)`.

   > > -10- Returns: `*this`.

   >     constexpr basic_string& assign(const charT* s);

   > > -11- Effects: Equivalent to: `return assign(s, traits::length(s));`

   >     constexpr basic_string& assign(const charT* s, size_type pos, size_type n);

   > > -?- Effects: Equivalent to: `return assign(basic_string_view<charT, traits>(s).substr(pos, n));`

### 3663(i). `basic_string(const T&, const Alloc&)` turns moves into copies

Section: 21.3.3.3 [string.cons], 21.3.3.7.3 [string.assign] Status: New Submitter: Jonathan Wakely Opened: 2022-01-21 Last modified: 2022-01-30

Priority: 3

View all other issues in [string.cons].

View all issues with New status.

Discussion:

This will do a copy not a move:

>     struct Str : std::string {
>       Str() = default;
>       Str(Str&& s) : std::string(std::move(s)) { }
>     };
>     Str s;
>     Str s2(std::move(s));

The problem is that the new C++17 constructor:

>     basic_string(const T&, const Alloc& = Alloc());

is an exact match, but the `basic_string` move constructor requires a derived-to-base conversion.

This is a regression since C++14, because the move constructor was called in C++14.

This problem also exists for `assign(const T&)` and `operator=(const T&)`.

We can fix this by constraining those functions with `!derived_from<T, basic_string>`, so that the move constructor is the only viable function. Libstdc++ has done something very similar since 2017, but using `!is_convertible<const T*, const basic_string*>` instead of `derived_from`.

[2022-01-30; Reflector poll]

Set priority to 3 after reflector poll. Jonathan to revise P/R to use `is_base_of` or `is_convertible` instead of `derived_from`.

Proposed resolution:

This wording is relative to N4901.

1. Modify 21.3.3.3 [string.cons] as indicated:

   >     template<class T>
   >       constexpr explicit basic_string(const T& t, const Allocator& a = Allocator());

   > > -7- Constraints:

   > > 1. (7.1) — `is_convertible_v<const T&, basic_string_view<charT, traits>>` is `true` and

   > > 2. (7.?) — `derived_from<T, basic_string>` is `false` and

   > > 3. (7.2) — `is_convertible_v<const T&, const charT*>` is `false`.

   > > -8- Effects: Creates a variable, `sv`, as if by `basic_string_view<charT, traits> sv = t;` and then behaves the same as `basic_string(sv.data(), sv.size(), a)`.

   > […]

   >     template<class T>
   >       constexpr basic_string& operator=(const T& t);

   > > -27- Constraints:

   > > 1. (27.1) — `is_convertible_v<const T&, basic_string_view<charT, traits>>` is `true` and

   > > 2. (27.?) — `derived_from<T, basic_string>` is `false` and

   > > 3. (27.2) — `is_convertible_v<const T&, const charT*>` is `false`.

   > > -28- Effects: Equivalent to:

   > > >     basic_string_view<charT, traits> sv = t;
   > > >     return assign(sv);

2. Modify 21.3.3.7.3 [string.assign] as indicated:

   >     template<class T>
   >       constexpr basic_string& assign(const T& t);

   > > -4- Constraints:

   > > 1. (4.1) — `is_convertible_v<const T&, basic_string_view<charT, traits>>` is `true` and

   > > 2. (4.?) — `derived_from<T, basic_string>` is `false` and

   > > 3. (4.2) — `is_convertible_v<const T&, const charT*>` is `false`.

   > > -5- Effects: Equivalent to:

   > > >     basic_string_view<charT, traits> sv = t;
   > > >     return assign(sv.data(), sv.size());

### 3664(i). LWG 3392 broke `std::ranges::distance(a, a+3)`

Section: 23.4.4.3 [range.iter.op.distance] Status: New Submitter: Arthur O'Dwyer Opened: 2022-01-23 Last modified: 2022-02-18

Priority: 2

View all other issues in [range.iter.op.distance].

View all issues with New status.

Discussion:

Consider the use of `std::ranges::distance(first, last)` on a simple C array. This works fine with `std::distance`, but currently does not work with `std::ranges::distance`.

>     // godbolt link
>     #include <ranges>
>     #include <cassert>

>     int main() {
>       int a[] = {1, 2, 3};
>       assert(std::ranges::distance(a, a+3) == 3);
>       assert(std::ranges::distance(a, a) == 0);
>       assert(std::ranges::distance(a+3, a) == -3);
>     }

Before LWG 3392, we had a single iterator-pair overload:

>     template<input_or_output_iterator I, sentinel_for<I> S>
>       constexpr iter_difference_t<I> distance(I first, S last);

which works fine for C pointers. After LWG 3392, we have two iterator-pair overloads:

>     template<input_or_output_iterator I, sentinel_for<I> S>
>       requires (!sized_sentinel_for<S, I>)
>         constexpr iter_difference_t<I> distance(I first, S last);

>     template<input_or_output_iterator I, sized_sentinel_for<I> S>
>       constexpr iter_difference_t<I> distance(const I& first, const S& last);

and unfortunately the one we want — `distance(I first, S last)` — is no longer viable because [with `I=int*`, `S=int*`], we have `sized_sentinel_for<S, I>` and so its constraints aren't satisfied. So we look at the other overload [with `I=int[3]`, `S=int[3]`], but unfortunately its constraints aren't satisfied either, because `int[3]` is not an `input_or_output_iterator`.

[2022-01-30; Reflector poll]

Set priority to 2 after reflector poll.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4901.

> > [Drafting Note: Thanks to Casey Carter. Notice that `sentinel_for<S, I>` already implies and subsumes `input_or_output_iterator<I>`, so that constraint wasn't doing anything; personally I'd prefer to remove it for symmetry (and to save the environment). Otherwise you'll have people asking why one of the `I`'s is constrained and the other isn't.]

> 1. Modify 23.2 [iterator.synopsis], header `<iterator>` synopsis, as indicated:

>    >     […]
>    >     // 23.4.4.3 [range.iter.op.distance], ranges::distance
>    >     template<classinput_or_output_iterator I, sentinel_for<I> S>
>    >       requires (!sized_sentinel_for<S, I>)
>    >       constexpr iter_difference_t<I> distance(I first, S last);
>    >     template<classinput_or_output_iterator I, sized_sentinel_for<decay_t<I>> S>
>    >       constexpr iter_difference_t<I> distance(const I& first, const S& last);
>    >     […]

> 2. Modify 23.4.4.3 [range.iter.op.distance] as indicated:

>    >     template<classinput_or_output_iterator I, sentinel_for<I> S>
>    >       requires (!sized_sentinel_for<S, I>)
>    >       constexpr iter_difference_t<I> ranges::distance(I first, S last);

>    > > -1- Preconditions: `[first, last)` denotes a range.

>    > > -2- Effects: Increments `first` until `last` is reached and returns the number of increments.

>    >     template<classinput_or_output_iterator I, sized_sentinel_for<decay_t<I>> S>
>    >       constexpr iter_difference_t<I> ranges::distance(const I& first, const S& last);

>    > > -3- Effects: Equivalent to: `return last - first;`

[2022-02-16; Arthur and Casey provide improved wording]

Proposed resolution:

This wording is relative to N4901.

> [Drafting Note: Arthur thinks it's a bit "cute" of the Effects: element to `static_cast` from `T(&)[N]` to `T* const&` in the array case, but it does seem to do the right thing in all cases, and it saves us from having to use an `if constexpr (is_array_v...)` or something like that.]

1. Modify 23.2 [iterator.synopsis], header `<iterator>` synopsis, as indicated:

   >     […]
   >     // 23.4.4.3 [range.iter.op.distance], ranges::distance
   >     template<classinput_or_output_iterator I, sentinel_for<I> S>
   >       requires (!sized_sentinel_for<S, I>)
   >       constexpr iter_difference_t<I> distance(I first, S last);
   >     template<classinput_or_output_iterator I, sized_sentinel_for<decay_t<I>> S>
   >       constexpr iter_difference_t<decay_t<I>> distance(const I&& first, const S& last);
   >     […]

2. Modify 23.4.4.3 [range.iter.op.distance] as indicated:

   >     template<classinput_or_output_iterator I, sentinel_for<I> S>
   >       requires (!sized_sentinel_for<S, I>)
   >       constexpr iter_difference_t<I> ranges::distance(I first, S last);

   > > -1- Preconditions: `[first, last)` denotes a range.

   > > -2- Effects: Increments `first` until `last` is reached and returns the number of increments.

   >     template<classinput_or_output_iterator I, sized_sentinel_for<decay_t<I>> S>
   >       constexpr iter_difference_t<decay_t<I>> ranges::distance(const I&& first, const S& last);

   > > -3- Effects: Equivalent to: `return last - static_cast<const decay_t<I>&>(first);`

### 3665(i). Is `std::allocator_traits<Alloc>::rebind_alloc` SFINAE-friendly?

Section: 20.10.8.2 [allocator.traits.types] Status: New Submitter: Jiang An Opened: 2022-01-24 Last modified: 2022-01-29

Priority: 3

View all other issues in [allocator.traits.types].

View all issues with New status.

Discussion:

20.10.8.2 [allocator.traits.types]/11 says that the instantiation of `rebind_alloc` is sometimes ill-formed, however, it's unclear such ill-formedness results in substitution failure or hard error. It seems that current implementations (libc++, libstd++, MSVC STL) give substitution errors, and we should reword 20.10.8.2 [allocator.traits.types]/11 with "Constraints:".

[2022-01-29; Daniel comments]

This issue has some overlap with LWG 3545 in regard to the question how we should handle the `rebind` member template of the `pointer_traits` primary template as specified by 20.10.3.2 [pointer.traits.types] p3. It would seem preferable to decide for the same approach in both cases.

[2022-03-04; Reflector poll]

Set priority to 3 after reflector poll. Probably NAD, since [allocator.requirements.general]/11 allows any allocator instantiation to fail with a hard error outside the immediate context, making it impossible to guarantee a SFINAE-friendly result. Also unclear what motivation there is for it being SFINAE friendly.

Proposed resolution:

### 3666(i). `join_view`'s difference type is too small

Section: 24.7.12 [range.join] Status: New Submitter: Tomasz Kamiński Opened: 2022-01-30 Last modified: 2022-01-31

Priority: 2

View all other issues in [range.join].

View all issues with New status.

Discussion:

Despite the fact that `join_view` may produce more elements than each joined view(s) contains, we require implementations to use the `common_type` of their difference types (per 24.7.12.3 [range.join.iterator] p3), which may lead to UB. As we already have provided implementation freedom to define extended integer-like types we should make provision for them to be used here as well. The same issue applies to the `join_with_view` as proposed by P2441.

[2022-03-04; Reflector poll]

Set priority to 2 after reflector poll. Might be a design issue.

Proposed resolution:

### 3668(i). `[recursive_]directory_iterator` constructors refer to undefined `options`

Section: 29.12.11.2 [fs.dir.itr.members], 29.12.12.2 [fs.rec.dir.itr.members] Status: New Submitter: Jonathan Wakely Opened: 2022-01-31 Last modified: 2022-02-05

Priority: 3

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

View all issues with New status.

Discussion:

29.12.11.2 [fs.dir.itr.members] p2 and 29.12.12.2 [fs.rec.dir.itr.members] p3 refer to the `options` parameter, but not all overloads have a parameter of that name.

We need some "for the overloads with ..." wording.

[2022-03-04; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

### 3669(i). `std::filesystem` operations should be observable behaviour

Section: 4.1.2 [intro.abstract] Status: New Submitter: Jens Maurer Opened: 2022-02-03 Last modified: 2022-02-07

Priority: 3

View all issues with New status.

Discussion:

4.1.2 [intro.abstract] p6.2 should be amended to say that `filesystem` operations such as `mkdir` are observable behaviour. Any resolution would need CWG review.

[2022-03-04; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

### 3673(i). §[locale.cons] Ambiguous argument in Throws for locale+name+category constructor

Section: 28.3.1.3 [locale.cons] Status: New Submitter: Hubert Tong Opened: 2022-02-12 Last modified: 2022-03-04

Priority: 3

View other active issues in [locale.cons].

View all other issues in [locale.cons].

View all issues with New status.

Discussion:

>     locale(const locale& other, const char* std_name, category);

has

> Throws: `runtime_error` if the argument is not valid, or is null.

There being three arguments, the statement is rather problematic. It looks like a copy/paste from

>     explicit locale(const char* std_name);

The conclusion, assuming that "the argument" is also `std_name` in the problem case, seems to be that the statement should be changed to read:

> Throws: `runtime_error` if `std_name` is not valid, or is null.

However there is implementation divergence over whether or not values for the category argument not explicitly described as valid by 28.3.1.2.1 [locale.category] result in `runtime_error`.

libc++ does not throw. libstdc++ does.

Code:

>     #include <locale>
>     #include <stdio.h>
>     #include <exception>
>     int main(void) {
>       std::locale Generic("C");
>       try {
>         std::locale Abomination(Generic, Generic, 0x7fff'ffff);
>       } catch (std::runtime_error&) {
>         fprintf(stderr, "Threw\n");
>       }
>     }

Compiler Explorer link.

[2022-03-04; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

### 3674(i). Removal of requirement for locale names for construction of locales not explained

Section: 28.3.1.4 [locale.members] Status: New Submitter: Hubert Tong Opened: 2022-02-12 Last modified: 2022-03-04

Priority: 2

View all other issues in [locale.members].

View all issues with New status.

Discussion:

LWG 2394 removed the only text in the wording that requires that the name of a locale is usable for constructing further locales.

The relevant notes from the wiki appear to make it seem like LWG thought the change was editorial.

Perhaps the resolution was motivated by a different defect than the one that led to the change?

Namely,

>     explicit locale(const char* std_name);

is said to use "standard C locale names".

There is no `LC_MESSAGES` in standard C.

Thus, it is a question whether the aforementioned constructor should be able to consume names produced by the C++ implementation.

See also the use of the name of the C++ locale in `locale::global()` for use with `setlocale`.

The following would restore the equivalence of locales that have the same name. It also addresses the suitability of the name for use with `setlocale` and the `locale(const char*)` constructor as a matter of QoI.

[2022-03-04; Reflector poll]

Set priority to 2 after reflector poll.

Proposed resolution:

This wording is relative to N4901.

1. Modify 28.3.1.4 [locale.members] as indicated:

   >     string name() const;

   > > -5- Returns: The name of `*this`, if it has one; otherwise, the string `"*"`.

   > > -?- Remarks: Two locales have identical names only if their facets have identical virtual function semantics.

   > > -?- Recommended practice: The name of a locale that has a name should be such that `setlocale(LC_ALL, name().c_str())` returns a non-null pointer. [Note 1: With such a name `locale(name().c_str())` succeeds and does not throw `runtime_error`. — end note]

### 3675(i). `std::ios_base::iword/pword` might be misspecified

Section: 29.5.2.6 [ios.base.storage] Status: New Submitter: Jiang An Opened: 2022-02-14 Last modified: 2022-03-04

Priority: 4

View all other issues in [ios.base.storage].

View all issues with New status.

Discussion:

Currently 29.5.2.6 [ios.base.storage] p5 and p8 say "On failure, a valid `long&/void*&` initialized to `0`". Such wording seems wrong, because a `long&/void*&` variable or return value can't be initialized with `0`. And the values of referenced objects may be underspecified, because an implementation may reuse the same `long/void*` objects on failure, and thus it's insufficient to specify the initial values of these objects only.

[2022-03-04; Reflector poll]

Set priority to 4 after reflector poll.

Proposed resolution:

This wording is relative to N4901.

1. Modify 29.5.2.6 [ios.base.storage] as indicated:

   >     long& iword(int idx);

   > > -3- […]

   > > -4- […]

   > > -5- Returns: On success `iarray[idx]`. On failure, an valid lvalue of type `long&` with value `0L` initialized to `0`.

   >     void*& pword(int idx);

   > > -6- […]

   > > -7- […]

   > > -8- Returns: On success `parray[idx]`. On failure, an valid lvalue of type `void*&` with a null pointer value initialized to `0`.

   > > -9- Remarks: After a subsequent call to `pword(int)` for the same object, the earlier return value may no longer be valid.

### 3676(i). Name of locale composed using `std::locale::none`

Section: 28.3.1.3 [locale.cons] Status: New Submitter: Hubert Tong Opened: 2022-02-14 Last modified: 2022-03-04

Priority: 3

View other active issues in [locale.cons].

View all other issues in [locale.cons].

View all issues with New status.

Discussion:

For

>     locale(const locale& other, const locale& one, category cats);

the Remarks say:

> The resulting locale has a name if and only if the first two arguments have names.

The case where `cats` is `locale::none` seems very similar to the issue that LWG 2295 reports with the case where the provided facet pointer is `nullptr`. That is, if no composition is actually occurring, then using the name of `other` seems to be reasonable.

It would help consistency if both cases are treated the same way.

Note: The `locale::all` case should not imply using the name of `one`. `locale::all` does not necessarily cover all of the C locale categories on a platform.

[2022-03-04; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

### 3677(i). Is a cv-qualified `pair` specially handled in uses-allocator construction?

Section: 20.10.7.2 [allocator.uses.construction] Status: New Submitter: Jiang An Opened: 2022-02-16 Last modified: 2022-03-04

Priority: 2

View other active issues in [allocator.uses.construction].

View all other issues in [allocator.uses.construction].

View all issues with New status.

Discussion:

It seems unclear whether cv-qualified `pair` specializations are considered as specializations of `pair` in 20.10.7.2 [allocator.uses.construction].

Currently MSVC STL only considered cv-unqualified pair types as such specializations, while libstdc++ accept both cv-unqualified and `const`-qualified pair types as such specializations. The resolution of LWG 3525 uses `remove_cv_t`, which possibly imply that the specialization of pair may be cv-qualified.

The difference can be observed via the following program:

>     #include <utility>
>     #include <memory>
>     #include <vector>
>     #include <cassert>

>     template<class T>
>     class payload_ator {

>       int payload{};

>     public:
>       payload_ator() = default;

>       constexpr explicit payload_ator(int n) noexcept : payload{n} {}

>       template<class U>
>       constexpr explicit payload_ator(payload_ator<U> a) noexcept : payload{a.payload} {}

>       friend bool operator==(payload_ator, payload_ator) = default;

>       template<class U>
>       friend constexpr bool operator==(payload_ator x, payload_ator<U> y) noexcept
>       {
>         return x.payload == y.payload;
>       }

>       using value_type = T;

>       constexpr T* allocate(std::size_t n) { return std::allocator<T>{}.allocate(n); }

>       constexpr void deallocate(T* p, std::size_t n) { return std::allocator<T>{}.deallocate(p, n); }

>       constexpr int get_payload() const noexcept { return payload; }
>     };

>     bool test()
>     {
>       constexpr int in_v = 42;
>       using my_pair_t = std::pair<int, std::vector<int, payload_ator<int>>>;
>       auto out_v = std::make_obj_using_allocator<const my_pair_t>(payload_ator<int>{in_v}).second.get_allocator().get_payload();
>       return in_v == out_v;
>     }

>     int main()
>     {
>       assert(test()); // passes only if a const-qualified pair specialization is considered as a pair specialization
>     }

[2022-03-04; Reflector poll]

Set priority to 2 after reflector poll.

Proposed resolution:

### 3678(i). Constructors of `std::chrono::time_zone` might be overly unspecified

Section: 27.11.5.1 [time.zone.overview] Status: New Submitter: Jiang An Opened: 2022-02-23 Last modified: 2022-03-04

Priority: 4

View all issues with New status.

Discussion:

In 27.11.5.1 [time.zone.overview], only defaulted move constructor and move assignment operator for `std::chrono::time_zone` are shown, other constructors are said to be "unspecified additional constructors". Presumably the intent is that the default constructor is not declared (suppressed) and the copy constructor is implicitly deleted, but it is not clear if they are not "unspecified additional constructors" and hence implicitly specified.

On the other hand, the defaulted definitions of move functions bring almost no specification, as no exposition only member is shown. So it is unspecified whether these functions are deleted, trivial, `constexpr`, or `noexcept`. Perhaps we want these functions to be non-deleted and `noexcept`, while triviality and `constexpr`-ness should be left unspecified.

[2022-03-04; Reflector poll]

Set priority to 4 after reflector poll.

Proposed resolution:

### 3679(i). Is `<ranges>` sufficient for `istream_view`?

Section: 24.6.5 [range.istream] Status: New Submitter: Barry Revzin Opened: 2022-02-24 Last modified: 2022-03-04

Priority: 3

View all issues with New status.

Discussion:

The following is rejected by libstdc++:

>     #include <ranges>

>     void call(std::ranges::istream_view<int>& v);

The error is quite cryptic, but ultimately the issue is not including `<istream>`. I think this currently isn't required to work, so the fact that it does not work is conforming. But should it be required to work?

I think either this should work or we should add a note to 24.6.5 [range.istream] about the include.

[2022-03-04; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

### 3680(i). Constructor of `move_only_function` with empty `ref`-qualifier is over-constrained

Section: 20.14.17.4.3 [func.wrap.move.ctor] Status: New Submitter: Zhihao Yuan Opened: 2022-02-27 Last modified: 2022-03-04

Priority: 2

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

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

View all issues with New status.

Discussion:

The following test compiles and holds:

>     struct X
>     {
>       int operator()() & { return 1; }  // #1
>       int operator()() && { return 2; } // #2
>     };

>     using T = move_only_function<int()>;
>     assert(T(X{})() == 1);

In other words, `#2` is never used. But if you really remove `#2`, the code doesn't compile.

The change was introduced between P0288R5 and P0288R6, with an intention (assumed) to require `move_only_function<R(Args...) cv>` erasing callable objects with `operator()` without `ref`-qualifiers. But the actual outcome outlawed programs that were valid when using `std::function`.

It also outlaws future programs such as

>     T x = [captures](this auto&) { return ...; }

where declaring `this auto&&` without forwarding only to satisfy `move_only_function`'s constraints would be strange.

[2022-03-04; Reflector poll]

Set priority to 2 after reflector poll. Probably needs a paper for LEWG.

Proposed resolution:

This wording is relative to N4901.

1. Modify 20.14.17.4.3 [func.wrap.move.ctor] as indicated:

   >     template<class VT>
   >       static constexpr bool is-callable-from = see below;

   > > -1- If `noex` is `true`, `is-callable-from<VT>` is equal to:

   > > >     is_nothrow_invocable_r_v<R, VT cv ref, ArgTypes...> &&
   > > >     is_nothrow_invocable_r_v<R, VT inv-quals, ArgTypes...>

   > > Otherwise, `is-callable-from<VT>` is equal to:

   > > >     is_invocable_r_v<R, VT cv ref, ArgTypes...> &&
   > > >     is_invocable_r_v<R, VT inv-quals, ArgTypes...>