Doc. no. N3522
Date: 2013-03-18
Project: Programming Language C++
Reply to: Alisdair Meredith <lwgchair@gmail.com>

C++ Standard Library Active Issues List (Revision R82)

Revised 2013-03-18 at 14:03:41 UTC

Reference ISO/IEC IS 14882:2011(E)

Also see:

The purpose of this document is to record the status of issues which have come before the Library Working Group (LWG) of the INCITS PL22.16 and ISO WG21 C++ Standards Committee. Issues represent potential defects in the ISO/IEC IS 14882:2011(E) document.

This document contains only library issues which are actively being considered by the Library Working Group, i.e., issues which have a status of New, Open, Ready, or Review. See Library Defect Reports List for issues considered defects and Library Closed Issues List for issues considered closed.

The issues in these lists are not necessarily formal ISO Defect Reports (DR's). While some issues will eventually be elevated to official Defect Report status, other issues will be disposed of in other ways. See Issue Status.

Prior to Revision 14, library issues lists existed in two slightly different versions; a Committee Version and a Public Version. Beginning with Revision 14 the two versions were combined into a single version.

This document includes [bracketed italicized notes] as a reminder to the LWG of current progress on issues. Such notes are strictly unofficial and should be read with caution as they may be incomplete or incorrect. Be aware that LWG support for a particular resolution can quickly change if new viewpoints or killer examples are presented in subsequent discussions.

For the most current official version of this document see http://www.open-std.org/jtc1/sc22/wg21/. Requests for further information about this document should include the document number above, reference ISO/IEC 14882:2011(E), and be submitted to Information Technology Industry Council (ITI), 1250 Eye Street NW, Washington, DC 20005.

Public information as to how to obtain a copy of the C++ Standard, join the standards committee, submit an issue, or comment on an issue can be found in the comp.std.c++ FAQ.

How to submit an issue

  1. Mail your issue to the author of this list.
  2. Specify a short descriptive title. If you fail to do so, the subject line of your mail will be used as the issue title.
  3. If the "From" on your email is not the name you wish to appear as issue submitter, then specify issue submitter.
  4. Provide a brief discussion of the problem you wish to correct. Refer to the latest working draft or standard using [section.tag] and paragraph numbers where appropriate.
  5. Provide proposed wording. This should indicate exactly how you want the standard to be changed. General solution statements belong in the discussion area. This area contains very clear and specific directions on how to modify the current draft. If you are not sure how to word a solution, you may omit this part. But your chances of a successful issue greatly increase if you attempt wording.
  6. It is not necessary for you to use html markup. However, if you want to, you can <ins>insert text like this</ins> and <del>delete text like this</del>. The only strict requirement is to communicate clearly to the list maintainer exactly how you want your issue to look.
  7. It is not necessary for you to specify other html font/formatting mark-up, but if you do the list maintainer will attempt to respect your formatting wishes (as described by html markup, or other common idioms).
  8. It is not necessary for you to specify open date or last modified date (the date of your mail will be used).
  9. It is not necessary for you to cross reference other issues, but you can if you like. You do not need to form the hyperlinks when you do, the list maintainer will take care of that.
  10. One issue per email is best.
  11. Between the time you submit the issue, and the next mailing deadline (date at the top of the Revision History), you own this issue. You control the content, the stuff that is right, the stuff that is wrong, the format, the misspellings, etc. You can even make the issue disappear if you want. Just let the list maintainer know how you want it to look, and he will try his best to accommodate you. After the issue appears in an official mailing, you no longer enjoy exclusive ownership of it.

Revision History

Issue Status

Issues reported to the LWG transition through a variety of statuses, indicating their progress towards a resolution. Typically, most issues will flow through the following stages.

New - The issue has not yet been reviewed by the LWG. Any Proposed Resolution is purely a suggestion from the issue submitter, and should not be construed as the view of LWG.

Open - The LWG has discussed the issue but is not yet ready to move the issue forward. There are several possible reasons for open status:

A Proposed Resolution for an open issue is still not be construed as the view of LWG. Comments on the current state of discussions are often given at the end of open issues in an italic font. Such comments are for information only and should not be given undue importance.

Review - Exact wording of a Proposed Resolution is now available for review on an issue for which the LWG previously reached informal consensus.

Ready - The LWG has reached consensus that the issue is a defect in the Standard, the Proposed Resolution is correct, and the issue is ready to forward to the full committee for further action as a Defect Report (DR).

Typically, an issue must have a proposed resolution in the currently published issues list, whose wording does not change during LWG review, to move to the Ready status.

Voting - This status should not be seen in a published issues list, but is a marker for use during meetings to indicate an issues was Ready in the pre-meeting mailing, the Proposed Resolution is correct, and the issue will be offered to the working group at the end of the current meeting to apply to the current working paper (WP) or to close in some other appropriate manner. This easily distinguishes such issues from those moving to Ready status during the meeting itself, that should not be forwarded until the next meeting. If the issue does not move forward, it should fall back to one of the other open states before the next list is published.

Immediate - This status should not be seen in a published issues list, but is a marker for use during meetings to indicate an issues was not Ready in the pre-meeting mailing, but the Proposed Resolution is correct, and the issue will be offered to the working group at the end of the current meeting to apply to the current working paper (WP) or to close in some other appropriate manner. This status is used only rarely, typically for fixes that are both small and obvious, and usually within a meeting of the expected publication of a revised standard. If the issue does not move forward, it should fall back to one of the other open states before the next list is published.

In addition, there are a few ways to categorise and issue that remains open to a resolution within the library, but is not actively being worked on.

Deferred - The LWG has discussed the issue, is not yet ready to move the issue forward, but neither does it deem the issue significant enough to delay publishing a standard or Technical Report. A typical deferred issue would be seeking to clarify wording that might be technically correct, but easily mis-read.

A Proposed Resolution for a deferred issue is still not be construed as the view of LWG. Comments on the current state of discussions are often given at the end of open issues in an italic font. Such comments are for information only and should not be given undue importance.

Core - The LWG has discussed the issue, and feels that some key part of resolving the issue is better handled by a cleanup of the language in the Core part of the standard. The issue is passed to the Core Working Group, which should ideally open a corresponding issue that can be linked from the library issue. Such issues will be revisitted after Core have made (or declined to make) any changes.

EWG - The LWG has discussed the issue, and wonder that some key part of resolving the issue is better handled by some (hopefully small) extension to the language. The issue is passed to the Evolution Working Group, which should ideally open a corresponding issue that can be linked from the library issue. Such issues will be revisitted after Evoltion have made (or declined to make) any recommendations. Positive recommendations from EWG will often mean the issue transition to Core status while we wait for some proposed new feature to land in the working paper.

Ultimately, all issues should reach closure with one of the following statuses.

DR - (Defect Report) - The full WG21/PL22.16 committee has voted to forward the issue to the Project Editor to be processed as a Potential Defect Report. The Project Editor reviews the issue, and then forwards it to the WG21 Convenor, who returns it to the full committee for final disposition. This issues list accords the status of DR to all these Defect Reports regardless of where they are in that process.

WP - (Working Paper) - The proposed resolution has not been accepted as a Technical Corrigendum, but the full WG21/PL22.16 committee has voted to apply the Defect Report's Proposed Resolution to the working paper.

C++11 - (C++ Standard, as revised for 2011) - The full WG21/PL22.16 committee has voted to accept the Defect Report's Proposed Resolution into the published 2011 revision to the C++ standard, ISO/IEC IS 14882:2011(E).

CD1 - (Committee Draft 2008) - The full WG21/PL22.16 committee has voted to accept the Defect Report's Proposed Resolution into the Fall 2008 Committee Draft.

TC1 - (Technical Corrigenda 1) - The full WG21/PL22.16 committee has voted to accept the Defect Report's Proposed Resolution as a Technical Corrigenda. Action on this issue is thus complete and no further action is possible under ISO rules.

TRDec - (Decimal TR defect) - The LWG has voted to accept the Defect Report's Proposed Resolution into the Decimal TR. Action on this issue is thus complete and no further action is expected.

Resolved - The LWG has reached consensus that the issue is a defect in the Standard, but the resolution adopted to resolve the issue came via some other mechanism than this issue in the list - typically by applying a formal paper, occasionally as a side effect of consolidating several interacting issue resolutions into a single issue.

Dup - The LWG has reached consensus that the issue is a duplicate of another issue, and will not be further dealt with. A Rationale identifies the duplicated issue's issue number.

NAD - The LWG has reached consensus that the issue is not a defect in the Standard.

NAD Editorial - The LWG has reached consensus that the issue can either be handled editorially, or is handled by a paper (usually linked to in the rationale).

NAD Future - In addition to the regular status, the LWG believes that this issue should be revisited at the next revision of the standard.

NAD Concepts - This status reflects an evolution of the language during the development of C++11, where a new feature entered the language, called concepts, that fundamentally changed the way templates would be specified and written. While this language feature was removed towards the end of the C++11 project, there is a clear intent to revisit this part of the language design. During that development, a number of issues were opened against the updated library related to use of that feature, or requesting fixes that would require exliciit use of the concepts feature. All such issues have been closed with this status, and may be revisitted should this or a similar language feature return for a future standard.

Tentatively - This is a status qualifier. The issue has been reviewed online, or at an unofficial meeting, but not in an official meeting, and some support has been formed for the qualified status. Tentatively qualified issues may be moved to the unqualified status and forwarded to full committee (if Ready) within the same meeting. Unlike Ready issues, Tentatively Ready issues will be reviewed in subcommittee prior to forwarding to full committee. When a status is qualified with Tentatively, the issue is still considered active.

Pending - This is a status qualifier. When prepended to a status this indicates the issue has been processed by the committee, and a decision has been made to move the issue to the associated unqualified status. However for logistical reasons the indicated outcome of the issue has not yet appeared in the latest working paper.

Issues are always given the status of New when they first appear on the issues list. They may progress to Open or Review while the LWG is actively working on them. When the LWG has reached consensus on the disposition of an issue, the status will then change to Dup, NAD, or Ready as appropriate. Once the full PL22.16 committee votes to forward Ready issues to the Project Editor, they are given the status of Defect Report ( DR). These in turn may become the basis for Technical Corrigenda (TC1), or are closed without action other than a Record of Response (Resolved ). The intent of this LWG process is that only issues which are truly defects in the Standard move to the formal ISO DR status.

Active Issues


1169. num_get not fully compatible with strto*

Section: 22.4.2.1.2 [facet.num.get.virtuals] Status: Open Submitter: Cosmin Truta Opened: 2009-07-04 Last modified: 2013-03-15

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

View all issues with Open status.

Discussion:

As specified in the latest draft, N2914, num_get is still not fully compatible with the following C functions: strtoul, strtoull, strtof and strtod.

In C, when conversion of a string to an unsigned integer type falls outside the representable range, strtoul and strtoull return ULONG_MAX and ULLONG_MAX, respectively, regardless whether the input field represents a positive or a negative value. On the other hand, the result of num_get conversion of negative values to unsigned integer types is zero. This raises a compatibility issue.

Moreover, in C, when conversion of a string to a floating-point type falls outside the representable range, strtof, strtod and strtold return ±HUGE_VALF, ±HUGE_VAL and ±HUGE_VALL, respectively. On the other hand, the result of num_get conversion of such out-of-range floating-point values results in the most positive/negative representable value. Although many C library implementations do implement HUGE_VAL (etc.) as the highest representable (which is, usually, the infinity), this isn't required by the C standard. The C library specification makes no statement regarding the value of HUGE_VAL and friends, which potentially raises the same compatibility issue as in the above case of unsigned integers. In addition, neither C nor C++ define symbolic constants for the maximum representable floating-point values (they only do so only for the maximum representable finite floating-point values), which raises a usability issue (it would be hard for the programmer to check the result of num_get against overflow).

As such, we propose to adjust the specification of num_get to closely follow the behavior of all of its underlying C functions.

[ 2010 Rapperswil: ]

Some concern that this is changing the specification for an existing C++03 function, but it was pointed out that this was underspecified as resolved by issue 23. This is clean-up for that issue in turn. Some concern that we are trying to solve the same problem in both clause 22 and 27.

Bill: There's a change here as to whether val is stored to in an error case.

Pablo: Don't think this changes whether val is stored to or not, but changes the value that is stored.

Bill: Remembers having skirmishes with customers and testers as to whether val is stored to, and the resolution was not to store in error cases.

Howard: Believes since C++03 we made a change to always store in overflow.

Everyone took some time to review the issue.

Pablo: C++98 definitely did not store any value during an error condition.

Dietmar: Depends on the question of what is considered an error, and whether overflow is an error or not, which was the crux of LWG 23.

Pablo: Yes, but given the "zero, if the conversion function fails to convert the entire field", we are requiring every error condition to store.

Bill: When did this happen?

Alisdair: One of the last two or three meetings.

Dietmar: To store a value in case of failure is a very bad idea.

Move to Open, needs more study.

[2011-03-24 Madrid meeting]

Move to deferred

[ 2011 Bloomington ]

The proposed wording looks good, no-one sure why this was held back before. Move to Review.

[2012,Kona]

Move to Open.

THe issues is what to do with -1. Should it match 'C' or do the "sane" thing. A fix here changes behavior, but is probably what we want.

Pablo to provide wording, with help from Howard.

Proposed resolution:

Change 22.4.2.1.2 [facet.num.get.virtuals] as follows:

Stage 3: The sequence of chars accumulated in stage 2 (the field) is converted to a numeric value by the rules of one of the functions declared in the header <cstdlib>:

The numeric value to be stored can be one of:

The resultant numeric value is stored in val. If the conversion function fails to convert the entire field, or if the field represents a value outside the range of representable values, ios_base::failbit is assigned to err.


1175. unordered complexity

Section: 23.2.5 [unord.req] Status: Open Submitter: Pablo Halpern Opened: 2009-07-17 Last modified: 2012-11-14

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.

Proposed resolution:

  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 23.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 unspecifiedimpldefdefault number of buckets in unordered_map. max_load_factor() returns 1.0.

    2 Complexity: ConstantLinear 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 unspecifiedimpldefdefault 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 quadraticLinear 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 23.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 unspecifiedimpldefdefault number of buckets in unordered_multimap. max_load_factor() returns 1.0.

    2 Complexity: ConstantLinear 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 unspecifiedimpldefdefault 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 quadraticLinear 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 23.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 unspecifiedimpldefdefault number of buckets in unordered_set. max_load_factor() returns 1.0.

    2 Complexity: ConstantLinear 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 unspecifiedimpldefdefault 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 quadraticLinear 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 23.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 unspecifiedimpldefdefault number of buckets in unordered_multiset. max_load_factor() returns 1.0.

    2 Complexity: ConstantLinear 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 unspecifiedimpldefdefault 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 quadraticLinear 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).


1213. Meaning of valid and singular iterator underspecified

Section: 24.2 [iterator.requirements] Status: Deferred Submitter: Daniel Krügler Opened: 2009-09-19 Last modified: 2012-11-14

View all other issues in [iterator.requirements].

View all issues with Deferred 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 24.2 [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. 20.6.12 [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 X [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

Proposed resolution:

Consider to await the paper.


1450. Contradiction in regex_constants

Section: 28.5.2 [re.matchflag] Status: Open Submitter: BSI Opened: 2010-08-25 Last modified: 2012-11-14

View all issues with Open status.

Discussion:

Addresses GB-127

The Bitmask Type requirements in 17.5.2.1.3 [bitmask.types] p.3 say that all elements on a bitmask type have distinct values, but 28.5.2 [re.matchflag] defines regex_constants::match_default and regex_constants::format_default as elements of the bitmask type regex_constants::match_flag_type, both with value 0. This is a contradiction.

[ Resolution proposed by ballot comment: ]

One of the bitmask elements should be removed from the declaration and should be defined separately, in the same manner as ios_base::adjustfield, ios_base::basefield and ios_base::floatfield are defined by 27.5.3.1.2 [ios::fmtflags] p.2 and Table 120. These are constants of a bitmask type, but are not distinct elements, they have more than one value set in the bitmask. regex_constants::format_default should be specified as a constant with the same value as regex_constants::match_default.

[ 2010-10-31 Daniel comments: ]

Strictly speaking, a bitmask type cannot have any element of value 0 at all, because any such value would contradict the requirement expressed in 17.5.2.1.3 [bitmask.types] p. 3:

for any pair Ci and Cj, Ci & Ci is nonzero

So, actually both regex_constants::match_default and regex_constants::format_default are only constants of the type regex_constants::match_flag_type, and no bitmask elements.

[ 2010-11-03 Daniel comments and provides a proposed resolution: ]

The proposed resolution is written against N3126 and considered as a further improvement of the fixes suggested by n3110.

Add the following sentence to 28.5.2 [re.matchflag] paragraph 1:

1 The type regex_constants::match_flag_type is an implementation-defined bitmask type (17.5.2.1.3). Matching a regular expression against a sequence of characters [first,last) proceeds according to the rules of the grammar specified for the regular expression object, modified according to the effects listed in Table 136 for any bitmask elements set. Type regex_constants::match_flag_type also defines the constants regex_constants::match_default and regex_constants::format_default.

[ 2011 Bloomington ]

It appears the key problem is the phrasing of the bitmask requirements. Jeremiah supplies updated wording.

Pete Becker has also provided an alternative resolution.

Ammend 17.5.2.1.3 [bitmask.types]:

Change the list of values for "enum bit mask" in p2 from

V0 = 1 << 0, V1 = 1 << 1, V2 = 1 << 2, V3 = 1 << 3, ....

to

V0 = 0, V1 = 1 << 0, V2 = 1 << 1, V3 = 1 << 2, ....

Here, the names C0, C1, etc. represent bitmask elements for this particular bitmask type. All such non-zero elements have distinct values such that, for any pair Ci and Cj where i != j, Ci & Ci is nonzero and Ci & Cj is zero.

Change bullet 3 of paragraph 4:

TheA non-zero value Y is set in the object X if the expression X & Y is nonzero.

Proposed resolution:

Ammend 17.5.2.1.3 [bitmask.types] p3:

Here, the names C0, C1, etc. represent bitmask elements for this particular bitmask type. All such elements have distinct, non-zero 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.

Add the following sentence to 28.5.2 [re.matchflag] paragraph 1:

1 The type regex_constants::match_flag_type is an implementation-defined bitmask type (17.5.2.1.3). The constants of that type, except for match_default and format_default, are bitmask elements. The match_default and format_default constants are empty bitmasks. Matching a regular expression against a sequence of characters [first,last) proceeds according to the rules of the grammar specified for the regular expression object, modified according to the effects listed in Table 136 for any bitmask elements set.


1526. C++ should not impose thread safety requirements on C99 library implementations

Section: 17.6.5.9 [res.on.data.races] Status: Open Submitter: BSI Opened: 2011-03-24 Last modified: 2012-11-14

View all issues with Open status.

Discussion:

Addresses GB-111

Section 17.6.5.9 [res.on.data.races], Data Race Avoidance, requires the C++ Standard Library to avoid data races that might otherwise result from two threads making calls to C++ Standard Library functions on distinct objects. The C standard library is part of the C++ Standard Library and some C++ Standary library functions (parts of the Localization library, as well as Numeric Conversions in 21.5), are specified to make use of the C standard library. Therefore, the C++ standard indirectly imposes a requirement on the thread safety of the C standard library. However, since the C standard does not address the concept of thread safety conforming C implementations exist that do no provide such guarantees. This conflict needs to be reconciled.

Suggested resolution by national body comment:

remove the requirement to make use of strtol() and sprintf() since these functions depend on the global C locale and thus cannot be made thread safe.

[2011-03-24 Madrid meeting]

Deferred

[ 2011 Bloomington ]

Alisdair: PJ, does this cause a problem in C?

PJ: Every implementation know of is thread safe.

Pete: There a couple of effects that are specified on strtol() and sprintf() which is a problem.

PJ: When C++ talks about C calls it should be "as if" calling the function.

Pete: Culprit is to string stuff. My fault.

PJ: Not your fault. You did what you were told. Distinct resolution to change wording.

Dietmar: What would we break if we change it back?

Pete: Nothing. If implemented on top of thread safe C library you are just fine.

Alisdair: Anyone want to clean up wording and put it back to what Pete gave us?

Alisdair: No volunteers. Do we want to mark as NAD? We could leave it as deferred.

Stefanus: Did original submitter care about this?

Lawrence: There is some work to make local calls thread safe. The resolution would be to call those thread safe version.

Pete: "As if called under single threaded C program"

Action Item (Alisdair): Write wording for this issue.

[2012, Kona]

Re-opened at the request of the concurrency subgroup, who feel there is an issue that needs clarifying for the (planned) 2017 standard.

Rationale:

No consensus to make a change at this time

[2012, Portland]

The concurrency subgroup decided to encourage the LWG to consider a change to 17.2 [library.c] or thereabouts to clarify that we are requiring C++-like thread-safety for setlocale, so that races are not introduced by C locale accesses, even when the C library allows it. This would require e.g. adding "and data race avoidance" at the end of 17.2 [library.c] p1:

"The C++ standard library also makes available the facilities of the C standard library, suitably adjusted to ensure static type safety and data race avoidance.",

with some further clarifications in the sections mentioned in 1526.

This seems to be consistent with existing implementations. This would technically not be constraining C implementation, but it would be further constraining C libraries used for both C and C++.

Proposed resolution:

This wording is relative to N3376.

  1. Change 17.2 [library.c] p1 as indicated:

    -1- The C++ standard library also makes available the facilities of the C standard library, suitably adjusted to ensure static type safety and data race avoidance.


2003. String exception inconsistency in erase.

Section: 21.4.1 [string.require] Status: Open Submitter: José Daniel García Sánchez Opened: 2010-10-21 Last modified: 2012-11-14

View other active issues in [string.require].

View all other issues in [string.require].

View all issues with Open status.

Discussion:

Clause 21.4.1 [string.require]p3 states:

No erase() or pop_back() member function shall throw any exceptions.

However in 21.4.6.5 [string::erase] p2 the first version of erase has

Throws: out_of_range if pos > size().

[2011-03-24 Madrid meeting]

Beman: Don't want to just change this, can we just say "unless otherwise specified"?

Alisdair: Leave open, but update proposed resolution to say something like "unless otherwise specified".

General agreement that it should be corrected but not a stop-ship.

Action: Update proposed wording for issue 2003 as above, but leave Open.

Proposed resolution:

Update [string.require]p/3:

3 No erase() or pop_back() member function shall throw any exceptions.


2013. Do library implementers have the freedom to add constexpr?

Section: 17.6.5.6 [constexpr.functions] Status: Review Submitter: Matt Austern Opened: 2010-11-12 Last modified: 2012-11-14

View all issues with Review status.

Discussion:

Suppose that a particular function is not tagged as constexpr in the standard, but that, in some particular implementation, it is possible to write it within the constexpr constraints. If an implementer tags such a function as constexpr, is that a violation of the standard or is it a conforming extension?

There are two questions to consider. First, is this allowed under the as-if rule? Second, if it does not fall under as-if, is there (and should there be) any special license granted to implementers to do this anyway, sort of the way we allow elision of copy constructors even though it is detectable by users?

I believe that this does not fall under "as-if", so implementers probably don't have that freedom today. I suggest changing the WP to grant it. Even if we decide otherwise, however, I suggest that we make it explicit.

[ 2011 Bloomington ]

General surprise this was not already in 'Ready' status, and so moved.

[ 2012 Kona ]

Some concern expressed when presented to full committee for the vote to WP status that this issue had been resolved without sufficient thought of the consequences for diverging library implementations, as users may use SFINAE to observe different behavior from otherwise identical code. Issue moved back to Review status, and will be discussed again in Portland with a larger group. Note for Portland: John Spicer has agreed to represent Core's concerns during any such discussion within LWG.

Proposed resolution:

In 17.6.4.6 [constexpr.functions], change paragraph 1 to:

This standard explicitly requires that certain standard library functions are constexpr [dcl.constexpr]. Additionally, an implementation may declare any function to be constexpr if that function's definition satisfies the necessary constraints. Within any header that provides any non-defining declarations of constexpr functions or constructors an implementation shall provide corresponding definitions.


2016. Allocators must be no-throw swappable

Section: 17.6.3.5 [allocator.requirements] Status: Open Submitter: Daniel Krügler Opened: 2010-11-17 Last modified: 2012-11-14

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with Open status.

Discussion:

During the Batavia meeting it turned out that there is a definition hole for types satisfying the Allocators requirements: The problem became obvious when it was discussed whether all swap functions of Containers with internal data handles can be safely tagged with noexcept or not. While it is correct that the implicit swap function of an allocator is required to be a no-throw operation (because move/copy-constructors and assignment operators are required to be no-throw functions), there are no such requirements for specialized swap overloads for a particular allocator.

But this requirement is essential because the Containers are required to support swappable Allocators, when the value allocator_traits<>::propagate_on_container_swap evaluates to true.

[2011-02-10 Alberto, Daniel, and Pablo collaborated on the proposed wording]

The proposed resolution (based on N3225) attempts to solve the following problems:

  1. Table 44 — Allocator requirements, expression rows X::propagate_on_container_copy_assignment, X::propagate_on_container_move_assignment, and X::propagate_on_container_swap only describe operations, but no requirements. In fact, if and only if these compile-time predicates evaluate to true, the additional requirements CopyAssignable, no-throw MoveAssignable, and no-throw lvalue Swappable, respectively, are imposed on the allocator types.
  2. 23.2.1 [container.requirements.general] p. 9 misses to refer to the correct swap conditions: The current wording does not relate to 17.6.3.2 [swappable.requirements] as it should and omits to mention that lvalues shall be swapped. Additional there is one situation described twice in p. 8 and p. 9 (undefined behaviour unless a.get_allocator() == b.get_allocator() or allocator_traits<allocator_type>::propagate_on_container_swap::value == true), which should be cleaned up.

[2011-04-08 Pablo comments]

I'm implementing a version of list now and I actually do find it impossible to write an exception-safe assignment operator unless I can assume that allocator assignment does not throw. (The problem is that I use a sentinel node and I need to allocate a new sentinel using the new allocator without destroying the old one -- then swap the allocator and sentinel pointer in atomically, without risk of an exception leaving one inconsistent with the other.

Please update the proposed resolution to add the nothrow requirement to copy-assignment.

Proposed resolution:

  1. Adapt the following three rows from Table 44 — Allocator requirements:

    Table 44 — Allocator requirements
    Expression Return type Assertion/note
    pre-/post-condition
    Default
    X::propagate_on_container_copy_assignment Identical to or derived from true_type
    or false_type
    true_type only if an allocator of type X should be copied
    when the client container is copy-assigned. See Note B, below.
    false_type
    X::propagate_on_container_move_assignment Identical to or derived from true_type
    or false_type
    true_type only if an allocator of type X should be moved
    when the client container is move-assigned. See Note B, below.
    false_type
    X::propagate_on_container_swap Identical to or derived from true_type
    or false_type
    true_type only if an allocator of type X should be swapped
    when the client container is swapped. See Note B, below.
    false_type
  2. Following 17.6.3.5 [allocator.requirements] p. 3 insert a new normative paragraph:

    Note B: If X::propagate_on_container_copy_assignment::value is true, X shall satisfy the CopyAssignable requirements (Table 39 [copyassignable]) and the copy operation shall not throw exceptions. If X::propagate_on_container_move_assignment::value is true, X shall satisfy the MoveAssignable requirements (Table 38 [moveassignable]) and the move operation shall not throw exceptions. If X::propagate_on_container_swap::value is true, lvalues of X shall be swappable (17.6.3.2 [swappable.requirements]) and the swap operation shall not throw exceptions.

  3. Modify 23.2.1 [container.requirements.general] p. 8 and p. 9 as indicated:

    8 - [..] The allocator may be replaced only via assignment or swap(). Allocator replacement is performed by copy assignment, move assignment, or swapping of the allocator only if allocator_traits<allocator_type>::propagate_on_container_copy_assignment::value, allocator_traits<allocator_type>::propagate_on_container_move_assignment::value, or allocator_traits<allocator_type>::propagate_on_container_swap::value is true within the implementation of the corresponding container operation. The behavior of a call to a container's swap function is undefined unless the objects being swapped have allocators that compare equal or allocator_traits<allocator_type>::propagate_on_container_swap::value is true. 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.

    9 - The expression a.swap(b), for containers a and b of a standard container type other than array, shall exchange the values of a and b without invoking any move, copy, or swap operations on the individual container elements. Lvalues of aAny Compare, Pred, or Hash objects belonging to a and b shall be swappable and shall be exchanged by unqualified calls to non-member calling swap as described in 17.6.3.2 [swappable.requirements]. If allocator_traits<allocator_type>::propagate_on_container_swap::value is true, then lvalues of allocator_type shall be swappable and the allocators of a and b shall also be exchanged using a an unqualified call to non-member swap call as described in 17.6.3.2 [swappable.requirements]. Otherwise, theythe allocators shall not be swapped, and the behavior is undefined unless a.get_allocator() == b.get_allocator(). Every iterator referring to an element in one container before the swap shall refer to the same element in the other container after the swap. It is unspecified whether an iterator with value a.end() before the swap will have value b.end() after the swap.


2018. regex_traits::isctype Returns clause is wrong

Section: 28.7 [re.traits] Status: Open Submitter: Jonathan Wakely Opened: 2010-11-16 Last modified: 2012-11-14

View all other issues in [re.traits].

View all issues with Open status.

Discussion:

28.7 [re.traits] p. 12 says:

returns true if f bitwise or'ed with the result of calling lookup_classname with an iterator pair that designates the character sequence "w" is not equal to 0 and c == '_'

If the bitmask value corresponding to "w" has a non-zero value (which it must do) then the bitwise or with any value is also non-zero, and so isctype('_', f) returns true for any f. Obviously this is wrong, since '_' is not in every ctype category.

There's a similar problem with the following phrases discussing the "blank" char class.

[2011-05-06: Jonathan Wakely comments and provides suggested wording]

DR 2019 added isblank support to <locale> which simplifies the definition of regex_traits::isctype by removing the special case for the "blank" class.

My suggestion for 2018 is to add a new table replacing the lists of recognized names in the Remarks clause of regex_traits::lookup_classname. I then refer to that table in the Returns clause of regex_traits::isctype to expand on the "in an unspecified manner" wording which is too vague. The conversion can now be described using the "is set" term defined by 17.5.2.1.3 [bitmask.types] and the new table to convey the intented relationship between e.g. [[:digit:]] and ctype_base::digit, which is not actually stated in the FDIS.

The effects of isctype can then most easily be described in code, given an "exposition only" function prototype to do the not-quite-so-unspecified conversion from char_class_type to ctype_base::mask.

The core of LWG 2018 is the "bitwise or'ed" wording which gives the wrong result, always evaluating to true for all values of f. That is replaced by the condition (f&x) == x where x is the result of calling lookup_classname with "w". I believe that's necessary, because the "w" class could be implemented by an internal "underscore" class i.e. x = _Alnum|_Underscore in which case (f&x) != 0 would give the wrong result when f==_Alnum.

The proposed resolution also makes use of ctype::widen which addresses the problem that the current wording only talks about "w" and '_' which assumes charT is char. There's still room for improvement here: the regex grammar in 28.13 [re.grammar] says that the class names in the table should always be recognized, implying that e.g. U"digit" should be recognized by regex_traits<char32_t>, but the specification of regex_traits::lookup_classname doesn't cover that, only mentioning char and wchar_t. Maybe the table should not distinguish narrow and wide strings, but should just have one column and add wording to say that regex_traits widens the name as if by using use_facet<ctype<charT>>::widen().

Another possible improvement would be to allow additional implementation-defined extensions in isctype. An implementation is allowed to support additional class names in lookup_classname, e.g. [[:octdigit:]] for [0-7] or [[:bindigit:]] for [01], but the current definition of isctype provides no way to use them unless ctype_base::mask also supports them.

[2011-05-10: Alberto and Daniel perform minor fixes in the P/R]

[ 2011 Bloomington ]

Consensus that this looks to be a correct solution, and the presentation as a table is a big improvement.

Concern that the middle section wording is a little muddled and confusing, Stefanus volunteered to reword.

Proposed resolution:

This wording is relative to the FDIS.

  1. Modify 28.7 [re.traits] p. 10 as indicated:

    template <class ForwardIterator>
      char_class_type lookup_classname(
        ForwardIterator first, ForwardIterator last, bool icase = false) const;
    

    -9- Returns: an unspecified value that represents the character classification named by the character sequence designated by the iterator range [first,last). If the parameter icase is true then the returned mask identifies the character classification without regard to the case of the characters being matched, otherwise it does honor the case of the characters being matched.(footnote 335) The value returned shall be independent of the case of the characters in the character sequence. If the name is not recognized then returns a value that compares equal to 0.

    -10- Remarks: For regex_traits<char>, at least the names "d", "w", "s", "alnum", "alpha", "blank", "cntrl", "digit", "graph", "lower", "print", "punct", "space", "upper" and "xdigit"narrow character names in Table X shall be recognized. For regex_traits<wchar_t>, at least the names L"d", L"w", L"s", L"alnum", L"alpha", L"blank", L"cntrl", L"digit", L"graph", L"lower", L"print", L"punct", L"space", L"upper" and L"xdigit"wide character names in Table X shall be recognized.

  2. Modify 28.7 [re.traits] p. 12 as indicated:

    bool isctype(charT c, char_class_type f) const;
    

    -11- Effects: Determines if the character c is a member of the character classification represented by f.

    -12- Returns: Converts f into a value m of type std::ctype_base::mask in an unspecified manner, and returns true if use_facet<ctype<charT> >(getloc()).is(m, c) is true. Otherwise returns true if f bitwise or'ed with the result of calling lookup_classname with an iterator pair that designates the character sequence "w" is not equal to 0 and c == '_', or if f bitwise or'ed with the result of calling lookup_classname with an iterator pair that designates the character sequence "blank" is not equal to 0 and c is one of an implementation-defined subset of the characters for which isspace(c, getloc()) returns true, otherwise returns false.except that when f represents membership of a character class named in Table X, the corresponding ctype_base::mask value shall be set in m. Given the function prototype

    template<class C>
       ctype_base::mask convert(typename regex_traits<C>::char_class_type);
    

    the result is determined as if by

    
    ctype_base::mask m = convert<charT>(f);
    const ctype<charT>& ct = use_facet<ctype<charT> >(getloc());
    if (ct.is(m, c))
      return true;
    charT w[1] = { ct.widen('w') };
    char_class_type x = lookup_classname(w, w+1);
    if ((f&x) == x && c == ct.widen('_'))
      return true;
    return false;
    

    [Example:

    
    regex_traits<char> t;
    string d("d");
    string u("upper");
    regex_traits<char>::char_class_type f;
    f = t.lookup_classname(d.begin(), d.end());
    f |= t.lookup_classname(u.begin(), u.end());
    ctype_base::mask m = convert<char>(f); // m == ctype_base::digit|ctype_base::upper
    

    end example]

    [Example:

    
    regex_traits<char> t;
    string w("w");
    regex_traits<char>::char_class_type f;
    f = t.lookup_classname(w.begin(), w.end());
    t.isctype('A', f); // returns true
    t.isctype('_', f); // returns true
    t.isctype(' ', f); // returns false
    

    end example]

  3. At the end of [re.traits] add a new Table X — Character class names and corresponding ctype masks:

    Table X — Character class names and corresponding ctype masks
    Narrow character name Wide character name Corresponding ctype_base::mask value
    "alnum" L"alnum" ctype_base::alnum
    "alpha" L"alpha" ctype_base::alpha
    "blank" L"blank" ctype_base::blank
    "cntrl" L"cntrl" ctype_base::cntrl
    "digit" L"digit" ctype_base::digit
    "d" L"d" ctype_base::digit
    "graph" L"graph" ctype_base::graph
    "lower" L"lower" ctype_base::lower
    "print" L"print" ctype_base::print
    "punct" L"punct" ctype_base::punct
    "space" L"space" ctype_base::space
    "s" L"s" ctype_base::space
    "upper" L"upper" ctype_base::upper
    "w" L"w" ctype_base::alnum
    "xdigit" L"xdigit" ctype_base::xdigit

2035. Output iterator requirements are broken

Section: 24.2.4 [output.iterators] Status: Open Submitter: Daniel Krügler Opened: 2011-02-27 Last modified: 2012-11-14

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

Proposed resolution:

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

    1. 17.6.3.2 [swappable.requirements] p5:

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

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

      a dereferenceable (24.2.1 [iterator.requirements.general]) pointer of type C*

    3. 20.6.3.2 [pointer.traits.functions]:

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

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

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

    5. 22.4.5.1.2 [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 (24.2.1 [iterator.requirements.general]).

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

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

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

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

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

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

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

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

  2. Edit 24.2.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", 24.2.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", 24.2.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 specificationend 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 dereferenceableincrementable.
    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", 24.2.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 specificationend 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", 24.2.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", 24.2.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 dereferenceableincrementable.
    --(++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. Missing definition for incrementable iterator

Section: 24.2.4 [output.iterators] Status: Open Submitter: Pete Becker Opened: 2011-02-27 Last modified: 2012-11-14

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 17.6.3.2 [swappable.requirements] there is a mention of "dereferenceable object"; in 17.6.3.5 [allocator.requirements] the table of Descriptive variable definitions refers to a "dereferenceable pointer"; 20.6.3.2 [pointer.traits.functions] refers to a "dereferenceable pointer"; in 22.4.5.1.2 [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:


2051. Explicit tuple constructors for more than one parameter

Section: 20.4.2 [tuple.tuple], 20.4.2.1 [tuple.cnstr] Status: Open Submitter: Ville Voutilainen Opened: 2011-05-01 Last modified: 2012-11-14

View all other issues in [tuple.tuple].

View all issues with Open status.

Discussion:

One of my constituents wrote the following:

-------snip------------

So far the only use I've found for std::tuple is as an ad-hoc type to emulate multiple return values. If the tuple ctor was made non-explicit one could almost think C++ supported multiple return values especially when combined with std::tie().

// assume types line_segment and point
// assume function double distance(point const&, point const&)

std::tuple<point, point>
closest_points(line_segment const& a, line_segment const& b) {
 point ax;
 point bx;
 /* some math */

 return {ax, bx};
}


double
distance(line_segment const& a, line_segment const& b) {
 point ax;
 point bx;
 std::tie(ax, bx) = closest_points(a, b);

 return distance(ax, bx);
}

-------snap----------

See also the messages starting from lib-29330.

Some notes:

  1. pair allows such a return
  2. a lambda with a deduced return type doesn't allow it for any type
  3. decltype refuses {1, 2}

I would recommend making non-unary tuple constructors non-explicit.

[Bloomington, 2011]

Move to NAD Future, this would be an extension to existing functionality.

[Portland, 2012]

Move to Open at the request of the Evolution Working Group.

Proposed resolution:


2052. Mixup between mapped_type and value_type for associative containers

Section: 23.2.4 [associative.reqmts] Status: Open Submitter: Marc Glisse Opened: 2011-05-04 Last modified: 2012-11-14

View other active issues in [associative.reqmts].

View all other issues in [associative.reqmts].

View all issues with Open status.

Discussion:

(this is basically reopening the first part of issue 2006, as discussed in the thread starting at c++std-lib-30698 )

Section 23.2.4 [associative.reqmts]

In Table 102, several uses of T (which means mapped_type here) should be value_type instead. This is almost editorial. For instance:

a_uniq.emplace(args)

Requires: T shall be EmplaceConstructible into X from args.

Effects: Inserts a T 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.

[ 2011 Bloomington ]

Not even an exhaustive list of problem locations. No reason to doubt issue.

Pablo agrees to provide wording.

[ 2011-09-04 Pablo Halpern provides improved wording ]

Proposed resolution:

In both section 23.2.4 [associative.reqmts] Table 102 and 23.2.5 [unord.req], Table 103, make the following text replacements:

Original text, in FDIS Replacement text
T is CopyInsertable into X and CopyAssignable. value_type is CopyInsertable into X, key_type is CopyAssignable, and mapped_type is CopyAssignable (for containers having a mapped_type)
T is CopyInsertable value_type is CopyInsertable
T shall be CopyInsertable value_type shall be CopyInsertable
T shall be MoveInsertable value_type shall be MoveInsertable
T shall be EmplaceConstructible value_type shall be EmplaceConstructible
T object value_type object

[ Notes to the editor: The above are carefully selected phrases that can be used for global search-and-replace within the specified sections without accidentally making changes to correct uses T. ]


2059. C++0x ambiguity problem with map::erase

Section: 23.4.4 [map] Status: Open Submitter: Christopher Jefferson Opened: 2011-05-18 Last modified: 2013-03-15

View all other issues in [map].

View all issues with Open status.

Discussion:

map::erase (and several related methods) took an iterator in C++03, but take a const_iterator in C++0x. This breaks code where the map's key_type has a constructor which accepts an iterator (for example a template constructor), as the compiler cannot choose between erase(const key_type&) and erase(const_iterator).

#include <map>

struct X
{
  template<typename T>
  X(T&) {}
};

bool operator<(const X&, const X&) { return false; }

void erasor(std::map<X,int>& s, X x)
{
  std::map<X,int>::iterator it = s.find(x);
  if (it != s.end())
    s.erase(it);
}

[ 2011 Bloomington ]

This issue affects only associative container erase calls, and is not more general, as these are the only functions that are also overloaded on another single arguement that might cause confusion - the erase by key method. The complete resolution should simply restore the iterator overload in addition to the const_iterator overload for all eight associative containers.

Proposed wording supplied by Alan Talbot, and moved to Review.

[2012, Kona]

Moved back to Open by post-meeting issues processing group.

Pablo very unhappy about case of breaking code with ambiguous conversion between both iterator types.

Alisdair strongly in favor of proposed resolution, this change from C++11 bit Chris in real code, and it took a while to track down the cause.

Move to open, bring in front of a larger group

Proposed wording from Jeremiah: erase(key) shall not participate in overload resolution if iterator is convertible to key. Note that this means making erase(key) a template-method

Poll Chris to find out if he already fixed his code, or fixed his library

Jeremiah - allow both overloads, but enable_if the const_iterator form as a template, requiring is_same to match only const_iterator.

Poll PJ to see if he has already applied this fix?

Proposed resolution:

Editorial note: The following things are different between 23.2.4 [associative.reqmts] p.8 and 23.2.5 [unord.req] p.10. These should probably be reconciled.

  1. First uses the convention "denotes"; second uses the convention "is".
  2. First redundantly says: "If no such element exists, returns a.end()." in erase table entry, second does not.

23.2.4 [associative.reqmts] Associative containers

8 In Table 102, X denotes an associative container class, a denotes a value of X, a_uniq denotes a value of X when X supports unique keys, a_eq denotes a value of X when X supports multiple keys, u denotes an identifier, i and j satisfy input iterator requirements and refer to elements implicitly convertible to value_type, [i,j) denotes a valid range, p denotes a valid const iterator to a, q denotes a valid dereferenceable const iterator to a, r denotes a valid dereferenceable iterator to a, [q1, q2) denotes a valid range of const iterators in a, il designates an object of type initializer_list<value_type>, t denotes a value of X::value_type, k denotes a value of X::key_type and c denotes a value of type X::key_compare. A denotes the storage allocator used by X, if any, or std::allocator<X::value_type> otherwise, and m denotes an allocator of a type convertible to A.

23.2.4 [associative.reqmts] Associative containers Table 102

Add row:

a.erase(r) iterator erases the element pointed to by r. Returns an iterator pointing to the element immediately following r prior to the element being erased. If no such element exists, returns a.end(). amortized constant

23.2.5 [unord.req] Unordered associative containers

10 In table 103: X is an unordered associative container class, a is an object of type X, b is a possibly const object of type X, a_uniq is an object of type X when X supports unique keys, a_eq is an object of type X when X supports equivalent keys, i and j are input iterators that refer to value_type, [i, j) is a valid range, p and q2 are valid const iterators to a, q and q1 are valid dereferenceable const iterators to a, r is a valid dereferenceable iterator to a, [q1,q2) is a valid range in a, il designates an object of type initializer_list<value_type>, t is a value of type X::value_type, k is a value of type key_type, hf is a possibly const value of type hasher, eq is a possibly const value of type key_equal, n is a value of type size_type, and z is a value of type float.

23.2.5 [unord.req] Unordered associative containers Table 103

Add row:

a.erase(r) iterator Erases the element pointed to by r. Returns the iterator immediately following r prior to the erasure. Average case O(1), worst case O(a.size()).

23.4.4.1 [map.overview] Class template map overview p. 2

iterator erase(iterator position);
iterator erase(const_iterator position);
size_type erase(const key_type& x);
iterator erase(const_iterator first, const_iterator last);

23.4.5.1 [multimap.overview] Class template multimap overview p. 2

iterator erase(iterator position);
iterator erase(const_iterator position);
size_type erase(const key_type& x);
iterator erase(const_iterator first, const_iterator last);

23.4.6.1 [set.overview] Class template set overview p. 2

iterator erase(iterator position);
iterator erase(const_iterator position);
size_type erase(const key_type& x);
iterator erase(const_iterator first, const_iterator last);

23.4.7.1 [multiset.overview] Class template multiset overview

iterator erase(iterator position);
iterator erase(const_iterator position);
size_type erase(const key_type& x);
iterator erase(const_iterator first, const_iterator last);

23.5.4.1 [unord.map.overview] Class template unordered_map overview p. 3

iterator erase(iterator position);
iterator erase(const_iterator position);
size_type erase(const key_type& x);
iterator erase(const_iterator first, const_iterator last);

23.5.5.1 [unord.multimap.overview] Class template unordered_multimap overview p. 3

iterator erase(iterator position);
iterator erase(const_iterator position);
size_type erase(const key_type& x);
iterator erase(const_iterator first, const_iterator last);

23.5.6.1 [unord.set.overview] Class template unordered_set overview p. 3

iterator erase(iterator position);
iterator erase(const_iterator position);
size_type erase(const key_type& x);
iterator erase(const_iterator first, const_iterator last);

23.5.7.1 [unord.multiset.overview] Class template unordered_multiset overview p. 3

iterator erase(iterator position);
iterator erase(const_iterator position);
size_type erase(const key_type& x);
iterator erase(const_iterator first, const_iterator last);

[diff.cpp03.containers] C.2.12 Clause 23: containers library

23.2.3, 23.2.4

Change: Signature changes: from iterator to const_iterator parameters

Rationale: Overspecification. Effects: The signatures of the following member functions changed from taking an iterator to taking a const_iterator:

Valid C++ 2003 code that uses these functions may fail to compile with this International Standard.


2062. Effect contradictions w/o no-throw guarantee of std::function swaps

Section: 20.8.11.2 [func.wrap.func], 20.8.11.2.2 [func.wrap.func.mod] Status: Open Submitter: Daniel Krügler Opened: 2011-05-28 Last modified: 2012-11-14

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

View all issues with Open status.

Discussion:

Howard Hinnant observed in reflector message c++std-lib-30841 that 20.8.11.2 [func.wrap.func] makes the member swap noexcept, even though the non-member swap is not noexcept.

The latter was an outcome of the discussions during the Batavia meeting and the Madrid meeting involving LWG 1349, which seems to indicate that the remaining noexcept specifier at the member swap is incorrect and should be removed.

But if we allow for a potentially throwing member swap of std::function, this causes another conflict with the exception specification for the following member function:

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

Effects: function(f).swap(*this);

Note that in this example the sub-expression function(f) does not cause any problems, because of the nothrow-guarantee given in 20.8.11.2.1 [func.wrap.func.con] p. 10. The problem is located in the usage of the swap which could potentially throw given the general latitude.

So, either the Madrid meeting decision need to be revised (and both member and free swap of std::function should be noexcept), or this function needs to be adapted as well, e.g. by taking the exception-specification away or by changing the semantics.

One argument for "swap-may-throw" would be to allow for small-object optimization techniques where the copy of the target may throw. But given the fact that the swap function has been guaranteed to be "Throws: Nothing" from TR1 on, it seems to me that that there would still be opportunities to perform small-object optimizations just restricted to the set of target copies that cannot throw.

In my opinion member swap of std::function has always been intended to be no-throw, because otherwise there would be no good technical reason to specify the effects of several member functions in terms of the "construct-swap" idiom (There are three functions that are defined this way), which provides the strong exception safety in this case. I suggest to enforce that both member swap and non-member swap of std::function are nothrow functions as it had been guaranteed since TR1 on.

[ 2011 Bloomington ]

Dietmar: May not be swappable in the first place.

Alisdair: This is wide contact. Then we should be taking noexcept off instead of putting it on. This is preferred resolution.

Pablo: This is bigger issue. Specification of assignment in terms of swap is suspect to begin with. It is over specification. How this was applied to string is a better example to work from.

Pablo: Two problems: inconsistency that should be fixed (neither should have noexcept), the other issues is that assignment should not be specified in terms of swap. There are cases where assignment should succeed where swap would fail. This is easier with string as it should follow container rules.

Action Item (Alisdair): There are a few more issues found to file.

Dave: This is because of allocators? The allocator makes this not work.

Howard: There is a type erased allocator in shared_ptr. There is a noexcept allocator in shared_ptr.

Pablo: shared_ptr is a different case. There are shared semantics and the allocator does move around. A function does not have shared semantics.

Alisdair: Function objects think they have unique ownership.

Howard: In function we specify semantics with copy construction and swap.

Action Item (Pablo): Write this up better (why assignment should not be defined in terms of swap)

Howard: Not having trouble making function constructor no throw.

Dietmar: Function must allocate memory.

Howard: Does not put stuff that will throw on copy or swap in small object optimization. Put those on heap. Storing allocator, but has to be no throw copy constructable.

Pablo: Are you allowed to or required to swap or move allocators in case or swap or move.

Dave: An allocator that is type erased should be different...

Pablo: it is

Dave: Do you need to know something about allocator types? But only at construction time.

Pablo: You could have allocators that are different types.

Dave: Swap is two ended operation.

Pablo: Opinion is that both have to say propagate on swap for them to swap.

John: It is not arbitrary. If one person says no. No is no.

Howard: Find noexcept swap to be very useful. Would like to move in that direction and bring container design along.

Dave: If you have something were allocator must not propagate you can detect that at construction time.

...

Pablo: Need to leave this open and discuss in smaller group.

Alisdair: Tried to add boost::any as TR2 proposal and ran into this issue. Only the first place where we run into issues with type erased allocators. Suggest we move it to open.

Action Item: Move to open.

Action Item (Pablo works with Howard and Daniel): Address the more fundamental issue (which may be multiple issues) and write up findings.

[ Original resolution: ]

This wording is relative to the FDIS.

  1. Modify the header <functional> synopsis in 20.8 [function.objects] as indicated:

    namespace std {
      […]
    
      template<class R, class... ArgTypes>
      void swap(function<R(ArgTypes...)>&, function<R(ArgTypes...)>&) noexcept;
    
      […]
    }
    
  2. Modify the class template function synopsis in 20.8.11.2 [func.wrap.func] as indicated:

    namespace std {
      […]
    
      // [func.wrap.func.alg], specialized algorithms:
      template<class R, class... ArgTypes>
      void swap(function<R(ArgTypes...)>&, function<R(ArgTypes...)>&) noexcept;
    
      […]
    }
    
  3. Modify 20.8.11.2.7 [func.wrap.func.alg] as indicated:

    template<class R, class... ArgTypes>
    void swap(function<R(ArgTypes...)>& f1, function<R(ArgTypes...)>& f2) noexcept;
    

    -1- Effects: f1.swap(f2);

Proposed resolution:


2063. Contradictory requirements for string move assignment

Section: 21.4 [basic.string] Status: Open Submitter: Howard Hinnant Opened: 2011-05-29 Last modified: 2012-11-14

View all other issues in [basic.string].

View all issues with Open status.

Discussion:

21.4.1 [string.require]/p4 says that basic_string is an "allocator-aware" container and behaves as described in 23.2.1 [container.requirements.general].

23.2.1 [container.requirements.general] describes move assignment in p7 and Table 99.

If allocator_traits<allocator_type>::propagate_on_container_move_assignment::value is false, and if the allocators stored in the lhs and rhs sides are not equal, then move assigning a string has the same semantics as copy assigning a string as far as resources are concerned (resources can not be transferred). And in this event, the lhs may have to acquire resources to gain sufficient capacity to store a copy of the rhs.

However 21.4.2 [string.cons]/p22 says:

basic_string<charT,traits,Allocator>&
operator=(basic_string<charT,traits,Allocator>&& str) noexcept;

Effects: If *this and str are not the same object, modifies *this as shown in Table 71. [Note: A valid implementation is swap(str). — end note ]

These two specifications for basic_string::operator=(basic_string&&) are in conflict with each other. It is not possible to implement a basic_string which satisfies both requirements.

Additionally assign from an rvalue basic_string is defined as:

basic_string& assign(basic_string&& str) noexcept;

Effects: The function replaces the string controlled by *this with a string of length str.size() whose elements are a copy of the string controlled by str. [ Note: A valid implementation is swap(str). — end note ]

It seems contradictory that this member can be sensitive to propagate_on_container_swap instead of propagate_on_container_move_assignment. Indeed, there is a very subtle chance for undefined behavior here: If the implementation implements this in terms of swap, and if propagate_on_container_swap is false, and if the two allocators are unequal, the behavior is undefined, and will likely lead to memory corruption. That's a lot to go wrong under a member named "assign".

[ 2011 Bloomington ]

Alisdair: Can this be conditional noexcept?

Pablo: We said we were not going to put in many conditional noexcepts. Problem is not allocator, but non-normative definition. It says swap is a valid operation which it is not.

Dave: Move assignment is not a critical method.

Alisdair: Was confusing assignment and construction.

Dave: Move construction is critical for efficiency.

Kyle: Is it possible to test for noexcept.

Alisdair: Yes, query the noexcept operator.

Alisdair: Agreed there is a problem that we cannot unconditionally mark these operations as noexcept.

Pablo: How come swap is not defined in alloc

Alisdair: It is in utility.

Pablo: Swap has a conditional noexcept. Is no throw move constructable, is no throw move assignable.

Pablo: Not critical for strings or containers.

Kyle: Why?

Pablo: They do not use the default swap.

Dave: Important for deduction in other types.

Alisdair: Would change the policy we adopted during FDIS mode.

Pablo: Keep it simple and get some vendor experience.

Alisdair: Is this wording correct? Concerned with bullet 2.

Pablo: Where does it reference containers section.

Alisdair: String is a container.

Alisdair: We should not remove redundancy piecemeal.

Pablo: I agree. This is a deviation from rest of string. Missing forward reference to containers section.

Pablo: To fix section 2. Only the note needs to be removed. The rest needs to be a forward reference to containers.

Alisdair: That is a new issue.

Pablo: Not really. Talking about adding one sentence, saying that basic string is a container.

Dave: That is not just a forward reference, it is a semantic change.

PJ: We intended to make it look like a container, but it did not satisfy all the requirements.

Pablo: Clause 1 is correct. Clause 2 is removing note and noexcept (do not remove the rest). Clause 3 is correct.

Alisdair: Not sure data() is correct (in clause 2).

Conclusion: Move to open, Alisdair and Pablo volunteered to provide wording

[ originally proposed wording: ]

This wording is relative to the FDIS.

  1. Modify the class template basic_string synopsis in 21.4 [basic.string]:

    namespace std {
      template<class charT, class traits = char_traits<charT>,
        class Allocator = allocator<charT> >
      class basic_string {
      public:
        […]
        basic_string& operator=(basic_string&& str) noexcept;
        […]
        basic_string& assign(basic_string&& str) noexcept;
        […]
      };
    }
    
  2. Remove the definition of the basic_string move assignment operator from 21.4.2 [string.cons] entirely, including Table 71 — operator=(const basic_string<charT, traits, Allocator>&&). This is consistent with how we define move assignment for the containers in Clause 23:

    basic_string<charT,traits,Allocator>&
    operator=(basic_string<charT,traits,Allocator>&& str) noexcept;
    

    -22- Effects: If *this and str are not the same object, modifies *this as shown in Table 71. [ Note: A valid implementation is swap(str). — end note ]

    -23- If *this and str are the same object, the member has no effect.

    -24- Returns: *this

    Table 71 — operator=(const basic_string<charT, traits, Allocator>&&)
    Element Value
    data() points at the array whose first element was pointed at by str.data()
    size() previous value of str.size()
    capacity() a value at least as large as size()
  3. Modify the paragraphs prior to 21.4.6.3 [string::assign] p.3 as indicated (The first insertion recommends a separate paragraph number for the indicated paragraph):

    basic_string& assign(basic_string&& str) noexcept;
    

    -?- Effects: Equivalent to *this = std::move(str). The function replaces the string controlled by *this with a string of length str.size() whose elements are a copy of the string controlled by str. [ Note: A valid implementation is swap(str). — end note ]

    -3- Returns: *this

[ 2012-08-11 Joe Gottman observes: ]

One of the effects of basic_string's move-assignment operator (21.4.2 [string.cons], Table 71) is

Element Value
data() points at the array whose first element was pointed at by str.data()

If a string implementation uses the small-string optimization and the input string str is small enough to make use of it, this effect is impossible to achieve. To use the small string optimization, a string has to be implemented using something like

union
{
   char buffer[SMALL_STRING_SIZE];
   char *pdata;
};

When the string is small enough to fit inside buffer, the data() member function returns static_cast<const char *>(buffer), and since buffer is an array variable, there is no way to implement move so that the moved-to string's buffer member variable is equal to this->buffer.

Resolution proposal:

Change Table 71 to read:

Element Value
data() points at the array whose first element was pointed at by str.data() that contains the same characters in the same order as str.data() contained before operator=() was called

Proposed resolution:


2070. allocate_shared should use allocator_traits<A>::construct

Section: 20.7.2.2.6 [util.smartptr.shared.create] Status: Open Submitter: Jonathan Wakely Opened: 2011-07-11 Last modified: 2012-11-14

View all issues with Open status.

Discussion:

20.7.2.2.6 [util.smartptr.shared.create] says:

-2- Effects: Allocates memory suitable for an object of type T and constructs an object in that memory via the placement new expression ::new (pv) T(std::forward<Args>(args)...). The template allocate_shared uses a copy of a to allocate memory. If an exception is thrown, the functions have no effect.

This explicitly requires placement new rather than using allocator_traits<A>::construct(a, (T*)pv, std::forward<Args>(args)...) In most cases that would result in the same placement new expression, but would allow more control over how the object is constructed e.g. using scoped_allocator_adaptor to do uses-allocator construction, or using an allocator declared as a friend to construct objects with no public constructors.

[ 2011-08-16 Bloomington: ]

Agreed to fix in principle, but believe that make_shared and allocate_shared have now diverged enough that their descriptions should be separated. Pablo and Stefanus to provide revised wording.

Daniel's (old) proposed resolution:

This wording is relative to the FDIS.

  1. Change the following paragraphs of 20.7.2.2.6 [util.smartptr.shared.create] as indicated (The suggested removal of the last sentence of p1 is not strictly required to resolve this issue, but is still recommended, because it does not say anything new but may give the impression that it says something new):

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

    -1- Requires: For the template make_shared, tThe expression ::new (pv) T(std::forward<Args>(args)...), where pv has type void* and points to storage suitable to hold an object of type T, shall be well formed. For the template allocate_shared, the expression allocator_traits<A>::construct(a, pt, std::forward<Args>(args)...), where pt has type T* and points to storage suitable to hold an object of type T, shall be well formed. A shall be an allocator ([allocator.requirements]). The copy constructor and destructor of A shall not throw exceptions.

    -2- Effects: Allocates memory suitable for an object of type T and constructs an object in that memory. The template make_shared constructs the object via the placement new expression ::new (pv) T(std::forward<Args>(args)...). The template allocate_shared uses a copy of a to allocate memory and constructs the object by calling allocator_traits<A>::construct(a, pt, std::forward<Args>(args)...). If an exception is thrown, the functions have no effect.

    -3- Returns: A shared_ptr instance that stores and owns the address of the newly constructed object of type T.

    -4- Postconditions: get() != 0 && use_count() == 1

    -5- Throws: bad_alloc, or, for the template make_shared, an exception thrown from the constructor of T, or, for the template allocate_shared, an exception thrown from A::allocate or from allocator_traits<A>::constructfrom the constructor of T.

    -6- Remarks: Implementations are encouraged, but not required, to perform no more than one memory allocation. [ Note: This provides efficiency equivalent to an intrusive smart pointer. — end note ]

    -7- [ Note: These functions will typically allocate more memory than sizeof(T) to allow for internal bookkeeping structures such as the reference counts. — end note ]

[2011-12-04: Jonathan and Daniel improve wording]

See also c++std-lib-31796

Proposed resolution:

This wording is relative to the FDIS.

  1. Change the following paragraphs of 20.7.2.2.6 [util.smartptr.shared.create] as indicated:

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

    -1- Requires: The expression ::new (pv) T(std::forward<Args>(args)...), where pv has type void* and points to storage suitable to hold an object of type T, shall be well formed. A shall be an allocator (17.6.3.5 [allocator.requirements]). The copy constructor and destructor of A shall not throw exceptions.

    -2- Effects: Equivalent to

     
    return allocate_shared<T>(allocator<T>(), std::forward<Args>(args)...);
    

    Allocates memory suitable for an object of type T and constructs an object in that memory via the placement new expression ::new (pv) T(std::forward<Args>(args)...). The template allocate_shared uses a copy of a to allocate memory. If an exception is thrown, the functions have no effect.

    -?- Remarks: An implementation may meet the effects (and the implied guarantees) without creating the allocator object [Note: That is, user-provided specializations of std::allocator may not be instantiated, the expressions ::new (pv) T(std::forward<Args>(args)...) and pv->~T() may be evaluated directly — end note].

    -3- Returns: A shared_ptr instance that stores and owns the address of the newly constructed object of type T.

    -4- Postconditions: get() != 0 && use_count() == 1

    -5- Throws: bad_alloc, or an exception thrown from A::allocate or from the constructor of T.

    -6- Remarks: Implementations are encouraged, but not required, to perform no more than one memory allocation. [Note: This provides efficiency equivalent to an intrusive smart pointer. — end note]

    -7- [Note: These functions will typically allocate more memory than sizeof(T) to allow for internal bookkeeping structures such as the reference counts. — end note]

  2. Add the following set of new paragraphs immediately following the previous paragraph 7 of 20.7.2.2.6 [util.smartptr.shared.create]:

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

    -?- Requires: The expressions allocator_traits<A>::construct(b, pt, std::forward<Args>(args)...) and allocator_traits<A>::destroy(b, pt) shall be well-formed and well-defined, where b has type A and is a copy of a and where pt has type T* and points to storage suitable to hold an object of type T. A shall meet the allocator requirements (17.6.3.5 [allocator.requirements]).

    -?- Effects: Uses an object a2 of type allocator_traits<A>::rebind_alloc<unspecified> that compares equal to a to allocate memory suitable for an object of type T. Uses a copy b of type A from a to construct an object of type T in that memory by calling allocator_traits<A>::construct(b, pt, std::forward<Args>(args)...). If an exception is thrown, the function has no effect.

    -?- Returns: A shared_ptr instance that stores and owns the address of the newly constructed object of type T. When ownership is given up, the effects are as follows: Uses a copy b2 of type A from a to destruct an object of type T by calling allocator_traits<A>::destroy(b2, pt2) where pt2 has type T* and refers to the newly constructed object. Then uses an object of type allocator_traits<A>::rebind_alloc<unspecified> that compares equal to a to deallocate the allocated memory.

    -?- Postconditions: get() != 0 && use_count() == 1

    -?- Throws: Nothing unless memory allocation or allocator_traits<A>::construct throws an exception.

    -?- Remarks: Implementations are encouraged, but not required, to perform no more than one memory allocation. [Note: Such an implementation provides efficiency equivalent to an intrusive smart pointer. — end note]

    -?- [Note: This function will typically allocate more memory than sizeof(T) to allow for internal bookkeeping structures such as the reference counts. — end note]


2072. Unclear wording about capacity of temporary buffers

Section: 20.6.11 [temporary.buffer] Status: Open Submitter: Kazutoshi Satoda Opened: 2011-08-10 Last modified: 2012-11-14

View all other issues in [temporary.buffer].

View all issues with Open status.

Discussion:

According to 20.6.11 [temporary.buffer] p1+2:

template <class T>
pair<T*, ptrdiff_t> get_temporary_buffer(ptrdiff_t n) noexcept;

-1- Effects: Obtains a pointer to storage sufficient to store up to n adjacent T objects. It is implementation-defined whether over-aligned types are supported (3.11).

-2- Returns: A pair containing the buffer's address and capacity (in the units of sizeof(T)), or a pair of 0 values if no storage can be obtained or if n <= 0.

I read this as prohibiting to return a buffer of which capacity is less than n, because such a buffer is not sufficient to store n objects.

The corresponding description in SGI STL is clear on this point, but I think it is a bit too verbose:

(for the return value, a pair P) [...] the buffer pointed to by P.first is large enough to hold P.second objects of type T. P.second is greater than or equal to 0, and less than or equal to len.

There seems to be two different targets of the "up to n" modification: The capacity of obtained buffer, and the actual number that the caller will store into the buffer.

First I read as the latter, and got surprised seeing that libstdc++ implementation can return a smaller buffer. I started searching about get_temporary_buffer(). After reading a quote from TC++PL at stackoverflow, I realized that the former is intended.

Such misinterpretation seems common:

Proposed resolution:


2075. Progress guarantees, lock-free property, and scheduling assumptions

Section: 1.10 [intro.multithread], 29.4 [atomics.lockfree], 29.6.5 [atomics.types.operations.req] Status: Open Submitter: Torvald Riegel Opened: 2011-08-18 Last modified: 2012-11-14

View all issues with Open status.

Discussion:

According to 1.10 [intro.multithread] p2:

"Implementations should ensure that all unblocked threads eventually make progress."

29.4 [atomics.lockfree] p2 declares the lock-free property for a particular object. However, "lock-free" is never defined, and in discussions that I had with committee members it seemed as if the standard's lock-free would be different from what lock-free means in other communities (eg, research, text books on concurrent programming, etc.).

Following 29.6.5 [atomics.types.operations.req] p7 is_lock_free() returns "true if the object is lock-free". What is returned if the object is only sometimes lock-free?

Basically, I would like to see clarifications for the progress guarantees so that users know what they can expect from implementations (and what they cannot expect!), and to give implementors a clearer understanding of which user expectations they have to implement.

  1. Elaborate on the intentions of the progress guarantee in 1.10 [intro.multithread] p2. As I don't know about your intentions, it's hard to suggest a resolution.

  2. Define the lock-free property. The definition should probably include the following points:

  3. Add a note explaining that compare-exchange-weak is not necessarily lock-free (but is nonblocking)? Or is it indeed intended to be lock-free (only allowed to fail spuriously but guaranteed to not fail eventually)? Implementing the latter might be a challenge on LL-SC machines or lead to space overheads I suppose, see the cacheline sharing example above.

[2011-12-01: Hans comments]

1.10 [intro.multithread] p2 was an intentional compromise, and it was understood at the time that it was not a precise statement. The wording was introduced by N3209, which discusses some of the issues. There were additional reflector discussions.

This is somewhat separable from the question of what lock-free means, which is probably a more promising question to focus on.

[2012, Kona]

General direction: lock-free means obstruction-free. Leave the current "should" recommendation for progress. It would take a lot of effort to try to do better.

[2012, Portland: move to Open]

The current wording of 1.10 [intro.multithread] p2 doesn't really say very much. As far as we can tell the term lock-free is nowhere defined in the standard.

James: we would prefer a different way to phrase it.

Hans: the research literature includes the term abstraction-free which might be a better fit.

Detlef: does Posix define a meaning for blocking (or locking) that we could use?

Hans: things like compare-exchange-strong can wait indefinitely.

Niklas: what about spin-locks -- still making no progress.

Hans: suspect we can only give guidance, at best. The lock-free meaning from the theoretical commmunity (forard progress will be made) is probably too strong here.

Atrur: what about livelocks?

Hans: each atomic modification completes, even if the whole thing is blocked.

Moved to open.

Proposed resolution:


2076. Bad CopyConstructible requirement in set constructors

Section: 23.4.6.2 [set.cons] Status: New Submitter: Jens Maurer Opened: 2011-08-20 Last modified: 2012-11-14

View all issues with New status.

Discussion:

23.4.6.2 [set.cons] paragraph 4 says:

Requires: If the iterator’s dereference operator returns an lvalue or a non-const rvalue, then Key shall be CopyConstructible.

I'm confused why a "non-const rvalue" for the return value of the iterator would require CopyConstructible; isn't that exactly the situation when you'd want to apply the move constructor?

The corresponding requirement for multimap seems better in that regard ([multimap.cons] paragraph 3):

Requires: If the iterator’s dereference operator returns an lvalue or a const rvalue pair<key_type, mapped_type>, then both key_type and mapped_type shall be CopyConstructible.

Obviously, if I have a const rvalue, I can't apply the move constructor (which will likely attempt modify its argument).

Dave Abrahams:

I think you are right. Proposed resolution: drop "non-" from 23.4.6.2 [set.cons] paragraph 3.

[2012, Kona]

The wording is in this area will be affected by Pablo's paper being adopted at this meeting. Wait for that paper to be applied before visiting this issue - deliberately leave in New status until the next meeting.

Proposed resolution:

This wording is relative to the FDIS.

Change 23.4.6.2 [set.cons] p3 as follows:

template <class InputIterator>
  set(InputIterator first, InputIterator last,
    const Compare& comp = Compare(), const Allocator& = Allocator());

-3- Effects: Constructs an empty set using the specified comparison object and allocator, and inserts elements from the range [first,last).

-4- Requires: If the iterator’s dereference operator returns an lvalue or a non-const rvalue, then Key shall be CopyConstructible.

-5- Complexity: Linear in N if the range [first,last) is already sorted using comp and otherwise N logN, where N is last - first.


2077. Further incomplete constraints for type traits

Section: 20.9.4.3 [meta.unary.prop] Status: Open Submitter: Daniel Krügler Opened: 2011-08-20 Last modified: 2012-11-14

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:


2078. Throw specification of async() incomplete

Section: 30.6.8 [futures.async] Status: Tentatively NAD Editorial Submitter: Nicolai Josuttis Opened: 2011-08-29 Last modified: 2012-11-14

View other active issues in [futures.async].

View all other issues in [futures.async].

View all issues with Tentatively NAD Editorial status.

Discussion:

The current throw specification of async() does state:

-6- Throws: system_error if policy is launch::async and the implementation is unable to start a new thread.

First it seems not clear whether this only applies if policy equals launch::async of if the async launch mode flag is set (if policy|launch::async!=0)

In the discussion Lawrence Crowl also wrote:

More generally, I think what we want to say is that if the implementation cannot successfully execute on one of the policies allowed, then it must choose another. The principle would apply to implementation-defined policies as well.

Peter Sommerlad:

Should not throw. That was the intent. "is async" meat exactly.

[2012, Portland: move to Tentatively NAD Editorial]

If no launch policy, it is undefined behavior.

Agree with Lawrence, should try all the allowed policies. We will rephrase so that the policy argument should be lauch::async. Current wording seems good enough.

We believe this choice of policy statement is really an editorial issue.

Proposed resolution:


2079. Required pow() overloads

Section: 26.8 [c.math] Status: New Submitter: Steve Clamage Opened: 2011-08-29 Last modified: 2012-11-14

View other active issues in [c.math].

View all other issues in [c.math].

View all issues with New status.

Discussion:

LWG issue 550 removed the functions:

float       pow(float, int);
double      pow(double, int);
long double pow(long double, int);

from header <cmath>. This change does not seem to be mentioned in Annex C, C.2.14.

Howard:

N3290 26.8 [c.math]/p11 says:

Moreover, there shall be additional overloads sufficient to ensure:

  1. If any argument corresponding to a double parameter has type long double, then all arguments corresponding to double parameters are effectively cast to long double.
  2. Otherwise, if any argument corresponding to a double parameter has type double or an integer type, then all arguments corresponding to double parameters are effectively cast to double.
  3. Otherwise, all arguments corresponding to double parameters are effectively cast to float.

From C99 7.12.7.4 we have:

double pow(double, double);

26.8 [c.math]/p11/b2 says that if the client calls pow(2.0f, 2), then the int for second argument causes the following effective call to be made:

pow(static_cast<double>(2.0f), static_cast<double>(2)) -> double

The first sentence of p11 implies that this is done by supplying the following additional overload:

double pow(float, int);

If the client calls pow(2.0, 2), then the same reasoning (b2 again) implies the following additional overload:

double pow(double, int);

If the client calls pow(2.0l, 2), then b1 implies the following additional overload:

long double pow(long double, int);

In all, p11 implies hundreds (perhaps thousands?) of extra overloads. All but one of which is a superset of the overloads required by C++98/03 (that one being pow(float, int) which had its return type changed from float to double).

In practice, at least some vendors implement p11 by using templated overloads as opposed to ordinary overloads.

Steve Clamage:

Thanks. I didn't see that those extra overloads were actually implied by p11, despite the first sentence. Without examples, the point is a bit subtle (at least for me).

Proposed resolution:


2080. Specify when once_flag becomes invalid

Section: 30.4.4 [thread.once] Status: Tentatively Ready Submitter: Nicolai Josuttis Opened: 2011-08-30 Last modified: 2012-11-14

View all issues with Tentatively Ready status.

Discussion:

In function call_once 30.4.4.2 [thread.once.callonce] paragraph 4 and 5 specify for call_once():

Throws: system_error when an exception is required (30.2.2 [thread.req.exception]), or any exception thrown by func.

Error conditions:

However, nowhere in 30.4.4 [thread.once] is specified, when a once-flag becomes invalid.

As far as I know this happens if the flag is used for different functions. So we either have to have to insert a sentence/paragraph in

30.4.4.2 Function call_once [thread.once.callonce]

or

30.4.4 Call once [thread.once]

explaining when a once_flag becomes invalidated or we should state as error condition something like:

Anthony Williams:

A once_flag is invalidated if you destroy it (e.g. it is an automatic object, or heap allocated and deleted, etc.)

If the library can detect that this is the case then it will throw this exception. If it cannot detect such a case then it will never be thrown.

Jonathan Wakely:

I have also wondered how that error can happen in C++, where the type system will reject a non-callable type being passed to call_once() and should prevent a once_flag being used after its destructor runs.

If a once_flag is used after its destructor runs then it is indeed undefined behaviour, so implementations are already free to throw any exception (or set fire to a printer) without the standard saying so.

My assumption was that it's an artefact of basing the API on pthreads, which says:

The pthread_once() function may fail if:

[EINVAL] If either once_control or init_routine is invalid.

Pete Becker:

Yes, probably. We had to clean up several UNIXisms that were in the original design.

[2012, Kona]

Remove error conditions, move to Review.

[2012, Portland: move to Tentatively Ready]

Concurrency move to Ready, pending LWG review.

LWG did not have time to perform the final review in Portland, so moving to tentatively ready to reflect the Concurrency belief that the issue is ready, but could use a final inspection from library wordsmiths.

Proposed resolution:

This wording is relative to N3337.

  1. Change 30.4.4.2 [thread.once.callonce] as indicated:

    template<class Callable, class ...Args>
    void call_once(once_flag& flag, Callable&& func, Args&&... args);
    

    […]

    -4- Throws: system_error when an exception is required (30.2.2), or any exception thrown by func.

    -5- Error conditions:

    • invalid_argument — if the once_flag object is no longer valid.

2085. Wrong description of effect 1 of basic_istream::ignore

Section: 27.7.2.3 [istream.unformatted] Status: New Submitter: Krzysztof Zelechowski Opened: 2011-09-11 Last modified: 2012-11-14

View other active issues in [istream.unformatted].

View all other issues in [istream.unformatted].

View all issues with New status.

Discussion:

27.7.2.3 [istream.unformatted] in N3242 currently has the following to say about the semantics of basic_istream::ignore:

[..]. Characters are extracted until any of the following occurs:

This statement, apart from being slightly ungrammatical, indicates that if (n == numeric_limits<streamsize>::max()), the method returns without extracting any characters.

The description intends to describe the observable behaviour of an implementation in terms of logical assertions. Logical assertions are not "bullets" that can be "entered" but need not; they are predicates that can evaluate to true or false.

The description contains two predicates, either of them causes extraction to terminate. In the incriminated case, the first predicate is evaluates to true because its premise is false, therefore no characters will be extracted.

The intended semantics would be described by the following statement:

[..]. Characters are extracted until any of the following occurs:

Proposed resolution:

This wording is relative to the FDIS.

Change 27.7.2.3 [istream.unformatted] p25 as indicated:

basic_istream<charT,traits>&
  ignore(streamsize n = 1, int_type delim = traits::eof());

-25- Effects: Behaves as an unformatted input function (as described in 27.7.2.3 [istream.unformatted], paragraph 1). After constructing a sentry object, extracts characters and discards them. Characters are extracted until any of the following occurs:


2087. iostream_category() and noexcept

Section: 27.5 [iostreams.base] Status: New Submitter: Nicolai Josuttis Opened: 2011-09-22 Last modified: 2012-11-14

View all other issues in [iostreams.base].

View all issues with New status.

Discussion:

In <system_error> we have:

const error_category& generic_category() noexcept;
const error_category& system_category() noexcept;

In <future> we have:

const error_category& future_category() noexcept;

But in <ios> we have:

const error_category& iostream_category();

Is there any reason that iostream_category() is not declared with noexcept or is this an oversight?

Daniel:

This looks like an oversight to me. We made the above mentioned changes as part of noexcept-ifying the thread library but iostream_category() was skipped, so it seems to be forgotten. There should be no reason, why it cannot be noexcept. When doing so, we should also make these functions noexcept (similar to corresponding overloads):

error_code make_error_code(io_errc e);
error_condition make_error_condition(io_errc e);

Suggested wording provided by Daniel.

Proposed resolution:

This wording is relative to the FDIS.

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

    #include <iosfwd>
    namespace std {
      […]
      error_code make_error_code(io_errc e) noexcept;
      error_condition make_error_condition(io_errc e) noexcept;
      const error_category& iostream_category() noexcept;
    }
    
  2. Change the prototype declarations in 27.5.6.5 [error.reporting] as indicated:

    error_code make_error_code(io_errc e) noexcept;
    

    -1- Returns: error_code(static_cast<int>(e), iostream_category()).

    error_condition make_error_condition(io_errc e) noexcept;
    

    -2- Returns: error_condition(static_cast<int>(e), iostream_category()).

    const error_category& iostream_category() noexcept;
    

    -3- Returns: A reference to an object of a type derived from class error_category.

    -4- The object’s default_error_condition and equivalent virtual functions shall behave as specified for the class error_category. The object’s name virtual function shall return a pointer to the string "iostream".


2088. std::terminate problem

Section: 18.8.3 [exception.terminate] Status: Open Submitter: Daniel Krügler Opened: 2011-09-25 Last modified: 2012-11-14

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

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, 18.8.3.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 18.8.3.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 18.8.3.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:


2089. std::allocator::construct should use uniform initialization

Section: 20.6.9.1 [allocator.members] Status: Open Submitter: David Krauss Opened: 2011-10-07 Last modified: 2012-11-14

View all other issues in [allocator.members].

View all issues with Open status.

Discussion:

When the EmplaceConstructible (23.2.1 [container.requirements.general]/13) requirement is used to initialize an object, direct-initialization occurs. Initializing an aggregate or using a std::initializer_list constructor with emplace requires naming the initialized type and moving a temporary. This is a result of std::allocator::construct using direct-initialization, not list-initialization (sometimes called "uniform initialization") syntax.

Altering std::allocator<T>::construct to use list-initialization would, among other things, give preference to std::initializer_list constructor overloads, breaking valid code in an unintuitive and unfixable way — there would be no way for emplace_back to access a constructor preempted by std::initializer_list without essentially reimplementing push_back.

std::vector<std::vector<int>> v;
v.emplace_back(3, 4); // v[0] == {4, 4, 4}, not {3, 4} as in list-initialization

The proposed compromise is to use SFINAE with std::is_constructible, which tests whether direct-initialization is well formed. If is_constructible is false, then an alternative std::allocator::construct overload is chosen which uses list-initialization. Since list-initialization always falls back on direct-initialization, the user will see diagnostic messages as if list-initialization (uniform-initialization) were always being used, because the direct-initialization overload cannot fail.

I can see two corner cases that expose gaps in this scheme. One occurs when arguments intended for std::initializer_list satisfy a constructor, such as trying to emplace-insert a value of {3, 4} in the above example. The workaround is to explicitly specify the std::initializer_list type, as in v.emplace_back(std::initializer_list<int>(3, 4)). Since this matches the semantics as if std::initializer_list were deduced, there seems to be no real problem here.

The other case is when arguments intended for aggregate initialization satisfy a constructor. Since aggregates cannot have user-defined constructors, this requires that the first nonstatic data member of the aggregate be implicitly convertible from the aggregate type, and that the initializer list have one element. The workaround is to supply an initializer for the second member. It remains impossible to in-place construct an aggregate with only one nonstatic data member by conversion from a type convertible to the aggregate's own type. This seems like an acceptably small hole.

The change is quite small because EmplaceConstructible is defined in terms of whatever allocator is specified, and there is no need to explicitly mention SFINAE in the normative text.

[2012, Kona]

Move to Open.

There appears to be a real concern with initializing aggregates, that can be performed only using brace-initialization. There is little interest in the rest of the issue, given the existence of 'emplace' methods in C++11.

Move to Open, to find an acceptable solution for intializing aggregates. There is the potential that EWG may have an interest in this area of language consistency as well.

Proposed resolution:

This wording is relative to the FDIS.

Change 20.6.9.1 [allocator.members] p12 as indicated:

template <class U, class... Args>
  void construct(U* p, Args&&... args);

12 Effects: ::new((void *)p) U(std::forward<Args>(args)...) if is_constructible<U, Args...>::value is true, else ::new((void *)p) U{std::forward<Args>(args)...}


2091. Misplaced effect in m.try_lock_for()

Section: 30.4.1.3 [thread.timedmutex.requirements] Status: Ready Submitter: Pete Becker Opened: 2011-10-18 Last modified: 2012-11-14

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

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

View all issues with Ready status.

Discussion:

30.4.1.3 [thread.timedmutex.requirements]/4 says, in part,

"Requires: If the tick period of [the argument] is not exactly convertible … [it] shall be rounded up …"

This doesn't belong in the requires clause. It's an effect. It belongs in paragraph 5. Nitpickingly, this would be a technical change: as written it imposes an obligation on the caller, while moving it imposes an obligation on the callee. Although that's certainly not what was intended.

Peter Dimov comments:

Not to mention that it should round down, not up. :-)

Incidentally, I see that the wrong try_lock requirement that the caller shall not own the mutex has entered the standard, after all. Oh well. Let's hope that the real world continues to ignore it.

[2012, Kona]

Remove the offending sentence from the requirements clause. Do not add it back anywhere else. The implementation already must have license to wake up late, so the rounding is invisible.

Move to Review.

[2012, Portland]

Concurrency move to Ready.

Proposed resolution:

This wording is relative to N3337.

  1. Change 30.4.1.3 [thread.timedmutex.requirements]/4 as indicated:

    -3- The expression m.try_lock_for(rel_time) shall be well-formed and have the following semantics:

    -4- Requires: If the tick period of rel_time is not exactly convertible to the native tick period, the duration shall be rounded up to the nearest native tick period. If m is of type std::timed_mutex, the calling thread does not own the mutex.


2092. Vague Wording for condition_variable_any

Section: 30.5.2 [thread.condition.condvarany] Status: Ready Submitter: Pete Becker Opened: 2011-10-20 Last modified: 2012-11-14

View all other issues in [thread.condition.condvarany].

View all issues with Ready status.

Discussion:

30.5.2 [thread.condition.condvarany]/4 says, in part, that condition_variable_any() throws an exception "if any native handle type manipulated is not available".

I don't know what that means. Is this intended to say something different from the analogous words for condition_variable() [30.5.1 [thread.condition.condvar]/4], "if some non-memory resource limitation prevents initialization"? If not, it should be worded the same way.

[2012, Kona]

Copy the corresponding wording from the condition_variable constructor in 30.5.1 [thread.condition.condvar] p4.

Move to Review.

[2012, Portland]

Concurrency move to Ready.

Proposed resolution:

This wording is relative to N3337.

  1. Change 30.4.1.3 [thread.timedmutex.requirements]/4 as indicated:

    condition_variable_any();
    

    […]

    -4- Error conditions:

    • resource_unavailable_try_againif any native handle type manipulated is not available if some non-memory resource limitation prevents initialization.
    • operation_not_permitted — if the thread does not have the privilege to perform the operation.

2093. Throws clause of condition_variable::wait with predicate

Section: 30.5.1 [thread.condition.condvar] Status: Ready Submitter: Alberto Ganesh Barbati Opened: 2011-10-27 Last modified: 2012-11-14

View other active issues in [thread.condition.condvar].

View all other issues in [thread.condition.condvar].

View all issues with Ready status.

Discussion:

the Throws: clause of condition_variable::wait/wait_xxx functions that take a predicate argument is:

Throws: system_error when an exception is required (30.2.2 [thread.req.exception]).

If executing the predicate throws an exception, I would expect such exception to propagate unchanged to the caller, but the throws clause seems to indicate that it gets mutated into a system_error. T hat's because of 17.5.1.4 [structure.specifications]/4:

"If F’s semantics contains a Throws:, Postconditions:, or Complexity: element, then that supersedes any occurrences of that element in the code sequence."

Is my interpretation correct? Does it match the intent?

Daniel comments:

I don't think that this interpretation is entirely correct, the wording does not say that std::system_error or a derived class must be thrown, it simply is underspecified in this regard (The extreme interpretation is that the behaviour would be undefined, but that would be too far reaching I think). We have better wording for this in 30.4.4.2 [thread.once.callonce] p4, where it says:

"Throws: system_error when an exception is required (30.2.2 [thread.req.exception]), or any exception thrown by func."

or in 30.3.2 [thread.thread.this] p6/p9:

"Throws: Nothing if Clock satisfies the TrivialClock requirements (20.11.3 [time.clock.req]) and operations of Duration do not throw exceptions. [ Note: instantiations of time point types and clocks supplied by the implementation as specified in 20.11.7 [time.clock] do not throw exceptions. — end note ]"

So, the here discussed Throws elements should add lines along the lines of

"Any exception thrown by operations of pred."

and similar wording for time-related operations:

"Any exception thrown by operations of Duration",

"Any exception thrown by operations of chrono::duration<Rep, Period>"

[2011-11-28: Ganesh comments and suggests wording]

As for the discussion about the exception thrown by the manipulation of time-related objects, I believe the argument applies to all functions declared in 30 [thread]. Therefore, instead of adding wording to each member, I would simply move those requirements from 30.3.2 [thread.thread.this] p6/p9 to a new paragraph in 30.2.4 [thread.req.timing].

As for 30.5.2 [thread.condition.condvarany], the member functions wait() and wait_until() are described only in terms of the Effects: clause (so strictly speaking, they need no changes), however, wait_for() is described with a full set of clauses including Throws: and Error conditions:. Either we should add those clauses to wait/wait_until with changes similar to the one above, or remove paragraphs 29 to 34 entirely. By the way, even paragraph 26 could be removed IMHO.

[2012, Kona]

We like the idea behind the proposed resolution.

Modify the first addition to read instead: "Functions that specify a timeout, will throw if an operation on a clock, time point, or time duration throws an exception."

In the note near the bottom change "even if the timeout has already expired" to "or if the timeout has already expired". (This is independent, but the original doesn't seem to make sense.)

Move to Review.

[2012, Portland]

Concurrency move to Ready with slightly ammended wording.

Proposed resolution:

This wording is relative to N3337.

  1. Add a new paragraph at the end of 30.2.4 [thread.req.timing]:

    […]

    -6- The resolution of timing provided by an implementation depends on both operating system and hardware. The finest resolution provided by an implementation is called the native resolution.

    -7- Implementation-provided clocks that are used for these functions shall meet the TrivialClock requirements (20.11.3 [time.clock.req]).

    -?- Functions that specify a timeout, will throw if, during the execution of this function, a clock, time point, or time duration throws an exception. [ Note: instantiations of clock, time point and duration types supplied by the implementation as specified in 20.11.7 [time.clock] do not throw exceptions. — end note]

  2. Change 30.3.2 [thread.thread.this] as indicated:

    template <class Clock, class Duration>
      void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);;
    

    -4- Effects: Blocks the calling thread for the absolute timeout (30.2.4 [thread.req.timing]) specified by abs_time.

    -5- Synchronization: None.

    -6- Throws: timeout-related exceptions (30.2.4 [thread.req.timing]).Nothing if Clock satisfies the TrivialClock requirements (20.11.3 [time.clock.req]) and operations of Duration do not throw exceptions. [ Note: instantiations of time point types and clocks supplied by the implementation as specified in 20.11.7 [time.clock] do not throw exceptions. — end note]

    template <class Rep, class Period>
      void sleep_for(const chrono::duration<Rep, Period>& rel_time);;
    

    -7- Effects: Blocks the calling thread for the relative timeout (30.2.4 [thread.req.timing]) specified by rel_time.

    -8- Synchronization: None.

    -9- Throws: timeout-related exceptions (30.2.4 [thread.req.timing]).Nothing if operations of chrono::duration<Rep, Period> do not throw exceptions. [ Note: instantiations of time point types and clocks supplied by the implementation as specified in 20.11.7 [time.clock] do not throw exceptions. — end note]

  3. Change 30.4.1.3 [thread.timedmutex.requirements] as indicated:

    -3- The expression m.try_lock_for(rel_time) shall be well-formed and have the following semantics:

    […]

    -5- Effects: The function attempts to obtain ownership of the mutex within the relative timeout (30.2.4 [thread.req.timing]) specified by rel_time. If the time specified by rel_time is less than or equal to rel_time.zero(), the function attempts to obtain ownership without blocking (as if by calling try_lock()). The function shall return within the timeout specified by rel_time only if it has obtained ownership of the mutex object. [Note: As with try_lock(), there is no guarantee that ownership will be obtained if the lock is available, but implementations are expected to make a strong effort to do so. — end note]

    […]

    -8- Synchronization: If try_lock_for() returns true, prior unlock() operations on the same object synchronize with (1.10 [intro.multithread]) this operation.

    -9- Throws: timeout-related exceptions (30.2.4 [thread.req.timing]).Nothing.

    -10- The expression m.try_lock_until(abs_time) shall be well-formed and have the following semantics:

    […]

    -12- Effects: The function attempts to obtain ownership of the mutex. If abs_time has already passed, the function attempts to obtain ownership without blocking (as if by calling try_lock()). The function shall return before the absolute timeout (30.2.4 [thread.req.timing]) specified by abs_time only if it has obtained ownership of the mutex object. [Note: As with try_lock(), there is no guarantee that ownership will be obtained if the lock is available, but implementations are expected to make a strong effort to do so. — end note]

    […]

    -15- Synchronization: If try_lock_until() returns true, prior unlock() operations on the same object synchronize with (1.10 [intro.multithread]) this operation.

    -16- Throws: timeout-related exceptions (30.2.4 [thread.req.timing]).Nothing.

  4. Change 30.5.1 [thread.condition.condvar] as indicated:

    template <class Predicate>
      void wait(unique_lock<mutex>& lock, Predicate pred);
    

    […]

    -15- Effects: Equivalent to:

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

    […]

    -17- Throws: std::system_error when an exception is required (30.2.2 [thread.req.exception]), timeout-related exceptions (30.2.4 [thread.req.timing]), or any exception thrown by pred.

    […]

    template <class Clock, class Duration>
      cv_status wait_until(unique_lock<mutex>& lock,
                           const chrono::time_point<Clock, Duration>& abs_time);
    

    […]

    -23- Throws: system_error when an exception is required (30.2.2 [thread.req.exception]) or timeout-related exceptions (30.2.4 [thread.req.timing]).

    […]

    template <class Rep, class Period>
      cv_status wait_for(unique_lock<mutex>& lock,
                         const chrono::duration<Rep, Period>& rel_time);
    

    […]

    -26- Effects: as ifEquivalent to:

    return wait_until(lock, chrono::steady_clock::now() + rel_time);
    

    […]

    -29- Throws: system_error when an exception is required (30.2.2 [thread.req.exception]) or timeout-related exceptions (30.2.4 [thread.req.timing]).

    […]

    template <class Clock, class Duration, class Predicate>
      bool wait_until(unique_lock<mutex>& lock,
                      const chrono::time_point<Clock, Duration>& abs_time,
                      Predicate pred);
    

    […]

    -32- Effects: Equivalent to:

    while (!pred())
      if (wait_until(lock, abs_time) == cv_status::timeout)
        return pred();
    return true;
    

    -33- Returns: pred()

    […]

    -36- Throws: std::system_error when an exception is required (30.2.2 [thread.req.exception]), timeout-related exceptions (30.2.4 [thread.req.timing]), or any exception thrown by pred.

    […]

    template <class Rep, class Period, class Predicate>
      bool wait_for(unique_lock<mutex>& lock,
                    const chrono::duration<Rep, Period>& rel_time,
                    Predicate pred);
    

    […]

    -39- Effects: as ifEquivalent to:

    return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred));
    

    […]

    -42- Returns: pred()

    […]

    -44- Throws: system_error when an exception is required (30.2.2 [thread.req.exception]), timeout-related exceptions (30.2.4 [thread.req.timing]), or any exception thrown by pred.

    […]

  5. Change 30.5.2 [thread.condition.condvarany] as indicated:

    template <class Lock, class Predicate>
      void wait(Lock& lock, Predicate pred);
    

    -14- Effects: Equivalent to:

    while (!pred())
      wait(lock);
    
    template <class Lock, class Clock, class Duration>
      cv_status wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time);
    

    […]

    -18- Throws: system_error when an exception is required (30.2.2 [thread.req.exception]) or any timeout-related exceptions (30.2.4 [thread.req.timing]).

    […]

    template <class Lock, class Rep, class Period>
      cv_status wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time);
    

    […]

    -20- Effects: as ifEquivalent to:

    return wait_until(lock, chrono::steady_clock::now() + rel_time);
    

    […]

    -23- Throws: system_error when an exception is required (30.2.2 [thread.req.exception]) or any timeout-related exceptions (30.2.4 [thread.req.timing]).

    […]

    template <class Lock, class Clock, class Duration, class Predicate>
      bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred);
    

    -25- Effects: Equivalent to:

    while (!pred())
      if (wait_until(lock, abs_time) == cv_status::timeout)
        return pred();
    return true;
    

    -26- Returns: pred()[Note: There is no blocking if pred() is initially true, or if the timeout has already expired. — end note]

    -27- [Note: The returned value indicates whether the predicate evaluates to true regardless of whether the timeout was triggered. end note]

    template <class Lock, class Rep, class Period, class Predicate>
      bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred);
    

    -28- Effects: as ifEquivalent to:

    return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred));
    

    -29- [Note: There is no blocking if pred() is initially true, even if the timeout has already expired. — end note] -30- Postcondition: lock is locked by the calling thread.

    -31- Returns: pred()

    -32- [Note: The returned value indicates whether the predicate evaluates to true regardless of whether the timeout was triggered. — end note]

    -33- Throws: system_error when an exception is required (30.2.2 [thread.req.exception]).

    -34- Error conditions:

    • equivalent error condition from lock.lock() or lock.unlock().

2094. duration conversion overflow shouldn't participate in overload resolution

Section: 20.11.5.1 [time.duration.cons] Status: Review Submitter: Vicente J. Botet Escriba Opened: 2011-10-31 Last modified: 2012-11-14

View all other issues in [time.duration.cons].

View all issues with Review status.

Discussion:

20.11.5.1 [time.duration.cons] says:

template <class Rep2, class Period2>
  constexpr duration(const duration<Rep2, Period2>& d);

Remarks: This constructor shall not participate in overload resolution unless treat_as_floating_point<rep>::value is true or both ratio_divide<Period2, period>::den is 1 and treat_as_floating_point<Rep2>::value is false.

The evaluation of ratio_divide<Period2, period>::den could make ratio_divide<Period2, period>::num overflow.

This occur for example when we try to create a millisecond (period=ratio<1,1000>) from an exa-second (Period2=ratio<1018>).

ratio_divide<ratio<1018>, ratio<1,1000>>::num is 1021 which overflows which makes the compiler error.

If the function f is overloaded with milliseconds and seconds

void f(milliseconds);
void f(seconds);

The following fails to compile.

duration<int,exa> r(1);
f(r);

While the conversion to seconds work, the conversion to milliseconds make the program fail at compile time. In my opinion, this program should be well formed and the constructor from duration<int,exa> to milliseconds shouldn't participate in overload resolution as the result can not be represented.

I think the wording of the standard can be improved so no misinterpretations are possible by adding that "no overflow is induced by the conversion".

[2012, Kona]

Move to Review.

Pete: The wording is not right.

Howard: Will implement this to be sure it works.

Jeffrey: If ratio needs a new hook, should it be exposed to users for their own uses?

Pete: No.

Move to Review, Howard to implement in a way that mere mortals can understand.

Proposed resolution:

This wording is relative to the FDIS.

Change the following paragraphs of 20.11.5.1 [time.duration.cons] p4 indicated:

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<rep>::value is true or both ratio_divide<Period2, period>::den is 1 and treat_as_floating_point<Rep2>::value is false. [ Note: This requirement prevents implicit truncation error when converting between integral-based duration types. Such a construction could easily lead to confusion about the value of the duration. — end note ]


2095. promise and packaged_task missing constructors needed for uses-allocator construction

Section: 30.6.5 [futures.promise], 30.6.9 [futures.task] Status: New Submitter: Jonathan Wakely Opened: 2011-11-01 Last modified: 2013-03-18

View other active issues in [futures.promise].

View all other issues in [futures.promise].

View all issues with New 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.

Proposed resolution:

[This wording is relative to the FDIS.]

  1. Add to 30.6.5 [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 30.6.5 [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 30.6.9 [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 30.6.9.1 [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]


2097. packaged_task constructors should be constrained

Section: 30.6.9.1 [futures.task.members] Status: New Submitter: Jonathan Wakely Opened: 2011-11-02 Last modified: 2012-11-14

View other active issues in [futures.task.members].

View all other issues in [futures.task.members].

View all issues with New status.

Discussion:

With the proposed resolution of 2067, this no longer selects the copy constructor:

std::packaged_task<void()> p1;
std::packaged_task<void()> p2(p1);

Instead this constructor is a better match:

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

This attempts to package a packaged_task, which internally tries to copy p2, which fails because the copy constructor is deleted. For at least one implementation the resulting error message is much less helpful than the expected "cannot call deleted function" because it happens after instantiating several more templates rather than in the context where the constructor is called.

I believe the solution is to constrain to the template constructors so the template argument F cannot be deduced as (possibly cv) packaged_task& or packaged_task. It could be argued this constraint is already implied because packaged_task is not copyable and the template constructors require that "invoking a copy of f shall behave the same as invoking f".

Daniel points out that the variadic constructor of std::thread described in 30.3.1.2 [thread.thread.constr] has a similar problem and suggests a similar wording change, which has been integrated below.

An alternative is to declare thread(thread&) and packaged_task(packaged_task&) as deleted.

[2012, Portland]

This issue appears to be more about library specification than technical concurrency issues, so should be handled in LWG.

Proposed resolution:

This wording is relative to the FDIS.

  1. Insert a new Remarks element to 30.3.1.2 [thread.thread.constr] around p3 as indicated:

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

    -3- Requires: F and each Ti in Args shall satisfy the MoveConstructible requirements. INVOKE(DECAY_COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...) (20.8.2) shall be a valid expression.

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

  2. Insert a new Remarks element to 30.6.9.1 [futures.task.members] around p2 as indicated:

    template <class F>
      packaged_task(F&& f);
    template <class F, class Allocator>
      explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f);
    

    -2- Requires: INVOKE(f, t1, t2, ..., tN, R), where t1, t2, ..., tN are values of the corresponding types in ArgTypes..., shall be a valid expression. Invoking a copy of f shall behave the same as invoking f.

    -?- Remarks: These constructors shall not participate in overload resolution if decay<F>::type is the same type as std::packaged_task<R(ArgTypes...)>.


2098. Minor Inconsistency between promise::set_value and promise::set_value_at_thread_exit

Section: 30.6.5 [futures.promise] Status: Review Submitter: Pete Becker Opened: 2011-11-14 Last modified: 2012-11-14

View other active issues in [futures.promise].

View all other issues in [futures.promise].

View all issues with Review status.

Discussion:

30.6.5 [futures.promise]/16 says that promise::set_value(const R&) throws any exceptions thrown by R's copy constructor, and that promise_set_value(R&&) throws any exceptions thrown by R's move constructor.

30.6.5 [futures.promise]/22 is the Throws: clause for promise::set_value_at_thread_exit. It has no corresponding requirements, only that these functions throw "future_error if an error condition occurs."

Daniel suggests wording to fix this: The approach is a bit more ambitious and also attempts to fix wording glitches of 30.6.5 [futures.promise]/16, because it would be beyond acceptable efforts of implementations to determine whether a constructor call of a user-defined type will indeed call a copy constructor or move constructor (in the first case it might be a template constructor, in the second case it might also be a copy-constructor, if the type has no move constructor).

[2012, Portland: move to Review]

Moved to Review by the concurrency working group, with no further comments.

Proposed resolution:

This wording is relative to the FDIS.

  1. Change 30.6.5 [futures.promise]/16 as indicated:

    void promise::set_value(const R& r);
    void promise::set_value(R&& r);
    void promise<R&>::set_value(R& r);
    void promise<void>::set_value();
    

    […]

    -16- Throws:

    • future_error if its shared state already has a stored value or exception, or
    • for the first version, any exception thrown by the copy constructor ofconstructor selected to copy an object of R, or
    • for the second version, any exception thrown by the move constructor ofconstructor selected to move an object of R.
  2. Change 30.6.5 [futures.promise]/22 as indicated:

    void promise::set_value_at_thread_exit(const R& r);
    void promise::set_value_at_thread_exit(R&& r);
    void promise<R&>::set_value_at_thread_exit(R& r);
    void promise<void>::set_value_at_thread_exit();
    

    […]

    -16- Throws: future_error if an error condition occurs.

    • future_error if its shared state already has a stored value or exception, or
    • for the first version, any exception thrown by the constructor selected to copy an object of R, or
    • for the second version, any exception thrown by the constructor selected to move an object of R.

2100. timed waiting functions cannot timeout if launch::async policy used

Section: 30.6.8 [futures.async] Status: Review Submitter: Jonathan Wakely Opened: 2011-11-14 Last modified: 2012-11-14

View other active issues in [futures.async].

View all other issues in [futures.async].

View all issues with Review status.

Discussion:

30.6.8 [futures.async] p5 says

If the implementation chooses the launch::async policy,

That should say a non-timed waiting function, otherwise, calling a timed waiting function can block indefinitely waiting for the associated thread to complete, rather than timing out after the specified time.

Since std::thread does not provide a timed_join() function (nor does Pthreads, making it impossible on many platforms) there is no way for a timed waiting function to try to join but return early due to timeout, therefore timed waiting functions either cannot guarantee to timeout or cannot be used to meet the requirement to block until the thread is joined. In order to allow timed waiting functions to timeout the requirement should only apply to non-timed waiting functions.

[2012, Portland: move to Review]

Detlef: Do we actually need this fix — is it detectable?

Yes — you will never get a timeout. Should we strike the whole paragraph?

Hans: issue with thread local destruction.

Niklas: I have a strong expectation that a timed wait will respect the timeout

agreed

Detlef: we want a timed wait that does not time out to return like a non-timed wait; but is this implementable?

Pablo: Could we simply append ", or else time out"

Detlef: the time out on the shared state needs implementing anyway, even if the underlying O/S does not support a timed join.

Hans: the net effect is the timeout does not cover the thread local destruction... ah, I see what you're doing

Detlef: happy with Pablo's proposal

Wording proposed is to append after the word "joined" add ", or else time out"

Moved to review with this wording.

Proposed resolution:

[This wording is relative to the FDIS.]

Change 30.6.8 [futures.async] p5 as indicated:

If the implementation chooses the launch::async policy,


2101. Some transformation types can produce impossible types

Section: 20.9.7 [meta.trans] Status: Open Submitter: Daniel Krügler Opened: 2011-11-18 Last modified: 2012-11-14

View all issues with Open status.

Discussion:

Table 53 — "Reference modifications" says in regard to the type trait add_lvalue_reference (emphasize mine)

If T names an object or function type then the member typedef type shall name T&;

The problem with this specification is that function types with cv-qualifier or ref-qualifier, like

void() const
void() &

are also affected by the first part of the rule, but this would essentially mean, that instantiating add_lvalue_reference with such a type would attempt to form a type that is not defined in the C++ type system, namely

void(&)() const
void(&)() &

The general policy for TransformationTraits is to define always some meaningful mapping type, but this does not hold for add_lvalue_reference, add_rvalue_reference, and in addition to these two for add_pointer as well. The latter one would attempt to form the invalid types

void(*)() const
void(*)() &

A possible reason why those traits were specified in this way is that in C++03 (and that means for TR1), cv-qualifier were underspecified in the core language and several compilers just ignored them during template instantiations. This situation became fixed by adopting CWG issues 295 and 547.

While there is possibly some core language clarification needed (see reflector messages starting from c++std-core-20740), it seems also clear that the library should fix the specification. The suggested resolution follows the style of the specification of the support concepts PointeeType and ReferentType defined in N2914.

[2012-02-10, Kona]

Move to NAD.

These cv- and ref-qualified function types are abberations in the type system, and do not represent any actual entity defined by the language. The notion of cv- and ref- qualification applies only to the implicit *this reference in a member function.

However, these types can be produced by quirks of template metaprogramming, the question remains what the library should do about it. For exmaple, add_reference returns the original type if passed a reference type, or a void type. Conversely, add_pointer will refurn a pointer to the referenced type when passed a reference.

It is most likely that the 'right' answer in any case will depend on the context that the question is being asked, in terms of forming these obscure types. The best the LWG can do is allow an error to propogate back to the user, so they can provide their own meaningful answer in their context - with additional metaprogramming on their part. The consensus is that if anyone is dangerous enough with templates to get themselves into this problem, they will also have the skills to resolve the problem themselves. This is not going to trip up the non-expert developer.

Lastly, it was noted that this problem arises only because the language is inconsistent in providing us these nonesense types that do no really represent anything in the language. There may be some way Core or Evolution could give us a more consistent type system so that the LWG does not need to invent an answer at all, should this question need resolving. This is another reason to not specify anything at the LWG trait level at this time, leaving the other working groups free to produce the 'right' answer that we can then follow without changing the meaning of exisitng, well-defined programs.

[2012-02-10, post-Kona]

Move back to Open. Daniel is concerned that this is not an issue we can simply ignore, further details to follow.

[2012-10-06, Daniel comments]

This issue really should be resolved as a defect: First, the argument that "forming these obscure types" should "allow an error to propagate" is inconsistent with the exact same "obscure type" that would be formed when std::add_lvalue_reference<void> wouldn't have an extra rules for void types, which also cannot form references. The originally proposed resolution attempts to apply the same solution for the same common property of void types and function types with cv-qualifiers or ref-qualifier. These functions had the property of ReferentType during concept time (see CWG 749 bullet three for the final wording).

Core issue CWG 1417 has clarified that any attempt to form a reference of a pointer to a function type with cv-qualifiers or ref-qualifier is ill-formed. Unfortunately, many compilers don't implement this yet.

I also would like to warn about so-called "obscure" types: The problem is that these can occur as the side effect of finding a best match overload of function templates, where this type is exactly correct for one of these overloads, but causes a deep (not-sfinae-friendly) error for others where one of these traits are part of the signature.

Existing experience with void types shows, that this extra rule is not so unexpected. Further, any usage of the result types of these traits as argument types or return types of functions would make these ill-formed (and in a template context would be sfinaed away), so the expected effects are rarely unnoticed. Checking all existing explicit usages of the traits add_rvalue_reference, add_lvalue_reference, and add_pointer didn't show any example where the error would be silent: add_rvalue_reference is used to specify the return value of declval() and the instantiation of declval<void() const>() would be invalid, because of the attempt to return a function type. Similarly, add_lvalue_reference is used to specify the return type of unique_ptr<T>::operator*(). Again, any instantiation with void() const wouldn't remain unnoticed. The trait add_pointer is used to specify the trait std::decay and this is an interesting example, because it is well-formed when instantiated with void types, too, and is heavily used throughout the library specification. All use-cases would not be negatively affected by the suggested acceptance of function types with cv-qualifiers or ref-qualifier, because they involve types that are either function arguments, function parameters or types were references are formed from.

The alternative would be to add an additional extra rule that doesn't define a type member 'type' when we have a function type with cv-qualifiers or ref-qualifier. This is better than the current state but it is not superior than the proposal to specify the result as the original type, because both variants are sfinae-friendly. A further disadvantage of the "non-type" approach here would be that any usage of std::decay would require special protection against these function types, because instantiating std::decay<void() const> again would lead to a deep, sfinae-unfriendly error.

The following example demonstrates the problem: Even though the second f template is the best final match here, the first one will be instantiated. During that process std::decay<T>::type becomes instantiated as well and will raise a deep error, because as part of the implementation the trait std::add_pointer<void() const> becomes instantiated:

#include <type_traits>

template<class T>
typename std::decay<T>::type f(T&& t);

template<class T, class U>
U f(U u);

int main() {
  f<void() const>(0);
}

When the here proposed resolution would be applied this program would be well-formed and selects the expected function.

Previous resolution:

  1. Change Table 53 — "Reference modifications" in 20.9.7.2 [meta.trans.ref] as indicated:

    Table 53 — Reference modifications
    Template Comments
    template <class T>
    struct
    add_lvalue_reference;
    If T names an object type or if T names a function type that does not have
    cv-qualifiers or a ref-qualifier
    then the member typedef type
    shall name T&; otherwise, if T names a type “rvalue reference to T1” then
    the member typedef type shall name T1&; otherwise, type shall name T.
    template <class T>
    struct
    add_rvalue_reference;
    If T names an object type or if T names a function type that does not have
    cv-qualifiers or a ref-qualifier
    then the member typedef type
    shall name T&&; otherwise, type shall name T. [ Note: This rule reflects
    the semantics of reference collapsing (8.3.2 [dcl.ref]). For example, when a type T
    names a type T1&, the type add_rvalue_reference<T>::type is not an
    rvalue reference. — end note ]
  2. Change Table 56 — "Pointer modifications" in 20.9.7.5 [meta.trans.ptr] as indicated:

    Table 56 — Pointer modifications
    Template Comments
    template <class T>
    struct add_pointer;
    The member typedef type shall name the same type as
    If T names a function type that has cv-qualifiers or a ref-qualifier
    then the member typedef type shall name T; otherwise, it
    shall name the same type as
    remove_reference<T>::type*.

The following revised proposed resolution defines - in the absense of a proper core language definition - a new term referenceable type as also suggested by the resolution for LWG 2196 as an umbrella of the negation of void types and function types with cv-qualifiers or ref-qualifier. This simplifies and minimizes the requires wording changes.

Proposed resolution:

This wording is relative to N3376.

  1. Add the following new definition to 17.3 [definitions] as indicated:

    referenceable type [defns.referenceable]

    An object type, a function type that does not have cv-qualifiers or a ref-qualifier, or a reference type. [Note: The term describes a type to which a reference can be created, including reference types. — end note]

  2. Change Table 53 — "Reference modifications" in 20.9.7.2 [meta.trans.ref] as indicated:

    Table 53 — Reference modifications
    Template Comments
    template <class T>
    struct
    add_lvalue_reference;
    If T names an object type or function typea referenceable type
    then the member typedef type
    shall name T&; otherwise, if T names a type “rvalue reference to T1” then
    the member typedef type shall name T1&; otherwise,
    type shall name T.
    [ Note: This rule reflects the semantics of reference collapsing (8.3.2 [dcl.ref]). — end note ]
    template <class T>
    struct
    add_rvalue_reference;
    If T names an object type or function typea referenceable type
    then the member typedef type
    shall name T&&; otherwise, type shall name T. [ Note: This rule reflects
    the semantics of reference collapsing (8.3.2 [dcl.ref]). For example, when a type T
    names a type T1&, the type add_rvalue_reference<T>::type is not an
    rvalue reference. — end note ]
  3. Change Table 56 — "Pointer modifications" in 20.9.7.5 [meta.trans.ptr] as indicated:

    Table 56 — Pointer modifications
    Template Comments
    template <class T>
    struct add_pointer;
    If T names a referenceable type or a (possibly cv-qualified) void type then
    Tthe member typedef type shall name the same type as
    remove_reference<T>::type*; otherwise, type shall name T.

2104. unique_lock move-assignment should not be noexcept

Section: 30.4.2.2 [thread.lock.unique] Status: New Submitter: Anthony Williams Opened: 2011-11-27 Last modified: 2012-11-14

View all issues with New status.

Discussion:

I just noticed that the unique_lock move-assignment operator is declared noexcept. This function may call unlock() on the wrapped mutex, which may throw.

Suggested change: remove the noexcept specification from unique_lock::operator=(unique_lock&&) in 30.4.2.2 [thread.lock.unique] and 30.4.2.2.1 [thread.lock.unique.cons].

Daniel:

I think the situation is actually a bit more complex as it initially looks.

First, the effects of the move-assignment operator are (emphasize mine):

Effects: If owns calls pm->unlock().

Now according to the BasicLockable requirements:

m.unlock()

3 Requires: The current execution agent shall hold a lock on m.

4 Effects: Releases a lock on m held by the current execution agent.

Throws: Nothing.

This shows that unlock itself is a function with narrow contract and for this reasons no unlock function of a mutex or lock itself does have a noexcept specifier according to our mental model.

Now the move-assignment operator attempts to satisfy these requirement of the function and calls it only when it assumes that the conditions are ok, so from the view-point of the caller of the move-assignment operator it looks as if the move-assignment operator would in total a function with a wide contract.

The problem with this analysis so far is, that it depends on the assumed correctness of the state "owns".

Looking at the construction or state-changing functions, there do exist several ones that depend on caller-code satisfying the requirements and there is one guy, who looks most suspicious:

unique_lock(mutex_type& m, adopt_lock_t);

11 Requires: The calling thread own the mutex.
[…]
13 Postconditions: pm == &m and owns == true.

because this function does not even call lock() (which may, but is not required to throw an exception if the calling thread does already own the mutex). So we have in fact still a move-assignment operator that might throw an exception, if the mutex was either constructed or used (call of lock) incorrectly.

The correct fix seems to me to also add a "Throws: Nothing" element to the move-assignment operator, because using it correctly shall now throw an exception.

Proposed resolution:

This wording is relative to the FDIS.

  1. Change 30.4.2.2 [thread.lock.unique], class template unique_lock synopsis as indicated:

    namespace std {
      template <class Mutex>
      class unique_lock {
      public:
        typedef Mutex mutex_type;
        […]
        unique_lock(unique_lock&& u) noexcept;
        unique_lock& operator=(unique_lock&& u) noexcept;
        […]
      };
    }
    
  2. Change 30.4.2.2.1 [thread.lock.unique.cons] around p22 as indicated:

    unique_lock& operator=(unique_lock&& u) noexcept;
    

    -22- Effects: If owns calls pm->unlock().

    -23- Postconditions: pm == u_p.pm and owns == u_p.owns (where u_p is the state of u just prior to this construction), u.pm == 0 and u.owns == false.

    -24- [Note: With a recursive mutex it is possible for both *this and u to own the same mutex before the assignment. In this case, *this will own the mutex after the assignment and u will not. — end note]

    -??- Throws: Nothing.


2106. move_iterator wrapping iterators returning prvalues

Section: 24.5.3 [move.iterators] Status: Open Submitter: Dave Abrahams Opened: 2011-11-30 Last modified: 2013-01-15

View all other issues in [move.iterators].

View all issues with Open status.

Discussion:

Shouldn't move_iterator be specialized so that if the iterator it wraps returns a prvalue when dereferenced, the move_iterator also returns by value? Otherwise, it creates a dangling reference.

Howard: I believe just changing move_iterator<I>::reference would do. A direction might be testing on is_reference<iterator_traits<I>::reference>, or is_reference<decltype(*declval<I>())>.

Daniel: I would prefer to use a consistent style among the iterator adaptors, so I suggest to keep with the iterator_traits typedefs if possible.

using reference = typename conditional<
  is_reference<typename iterator_traits<Iterator>::reference>::value,
  value_type&&,
  value_type
>::type;

We might also want to ensure that if Iterator's reference type is a reference, the referent is equal to value_type (after removal of cv-qualifiers). In general we have no such guarantee.

Marc: In the default case where we don't return value_type&&, should we use value_type or should we keep the reference type of the wrapped iterator?

Daniel: This suggestion looks appealing at first, but the problem here is that using this typedef can make it impossible for move_iterator to satisfy its contract, which means returning an rvalue of the value type (Currently it says rvalue-reference, but this must be fixed as of this issue anyway). I think that user-code can reasonably expect that when it has constructed an object m of move_iterator<It>, where It is a valid mutable iterator type, the expression

It::value_type&& rv = *m;

is well-formed.

Let's set R equal to iterator_traits<Iterator>::reference in the following. We can discuss the following situations:

  1. R is a reference type: We can only return the corresponding xvalue of R, if value_type is reference-related to the referent type, else this is presumably no forward iterator and we cannot say much about it, except that it must be convertible to value_type, so it better should return a prvalue.
  2. R is not a reference type: In this case we can rely on a conversion to value_type again, but not much more. Assume we would return R directly, this might turn out to have a conversion to an lvalue-reference type of the value type (for example). If that is the case, this would indirectly violate the contract of move_iterator.

In regard to the first scenario I suggest that implementations are simply required to check that V2 = remove_cv<remove_reference<R>::type>::type is equal to the value type V1 as a criterion to return this reference as an xvalue, in all other cases it should return the value type directly as prvalue.

The additional advantage of this strategy is, that we always ensure that reference has the correct cv-qualification, if R is a real reference.

It is possible to improve this a bit by indeed supporting reference-related types, this would require to test is_same<V1, V2>::value || is_base_of<V1, V2>::value instead. I'm unsure whether (a) this additional effort is worth it and (b) a strict reading of the forward iterator requirements seems not to allow to return a reference-related type (Whether this is a defect or not is another question).

[2011-12-05: Marc Glisse comments and splits into two resolution alternatives]

I guess I am looking at the speed of:

value_type x;
x = *m;

(copy construction would likely trigger copy elision and thus be neutral) instead of the validity of:

value_type&& x = *m;

In this sense, Daniels earlier proposition that ignored value_type and just did switch_lvalue_ref_to_rvalue_ref<reference> was easier to understand (and it didn't require thinking about reference related types).

The currently proposed resolution has been split into two alternatives.

[2012, Kona]

Move to Review.

Alisdair: This only applies to input iterators, so keep that in mind when thinking about this.

STL: I see what B is doing, but not A.

Howard: I agree.

Alisdair: Should we use add_rvalue_reference?

STL: No, we do not want reference collapsing.

STL: Re A, messing with the CV qualification scares me.

Alisdair: Agree. That would break my intent.

STL: Actually I don't think it's actually wrong, but I still don't see what it's doing.

Alisdair: A is picking the value type, B is picking the proxy type.

Howard: I like returning the proxy type.

STL: Returning a reference (B) seems right, because the requirements say "reference". I suspect that B works correctly if you have a move iterator wrapping a move iterator wrapping a thing. I think that A would mess up the type in the middle.

Considerable discussion about which version is correct, checking various examples.

STL: Still think B is right. Still don't understand A. In A we are losing the proxyness.

Howard: Agree 100%. We don't want to lose the proxy. If it's const, so be it.

STL: B is also understandable by mortals.

Howard: Remove to review, keep A but move it out of the proposed resolution area (but keep it for rational).

Alisdair: Adding an explanatory note might be a good idea, if someone wants to write one.

Walter: Concerned about losing the word "reference" in p.1.

Howard: move_iterator will return an xvalue or a prvalue, both of which are rvalues.

[Proposed resolution A, rejected in preference to the currently proposed resolution (B)

  1. Change 24.5.3 [move.iterators] p1 as indicated:

    Class template move_iterator is an iterator adaptor with the same behavior as the underlying iterator except that its dereference operator implicitly converts the value returned by the underlying iterator’s dereference operator to an rvalue referenceof the value type. Some generic algorithms can be called with move iterators to replace copying with moving.

  2. Change 24.5.3.1 [move.iterator], class template move_iterator synopsis, as indicated:

    namespace std {
      template <class Iterator>
      class move_iterator {
      public:
        typedef Iterator iterator_type;
        typedef typename iterator_traits<Iterator>::difference_type difference_type;
        typedef Iterator pointer;
        typedef typename iterator_traits<Iterator>::value_type value_type;
        typedef typename iterator_traits<Iterator>::iterator_category iterator_category;
        typedef value_type&&see below reference;
        […]
      };
    }
    
  3. Immediately following the class template move_iterator synopsis in 24.5.3.1 [move.iterator] insert a new paragraph as indicated:

    -?- Let R be iterator_traits<Iterator>::reference and let V be iterator_traits<Iterator>::value_type. If is_reference<R>::value is true and if remove_cv<remove_reference<R>::type>::type is the same type as V, the template instantiation move_iterator<Iterator> shall define the nested type named reference as a synonym for remove_reference<R>::type&&, otherwise as a synonym for V.

]

[2012, Portland: Move to Tentatively Ready]

AJM wonders if the implied trait might be useful elsewhere, and worth adding to type traits as a transformation type trait.

Suspicion that the Range SG might find such a trait useful, but wait until there is clear additional use of such a trait before standardizing.

Minor wording tweak to use add_rvalue_reference rather than manually adding the &&, then move to Tentatively Ready.

[2013-01-09 Howard Hinnat comments]

I believe the P/R for LWG 2106 is incorrect (item 3). The way it currently reads, move_iterator<I>::reference is always an lvalue reference. I.e. if R is an lvalue reference type, then reference becomes add_rvalue_reference<R>::type which is just R. And if R is not a reference type, then reference becomes R (which is also just R ;-)).

I believe the correct wording is what was there previously:

-?- Let R be iterator_traits<Iterator>::reference. If is_reference<R>::value is true, the template instantiation move_iterator<Iterator> shall define the nested type named reference as a synonym for remove_reference<R>::type&&, otherwise as a synonym for R.

Additionally Marc Glisse points out that move_iterator<I>::operator*() should return static_cast<reference>(*current), not std::move(*current).

Previous resolution:

This wording is relative to the FDIS.

  1. Change 24.5.3 [move.iterators] p1 as indicated:

    Class template move_iterator is an iterator adaptor with the same behavior as the underlying iterator except that its dereference operator implicitly converts the value returned by the underlying iterator’s dereference operator to an rvalue reference. Some generic algorithms can be called with move iterators to replace copying with moving.

  2. Change 24.5.3.1 [move.iterator], class template move_iterator synopsis, as indicated:

    namespace std {
      template <class Iterator>
      class move_iterator {
      public:
        typedef Iterator iterator_type;
        typedef typename iterator_traits<Iterator>::difference_type difference_type;
        typedef Iterator pointer;
        typedef typename iterator_traits<Iterator>::value_type value_type;
        typedef typename iterator_traits<Iterator>::iterator_category iterator_category;
        typedef value_type&&see below reference;
        […]
      };
    }
    
  3. Immediately following the class template move_iterator synopsis in 24.5.3.1 [move.iterator] insert a new paragraph as indicated:

    -?- Let R be iterator_traits<Iterator>::reference. If is_reference<R>::value is true, the template instantiation move_iterator<Iterator> shall define the nested type named reference as a synonym for add_rvalue_reference<R>::type, otherwise as a synonym for R.

Proposed resolution:

This wording is relative to N3485.

  1. Change 24.5.3 [move.iterators] p1 as indicated:

    Class template move_iterator is an iterator adaptor with the same behavior as the underlying iterator except that its indirection operator implicitly converts the value returned by the underlying iterator’s indirection operator to an rvalue reference. Some generic algorithms can be called with move iterators to replace copying with moving.

  2. Change 24.5.3.1 [move.iterator], class template move_iterator synopsis, as indicated:

    namespace std {
      template <class Iterator>
      class move_iterator {
      public:
        typedef Iterator iterator_type;
        typedef typename iterator_traits<Iterator>::difference_type difference_type;
        typedef Iterator pointer;
        typedef typename iterator_traits<Iterator>::value_type value_type;
        typedef typename iterator_traits<Iterator>::iterator_category iterator_category;
        typedef value_type&&see below reference;
        […]
      };
    }
    
  3. Immediately following the class template move_iterator synopsis in 24.5.3.1 [move.iterator] insert a new paragraph as indicated:

    -?- Let R be iterator_traits<Iterator>::reference. If is_reference<R>::value is true, the template instantiation move_iterator<Iterator> shall define the nested type named reference as a synonym for remove_reference<R>::type&&, otherwise as a synonym for R.

  4. Edit 24.5.3.3.4 [move.iter.op.star] p1 as indicated:

    reference operator*() const;
    

    -1- Returns: std::movestatic_cast<reference>(*current).


2108. No way to identify allocator types that always compare equal

Section: 17.6.3.5 [allocator.requirements] Status: Open Submitter: Jonathan Wakely Opened: 2011-12-01 Last modified: 2012-11-14

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with Open status.

Discussion:

Whether two allocator objects compare equal affects the complexity of container copy and move assignments and also the possibility of an exception being thrown by container move assignments. The latter point means container move assignment cannot be noexcept when propagate_on_container_move_assignment (POCMA) is false for the allocator because there is no way to detect at compile-time if two allocators will compare equal. LWG 2013 means this affects all containers using std::allocator, but even if that is resolved, this affects all stateless allocators which do not explicitly define POCMA to true_type.

One solution would be to add an "always_compare_equal" trait to allocator_traits, but that would be duplicating information that is already defined by the type's equality operator if that operator always returns true. Requiring users to write operator== that simply returns true and also explicitly override a trait to repeat the same information would be unfortunate and risk user errors that allow the trait and actual operator== to disagree.

Dave Abrahams suggested a better solution in message c++std-lib-31532, namely to allow operator== to return true_type, which is convertible to bool but also detectable at compile-time. Adopting this as the recommended way to identify allocator types that always compare equal only requires a slight relaxation of the allocator requirements so that operator== is not required to return bool exactly.

The allocator requirements do not make it clear that it is well-defined to compare non-const values, that should be corrected too.

In message c++std-lib-31615 Pablo Halpern suggested an always_compare_equal trait that could still be defined, but with a sensible default value rather than requiring users to override it, and using that to set sensible values for other allocator traits:

Do we still need always_compare_equal if we can have an operator== that returns true_type? What would its default value be? is_empty<A> || is_convertible<decltype(a == a), true_type>::value, perhaps? One benefit I see to such a definition is that stateless C++03 allocators that don't use the true_type idiom will still benefit from the new trait.

[…]

One point that I want to ensure doesn't get lost is that if we adopt some sort of always_compare_equal-like trait, then propagate_on_container_swap and propagate_on_container_move_assignment should default to always_compare_equal. Doing this will eliminate unnecessary requirements on the container element type, as per [LWG 2103].

Optionally, operator== for std::allocator could be made to return true_type, however if LWG 2103 is adopted that is less important.

Alberto Ganesh Barbati: Suggest either always_compare_equal, all_objects_(are_)equivalent, or all_objects_compare_equal.

Proposed resolution:

This wording is relative to the FDIS.

  1. Change Table 27 — "Descriptive variable definitions" in 17.6.3.5 [allocator.requirements]:

    Table 27 — Descriptive variable definitions
    Variable Definition
    a3, a4 an rvalue ofvalues of (possibly const) type X
    b a value of (possibly const) type Y
  2. Change Table 28 — "Allocator requirements" in 17.6.3.5 [allocator.requirements]:

    Table 28 — Allocator requirements
    Expression Return type Assertion/note pre-/post-condition Default
    a1 == a2a3 == a4 convertible to bool returns true only if storage
    allocated from each can be
    deallocated via the other.
    operator== shall be reflexive,
    symmetric, and transitive, and
    shall not exit via an exception.
    a1 != a2a3 != a4 convertible to bool same as !(a1 == a2)!(a3 == a4)
    a3 == b convertible to bool same as a3 ==
    Y::rebind<T>::other(b)
    a3 != b convertible to bool same as !(a3 == b)
    […]
    a.select_on_-
    container_copy_-
    construction()
    X Typically returns either a or
    X()
    return a;
    X::always_compares_equal Identical to or derived
    from true_type or
    false_type
    true_type if the expression x1 == x2 is
    guaranteed to be true for any two (possibly
    const) values x1, x2 of type X, when
    implicitly converted to bool. See Note B, below.
    true_type, if is_empty<X>::value is true or if
    decltype(declval<const X&>() == declval<const X&>())
    is convertible to true_type, otherwise false_type.
    […]

    Note A: […]

    Note B: If X::always_compares_equal::value or XX::always_compares_equal::value evaluate to true and an expression equivalent to x1 == x2 or x1 != x2 for any two values x1, x2 of type X evaluates to false or true, respectively, the behaviour is undefined.

  3. Change class template allocator_traits synopsis, 20.6.8 [allocator.traits] as indicated:

    namespace std {
      template <class Alloc> struct allocator_traits {
        typedef Alloc allocator_type;
        […]
        typedef see below always_compares_equal;
        typedef see below propagate_on_container_copy_assignment;
        […]
      };
    }
    
  4. Insert the following between 20.6.8.1 [allocator.traits.types] p6 and p7 as indicated:

    typedef see below always_compares_equal;
    

    -?- Type: Alloc::always_compares_equal if such a type exists; otherwise, true_type if is_empty<Alloc>::value is true or if decltype(declval<const Alloc&>() == declval<const Alloc&>()) is convertible to true_type; otherwise, false_type .

    typedef see below propagate_on_container_copy_assignment;
    

    -7- Type: Alloc::propagate_on_container_copy_assignment if such a type exits, otherwise false_type.

  5. Change class template allocator synopsis, 20.6.9 [default.allocator] as indicated:

    namespace std {
      template <class T> class allocator;
    
      // specialize for void:
      template <> class allocator<void> {
      public:
        typedef void* pointer;
        typedef const void* const_pointer;
        // reference-to-void members are impossible.
        typedef void value_type;
        template <class U> struct rebind { typedef allocator<U> other; };
      };
    
      template <class T> class allocator {
      public:
        typedef size_t size_type;
        typedef ptrdiff_t difference_type;
        typedef T* pointer;
        typedef const T* const_pointer;
        typedef T& reference;
        typedef const T& const_reference;
        typedef T value_type;
        template <class U> struct rebind { typedef allocator<U> other; };
        typedef true_type always_compares_equal;
    
        […]
      };
    }
    

2109. Incorrect requirements for hash specializations

Section: 19.5.5 [syserr.hash], 20.7.2.6 [util.smartptr.hash], 20.8.12 [unord.hash], 20.13.1 [type.index.synopsis], 21.6 [basic.string.hash], 23.3.7 [vector.bool], 30.3.1.1 [thread.thread.id] Status: Tentatively Ready Submitter: Daniel Krügler Opened: 2011-12-04 Last modified: 2012-11-14

View all issues with Tentatively Ready status.

Discussion:

20.7.2.6 [util.smartptr.hash] p2 is specified as follows:

Requires: the template specializations shall meet the requirements of class template hash (20.8.12).

The problem here is the usage of a Requires element, which is actually a pre-condition that a user of a component has to satisfy. But the intent of this wording is actually to be a requirement on implementations. The Requires element should be removed here and the wording should be improved to say what it was intended for.

We have similar situations in basically all other places where the specification of library-provided hash specializations is defined. Usually, the Requires element is incorrect. In the special case of hash<unique_ptr<T, D>> the implementation depends on the behaviour of hash specializations, that could be user-provided. In this case the specification needs to separate the requirements on these specializations and those that are imposed on the implementation.

[2012, Kona]

Update wording and move to Review.

Believe a simpler formulation is to simply string the term Requires: and leave the current wording intact, rather than strike the whole clause and replace it.

[Originally proposed wording for reference

  1. Change 19.5.5 [syserr.hash] as indicated:

    template <> struct hash<error_code>;
    

    -1- Requires: the template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <system_error> provides a definition for a specialization of the template hash<error_code>. The requirements for the members of this specialization are given in sub-clause 20.8.12 [unord.hash].

  2. Change 20.5.3 [bitset.hash] as indicated:

    template <size_t N> struct hash<bitset<N> >;
    

    -1- Requires: the template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <bitset> provides a definition for a partial specialization of the hash class template for specializations of class template bitset<N>. The requirements for the members of instantiations of this specialization are given in sub-clause 20.8.12 [unord.hash].

  3. Change 20.7.2.6 [util.smartptr.hash] as indicated:

    template <class T, class D> struct hash<unique_ptr<T, D> >;
    

    -1- Requires: the template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <memory> provides a definition for a partial specialization of the hash class template for specializations of class template unique_ptr<T, D>. The requirements for the members of instantiations of this specialization are given in sub-clause 20.8.12 [unord.hash]. For an object p of type UP, where UP is unique_ptr<T, D>, hash<UP>()(p) shall evaluate to the same value as hash<typename UP::pointer>()(p.get()). The specialization hash<typename UP::pointer> shall be well-formed.

    -?- Requires: The specialization hash<typename UP::pointer> shall be well-formed and well-defined [Note: the general requirements of class template hash (20.8.12 [unord.hash]) are implied — end note].

    template <class T> struct hash<shared_ptr<T> >;
    

    -2- Requires: the template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <memory> provides a definition for a partial specialization of the hash class template for specializations of class template shared_ptr<T>. The requirements for the members of instantiations of this specialization are given in sub-clause 20.8.12 [unord.hash]. For an object p of type shared_ptr<T>, hash<shared_ptr<T> >()(p) shall evaluate to the same value as hash<T*>()(p.get()).

  4. Change 20.8.12 [unord.hash] p2 as indicated: [Comment: For unknown reasons the extended integer types are not mentioned here, which looks like an oversight to me and makes also the wording more complicated. See 2119 for this part of the problem. — end comment]

    template <> struct hash<bool>;
    template <> struct hash<char>;
    […]
    template <> struct hash<long double>;
    template <class T> struct hash<T*>;
    

    -2- Requires: the template specializations shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <functional> provides definitions for specializations of the hash class template for each cv-unqualified arithmetic type except for the extended integer types. This header also provides a definition for a partial specialization of the hash class template for any pointer type. The requirements for the members of these specializations are given in sub-clause 20.8.12 [unord.hash].

  5. Change 20.13.4 [type.index.hash] p1 as indicated:

    template <> struct hash<type_index>;
    

    -1- Requires: the template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <typeindex> provides a definition for a specialization of the template hash<type_index>. The requirements for the members of this specialization are given in sub-clause 20.8.12 [unord.hash]. For an object index of type type_index, hash<type_index>()(index) shall evaluate to the same result as index.hash_code().

  6. Change 21.6 [basic.string.hash] p1 as indicated:

    template <> struct hash<string>;
    template <> struct hash<u16string>;
    template <> struct hash<u32string>;
    template <> struct hash<wstring>;
    

    -1- Requires: the template specializations shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <string> provides definitions for specializations of the hash class template for the types string, u16string, u32string, and wstring. The requirements for the members of these specializations are given in sub-clause 20.8.12 [unord.hash].

  7. Change 23.3.7 [vector.bool] p7 as indicated:

    template <class Allocator> struct hash<vector<bool, Allocator> >;
    

    -7- Requires: the template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <vector> provides a definition for a partial specialization of the hash class template for specializations of class template vector<bool, Allocator>. The requirements for the members of instantiations of this specialization are given in sub-clause 20.8.12 [unord.hash].

  8. Change 30.3.1.1 [thread.thread.id] p14 as indicated:

    template <> struct hash<thread::id>;
    

    -14- Requires: the template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <thread> provides a definition for a specialization of the template hash<thread::id>. The requirements for the members of this specialization are given in sub-clause 20.8.12 [unord.hash].

]

[2012, Portland: Move to Tentatively Ready]

No further wording issues, so move to Tentatively Ready (post meeting issues processing).

Proposed resolution:

  1. Change 19.5.5 [syserr.hash] as indicated:

    template <> struct hash<error_code>;
    

    -1- Requires: tThe template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash].

  2. Change 20.5.3 [bitset.hash] as indicated:

    template <size_t N> struct hash<bitset<N> >;
    

    -1- Requires: tThe template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash]).

  3. Change 20.7.2.6 [util.smartptr.hash] as indicated:

    template <class T, class D> struct hash<unique_ptr<T, D> >;
    

    -1- Requires: tThe template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash]). For an object p of type UP, where UP is unique_ptr<T, D>, hash<UP>()(p) shall evaluate to the same value as hash<typename UP::pointer>()(p.get()). The specialization hash<typename UP::pointer> shall be well-formed.

    -?- Requires: The specialization hash<typename UP::pointer> shall be well-formed and well-defined, and shall meet the requirements of class template hash (20.8.12 [unord.hash]).

    template <class T> struct hash<shared_ptr<T> >;
    

    -2- Requires: tThe template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash]). For an object p of type shared_ptr<T>, hash<shared_ptr<T> >()(p) shall evaluate to the same value as hash<T*>()(p.get()).

  4. Change 20.8.12 [unord.hash] p2 as indicated: [Comment: For unknown reasons the extended integer types are not mentioned here, which looks like an oversight to me and makes also the wording more complicated. See 2119 for this part of the problem. — end comment]

    template <> struct hash<bool>;
    template <> struct hash<char>;
    […]
    template <> struct hash<long double>;
    template <class T> struct hash<T*>;
    

    -2- Requires: tThe template specializations shall meet the requirements of class template hash (20.8.12 [unord.hash]).

  5. Change 20.13.4 [type.index.hash] p1 as indicated:

    template <> struct hash<type_index>;
    

    -1- Requires: tThe template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash]). For an object index of type type_index, hash<type_index>()(index) shall evaluate to the same result as index.hash_code().

  6. Change 21.6 [basic.string.hash] p1 as indicated:

    template <> struct hash<string>;
    template <> struct hash<u16string>;
    template <> struct hash<u32string>;
    template <> struct hash<wstring>;
    

    -1- Requires: tThe template specializations shall meet the requirements of class template hash (20.8.12 [unord.hash]).

  7. Change 23.3.7 [vector.bool] p7 as indicated:

    template <class Allocator> struct hash<vector<bool, Allocator> >;
    

    -7- Requires: tThe template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash]).

  8. Change 30.3.1.1 [thread.thread.id] p14 as indicated:

    template <> struct hash<thread::id>;
    

    -14- Requires: tThe template specialization shall meet the requirements of class template hash (20.8.12 [unord.hash]).


2111. Which unexpected/terminate handler is called from the exception handling runtime?

Section: 18.8.3.4 [terminate], D.13.3 [unexpected] Status: Open Submitter: Howard Hinnant Opened: 2011-12-06 Last modified: 2012-11-14

View all other issues in [terminate].

View all issues with Open status.

Discussion:

Prior to N3242, modified by N3189, we said this about unexpected():

Effects: Calls the unexpected_handler function in effect immediately after evaluating the throw-expression (D.13.1), if called by the implementation, or calls the current unexpected_handler, if called by the program.

and this about terminate():

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.

But now in both places we say:

Calls the current unexpected_handler function.

and:

Calls the current terminate function.

The difference is that in C++98/03 if a destructor reset a handler during stack unwinding, that new handler was not called if the unwinding later led to unexpected() or terminate() being called. But these new words say that this new handler is called. This is an ABI-breaking change in the way exceptions are handled. Was this change intentional?

N3189 was mainly about introducing exception safety and getters for the handlers. I don't recall the issue of which handler gets called being part of the discussion.

I propose that we revert to the C++98/03 behavior in this regard, lest ABI's such as the Itanium ABI are invalidated. A mechanical way to do this is to revert bullets 9 and 12 of N3189.

[2011-12-09: Daniel comments]

There was no such semantic change intended. It was an unfortunate side effect when trying to better separate different responsibilities in the previous wording.

A related issue is 2088.

[2012-01-30: Howard comments]

The C++98/03 wording is somewhat ambiguous:

Calls the terminate_handler function in effect immediately after evaluating the throw-expression...

There are potentially two throw-expressions being referred to here, and it is not clear if this sentence is referring to just the first or both:

  1. throw assignment-expression;
  2. throw;

There is ample evidence in current implementations that it is understood that only 1. was meant. But clearly both 1 and 2 could have been meant. We need a clarification. Does an execution of a rethrow (throw;) update which handlers can potentially be called?

  1. throw; // update handlers to get_xxx()?

My opinion: Go with existing practice, and clarify what that practice is, if surveys find that everyone does the same thing. Gcc 4.2 and Apple do 1. only, and do not reset the handlers to the current handlers on throw;.

If current practice is not unanimously one way or the other, I have no strong opinion. I have not found a motivating use case for the use of any particular handler. Most applications set the handlers once at the beginning of the program and then do not change them, and so will not be impacted by whatever decision is made here.

Proposed resolution:


2112. User-defined classes that cannot be derived from

Section: 17.6.5 [conforming], 20.6.8 [allocator.traits], 20.12.1 [allocator.adaptor.syn] Status: Open Submitter: Daniel Krügler Opened: 2011-11-30 Last modified: 2012-11-14

View all other issues in [conforming].

View all issues with Open status.

Discussion:

It is a very established technique for implementations to derive internally from user-defined class types that are used to customize some library component, e.g. deleters and allocators are typical candidates. The advantage of this approach is to possibly take advantage of the empty-base-class optimization (EBCO).

Whether or whether not libraries did take advantage of such a detail didn't much matter in C++03. Even though there did exist a portable idiom to prevent that a class type could be derived from, this idiom has never reached great popularity: The technique required to introduce a virtual base class and it did not really prevent the derivation, but only any construction of such a type. Further, such types are not empty as defined by the std::is_empty trait, so could easily be detected by implementations from TR1 on.

With the new C++11 feature of final classes and final member functions it is now very easy to define an empty, but not derivable from class type. From the point of the user it is quite natural to use this feature for types that he or she did not foresee to be derivable from.

On the other hand, most library implementations (including third-party libraries) often take advantage of EBCO applied to user-defined types used to instantiate library templates internally. As the time of submitting this issue the following program failed to compile on all tested library implementations:

#include <memory>

struct Noop final {
 template<class Ptr>
 void operator()(Ptr) const {}
};

std::unique_ptr<int, Noop> up;

In addition, many std::tuple implementations with empty, final classes as element types failed as well, due to a popular inheritance-based implementation technique. EBCO has also a long tradition to be used in library containers to efficiently store potentially stateless, empty allocators.

It seems that both user and library did the best they could: None of the affected types did impose explicit requirements on the corresponding user-defined types to be derivable from (This capability was not part of the required operations), and libraries did apply EBCO whereever possible to the convenience of the customer.

Nonetheless given the existence of non-derivable-from class types in C++11, libraries have to cope with failing derivations. How should that problem be solved?

It would certainly be possible to add weazel wording to the allocator requirements similar to what we had in C++03, but restricted to derivation-from requirements. I consider this as the bad solution, because it would add new requirements that never had existed before in this explicit form onto types like allocators.

Existing libraries presumably will need internal traits like __is_final or __is_derivable to make EBCO possible in the current form but excluding non-derivable class types. As of this writing this seems to happen already. Problem is that without a std::is_derivable trait, third-party libraries have no portable means to do the same thing as standard library implementations. This should be a good reason to make such a trait public available soon, but seems not essential to have now. Further, this issue should also be considered as a chance to recognice that EBCO has always been a very special corner case (There exist parallels to the previously existing odd core language rule that did make the interplay between std::auto_ptr and std::auto_ptr_ref possible) and that it would be better to provide explicit means for space-efficient storage, not necessarily restricted to inheritance relations, e.g. by marking data members with a special attribute.

At least two descriptions in the current standard should be fixed now for better clarification:

  1. As mentioned by Ganesh, 20.6.8 [allocator.traits] p1 currently contains a (non-normative) note "Thus, it is always possible to create a derived class from an allocator." which should be removed.

  2. As pointed out by Howard, the specification of scoped_allocator_adaptor as of 20.12.1 [allocator.adaptor.syn] already requires derivation from OuterAlloc, but only implies indirectly the same for the inner allocators due to the exposition-only description of member inner. This indirect implication should be normatively required for all participating allocators.

[2012, Kona]

What we really need is a type trait to indicate if a type can be derived from. Howard reports Clang and libc++ have had success with this approach.

Howard to provide wording, and AJM to alert Core that we may be wanting to add a new trait that requires compiler support.

Proposed resolution:


2114. Incorrect "contextually convertible to bool" requirements

Section: 17.6.3.3 [nullablepointer.requirements], 24.2.3 [input.iterators], 24.2.7 [random.access.iterators], 25.1 [algorithms.general], 25.4 [alg.sorting], 30.2.1 [thread.req.paramname] Status: Open Submitter: Daniel Krügler Opened: 2011-12-09 Last modified: 2012-11-14

View all issues with Open status.

Discussion:

As of 17.6.3.1 [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.7.1.4 [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.7.1.2.2 [unique.ptr.single.dtor] p2, 20.7.1.2.3 [unique.ptr.single.asgn] p9, 20.7.1.2.4 [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.4 [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.2.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 30.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 30.5.1 [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 30.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. 30.5.1 [thread.condition.condvar] p32+33+42 or 30.5.2 [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 17.6.3 [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.

Proposed resolution:

This wording is relative to the FDIS.

  1. Change Table 25 — "NullablePointer requirements" in 17.6.3.3 [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 24.2.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 24.2.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.8 [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 4 [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 4 [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 4 [conv]). binary_pred shall not apply any non-constant function through the dereferenced iterators.

  5. Change 25.4 [alg.sorting] p2 as indicated:

    -2- Compare is a function object type (20.8 [function.objects]). The return value of the function call operation applied to an object of type Compare, when implicitly or contextually converted to bool (4 [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 30.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 boolPredicate is a function object type (20.8 [function.objects]). The return value of the function call operation applied to an object of type Predicate, when implicitly or contextually converted to bool (4 [conv]), yields true if the corresponding test condition is satisfied, and false otherwise.


2115. Undefined behaviour for valarray assignments with mask_array index?

Section: 26.6.8 [template.mask.array] Status: Open Submitter: Thomas Plum Opened: 2011-12-10 Last modified: 2012-11-14

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.6.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.6.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. std::swap noexcept(what?)

Section: 20.9.4.3 [meta.unary.prop] Status: Open Submitter: Dave Abrahams Opened: 2011-12-09 Last modified: 2012-11-14

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 12.8 [class.copy] p11:

A defaulted copy/move constructor for a class X is defined as deleted (8.4.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 desturctor 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.

Proposed resolution:


2117. ios_base manipulators should have showgrouping/noshowgrouping

Section: 22.4.2.2.2 [facet.num.put.virtuals], 27.5.3.1.2 [ios::fmtflags], 27.5.6.1 [fmtflags.manip] Status: Open Submitter: Benjamin Kosnik Opened: 2011-12-15 Last modified: 2012-11-14

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)

Proposed resolution:

This wording is relative to the FDIS.

  1. Insert in 22.4.2.2.2 [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, 27.5.1 [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, 27.5.3 [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 27.5.3.1.2 [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.


2118. unique_ptr for array does not support cv qualification conversion of actual argument

Section: 20.7.1.3 [unique.ptr.runtime] Status: Open Submitter: Alf P. Steinbach Opened: 2011-12-16 Last modified: 2012-12-25

View all other issues in [unique.ptr.runtime].

View all issues with Open status.

Discussion:

N3290 20.7.1.3.1 [unique.ptr.runtime.ctor] "unique_ptr constructors":

These constructors behave the same as in the primary template except that they do not accept pointer types which are convertible to pointer. [Note: One implementation technique is to create private templated overloads of these members. — end note]

This language excludes even pointer itself as type for the actual argument.

But of more practical concern is that both Visual C++ 10.0 and MinGW g++ 4.1.1 reject the code below, where only an implicit cv qualification is needed, which cv qualification is supported by the non-array version:

#include <memory>
using namespace std;

struct T {};

T* foo() { return new T; }
T const* bar() { return foo(); }

int main()
{
   unique_ptr< T const >       p1( bar() );        // OK
   unique_ptr< T const [] >    a1( bar() );        // OK

   unique_ptr< T const >       p2( foo() );        // OK
   unique_ptr< T const [] >    a2( foo() );        // ? this is line #15
}

The intent seems to be clearly specified in 20.7.1.3 [unique.ptr.runtime]/1 second bullet:

— Pointers to types derived from T are rejected by the constructors, and by reset.

But the following language in 20.7.1.3.1 [unique.ptr.runtime.ctor] then rejects far too much...

Proposed new wording of N3290 20.7.1.3.1 [unique.ptr.runtime.ctor] "unique_ptr constructors":

These constructors behave the same as in the primary template except that actual argument pointers p to types derived from T are rejected by the constructors. [Note: One implementation technique is to create private templated overloads of these members. — end note]

This will possibly capture the intent better, and avoid the inconsistency between the non-array and array versions of unique_ptr, by using nearly the exact same phrasing as for the paragraph explaining the intent.

[2012-08-25 Geoffrey Romer comments in c++std-lib-32978]

  1. The current P/R seems to intend to support at least two different implementation techniques — additional unusable templates that catch forbidden arguments or replacing existing constructors by templates that ensure ill-formed code inside the template body, when the requirements are not met. It seems unclear whether the current wording allows the second approach, though. It should be considered to allow both strategies or if that is not possible the note should be clearer.

  2. The very same problem exists for the reset member function, but even worse, because the current specification is more than clear that the deleted reset function will catch all cases not equal to pointer. It seems confusing at best to have different policies for the constructor and for the reset function. In this case, the question in regard to implementation freedom mentioned above is even more important.

  3. It's awkward to refer to "the constructors" twice in the same sentence; I suggest revising the sentence as "...except that they do not accept argument pointers p to types derived from T"

[2012-12-20: Geoffrey Romer comments and provides a revised resolution]

The array specialization of unique_ptr differs from the primary template in several ways, including the following:

The common intent of all these restrictions appears to be to disallow implicit conversions from pointer-to-derived-class to pointer-to-base-class in contexts where the pointer is known to point to an array, because such conversions are inherently unsafe; deleting or subscripting the result of such a conversion leads to undefined behavior (see also CWG 1504). However, these restrictions have the effect of disallowing all implicit conversions in those contexts, including most notably cv-qualification, but also user-defined conversions, and possibly others. This PR narrows all those restrictions, to disallow only unsafe pointer-to-derived to pointer-to-base conversions, while allowing all others.

I removed the nebulous language stating that certain functions "will not accept" certain arguments. Instead I use explicitly deleted template functions, which participate in overload resolution only for pointer-to-derived to pointer-to-base conversions. This is more consistent with the existing text and easier to express correctly than an approach based on declaring certain types of calls to be ill-formed, but may produce inferior compiler diagnostics.

Wherever possible, this PR defines the semantics of template specializations in terms of their differences from the primary template. This improves clarity and minimizes the risk of unintended differences (e.g. LWG 2169, which this PR also fixes). This PR also makes it explicit that the specialization inherits the description of all members, not just member functions, from the primary template and, in passing, clarifies the default definition of pointer in the specialization.

This resolution only disallows pointer-to-derived to pointer-to-base conversions between ordinary pointer types; if user-defined pointer types provide comparable conversions, it is their responsibility to ensure they are safe. This is consistent with C++'s general preference for expressive power over safety, and for assuming the user knows what they're doing; furthermore, enforcing such a restriction on user-defined types appears to be impractical without cooperation from the user.

The "base class without regard to cv-qualifiers" language is intended to parallel the specification of std::is_base_of.

Jonathan Wakely has a working implementation of this PR patched into libstdc++.

Previous resolution:

This wording is relative to the FDIS.

Change 20.7.1.3.1 [unique.ptr.runtime.ctor] as indicated:

explicit unique_ptr(pointer p) noexcept;
unique_ptr(pointer p, see below d) noexcept;
unique_ptr(pointer p, see below d) noexcept;

These constructors behave the same as in the primary template except that they do not accept pointer types which are convertible to pointerargument pointers p to types derived from T are rejected by the constructors. [Note: One implementation technique is to create private templated overloads of these members. — end note]

Proposed resolution:

This wording is relative to N3485.

  1. Revise 20.7.1.1.3 [unique.ptr.dltr.dflt1] as follows

    namespace std {
      template <class T> struct default_delete<T[]> {
        constexpr default_delete() noexcept = default;
        template <class U> default_delete(const default_delete<U>&) noexcept;
        void operator()(T*) const;
        template <class U> void operator()(U*) const = delete;
      };
    }
    

    -?- Descriptions are provided below only for member functions that have behavior different from the primary template.

    template <class U> default_delete(const default_delete<U>&) noexcept;
    

    -?- This constructor behaves the same as in the primary template except that it shall not participate in overload resolution unless:

    • U is an array type, and

    • V* is implicitly convertible to T*, and

    • T is not a base class of V (without regard to cv-qualifiers),

    where V is the array element type of U.

    void operator()(T* ptr) const;
    

    -1- Effects: calls delete[] on ptr.

    -2- Remarks: If T is an incomplete type, the program is ill-formed.

    template <class U> void operator()(U*) const = delete;
    

    -?- Remarks: This function shall not participate in overload resolution unless T is a base class of U (without regard to cv-qualifiers).

  2. Revise 20.7.1.2 [unique.ptr.single]/3 as follows:

    If the type remove_reference<D>::type::pointer exists, then unique_ptr<T, D>::pointer shall be a synonym for remove_reference<D>::type::pointer. Otherwise unique_ptr<T, D>::pointer shall be a synonym for Telement_type*. The type unique_ptr<T, D>::pointer shall satisfy the requirements of NullablePointer (17.6.3.3 [nullablepointer.requirements]).

  3. Revise 20.7.1.3 [unique.ptr.runtime] as follows:

    namespace std {
      template <class T, class D> class unique_ptr<T[], D> {
      public:
        typedef see below pointer;
        typedef T element_type;
        typedef D deleter_type;
    
        // 20.7.1.3.1, constructors
        constexpr unique_ptr() noexcept;
        explicit unique_ptr(pointer p) noexcept;
        template <class U> explicit unique_ptr(U* p) = delete;
        unique_ptr(pointer p, see below d) noexcept;
        template <class U> unique_ptr(U* p, see below d) = delete;
        unique_ptr(pointer p, see below d) noexcept;
        template <class U> unique_ptr(U* p, see below d) = delete;
        unique_ptr(unique_ptr&& u) noexcept;
        constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { }
        template <class U, class E> unique_ptr(unique_ptr<U, E>&& u) noexcept;
    
        // destructor
        ~unique_ptr();
    
        // assignment
        unique_ptr& operator=(unique_ptr&& u) noexcept;
        template <class U, class E> unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept;
        unique_ptr& operator=(nullptr_t) noexcept;
    
        // 20.7.1.3.2, observers
        T& operator[](size_t i) const;
        pointer get() const noexcept;
        deleter_type& get_deleter() noexcept;
        const deleter_type& get_deleter() const noexcept;
        explicit operator bool() const noexcept;
    
        // 20.7.1.3.3 modifiers
        pointer release() noexcept;
        void reset(pointer p = pointer()) noexcept;
        void reset(nullptr_t) noexcept;
        template <class U> void reset(U*) = delete;
        void swap(unique_ptr& u) noexcept;
    
        // disable copy from lvalue
        unique_ptr(const unique_ptr&) = delete;
        unique_ptr& operator=(const unique_ptr&) = delete;
      };
    }
    

    -1- A specialization for array types is provided with a slightly altered interface.

    • Conversions between different types of unique_ptr<T[], D>from unique_ptr<Derived[]> to unique_ptr<Base[]>, where Base is a base class of Derived, from auto_ptr, or to or from the non-array forms of unique_ptr produce an ill-formed program.

    • Pointers to types derived from T are rejected by the constructors, and by reset.

    • The observers operator* and operator-> are not provided.

    • The indexing observer operator[] is provided.

    • The default deleter will call delete[].

    -2- Descriptions are provided below only for member functions that have behavior differentmembers that differ from the primary template.

    -3- The template argument T shall be a complete type.

  4. Revise 20.7.1.3.1 [unique.ptr.runtime.ctor] as follows:

    explicit unique_ptr(pointer p) noexcept;
    unique_ptr(pointer p, see below d) noexcept;
    unique_ptr(pointer p, see below d) noexcept;
    template <class U> explicit unique_ptr(U* p) = delete;
    template <class U> unique_ptr(U* p, see below d) = delete;
    template <class U> unique_ptr(U* p, see below d) = delete;
    

    These constructors behave the same as in the primary template except that they do not accept pointer types which are convertible to pointer. [Note: One implementation technique is to create private templated overloads of these members. — end note]These constructors shall not participate in overload resolution unless:

    • pointer is a pointer type, and

    • U* is implicitly convertible to pointer, and

    • T is a base class of U (without regard to cv-qualifiers).

    The type of d is determined as in the corresponding non-deleted constructors.

    template <class U, class E> unique_ptr(unique_ptr<U, E>&& u) noexcept;
    

    -?- This constructor behaves the same as in the primary template, except that it shall not participate in overload resolution unless:

    • unique_ptr<U, E>::pointer is implicitly convertible to pointer, and

    • U is an array type, and

    • either D is a reference type and E is the same type as D, or D is not a reference type and E is implicitly convertible to D, and

    • either at least one of pointer and unique_ptr<U, E>::pointer is not a pointer type, or T is not a base class of the array element type of U (without regard to cv-qualifiers).

  5. Insert a new sub-clause following 20.7.1.3.1 [unique.ptr.runtime.ctor] as follows:

    ?? unique_ptr assignment [unique.ptr.runtime.asgn]

    template <class U, class E> unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept;
    

    -?- This operator behaves the same as in the primary template, except that it shall not participate in overload resolution unless:

    • unique_ptr<U, E>::pointer is implicitly convertible to pointer, and

    • U is an array type, and

    • either D is a reference type and E is the same type as D, or D is not a reference type and E is implicitly convertible to D, and

    • either at least one of pointer and unique_ptr<U, E>::pointer is not a pointer type, or T is not a base class of the array element type of U (without regard to cv-qualifiers).

  6. Revise 20.7.1.3.3 [unique.ptr.runtime.modifiers] as follows:

    void reset(pointer p = pointer()) noexcept;
    void reset(nullptr_t p) noexcept;
    template <class U> void reset(U*) = delete;
    

    -1- Effects: If get() == nullptr there are no effects. Otherwise get_deleter()(get()).

    -2- Postcondition: get() == p.

    -?- This function shall not participate in overload resolution unless:

    • pointer is a pointer type, and

    • U* is implicitly convertible to pointer, and

    • T is a base class of U (without regard to cv-qualifiers).


2119. Missing hash specializations for extended integer types

Section: 20.8.12 [unord.hash] Status: Open Submitter: Daniel Krügler Opened: 2011-12-16 Last modified: 2012-11-14

View other active issues in [unord.hash].

View all other issues in [unord.hash].

View all issues with Open status.

Discussion:

According to the header <functional> synopsis 20.8 [function.objects] and to the explicit description in 20.8.12 [unord.hash] class template hash specializations shall be provided for all arithmetic types that are not extended integer types. This is not explicitly mentioned, but neither the list nor any normative wording does include them, so it follows by implication.

What are the reasons that extended integer types are excluded? E.g. for numeric_limits corresponding specializations are required. I would expect that an unordered_map with key type std::uintmax_t would just work, but that depends now on whether this type is an extended integer type or not.

This issue is not asking for also providing specializations for the cv-qualified arithmetic types. While this is surely a nice-to-have feature, I consider that restriction as a more secondary problem in practice.

The proposed resolution also fixes a problem mentioned in 2109 in regard to confusing requirements on user-defined types and those on implementations.

[2012, Kona]

Move to Open.

Agreed that it's a real issue and that the proposed wording fixes it. However, the wording change is not minimal and isn't consistent with the way we fixed hash wording elsewhere.

Alisdair will provide updated wording.

Proposed resolution:

This wording is relative to the FDIS.

Change 20.8.12 [unord.hash] p2 as indicated:

template <> struct hash<bool>;
template <> struct hash<char>;
[…]
template <> struct hash<long double>;
template <class T> struct hash<T*>;

-2- Requires: the template specializations shall meet the requirements of class template hash (20.8.12 [unord.hash])The header <functional> provides definitions for specializations of the hash class template for each cv-unqualified arithmetic type. This header also provides a definition for a partial specialization of the hash class template for any pointer type. The requirements for the members of these specializations are given in sub-clause 20.8.12 [unord.hash].


2120. What should async do if neither 'async' nor 'deferred' is set in policy?

Section: 30.6.8 [futures.async] Status: Review Submitter: Jonathan Wakely Opened: 2012-01-01 Last modified: 2012-11-14

View other active issues in [futures.async].

View all other issues in [futures.async].

View all issues with Review status.

Discussion:

Implementations already disagree, one returns an invalid future with no shared state, one chooses policy == async and one chooses policy == deferred, see c++std-lib-30839, c++std-lib-30840 and c++std-lib-30844. It's not clear if returning an invalid future is allowed by the current wording.

If the intention is to allow an empty future to be returned, then 30.6.8 [futures.async] p3 and p4 should be adjusted to clarify that a shared state might not be created and an invalid future might be returned.

If the intention is that a valid future is always returned, p3 should say something about the case where none of the conditions applies.

[2012, Portland: move to Review]

We could make it undefined if no launch policy is defined.

Hans: If no launch policy is specified the behaviour is undefined

Artur: or implementation defined?

Hans: no: we don't want people to do this

[Proposed wording]

This wording is relative to N3376

Add a third bullet to the end of the list in 30.6.8p3

"if no valid launch policy is provided the behaviour is undefined"

Moved to review

Proposed resolution:

[This wording is relative to N3376]

Add a third bullet to the end of the list in 30.6.8 [futures.async]p3

– if no valid launch policy is provided the behaviour is undefined

2121. app for string streams

Section: 27.8.6 [stringstream.cons] Status: New Submitter: Nicolai Josuttis Opened: 2012-01-15 Last modified: 2012-11-14

View all issues with New status.

Discussion:

This issue was raised while discussing issue 1448.

Note the following program:

string s("s1: 123456789");
ostringstream s1(s, ios_base::out|ios_base::app);
s1 << "hello";
cout << s1.str() << endl;

With g++4.x it prints:

s1: 123456789hello

With VisualC++10 it prints:

hello23456789

From my intuitive understanding the flag "app" should result in the output of g++4.x. I also would read that from 27.5.3.1.4 [ios::openmode] claiming:

app   seek to end before each write

However in issue 1448 P.J.Plauger comments:

I think we should say nothing special about app at construction time (thus leaving the write pointer at the beginning of the buffer). Leave implementers wiggle room to ensure subsequent append writes as they see fit, but don't change existing rules for initial seek position.

Note that the flag ate on both platforms appends "hello" to s.

Proposed resolution:


2122. merge() stability for lists versus forward lists

Section: 23.3.5.5 [list.ops], 23.3.4.6 [forwardlist.ops] Status: Open Submitter: Nicolai Josuttis Opened: 2012-01-15 Last modified: 2012-11-14

View all other issues in [list.ops].

View all issues with Open status.

Discussion:

forward_list::merge() is specified in 23.3.4.6 [forwardlist.ops], p19 as follows:

This operation shall be stable: for equivalent elements in the two lists, the elements from *this shall always precede the elements from x.

But list::merge() is only specified in 23.3.5.5 [list.ops], p24 as follows:

Remarks: Stable.

Note that in general we define "stable" only for algorithms (see [defns.stable] and 17.6.5.7 [algorithm.stable]) so for member function we should explain it everywhere we use it.

Thus for lists we have to add:

Stable: for equivalent elements in the two lists, the elements from the list always precede the elements from the argument list.

This, BTW, was the specification we had with C++03.

In addition, I wonder whether we also have some guarantees regarding stability saying that the order of equivalent elements of each list merged remains stable (which would be my interpretation of just saying "stable", BTW).

Thus, I'd expect that for equivalent elements we guarantee that

[2012, Kona]

Move to Open.

STL says we need to fix up 17.6.5.7 to be stronger, and then the remarks for merge should just say "Remarks: Stable (see 17.6.5.7)"

Assigned to STL for word-smithing.

Proposed resolution:

This wording is relative to the FDIS.

  1. Change 23.3.5.5 [list.ops] as indicated:

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

    […]

    -24- Remarks: StableThis operation shall be stable: for equivalent elements in the two lists, the elements from *this shall always precede the elements from x and the order of equivalent elements of *this and x remains stable. If (&x != this) the range [x.begin(), x.end()) is empty after the merge. No elements are copied by this operation. The behavior is undefined if this->get_allocator() != x.get_allocator().

  2. Change 23.3.4.6 [forwardlist.ops] as indicated:

    void merge(forward_list<T,Allocator>& x);
    void merge(forward_list<T,Allocator>&& x);
    template <class Compare> void merge(forward_list<T,Allocator>& x, Compare comp);
    template <class Compare> void merge(forward_list<T,Allocator>&& x, Compare comp);

    […]

    -19- Effects: Merges x into *this. This operation shall be stable: for equivalent elements in the two lists, the elements from *this shall always precede the elements from x and the order of equivalent elements of *this and x remains stable. x is empty after the merge. If an exception is thrown other than by a comparison there are no effects. Pointers and references to the moved elements of x now refer to those same elements but as members of *this. Iterators referring to the moved elements will continue to refer to their elements, but they now behave as iterators into *this, not into x.


2125. TimedMutex specification problem

Section: 30.4.1.3 [thread.timedmutex.requirements], 30.4.1.3.1 [thread.timedmutex.class] Status: Tentatively NAD Editorial Submitter: Vicente J. Botet Escriba Opened: 2012-01-01 Last modified: 2012-11-14

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

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

View all issues with Tentatively NAD Editorial status.

Discussion:

30.4.1.3.1 [thread.timedmutex.class] says:

The class timed_mutex shall satisfy all of the TimedMutex requirements (30.4.1.3 [thread.timedmutex.requirements]). It shall be a standardlayout class (Clause 9 [class]).

Problem here is that 30.4.1.3 [thread.timedmutex.requirements] does not define a requirement set named "TimedMutex", it only refers to "timed mutex types"

[See also issue 2126]

[2012, Portland: move to Tentatively NAD Editorial]

We have timed mutex type, but it is labeled timed mutex requirements

We can make a suggestion, but will send to the editor as it seems purely editorial. There is a typo, and we don't have the timed mutex but 30.4.1.3 [thread.timedmutex.requirements] already says timed mutex type, and we need to reuse that term down in the class to fulfil the mutex requirement.

[To Editor:]

Replace this one with timed mutex type.

Proposed resolution:


2126. Several specification problems in regard to mutex requirements

Section: 30.4.1 [thread.mutex.requirements], 30.4.1.2.1 [thread.mutex.class], 30.4.1.2 [thread.mutex.requirements.mutex], 30.4.1.2.2 [thread.mutex.recursive], 30.4.1.3 [thread.timedmutex.requirements], 30.4.1.3.1 [thread.timedmutex.class], 30.4.1.3.2 [thread.timedmutex.recursive] Status: Tentatively NAD Editorial Submitter: Pete Becker Opened: 2012-01-16 Last modified: 2012-11-14

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

View all issues with Tentatively NAD Editorial status.

Discussion:

30.4.1.2.1 [thread.mutex.class]/3 says that the class mutex "shall satisfy all the Mutex requirements (30.4.1 [thread.mutex.requirements])". 30.4.1.2.1 [thread.mutex.class] is part of 30.4.1 [thread.mutex.requirements], so at the very least, this requirement is recursive. But worse, there is nothing that says what "the Mutex requirements" refers to. For example, the "Lockable requirements" section starts with "A type L meets the Lockable requirements if …". There is no such statement for "the Mutex requirements".

Organizationally, paragraphs 1-26 in 30.4.1.2 [thread.mutex.requirements.mutex] should probably be in a subclause with a name. (This is actually an ISO requirement, to avoid exactly this kind of ambiguous referencing) Then the first sentence of 30.4.1.2.1 [thread.mutex.class]/3 can become a note: "The class mutex meets the requirements of (whatever)", since that subclause already says that the mutex types "shall meet the requirements set out in this section."

And similarly for 30.4.1.2.2 [thread.mutex.recursive]/2 (recursive_mutex).

30.4.1.3 [thread.timedmutex.requirements], Timed mutex types, also needs the same rearrangement: its introductory requirements should be moved into a subclause, and the first sentences of 30.4.1.3.1 [thread.timedmutex.class]/2 and 30.4.1.3.2 [thread.timedmutex.recursive]/2 should be turned into notes that refer to this new subclause and to the new subclause in 30.4.1.2 [thread.mutex.requirements.mutex].

[See also issue 2125]

[2012, Portland: move to Tentatively NAD Editorial]

Seems no real ambiguity. May need some reorg of text rather then changing the wording.

Is there much that needs to be changed? But Pete's suggestion of putting requirement in separate sub section is good. Should be the direction to editor.

Suggest this is an editorial change. Happy with Pete's comments.

Proposed resolution:


2127. Move-construction with raw_storage_iterator

Section: 20.6.10 [storage.iterator] Status: Open Submitter: Jonathan Wakely Opened: 2012-01-23 Last modified: 2012-11-14

View all other issues in [storage.iterator].

View all issues with Open status.

Discussion:

Aliaksandr Valialkin pointed out that raw_storage_iterator only supports constructing a new object from lvalues so cannot be used to construct move-only types:

template <typename InputIterator, typename T>
void move_to_raw_buffer(InputIterator first, InputIterator last, T *raw_buffer)
{
  std::move(first, last, std::raw_storage_iterator<T *, T>(raw_buffer));
}

This could easily be solved by overloading operator= for rvalues.

Dave Abrahams:

raw_storage_iterator causes exception-safety problems when used with any generic algorithm. I suggest leaving it alone and not encouraging its use.

Proposed resolution:

This wording is relative to N3337.

  1. Add a new signature to the synopsis in 20.6.10 [storage.iterator] p1:

    namespace std {
      template <class OutputIterator, class T>
      class raw_storage_iterator
        : public iterator<output_iterator_tag,void,void,void,void> {
      public:
        explicit raw_storage_iterator(OutputIterator x);
    
        raw_storage_iterator<OutputIterator,T>& operator*();
        raw_storage_iterator<OutputIterator,T>& operator=(const T& element);
        raw_storage_iterator<OutputIterator,T>& operator=(T&& element);
        raw_storage_iterator<OutputIterator,T>& operator++();
        raw_storage_iterator<OutputIterator,T> operator++(int);
    };
    }
    
  2. Insert the new signature and a new paragraph before p4:

    raw_storage_iterator<OutputIterator,T>& operator=(const T& element);
    raw_storage_iterator<OutputIterator,T>& operator=(T&& element);
    

    -?- Requires: For the first signature T shall be CopyConstructible. For the second signature T shall be MoveConstructible.

    -4- Effects: Constructs a value from element at the location to which the iterator points.

    -5- Returns: A reference to the iterator.


2128. Absence of global functions cbegin/cend

Section: 24.3 [iterator.synopsis], 24.6.5 [iterator.range] Status: Open Submitter: Dmitry Polukhin Opened: 2012-01-23 Last modified: 2012-11-14

View all other issues in [iterator.synopsis].

View all issues with Open status.

Discussion:

All standard containers support cbegin/cend member functions but corresponding global functions are missing. Proposed resolution it to add global cbegin/cend functions by analogy with global begin/end functions. This addition will unify things for users.

[2012, Kona]

STL: Range-based for loops do not use global begin/end (anymore).

Alisdair: We will have to make sure these will be available through many headers.

STL: Do this, including r and cr. This won't add any additional work.

Matt: Users will find it strange if these are not all available.

Alisdair: Should we have these available everywhere begin/end are available?

Marshall: Yes. Not any extra work.

Howard: Adding all of these means we need all of <iterator>.

STL: We already need it all.

Matt: We have to be careful what we are requiring if we include the r versions.

Jeffrey: If we include r, should they adapt if the container does not define reverse iteration?

STL: No. No special behavior. Should fail to compile. Up to user to add the reverse code--it's easy.

Howard: Anyway it will SFINAE out.

Alisdair: Error messages due to SFINAE are harder to understand than simple failure to compile.

STL: Agrees that SFINAE makes error messages much worse.

Action: STL to provide additional wording for the r variants. Move to Review once that wording is availalbe.

Proposed resolution:

This wording is relative to N3337.

  1. In 24.3 [iterator.synopsis], header iterator synopsis, add the following declarations::

    namespace std {
      […]
      // 24.6.5, range access:
      template <class C> auto begin(C& c) -> decltype(c.begin());
      template <class C> auto begin(const C& c) -> decltype(c.begin());
      template <class C> auto end(C& c) -> decltype(c.end());
      template <class C> auto end(const C& c) -> decltype(c.end());
      template <class C> auto cbegin(const C& c) -> decltype(c.cbegin());
      template <class C> auto cend(const C& c) -> decltype(c.cend());
      template <class T, size_t N> T* begin(T (&array)[N]);
      template <class T, size_t N> T* end(T (&array)[N]);
      template <class T, size_t N> const T* cbegin(T (&array)[N]);
      template <class T, size_t N> const T* cend(T (&array)[N]);
    }
    
  2. In 24.6.5 [iterator.range] after p5 add the following series of paragraphs:

    template <class C> auto cbegin(const C& c) -> decltype(c.cbegin());
    

    -?- Returns: c.cbegin().

    template <class C> auto cend(const C& c) -> decltype(c.cend());
    

    -?- Returns: c.cend().

    template <class T, size_t N> const T* cbegin(T (&array)[N]);
    

    -?- Returns: array.

    template <class T, size_t N> const T* cend(T (&array)[N]);
    

    -?- Returns: array + N.


2129. User specializations of std::initializer_list

Section: 17.6.4.2.1 [namespace.std], 18.9 [support.initlist] Status: Open Submitter: Richard Smith Opened: 2012-01-18 Last modified: 2012-11-14

View other active issues in [namespace.std].

View all other issues in [namespace.std].

View all issues with Open status.

Discussion:

Since the implementation is intended to magically synthesize instances of std::initializer_list (rather than by a constructor call, for instance), user specializations of this type can't generally be made to work. I can't find any wording which makes such specializations ill-formed, though, which leads me to suspect that they're technically legal under the provisions of 17.6.4.2.1 [namespace.std] p1.

[2012, Kona]

This sounds correct, but we need wording for a resultion.

Marshall Clow volunteers to produce wording.

Proposed resolution:


2130. Missing ordering constraints

Section: 29.3 [atomics.order] Status: Review Submitter: Mark Batty Opened: 2012-02-22 Last modified: 2012-11-14

View all other issues in [atomics.order].

View all issues with Review status.

Discussion:

C11 issue 407

It seems that both C11 and C++11 are missing the following two derivatives of this rule:

For atomic modifications A and B of an atomic object M, if there is a memory_order_seq_cst fence X such that A is sequenced before X, and X precedes B in S, then B occurs later than A in the modification order of M.

For atomic modifications A and B of an atomic object M, if there is a memory_order_seq_cst fence Y such that Y is sequenced before B, and A precedes Y in S, then B occurs later than A in the modification order of M.

Above wording has been suggested for the Technical Corrigendum of C11 via issue 407, details can be found here.

[2012-03-19: Daniel proposes a slightly condensed form to reduce wording duplications]

[2012-03-20: Hans comments]

The usage of the term atomic operations in 29.3 [atomics.order] p7 is actually incorrect and should better be replaced by atomic modifications as used in the C11 407 wording.

There seems to be a similar wording incorrectness used in 1.10 [intro.multithread] p17 which should be corrected as well.

[2012, Portland: move to Review]

Olivier: does the fence really participate in the modifications?

Hans: S is the total set of all sequentially consistent operations, and sequentially consistent fences are in S.

Olivier: this sort of combination of a pair of half-open rules seems to imply the write must make it to main memory

But not all implementations treat a fence as a memory operation; cannot observe the half-open rule.

Hans: not sure this is actually prevented here. You could defer until the next load. What the wording doesn't quite show is that the third bullet in the new wording is already in the standard.

Hans: it is the interaction between fences on one side and other memory modifications on the other that is being defined here.

Pablo: S is not directly observable; it is a hypothetic ordering.

Moved to review

Hans: to alert C liaison

Proposed resolution:

This wording is relative to N3376.

  1. [Drafting note: The project editor is kindly asked to consider to replace in 1.10 [intro.multithread] p17 the phrase "before an operation B on M" by "before a modification B of M".]

  2. Change 29.3 [atomics.order] paragraph 7 as indicated: [Drafting note: Note that the wording change intentionally does also replace the term atomic operation by atomic modification]

    -7- For atomic operations A and B on an atomic object M, if there are memory_order_seq_cst fences X and Y such that A is sequenced before X, Y is sequenced before B, and X precedes Y in S, then B occurs later than A in the modification order of M. For atomic modifications A and B of an atomic object M, B occurs later than A in the modification order of M if:

    -8- [ Note: memory_order_seq_cst ensures sequential consistency only for a program that is free of data races and uses exclusively memory_order_seq_cst operations. Any use of weaker ordering will invalidate this guarantee unless extreme care is used. In particular, memory_order_seq_cst fences ensure a total order only for the fences themselves. Fences cannot, in general, be used to restore sequential consistency for atomic operations with weaker ordering specifications. — end note ]


2131. Member function getline taking a string as parameter

Section: 27.7.2.3 [istream.unformatted] Status: New Submitter: Loïc Joly Opened: 2012-03-05 Last modified: 2012-11-14

View other active issues in [istream.unformatted].

View all other issues in [istream.unformatted].

View all issues with New status.

Discussion:

I think the following code should be legal:

void f(std::istream& is)
{
  std::string s;
  is.getline(s); // Would be equivalent to std::getline(is, s)
}

Proposed resolution:

This wording is relative to N3376.

  1. Change the class template basic_istream synopsis, 27.7.2.1 [istream], as indicated

    namespace std {
      template <class charT, class traits = char_traits<charT> >
      class basic_istream : virtual public basic_ios<charT,traits> {
      public:
        […]
        // 27.7.2.3 Unformatted input:
        […]
        basic_istream<charT,traits>& getline(char_type* s, streamsize n);
        basic_istream<charT,traits>& getline(char_type* s, streamsize n,
          char_type delim);
        template<class Allocator>
        basic_istream<charT,traits>& getline(basic_string<charT,traits,Allocator>& str);
        template<class Allocator>
        basic_istream<charT,traits>& getline(basic_string<charT,traits,Allocator>& str,
          char_type delim);
        […]
      };
    }
    
  2. Insert the following two new prototype descriptions after 27.7.2.3 [istream.unformatted] paragraph 24:

    basic_istream<charT,traits>& getline(char_type* s, streamsize n);
    

    -24- Returns: getline(s,n,widen('\n'))

    template<class Allocator>
    basic_istream<charT,traits>& getline(basic_string<charT,traits,Allocator>& str);
    

    -??- Returns: std::getline(*this, str)

    template<class Allocator>
    basic_istream<charT,traits>& getline(basic_string<charT,traits,Allocator>& str, char_type delim);
    

    -??- Returns: std::getline(*this, str, delim)


2132. std::function ambiguity

Section: 20.8.11.2.1 [func.wrap.func.con] Status: Review Submitter: Ville Voutilainen Opened: 2012-02-28 Last modified: 2012-12-25

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

View all issues with Review status.

Discussion:

Consider the following:

#include <functional>

void f(std::function<void()>) {}
void f(std::function<void(int)>) {}

int main() {
  f([]{});
  f([](int){});
}

The calls to f in main are ambiguous. Apparently because the conversion sequences to std::function from the lambdas are identical. The standard specifies that the function object given to std::function "shall be Callable (20.8.11.2) for argument types ArgTypes and return type R." It doesn't say that if this is not the case, the constructor isn't part of the overload set.

Daniel: During the preparation of N3123 it turned out that there are no longer reasons to refer to INVOKE as a conceptually entity alone, its real implementation as a function template invoke is possible but was deferred for a later point in time. Defining a type trait for the Callable requirement would also be possible, so there seem to be no technical reasons why the template constructor of std::function should not be constrained. The below suggested wording does this without introducing a special trait for this. This corresponds to the way that has been used to specify the result_of trait. Note that the definition of the Callable requirement is perfectly suitable for this, because it is a pure syntactically based requirement and can be directly transformed into a constrained template.

The suggested resolution also applies such wording to the "perfectly forwarding" assignment operator

template<class F> function& operator=(F&&);

The positive side-effect of this is that it automatically implements a solution to a problem similar to that mentioned in issue 1234.

It would be possible to apply similar constraints to the member signatures

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

template<class F, class A> void assign(F&&, const A&);

as well. At this point there does not seem to be a pestering reason to do so.

[2012-10 Portland: Move to Review]

STL: This is a real issue, but does not like a resolution relying on a SFINAEable metafunction that is not specified and available to the users.

packaged_task has the same issue.

STL strongly wants to see an is_callable type trait to clarify the proposed wording.

Jeremiah concerned about holding up what appears to be a correct resolution for a hypothetical better one later - the issue is real.

Why must f by CopyConstructible? Surely MoveConstructible would be sufficient?

Answer: because function is CopyConstructible, and the bound functor is type-erased so must support all the properties of function itself.

Replace various applications of declval in the proposed resolution with simply using the passed functor object, f.

Alisdair to apply similar changes to packaged_task.

[2012-11-09, Vicente J. Botet Escriba provides another example]

Consider the following:

class AThreadWrapper {
public:
  explicit operator std::thread();
  ...
};
std::thread th = std::thread(AThreadWrapper); // call to conversion operator intended

The call to the conversion operator is overloaded with the thread constructor. But thread constructor requirement makes it fail as AThreadWrapper is not a Callable and the compiler tries to instantiate the thread constructor and fails.

Proposed resolution:

This wording is relative to N3376.

  1. Change the following paragraphs in 20.8.11.2.1 [func.wrap.func.con]: [Editorial comment: The removal of the seemingly additional no-throw requirements of copy constructor and destructor of A is recommended, because they are already part of the Allocator requirements. Similar clean-up has been suggested by 2070end comment]

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

    -7- Requires: F shall be CopyConstructible. f shall be Callable (20.8.11.2 [func.wrap.func]) for argument types ArgTypes and return type R. The copy constructor and destructor of A shall not throw exceptions.

    -?- Remarks: These constructors shall not participate in overload resolution unless f is Callable (20.8.11.2 [func.wrap.func]) for argument types ArgTypes... and return type R.

    […]

    template<class F> function& operator=(F&& f);
    

    -18- Effects: function(std::forward<F>(f)).swap(*this);

    -19- Returns: *this

    -?- Remarks: This assignment operator shall not participate in overload resolution unless declval<typename decay<F>::type&>() is Callable (20.8.11.2 [func.wrap.func]) for argument types ArgTypes... and return type R.


2133. Attitude to overloaded comma for iterators

Section: 17.6.5.4 [global.functions] Status: Open Submitter: Yakov Galka Opened: 2012-01-25 Last modified: 2013-03-18

View all other issues in [global.functions].

View all issues with Open status.

Discussion:

17.6.5.4 [global.functions] says

Unless otherwise specified, global and non-member functions in the standard library shall not use functions from another namespace which are found through argument-dependent name lookup (3.4.2).

This sounds clear enough. There are just two problems:

  1. Both implementations I tested (VS2005 and GCC 3.4.3) do unqualified calls to the comma operator in some parts of the library with operands of user-defined types.

  2. The standard itself does this in the description of some algorithms. E.g. uninitialized_copy is defined as:

    Effects:

    for (; first != last; ++result, ++first)
      ::new (static_cast<void*>(&*result))
        typename iterator_traits<ForwardIterator>::value_type(*first);
    

If understood literally, it is required to call operator,(ForwardIterator, InputIterator).

For detailed discussion with code samples see here.

Proposal:

  1. Add an exception to the rule in 17.6.5.4 [global.functions] by permitting the implementation to call the comma operator as much as it wants to. I doubt we want this. or
  2. Fix the description of the said algorithms and perhaps add a note to 17.6.5.4 [global.functions] that brings attention of the implementers to avoid this pitfall.

[2013-03-15 Issues Teleconference]

Moved to Open.

There are real questions here, that may require a paper to explore and answer properly.

Proposed resolution:


2134. Redundant Mutex requirement?

Section: 30.4.1.2 [thread.mutex.requirements.mutex] Status: Tentatively NAD Editorial Submitter: Pete Becker Opened: 2012-03-05 Last modified: 2012-11-14

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

View all issues with Tentatively NAD Editorial status.

Discussion:

30.4.1.2 [thread.mutex.requirements.mutex]/11 says that prior unlock operations synchronize with m.lock().

30.4.1.2 [thread.mutex.requirements.mutex]/19 says that if m.try_lock() succeeds, prior unlock operations synchronize with the operation.

30.4.1.2 [thread.mutex.requirements.mutex]/25 says that m.unlock() synchronizes with subsequent successful lock operations.

Does the third requirement add anything to the first two? If not, it should probably be a non-normative note.

[2012, Portland: move to Tentatively NAD Editorial]

Agree that third note should be non-normative and adds nothing.

Seems An Editorial change, but does changing a normative to non-normative wording makes it a non-editorial change?

Ask the editor. If not editorial, then we will agree on the fix as removal of the third point, then we will put it in ready state for Bristol.

Proposed resolution:


2135. Unclear requirement for exceptions thrown in condition_variable::wait()

Section: 30.5.1 [thread.condition.condvar], 30.5.2 [thread.condition.condvarany] Status: Open Submitter: Pete Becker Opened: 2012-03-06 Last modified: 2012-11-14

View other active issues in [thread.condition.condvar].

View all other issues in [thread.condition.condvar].

View all issues with Open status.

Discussion:

condition_varible::wait() (and, presumably, condition_variable_any::wait(), although I haven't looked at it) says that it calls lock.unlock(), and if condition_variable::wait() exits by an exception it calls lock.lock() on the way out. But if the initial call to lock.unlock() threw an exception, does it make sense to call lock.lock()? We simply don't know the state of that lock object, and it's probably better not to touch it.

That aside, once the wait() call has been unblocked, it calls lock.lock(). If lock.lock() throws an exception, what happens? The requirement is:

If the function exits via an exception, lock.lock() shall be called prior to exiting the function scope.

That can be read in two different ways. One way is as if it said "lock.lock() shall have been called …", i.e. the original, failed, call to lock.lock() is all that's required. But a more natural reading is that wait has to call lock.lock() again, even though it already failed.

I think this wording suffers from being too general. There are two possible exception sources: the initial call to lock.unlock() and the final call to lock.lock(). Each one should have its own requirement. Lumping them together muddles things.

[2012, Portland: move to Open]

Pablo: unlock failing is easy -- the call leaves it locked. The second case, trying to lock fails -- what can you do? This is an odd state as we had it locked before was called wait. Maybe we should call terminate as we cannot meet the post-conditions. We could throw a different exception.

Hans: calling terminate makes sense as we're likely to call it soon anyway and at least we have some context.

Detlef: what kind of locks might be being used?

Pablo: condition variables are 'our' locks so this is less of a problem. condition_variable_any might be more problematic.

The general direction is to call terminate if the lock cannot be reacquired.

Pablo: Can we change the wording to 'leaves the mutex locked' ?

Hans: so if the unlock throws we simply propagate the exception.

Move the issue to open and add some formal wording at a later time.

Proposed resolution:


2136. Postconditions vs. exceptions

Section: 17.5.1 [structure] Status: Open Submitter: Jens Maurer Opened: 2012-03-08 Last modified: 2012-11-14

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 17.6.4.11 [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.

Proposed resolution:


2137. Misleadingly constrained post-condition in the presence of exceptions

Section: 28.8.3 [re.regex.assign] Status: Open Submitter: Jonathan Wakely Opened: 2012-03-08 Last modified: 2012-11-14

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

View all issues with Open status.

Discussion:

The post-conditions of basic_regex<>::assign 28.8.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 paragaraphs, and then reviews clauses 18-30 to apply that guarantee consistently. We do not want to pick up these issues piecemeal, as we risk openning many issues in an ongoing process.

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.


2138. atomic_flag::clear should not accept memory_order_consume

Section: 29.7 [atomics.flag] Status: Review Submitter: Ben Viglietta Opened: 2012-03-08 Last modified: 2012-11-14

View other active issues in [atomics.flag].

View all other issues in [atomics.flag].

View all issues with Review status.

Discussion:

N3376 29.7 [atomics.flag]/7 says this about atomic_flag::clear:

Requires: The order argument shall not be memory_order_acquire or memory_order_acq_rel.

In addition, memory_order_consume should be disallowed, since it doesn't meaningfully apply to store operations. It's already disallowed on the analogous atomic<T>::store. The proposed updated text would be:

Requires: The order argument shall not be memory_order_consume, memory_order_acquire, or memory_order_acq_rel.

[2012, Portland: move to Review]

Hans: this is a clear oversight.

Moved to review

Proposed resolution:

[This wording is relative to N3376.]

void atomic_flag_clear(volatile atomic_flag *object) noexcept;
void atomic_flag_clear(atomic_flag *object) noexcept;
void atomic_flag_clear_explicit(volatile atomic_flag *object, memory_order order) noexcept;
void atomic_flag_clear_explicit(atomic_flag *object, memory_order order) noexcept;
void atomic_flag::clear(memory_order order = memory_order_seq_cst) volatile noexcept;
void atomic_flag::clear(memory_order order = memory_order_seq_cst) noexcept;

-7- Requires: The order argument shall not be memory_order_consume, memory_order_acquire, nor memory_order_acq_rel.

-8- Effects: Atomically sets the value pointed to by object or by this to false. Memory is affected according to the value of order.


2139. What is a user-defined type?

Section: 17.6.4.2.1 [namespace.std], 19.5 [syserr], 20.6.7.1 [allocator.uses.trait], 20.8.9.1.1 [func.bind.isbind], X [func.bind.isplace], 20.8.12 [unord.hash], 20.9.7.6 [meta.trans.other], 22.3.1 [locale], 22.4.1.4 [locale.codecvt], 28.12.1.4 [re.regiter.incr] Status: Deferred Submitter: Loïc Joly Opened: 2012-03-08 Last modified: 2012-11-14

View other active issues in [namespace.std].

View all other issues in [namespace.std].

View all issues with Deferred status.

Discussion:

The expression "user-defined type" is used in several places in the standard, but I'm not sure what it means. More specifically, is a type defined in the standard library a user-defined type?

From my understanding of English, it is not. From most of the uses of this term in the standard, it seem to be considered as user defined. In some places, I'm hesitant, e.g. 17.6.4.2.1 [namespace.std] p1:

A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.

Does it mean we are allowed to add in the namespace std a specialization for std::vector<std::pair<T, U>>, for instance?

Additional remarks from the reflector discussion: The traditional meaning of user-defined types refers to class types and enum types, but the library actually means here user-defined types that are not (purely) library-provided. Presumably a new term - like user-provided type - should be introduced and properly defined.

[ 2012-10 Portland: Move to Deferred ]

The issue is real, in that we never define this term and rely on a "know it when I see it" intuition. However, there is a fear that any attempt to pin down a definition is more likely to introduce bugs than solve them - getting the wording for this precisely correct is likely far more work than we are able to give it.

There is unease at simple closing as NAD, but not real enthusiasm to provide wording either. Move to Deferred as we are not opposed to some motivated individual coming back with full wording to review, but do not want to go out of our way to encourage someone to work on this in preference to other issues.

Proposed resolution:


2140. Meaning of notify_all_at_thread_exit synchronization requirement?

Section: 30.5 [thread.condition] Status: Review Submitter: Pete Becker Opened: 2012-03-06 Last modified: 2012-11-14

View other active issues in [thread.condition].

View all other issues in [thread.condition].

View all issues with Review status.

Discussion:

notify_all_at_thread_exit has the following synchronization requirement:

Synchronization: The call to notify_all_at_thread_exit and the completion of the destructors for all the current thread's variables of thread storage duration synchronize with (1.10 [intro.multithread]) calls to functions waiting on cond.

The functions waiting on cond have already been called, otherwise they wouldn't be waiting. So how can a subsequent call to notify_all_at_thread_exit synchronize with them?

Also, "synchronizes with" is a relationship between library calls (1.10 [intro.multithread]/8), so it's not meaningful for completion of destructors for non-library objects. Presumably the intention wasn't so make library destructors special here.

[2012-03-09 Jeffrey Yasskin comments:]

I think the text should say that "notify_all_at_thread_exit and destructor calls are sequenced before the lk.unlock()", and leave it at that, unless there's a funny implementation I haven't thought of.

[2012-03-19 Hans Boehm comments:]

I think the synchronization clause should just be replaced with (modulo wording tweaks):

"The implied lk.unlock() call is sequenced after the destruction of all objects with thread storage duration associated with the current thread."

as Jeffrey suggested.

To use this correctly, the notifying thread has to essentially acquire the lock, set a variable indicating it's done, call notify_all_at_thread_exit(), while the waiting thread acquires the lock, and repeatedly waits on the cv until the variable is set, and then releases the lock. That ensures that we have the proper synchronizes with relationship as a result of the lock.

[2012, Portland: move to Review]

The lk.unlock() refers back to the wording the previous paragraph.

Moved to review

Proposed resolution:

This wording is relative to N3376.

  1. Modify 30.5 [thread.condition] p8 as indicated:

    void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
    

    […]

    -8- Synchronization: The call to notify_all_at_thread_exit and the completion of the destructors for all the current thread's variables of thread storage duration synchronize with (1.10 [intro.multithread]) calls to functions waiting on cond The implied lk.unlock() call is sequenced after the destruction of all objects with thread storage duration associated with the current thread.


2141. common_type trait produces reference types

Section: 20.9.7.6 [meta.trans.other] Status: Review Submitter: Doug Gregor Opened: 2012-03-11 Last modified: 2013-03-18

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

View all issues with Review status.

Discussion:

The type computation of the common_type type trait is defined as

template <class T, class U>
 struct common_type<T, U> {
   typedef decltype(true ? declval<T>() : declval<U>()) type;
 };

This means that common_type<int, int>::type is int&&, because

Users of common_type do not expect to get a reference type as the result; the expectation is that common_type will return a non-reference type to which all of the types can be converted.

Daniel: In addition to that it should be noted that without such a fix the definition of std::unique_ptr's operator< in 20.7.1.4 [unique.ptr.special] (around p4) is also broken: In the most typical case (with default deleter), the determination of the common pointer type CT will instantiate std::less<CT> which can now be std::less<T*&&>, which will not be the specialization of pointer types that guarantess a total order.

Given the historic constext of common_type original specification, the proper resolution to me seems to be using std::decay instead of std::remove_reference:

template <class T, class U>
struct common_type<T, U> {
  typedef typename decay<decltype(true ? declval<T>() : declval<U>())>::type type;
};

At that time rvalues had no identity in this construct and rvalues of non-class types have no cv-qualification. With this change we would ensure that

common_type<int, int>::type == common_type<const int, const int>::type == int

Note that this harmonizes with the corresponding heterogenous case, which has already the exact same effect:

common_type<int, long>::type == common_type<const int, const long>::type == long

[2012-10-11 Daniel comments]

While testing the effects of applying the proposed resolution I noticed that this will have the effect that the unary form of common_type, like

common_type<int>

is not symmetric to the n-ary form (n > 1). This is unfortunate, because this difference comes especially to effect when common_type is used with variadic templates. As an example consider the following make_array template:

#include <array>
#include <type_traits>
#include <utility>

template<class... Args>
std::array<typename std::common_type<Args...>::type, sizeof...(Args)>
make_array(Args&&... args)
{
  typedef typename std::common_type<Args...>::type CT;
  return std::array<CT, sizeof...(Args)>{static_cast<CT>(std::forward<Args>(args))...};
}

int main()
{
  auto a1 = make_array(0); // OK: std::array<int, 1>
  auto a2 = make_array(0, 1.2); // OK: std::array<double, 2>
  auto a3 = make_array(5, true, 3.1415f, 'c'); // OK: std::array<float, 4>

  int i = 0;
  auto a1b = make_array(i); // Error, attempt to form std::array<int&, 1>

  auto a2b = make_array(i, 1.2); // OK: std::array<double, 2>
  auto a2c = make_array(i, 0); // OK: std::array<int, 2>
}

The error for a1b only happens in the unary case and it is easy that it remains unnoticed during tests. You cannot explain that reasonably to the user here.

Of-course it is possible to fix that in this example by applying std::decay to the result of the std::common_type deduction. But if this is necessary here, I wonder why it should also be applied to the binary case, where it gives the wrong illusion of a complete type decay? The other way around: Why is std::decay not also applied to the unary case as well?

This problem is not completely new and was already observed for the original std::common_type specification. At this time the decltype rules had a similar asymmetric effect when comparing

std::common_type<const int, const int>::type (equal to 'int' at this time)

with:

std::common_type<const int>::type (equal to 'const int')

and I wondered whether the unary form shouldn't also perform the same "decay" as the n-ary form.

This problem makes me think that the current resolution proposal might not be ideal and I expect differences in implementations (for those who consider to apply this proposed resolution already). I see at least three reasonable options:

  1. Accept the current wording suggestion for LWG 2141 as it is and explain that to users.

  2. Keep std::common_type as currently specified in the Standard and tell users to use std::decay where needed. Also fix other places in the library, e.g. the comparison functions of std::unique_ptr or a most of the time library functions.

  3. Apply std::decay also in the unary specialization of std::common_type with the effect that std::common_type<const int&>::type returns int.

[2012-10-11 Marc Glisse comments]

If we are going with decay everywhere, I wonder whether we should also decay in the 2-argument version before and not only after. So if I specialize common_type<mytype, double>, common_type<const mytype, volatile double&> would automatically work.

[2012-10-11 Daniel provides wording for bullet 3 of his list:]

  1. Change 20.9.7.6 [meta.trans.other] p3 as indicated:

    template <class T>
    struct common_type<T> {
      typedef typename decay<T>::type type;
    };
    
    template <class T, class U>
    struct common_type<T, U> {
      typedef typename decay<decltype(true ? declval<T>() : declval<U>())>::type type;
    };
    

[2013-03-15 Issues Teleconference]

Moved to Review.

Want to carefully consider the effect of decay vs. remove_reference with respect to constenss before adopting, although this proposed resolution stands for review in Bristol.

Proposed resolution:

This wording is relative to N3376.

  1. In 20.9.7.6 [meta.trans.other] p3, change the common_type definition to

    template <class T, class U>
    struct common_type<T, U> {
      typedef typename decay<decltype(true ? declval<T>() : declval<U>())>::type type;
    };
    

2142. packaged_task::operator() synchronization too broad?

Section: 30.6.9.1 [futures.task.members] Status: Open Submitter: Pete Becker Opened: 2012-03-12 Last modified: 2012-11-14

View other active issues in [futures.task.members].

View all other issues in [futures.task.members].

View all issues with Open status.

Discussion:

According to 30.6.9.1 [futures.task.members] p.18:

[A] successful call to [packaged_task::]operator() synchronizes with a call to any member function of a future or shared_future object that shares the shared state of *this.

This requires that the call to operator() synchronizes with calls to future::wait_for, future::wait_until, shared_future::wait_for, and shared_future::wait_until, even when these functions return because of a timeout.

[2012, Portland: move to Open]

If it said "a successful return from" (or "a return from" to cover exceptions) the problem would be more obvious.

Detlef: will ask Anthony Williams to draft some wording.

Moved to open (Anthony drafted to draft)

Proposed resolution:


2143. ios_base::xalloc should be thread-safe

Section: 27.5.3 [ios.base] Status: New Submitter: Alberto Ganesh Barbati Opened: 2012-03-14 Last modified: 2012-11-14

View all other issues in [ios.base].

View all issues with New status.

Discussion:

The static function ios_base::xalloc() could be called from multiple threads and is not covered by 17.6.4.10 [res.on.objects] and 17.6.5.9 [res.on.data.races]. Adding a thread-safety requirement should not impose a significant burden on implementations, as the function can be easily implemented with hopefully lock-free atomics.

Proposed resolution:

This wording is relative to N3376.

  1. In 27.5.3.5 [ios.base.storage] add a new paragraph after paragraph 1:

    static int xalloc();
    

    -1- Returns: index ++.

    -?- Remarks: Concurrent access to this function by multiple threads shall not result in a data race (1.10 [intro.multithread]).


2144. Missing noexcept specification in type_index

Section: 20.13 [type.index] Status: Tentatively Ready Submitter: Daniel Krügler Opened: 2012-03-18 Last modified: 2013-03-18

View all other issues in [type.index].

View all issues with Tentatively Ready status.

Discussion:

The class type type_index is a thin wrapper of type_info to adapt it as a valid associative container element. Similar to type_info, all member functions have an effective noexcept(true) specification, with the exception of hash_code() and name(). The actual effects of these functions is a direct call to type_info's hash_code() and name function, but according to 18.7 [support.rtti] these are both noexcept functions, so there is no reason for not declaring them as noexcept, too. In fact, one of the suggested changes of the original proposing paper N2530 specifically was to ensure that type_info would get a hash_code() function that guarantees not to throw exceptions (during that time the hash requirements did not allow to exit with an exception). From this we can conclude that type_index::hash_code() was intended to be nothrow.

It seems both consistent and technically simply to require these functions to be noexcept.

[2013-03-15 Issues Teleconference]

Moved to Tentatively Ready.

Proposed resolution:

This wording is relative to N3376.

  1. Modify the class type_index synopsis, 20.13.2 [type.index.overview] as indicated:

    namespace std {
      class type_index {
      public:
        type_index(const type_info& rhs) noexcept;
        bool operator==(const type_index& rhs) const noexcept;
        bool operator!=(const type_index& rhs) const noexcept;
        bool operator< (const type_index& rhs) const noexcept;
        bool operator<= (const type_index& rhs) const noexcept;
        bool operator> (const type_index& rhs) const noexcept;
        bool operator>= (const type_index& rhs) const noexcept;
        size_t hash_code() const noexcept;
        const char* name() const noexcept;
      private:
        const type_info* target; // exposition only
        // Note that the use of a pointer here, rather than a reference,
        // means that the default copy/move constructor and assignment
        // operators will be provided and work as expected.
      };
    }
    
  1. Modify the prototype definitions in 20.13.3 [type.index.members] as indicated:

    size_t hash_code() const noexcept;
    

    -8- Returns: target->hash_code()

    const char* name() const noexcept;
    

    -9- Returns: target->name()


2145. error_category default constructor

Section: 19.5.1 [syserr.errcat] Status: Ready Submitter: Howard Hinnant Opened: 2012-03-21 Last modified: 2012-11-14

View all other issues in [syserr.errcat].

View all issues with Ready status.

Discussion:

Should error_category have a default constructor?

If you look at the synopsis in 19.5.1.1 [syserr.errcat.overview], it appears the answer is no. There is no default constructor declared and there is another constructor declared (which should inhibit a default constructor).

However in paragraph 1 of the same section, descriptive text says:

Classes may be derived from error_category to support categories of errors in addition to those defined in this International Standard.

How shall classes derived from error_category construct their base?

Jonathan Wakely: In N2066 error_category was default-constructible. That is still the case in N2241, because no other constructor is declared. Then later N2422 (issue 6) declares the copy constructor as deleted, but doesn't add a default constructor, causing it to be no longer default-constructible. That looks like an oversight to me, and I think there should be a public default constructor.

Daniel: A default-constructor indeed should be provided to allow user-derived classes as described by the standard. I suggest this one to be both noexcept and constexpr. The latter allows user-derived non-abstract classes to take advantage of the special constant initialization rule of 3.6.2 [basic.start.init] p2 b2 for objects with static (or thread) storage duration in namespace scope. Note that a constexpr constructor is feasible here, even though there exists a non-trivial destructor and even though error_category is not a literal type (see std::mutex for a similar design choice).

In addition to that the proposed resolution fixes another minor glitch: According to 17.5.2.2 [functions.within.classes] virtual destructors require a semantics description.

Alberto Ganesh Barbati: I would suggest to remove =default from the constructor instead. Please consider that defaulting a constructor or destructor may actually define them as deleted under certain conditions (see 12.1 [class.ctor]/5 and 12.4 [class.dtor]/5). Removing =default is easier than providing wording to ensures that such conditions do not occur.

[2012-10 Portland: move to Ready]

The issue is real and the resolution looks good.

Are there similar issues elsewhere in this clause?

Potential to add constexpr to more constructors, but clearly a separable issue.

Proposed resolution:

This wording is relative to N3376.

  1. Modify the class error_category synopsis, 19.5.1.1 [syserr.errcat.overview] as indicated: [Drafting note: According to the general noexcept library guidelines destructors should not have any explicit exception specification. This destructor was overlooked during the paper analysis — end note]

    namespace std {
      class error_category {
      public:
        constexpr error_category() noexcept;
        virtual ~error_category() noexcept;
        error_category(const error_category&) = delete;
        error_category& operator=(const error_category&) = delete;
        virtual const char* name() const noexcept = 0;
        virtual error_condition default_error_condition(int ev) const noexcept;
        virtual bool equivalent(int code, const error_condition& condition) const noexcept;
        virtual bool equivalent(const error_code& code, int condition) const noexcept;
        virtual string message(int ev) const = 0;
        bool operator==(const error_category& rhs) const noexcept;
        bool operator!=(const error_category& rhs) const noexcept;
        bool operator<(const error_category& rhs) const noexcept;
      };
    }
    
  2. Before 19.5.1.2 [syserr.errcat.virtuals] p1 insert a new prototype description as indicated:

    virtual ~error_category();
    

    -?- Effects: Destroys an object of class error_category.

  3. Before 19.5.1.3 [syserr.errcat.nonvirtuals] p1 insert a new prototype description as indicated:

    constexpr error_category() noexcept;
    

    -?- Effects: Constructs an object of class error_category.


2146. Are reference types Copy/Move-Constructible/Assignable or Destructible?

Section: 17.6.3.1 [utility.arg.requirements] Status: Open Submitter: Nikolay Ivchenkov Opened: 2012-03-23 Last modified: 2013-03-18

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

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

View all issues with Open status.

Discussion:

According to 17.6.3.1 [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.

Proposed resolution:


2147. Unclear hint type in Allocator's allocate function

Section: 17.6.3.5 [allocator.requirements] Status: Ready Submitter: Daniel Krügler Opened: 2012-03-05 Last modified: 2012-11-14

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with Ready status.

Discussion:

According to Table 28 — "Allocator requirements", the expression

a.allocate(n, u)

expects as second argument a value u that is described in Table 27 as:

a value of type YY::const_pointer obtained by calling YY::allocate, or else nullptr.

This description leaves it open, whether or whether not a value of type YY::const_void_pointer is valid or not. The corresponding wording in C++03 is nearly the same, but in C++03 there did not exist the concept of a general void_pointer for allocators. There is some evidence for support of void pointers because the general allocator_traits template declares

static pointer allocate(Alloc& a, size_type n, const_void_pointer hint);

and the corresponding function for std::allocator<T> is declared as:

pointer allocate(size_type, allocator<void>::const_pointer hint = 0);

As an additional minor wording glitch (especially when comparing with the NullablePointer requirements imposed on const_pointer and const_void_pointer), the wording seems to exclude lvalues of type std::nullptr_t, which looks like an unwanted artifact to me.

[ 2012-10 Portland: Move to Ready ]

No strong feeling that this is a big issue, but consensus that the proposed resolution is strictly better than the current wording, so move to Ready.

Proposed resolution:

This wording is relative to N3376.

  1. Change Table 27 — "Descriptive variable definitions" in 17.6.3.5 [allocator.requirements]:

    Table 27 — Descriptive variable definitions
    Variable Definition
    u a value of type YY::const_pointer obtained by calling YY::allocate, or else nullptrXX::const_void_pointer obtained by conversion from a result value of YY::allocate, or else a value of type (possibly const) std::nullptr_t.

2148. Hashing enums should be supported directly by std::hash

Section: 20.8.12 [unord.hash] Status: Open Submitter: Ville Voutilainen Opened: 2012-04-10 Last modified: 2012-11-14

View other active issues in [unord.hash].

View all other issues in [unord.hash].

View all issues with Open status.

Discussion:

The paper proposes various hashing improvements. What it doesn't mention is hashing of enums; enums are integral types, and users expect them to have built-in hashing support, rather than having to convert enums to ints for uses with unordered containers and other uses of hashes. Daniel Krügler explains in c++std-lib-32412 that this is not achievable with a SFINAEd hash specialization because it would require a partial specialization with a type parameter and a non-type parameter with a default argument, which is currently not allowed, and hence the fixes in N3333 should be adopted instead.

[2012-10 Portland: Move to Open]

We agree this is a real issue that should be resolved, by specifying such a hash.

It is not clear that we should specify this as calling hash on the underlying_type, or whether that is overspecification and we merely require that the hash be supplied.

STL already has shipped an implementation, and is keen to provide wording.

Proposed resolution:


2149. Concerns about 20.8/5

Section: 20.8 [function.objects] Status: Open Submitter: Scott Meyers Opened: 2012-02-15 Last modified: 2012-11-14

View all other issues in [function.objects].

View all issues with Open status.

Discussion:

20.8 [function.objects] p5 says:

To enable adaptors and other components to manipulate function objects that take one or two arguments it is required that the function objects correspondingly provide typedefs argument_type and result_type for function objects that take one argument and first_argument_type, second_argument_type, and result_type for function objects that take two arguments.

I have two concerns about this paragraph. First, the wording appears to prescribe a requirement for all function objects in valid C++ programs, but it seems unlikely that that is the intent. As such, the scope of the requirement is unclear. For example, there is no mention of these typedefs in the specification for closures (5.1.2), and Daniel Krügler has explained in the thread at http://tinyurl.com/856plkn that conforming implementations can detect the difference between closures with and without these typedefs. (Neither gcc 4.6 nor VC10 appear to define typedefs such as result_type for closure types. I have not tested other compilers.)

Second, the requirement appears to be unimplementable in some cases, notably for function objects returned from std::bind, as Howard Hinnant explains in the thread at http://tinyurl.com/6q5bos4.

From what I can tell, the standard already defines which adaptability typedefs must be provided by various kinds of function objects in the specifications for those objects. Examples include the function objects specified in 20.8.3 [refwrap]-20.8.8 [negators]. I therefore suggest that 20.8 [function.objects]/5 simply be removed from the standard. I don't think it adds anything except opportunities for confusion.

[2012-10 Portland: Move to Open]

This wording caused confusion earlier in the week when reviewing Stefan's paper on greater<>.

This phrasing sounds normative, but is actually descriptive but uses unfortunate wording.

The main reason this wording exists is to document the protocol required to support the legacy binders in Annex D.

Stefan points out that unary_negate and binary_negate have not been deprecated and rely on this. He plans a paper to remove this dependency.

Consensus that this wording is inadequate, confusing, and probably should be removed. However, that leaves a big hole in the specification for the legacy binders, that needs filling.

While not opposed to striking this paragraph, we will need the additional wording to fix the openning hole before this issue can move forward.

Proposed resolution:

This wording is relative to N3376.

Remove 20.8 [function.objects] p5:

To enable adaptors and other components to manipulate function objects that take one or two arguments it is required that the function objects correspondingly provide typedefs argument_type and result_type for function objects that take one argument and first_argument_type, second_argument_type, and result_type for function objects that take two arguments.


2150. Unclear specification of find_end

Section: 25.2.6 [alg.find.end] Status: New Submitter: Andrew Koenig Opened: 2012-03-28 Last modified: 2012-11-14

View all issues with New status.

Discussion:

25.2.6 [alg.find.end] describes the behavior of find_end as returning:

The last iterator i in the range [first1,last1 - (last2 - first2)) such that for any nonnegative integer n < (last2 - first2), the following corresponding conditions hold: *(i + n) == *(first2 + n), pred(*(i + n), *(first2 + n)) != false.

Does "for any" here mean "for every" or "there exists a"? I think it means the former, but it could be interpreted either way.

Daniel: The same problem exists for the following specifications from Clause 25 [algorithms]:

  1. 25.2.13 [alg.search] p2 and p6
  2. 25.3.10 [alg.reverse] p4
  3. 25.3.13 [alg.partitions] p5 and p9
  4. 25.4 [alg.sorting] p5
  5. 25.4.2 [alg.nth.element] p1
  6. 25.4.3.1 [lower.bound] p2
  7. 25.4.3.2 [upper.bound] p2
  8. 25.4.7 [alg.min.max] p21 and p23

Proposed resolution:

This wording is relative to N3376.

  1. Change 25.2.6 [alg.find.end] p2 as indicated:

    template<class ForwardIterator1, class ForwardIterator2>
    ForwardIterator1 
    find_end(ForwardIterator1 first1, ForwardIterator1 last1,
             ForwardIterator2 first2, ForwardIterator2 last2);
    template<class ForwardIterator1, class ForwardIterator2,
             class BinaryPredicate>
    ForwardIterator1
    find_end(ForwardIterator1 first1, ForwardIterator1 last1,
             ForwardIterator2 first2, ForwardIterator2 last2,
             BinaryPredicate pred);
    

    […]

    -2- Returns: The last iterator i in the range [first1,last1 - (last2 - first2)) such that for anyevery nonnegative integer n < (last2 - first2), the following corresponding conditions hold: *(i + n) == *(first2 + n), pred(*(i + n), *(first2 + n)) != false. Returns last1 if [first2,last2) is empty or if no such iterator is found.

  2. Change 25.2.13 [alg.search] p2 and p6 as indicated:

    template<class ForwardIterator1, class ForwardIterator2>
    ForwardIterator1
    search(ForwardIterator1 first1, ForwardIterator1 last1,
           ForwardIterator2 first2, ForwardIterator2 last2);
    template<class ForwardIterator1, class ForwardIterator2,
             class BinaryPredicate>
    ForwardIterator1
    search(ForwardIterator1 first1, ForwardIterator1 last1,
           ForwardIterator2 first2, ForwardIterator2 last2,
           BinaryPredicate pred);
    

    […]

    -2- Returns: The first iterator i in the range [first1,last1 - (last2-first2)) such that for anyevery nonnegative integer n less than last2 - first2 the following corresponding conditions hold: *(i + n) == *(first2 + n), pred(*(i + n), *(first2 + n)) != false. Returns first1 if [first2,last2) is empty, otherwise returns last1 if no such iterator is found.

    […]

    template<class ForwardIterator, class Size, class T>
    ForwardIterator
    search_n(ForwardIterator first, ForwardIterator last, Size count,
             const T& value);
    template<class ForwardIterator, class Size, class T,
             class BinaryPredicate>
    ForwardIterator
    search_n(ForwardIterator first, ForwardIterator last, Size count,
             const T& value, BinaryPredicate pred);
    

    […]

    -6- Returns: The first iterator i in the range [first,last-count) such that for anyevery non-negative integer n less than count the following corresponding conditions hold: *(i + n) == value, pred(*(i + n),value) != false. Returns last if no such iterator is found.

  3. Change 25.3.10 [alg.reverse] p4 as indicated:

    template<class BidirectionalIterator, class OutputIterator>
    OutputIterator
    reverse_copy(BidirectionalIterator first,
                 BidirectionalIterator last, OutputIterator result);
    

    […]

    -4- Effects: Copies the range [first,last) to the range [result,result+(last-first)) such that for anyevery non-negative integer i < (last - first) the following assignment takes place: *(result + (last - first) - i) = *(first + i).

  4. Change 25.3.13 [alg.partitions] p5 and p9 as indicated:

    template<class ForwardIterator, class Predicate>
    ForwardIterator
    partition(ForwardIterator first,
              ForwardIterator last, Predicate pred);
    

    […]

    -5- Returns: An iterator i such that for anyevery iterator j in the range [first,i) pred(*j) != false, and for anyevery iterator k in the range [i,last), pred(*k) == false.

    […]

    template<class BidirectionalIterator, class Predicate>
    BidirectionalIterator
    stable_partition(BidirectionalIterator first,
                     BidirectionalIterator last, Predicate pred);
    

    […]

    -9- Returns: An iterator i such that for anyevery iterator j in the range [first,i), pred(*j) != false, and for anyevery iterator k in the range [i,last), pred(*k) == false. The relative order of the elements in both groups is preserved.

  5. Change 25.4 [alg.sorting] p5 as indicated:

    -5- A sequence is sorted with respect to a comparator comp if for anyevery iterator i pointing to the sequence and anyevery non-negative integer n such that i + n is a valid iterator pointing to an element of the sequence, comp(*(i + n), *i) == false.

  6. Change 25.4.2 [alg.nth.element] p1 as indicated:

    template<class RandomAccessIterator>
    void nth_element(RandomAccessIterator first, RandomAccessIterator nth,
                     RandomAccessIterator last);
    template<class RandomAccessIterator, class Compare>
    void nth_element(RandomAccessIterator first, RandomAccessIterator nth,
                     RandomAccessIterator last, Compare comp);
    

    -1- After nth_element the element in the position pointed to by nth is the element that would be in that position if the whole range were sorted. Also for anyevery iterator i in the range [first,nth) and anyevery iterator j in the range [nth,last) it holds that: !(*i > *j) or comp(*j, *i) == false.

  7. Change 25.4.3.1 [lower.bound] p2 as indicated:

    template<lass ForwardIterator, class T>
    ForwardIterator
    lower_bound(ForwardIterator first, ForwardIterator last,
                const T& value);
    template<class ForwardIterator, class T, class Compare>
    ForwardIterator
    lower_bound(ForwardIterator first, ForwardIterator last,
                const T& value, Compare comp);
    

    […]

    -2- Returns: The furthermost iterator i in the range [first,last] such that for anyevery iterator j in the range [first,i) the following corresponding conditions hold: *j < value or comp(*j, value) != false.

  8. Change 25.4.3.2 [upper.bound] p2 as indicated:

    template<lass ForwardIterator, class T>
    ForwardIterator
    upper_bound(ForwardIterator first, ForwardIterator last,
                const T& value);
    template<class ForwardIterator, class T, class Compare>
    ForwardIterator
    upper_bound(ForwardIterator first, ForwardIterator last,
                const T& value, Compare comp);
    

    […]

    -2- Returns: The furthermost iterator i in the range [first,last] such that for anyevery iterator j in the range [first,i) the following corresponding conditions hold: !(value < *j) or comp(value, *j) == false.

  9. Change 25.4.7 [alg.min.max] p21 and p23 as indicated:

    template<class ForwardIterator>
    ForwardIterator min_element(ForwardIterator first, ForwardIterator last);
    template<class ForwardIterator, class Compare>
    ForwardIterator min_element(ForwardIterator first, ForwardIterator last,
                                Compare comp);
    

    -21- Returns: The first iterator i in the range [first,last) such that for anyevery iterator j in the range [first,last) the following corresponding conditions hold: !(*j < *i) or comp(*j, *i) == false. Returns last if first == last.

    […]

    template<class ForwardIterator>
    ForwardIterator max_element(ForwardIterator first, ForwardIterator last);
    template<class ForwardIterator, class Compare>
    ForwardIterator max_element(ForwardIterator first, ForwardIterator last,
                                Compare comp);
    

    -23- Returns: The first iterator i in the range [first,last) such that for anyevery iterator j in the range [first,last) the following corresponding conditions hold: !(*i < *j) or comp(*i, *j) == false. Returns last if first == last.


2151. basic_string<>::swap semantics ignore allocators

Section: 21.4.1 [string.require] Status: Open Submitter: Robert Shearer Opened: 2012-04-13 Last modified: 2013-03-18

View other active issues in [string.require].

View all other issues in [string.require].

View all issues with Open status.

Discussion:

In C++11, basic_string is not described as a "container", and is not governed by the allocator-aware container semantics described in sub-clause 23.2 [container.requirements]; as a result, and requirements or contracts for the basic_string interface must be documented in Clause 21 [strings].

Sub-clause 21.4.6.8 [string::swap] defines the swap member function with no requirements, and with guarantees to execute in constant time without throwing. Fulfilling such a contract is not reasonable in the presence of unequal non-propagating allocators.

In contrast, 23.2.1 [container.requirements.general] p7 declares the behavior of member swap for containers with unequal non-propagating allocators to be undefined.

Resolution proposal:

Additional language from Clause 23 [containers] should probably be copied to Clause 21 [strings]. I will refrain from an exactly recommendation, however, as I am raising further issues related to the language in Clause 23 [containers].

[2013-03-15 Issues Teleconference]

Moved to Open.

Alisdair has offered to provide wording.

Telecon notes that 23.2.1 [container.requirements.general]p13 says that string is an allocator-aware container.

Proposed resolution:


2152. Instances of standard container types are not swappable

Section: 17.6.3.2 [swappable.requirements], 23.2.1 [container.requirements.general] Status: Open Submitter: Robert Shearer Opened: 2012-04-13 Last modified: 2012-11-14

View all other issues in [swappable.requirements].

View all issues with Open status.

Discussion:

Sub-clause 17.6.3.2 [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 23.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.3.2 [pairs.pair] p31, 20.4.2.3 [tuple.swap] p2, 25.3.3 [alg.swap] p2, and 25.3.3 [alg.swap] p6, which use the binary definition). This renders many of the mutating sequence algorithms of sub-clause 25.3 [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.3 [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 23.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.

Proposed resolution:


2153. Narrowing of the non-member swap contract

Section: 20.2.2 [utility.swap], 17.6.3.2 [swappable.requirements], 23.2.1 [container.requirements.general] Status: Open Submitter: Robert Shearer Opened: 2012-04-13 Last modified: 2013-03-18

View all issues with Open 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 17.6.3.2 [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 17.6.3.2 [swappable.requirements] is as a guide to the "right" semantics to provide for a non-member swap function (called in the context defined by 17.6.3.2 [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 telocon, and there is no proposed resolution.

Proposed resolution:


2154. What exactly does compile-time complexity imply?

Section: 26.5.1.3 [rand.req.urng] Status: New Submitter: John Salmon Opened: 2012-04-26 Last modified: 2012-11-14

View all issues with New status.

Discussion:

The expressions G::min() and G::max() in Table 116 in 26.5.1.3 [rand.req.urng] are specified as having "compile-time" complexity.

It is not clear what, exactly, this requirement implies. If a URNG has a method:

static int min();

then is the method required to have a constexpr qualifier? I believe the standard would benefit from clarification of this point.

Proposed resolution:


2155. Macro __bool_true_false_are_defined should be removed

Section: 18.10 [support.runtime] Status: Open Submitter: Thomas Plum Opened: 2012-04-30 Last modified: 2013-03-18

View other active issues in [support.runtime].

View all other issues in [support.runtime].

View all issues with Open status.

Discussion:

Since C99, the C standard describes a macro named __bool_true_false_are_defined.

In the process of harmonizing C++11 with C99, this name became part of the C++ standard.

I propose that all mention of this name should be removed from the C and C++ standards.

Here's the problem: The name was originally proposed as a transition tool, so that the headers for a project could contain lines like the following.

#if !defined(__bool_true_false_are_defined)
#define bool int /* or whatever */
#define true 1
#define false 0
#endif

Then when the project was compiled by a "new" compiler that implemented bool as defined by the evolving C++98 or C99 standards, those lines would be skipped; but when compiled by an "old" compiler that didn't yet provide bool, true, and false, then the #define's would provide a simulation that worked for most purposes.

It turns out that there is an unfortunate ambiguity in the name. One interpretation is as shown above, but a different reading says "bool, true, and false are #define'd", i.e. that the meaning of the macro is to assert that these names are macros (not built-in) ... which is true in C, but not in C++.

In C++11, the name appears in parentheses followed by a stray period, so some editorial change is needed in any event:

18.10 [support.runtime] para 1:

Headers <csetjmp> (nonlocal jumps), <csignal> (signal handling), <cstdalign> (alignment), <cstdarg> (variable arguments), <cstdbool> (__bool_true_false_are_defined). <cstdlib> (runtime environment getenv(), system()), and <ctime> (system clock clock(), time()) provide further compatibility with C code.

However, para 2 says

"The contents of these headers are the same as the Standard C library headers <setjmp.h>, <signal.h>, <stdalign.h>, <stdarg.h>, <stdbool.h>, <stdlib.h>, and <time.h>, respectively, with the following changes:",

and para 8 says

"The header <cstdbool> and the header <stdbool.h> shall not define macros named bool, true, or false."

Thus para 8 doesn't exempt the C++ implementation from the arguably clear requirement of the C standard, to provide a macro named __bool_true_false_are_defined defined to be 1.

Real implementations of the C++ library differ, so the user cannot count upon any consistency; furthermore, the usefulness of the transition tool has faded long ago.

That's why my suggestion is that both C and C++ standards should eliminate any mention of __bool_true_false_are_defined. In that case, the name belongs to implementers to provide, or not, as they choose.

[2013-03-15 Issues Teleconference]

Moved to Open.

While not strictly necessary, the clean-up look good.

We would like to hear from our C liaison before moving on this issue though.

Proposed resolution:


2156. Unordered containers' reserve(n) reserves for n-1 elements

Section: 23.2.5 [unord.req] Status: Open Submitter: Daniel James Opened: 2012-05-07 Last modified: 2013-03-18

View other active issues in [unord.req].

View all other issues in [unord.req].

View all issues with Open status.

Discussion:

I think that unordered containers' reserve doesn't quite do what it should. I'd expect after calling x.reserve(n) to be able to insert n elements without invalidating iterators. But as the standard is written (I'm looking at n3376), I think the guarantee only holds for n-1 elements.

For a container with max_load_factor of 1, reserve(n) is equivalent to rehash(ceil(n/1)), ie. rehash(n). rehash(n) requires that the bucket count is >= n, so it can be n (Table 103). The rule is that insert shall not affect the validity of iterators if (N + n) < z * B (23.2.5 [unord.req] p15). But for this case the two sides of the equation are equal, so insert can affect the validity of iterators.

[2013-03-16 Howard comments and provides wording]

Given the following:

LF := load_factor()
MLF := max_load_factor()
S := size()
B := bucket_count()

LF == S/B

The container has an invariant:

LF <= MLF

Therefore:

MLF >= S/B
S <= MLF * B
B >= S/MLF

[2013-03-15 Issues Teleconference]

Moved to Open.

Howard to provide rationale and potentally revised wording.

Proposed resolution:

This wording is relative to N3485.

  1. In 23.2.5 [unord.req] Table 103 — Unordered associative container requirements, change the post-condition in the row for a.rehash(n) to:

    Post: a.bucket_count() >= a.size() / a.max_load_factor() and a.bucket_count() >= n.
  2. In 23.2.5 [unord.req]/p15 change

    The insert and emplace members shall not affect the validity of iterators if (N+n) <= z * B, where N is the number of elements in the container prior to the insert operation, n is the number of elements inserted, B is the container’s bucket count, and z is the container’s maximum load factor.

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

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

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 23.3.2.8 [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 23.3.2.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.

Proposed resolution:

This wording is relative to N3376.

Add the following new paragraph between the current 23.3.2.8 [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).


2158. Conditional copy/move in std::vector

Section: 23.3.6.3 [vector.capacity] Status: New Submitter: Nikolay Ivchenkov Opened: 2012-05-08 Last modified: 2012-11-14

View other active issues in [vector.capacity].

View all other issues in [vector.capacity].

View all issues with New 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 – 23.3.6.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:

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

Proposed resolution:


2159. atomic_flag initialization

Section: 29.7 [atomics.flag] Status: Open Submitter: Alberto Ganesh Barbati Opened: 2012-05-24 Last modified: 2012-11-14

View other active issues in [atomics.flag].

View all other issues in [atomics.flag].

View all issues with Open status.

Discussion:

29.7 [atomics.flag]/4 describes the ATOMIC_FLAG_INIT, but it's not quite clear about a couple of points:

  1. it's said that ATOMIC_FLAG_INIT "can be used to initialize an object of type atomic_flag" and the following example:

    std::atomic_flag guard = ATOMIC_FLAG_INIT;
    

    is presented. It's not clear whether the macro can also be used in the other initialization contexts:

    std::atomic_flag guard ATOMIC_FLAG_INIT; 
    std::atomic_flag guard {ATOMIC_FLAG_INIT};
    
    struct A { std::atomic_flag flag; A(); };
    A::A() : flag (ATOMIC_FLAG_INIT); 
    A::A() : flag {ATOMIC_FLAG_INIT};
    

    Please also note that examples are non-normative, according to the ISO directives, meaning that the wording presents no normative way to use the macro.

  2. it's said that "It is unspecified whether an uninitialized atomic_flag object has an initial state of set or clear.". I believe the use of "uninitialized" is inappropriate. First of all, if an object is uninitialized it is obvious that we cannot assert anything about its state. Secondly, it doesn't address the following cases:

    std::atomic_flag a; // object is "initialized" by trivial default constructor
    std::atomic_flag a {}; // object is value-initialized
    static std::atomic_flag a; // object is zero-initialized
    

    strictly speaking a trivial constructor "initializes" the object, although it doesn't actually initialize the sub-objects.

  3. it's said that "For a static-duration object, that initialization shall be static.". Considering the following example:

    struct A
    {
      A(); // user-provided, not constexpr
    
      std::atomic_flag flag = ATOMIC_FLAG_INIT;
      // possibly other non-static data members
    };
    
    static A a;
    

    The object a.flag (as a sub-object of the object a) has static-duration, yet the initialization has to be dynamic because A::A is not constexpr.

[2012, Portland]

We would like to be able to allow more initialisation contexts for example:

  1. C struct
  2. C++ constructor initializer-list

However we need further input from experts with implementation specific knowledge to identify which additional contexts (if any) would be universally valid.

Moved to open

Proposed resolution:

[This wording is relative to N3376.]

Change 29.7 [atomics.flag]/4 as follows:

The macro ATOMIC_FLAG_INIT shall be defined in such a way that it can be used to initialize an object of type atomic_flag to the clear state. The macro can be used in the form:

atomic_flag guard = ATOMIC_FLAG_INIT;

It's unspecified whether the macro can be used in other initialization contexts. For a complete static-duration object, that initialization shall be static. It is unspecified whether an uninitialized Unless initialized with ATOMIC_FLAG_INIT, it is unspecified whether an atomic_flag object has an initial state of set or clear. [ Example:

atomic_flag guard = ATOMIC_FLAG_INIT;

end example ]


2160. Unintended destruction ordering-specification of resize

Section: 23.3.6.3 [vector.capacity] Status: Open Submitter: Daniel Krügler Opened: 2012-06-07 Last modified: 2013-03-18

View other active issues in [vector.capacity].

View all other issues in [vector.capacity].

View all issues with Open status.

Discussion:

As part of resolving LWG issue 2033 a wording change was done for resize() to respect the problem mentioned in the question:

Does a call to 'void resize(size_type sz)' of std::vector require the element type to be MoveAssignable because the call erase(begin() + sz, end()) mentioned in the Effects paragraph would require the element type to be MoveAssignable?

The wording change was to replace in 23.3.3.3 [deque.capacity] and 23.3.6.3 [vector.capacity]:

-1- Effects: If sz <= size(), equivalent to erase(begin() + sz, end()); […]

by:

-1- Effects: If sz <= size(), equivalent to calling pop_back() size() - sz times. […]

The overlooked side-effect of this wording change is that this implies a destruction order of the removed elements to be in reverse order of construction, but the previous version did not impose any specific destruction order due to the way how the semantics of erase is specified in Table 100.

Given the program:

#include <vector>
#include <iostream>

struct Probe {
  int value;
  Probe() : value(0) {}
  Probe(int value) : value(value) {}
  ~Probe() { std::cout << "~Probe() of " << value << std::endl; }
};

int main() {
  std::vector<Probe> v;
  v.push_back(Probe(1));
  v.push_back(Probe(2));
  v.push_back(Probe(3));
  std::cout << "---" << std::endl;
  v.resize(0);
}

the last three lines of the output for every compiler I tested was:

~Probe() of 1
~Probe() of 2
~Probe() of 3

but a conforming implementation would now need to change this order to

~Probe() of 3
~Probe() of 2
~Probe() of 1

This possible stringent interpretation makes sense, because one can argue that sequence containers (or at least std::vector) should have the same required destruction order of it's elements, as elements of a C array or controlled by memory deallocated with an array delete have. I also learned that libc++ does indeed implement std::vector::resize in a way that the second output form is observed.

While I agree that required reverse-destruction would better mimic the natural behaviour of std::vector this was not required in C++03 and this request may be too strong. My current suggestion would be to restore the effects of the previous wording in regard to the destruction order, because otherwise several currently existing implementations would be broken just because of this additional requirement.

[2013-03-15 Issues Teleconference]

Moved to Open.

Jonathan says that he believes this is a valid issue.

Walter wonders if this was intended when we made the previous change - if so, this would be NAD.

Jonathan said that Issue 2033 doesn't mention ordering.

Walter then asked if anyone is really unhappy that we're destroying items in reverse order of construction.

Jonathan points out that this conflicts with existing practice (libstc++, but not libc++).

Jonathan asked for clarification as to whether this change was intended by 2033.

Proposed resolution:


2161. const equivalence of std::map

Section: 23.4 [associative], 23.5 [unord] Status: New Submitter: Bjarne Stroustrup Opened: 2012-06-18 Last modified: 2012-11-14

View all other issues in [associative].

View all issues with New status.

Discussion:

As described in the reflector discussion c++std-core-21860 consider the following example:

map<const int,int< mci{};
map<int,int< mi = mci; // ??
mci[1] = 2;
mi[1] = 2;

Should it be required that the marked initialization is well-formed? As a possible solution this could be realized by an alias template:

template <class K, class T>
struct OriginalMap { […] };

template <class K, class T>
using ImprovedMap = OriginalMap<const K, T>;

Proposed resolution:


2162. allocator_traits::max_size missing noexcept

Section: 17.6.3.5 [allocator.requirements], 20.6.8.2 [allocator.traits.members], 20.6.8 [allocator.traits] Status: Review Submitter: Bo Persson Opened: 2012-07-03 Last modified: 2012-11-14

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with Review status.

Discussion:

N3376 describes in 20.6.8.2 [allocator.traits.members]/7

static size_type max_size(Alloc& a);

Returns: a.max_size() if that expression is well-formed; otherwise, numeric_limits<size_type>::max().

The max_size function is supposed to call one of two functions that are both noexcept. To make this intermediate function useful for containers, it should preserve the noexcept attribute.

Proposed changes:

In 20.6.8 [allocator.traits] and 20.6.8.2 [allocator.traits.members]/7, change the function signature to

static size_type max_size(Alloc& a) noexcept;

[2012-08-05 Daniel comments]

On the first sight this does not seem like a defect of the specification, because the Allocator requirements in 17.6.3.5 [allocator.requirements] (Table 28) do not impose a no-throw requirement onto max_size(); the table just describes the fall-back implementation for max_size() if a given allocator does not provide such a function.

std::allocator as a special model of this concept and is allowed to increase the exception-guarantees for max_size(), but this does not imply a corresponding rules for other allocators.

Furthermore, max_size() of Containers is not specified in terms of Allocator::max_size(), so again this is not a real contradiction.

Nonetheless I think that the following stronger decision should be considered:

  1. Require that for all Allocators (as specified in 17.6.3.5 [allocator.requirements]) max_size() never throws an exception. This would it make much more useful to call this function in situations where no exception should leave the context.

  2. Require that for all Allocators (as specified in 17.6.3.5 [allocator.requirements]) max_size() can be called on const allocator object. Together with the previous item this would allow an implementation of a container's max_size() function to delegate to the allocator's max_size() function.

In regard to the second statement it should be mentioned that there are two current specification deviations from that in the draft:

  1. The synopsis of 20.6.8 [allocator.traits] uses a const allocator argument as part of the signature of the max_size function.

  2. Both the synopsis of 20.12.1 [allocator.adaptor.syn] and the member specification in 20.12.4 [allocator.adaptor.members] p8 declare scoped_allocator_adaptor::max_size as const member function, but this function delegates to

    allocator_traits<OuterAlloc>::max_size(outer_allocator())
    

    where outer_allocator() resolves to the member function overload returning a const outer_allocator_type&.

The question arises whether these current defects actually point to a defect in the Allocator requirements and should be fixed there.

[ 2012-10 Portland: Move to Review ]

Consensus that the change seems reasonable, and that for any given type the template is intantiated with the contract should be 'wide' so this meets the guidelines we agreed in Madrid for C++11.

Some mild concern that while we don't imagine many allocator implementations throwing on this method, it is technically permited by current code that we would not be breaking, by turning throw expressions into disguised terminate calls. In this case, an example might be an instrumented 'logging' allocator that writes every function call to a log file or database, and might throw if that connection/file were no longer available.

Another option would be to make exception spefication a conditional no-except, much like we do for some swap functions and assignment operators. However, this goes against the intent of the Madrid adoption of noexcept which is that vendors are free to add such extensions, but we look for a clear line in the library specification, and do not want to introduce conditional-noexcept piecemeal. A change in our conventions here would require a paper addressing the library specification as a whole.

Consensus was to move forward, but move the issue only to Review rather than Ready to allow time for further comments. This issue should be considered 'Ready' next time it is reviewed unless we get such comments in the meantime.

Proposed resolution:

In 20.6.8 [allocator.traits] and 20.6.8.2 [allocator.traits.members]/7, change the function signature to

static size_type max_size(Alloc& a) noexcept;

2163. nth_element requires inconsistent post-conditions

Section: 25.4.2 [alg.nth.element] Status: Ready Submitter: Peter Sommerlad Opened: 2012-07-06 Last modified: 2012-11-14

View all issues with Ready status.

Discussion:

The specification of nth_element refers to operator< whereas all sorting without a compare function is based on operator<. While it is true that for all regular types both operators should be defined accordingly, all other sorting algorithms only rely on existence of operator<. So I guess the paragraph p1

After nth_element the element in the position pointed to by nth is the element that would be in that position if the whole range were sorted. Also for any iterator i in the range [first,nth) and any iterator j in the range [nth,last) it holds that: !(*i > *j) or comp(*j, *i) == false.

should read

After nth_element the element in the position pointed to by nth is the element that would be in that position if the whole range were sorted. Also for any iterator i in the range [first,nth) and any iterator j in the range [nth,last) it holds that: !(*j < *i) or comp(*j, *i) == false.

Note only "!(*i > *j)" was changed to "!(*j < *i)" and it would be more symmetric with comp(*j, *i) as well.

In theory this might be a semantic change to the spec, but I believe the mistake is unintended.

[ 2012-10 Portland: Move to Ready ]

This is clearly correct by inspection, moved to Ready by unanimous consent.

Proposed resolution:

This wording is relative to N3376.

  1. Change 25.4.2 [alg.nth.element] p1 as indicated:

    template<class RandomAccessIterator>
    void nth_element(RandomAccessIterator first, RandomAccessIterator nth,
                     RandomAccessIterator last);
    template<class RandomAccessIterator, class Compare>
    void nth_element(RandomAccessIterator first, RandomAccessIterator nth,
                     RandomAccessIterator last, Compare comp);
    

    -1- After nth_element the element in the position pointed to by nth is the element that would be in that position if the whole range were sorted. Also for any iterator i in the range [first,nth) and any iterator j in the range [nth,last) it holds that: !(*i > *j)!(*j < *i) or comp(*j, *i) == false.


2164. What are the semantics of vector.emplace(vector.begin(), vector.back())?

Section: 23.3.6.5 [vector.modifiers], 23.2 [container.requirements] Status: New Submitter: Howard Hinnant Opened: 2012-07-07 Last modified: 2012-11-14

View all other issues in [vector.modifiers].

View all issues with New status.

Discussion:

Nikolay Ivchenkov recently brought the following example on the std-discussion newsgroup, asking whether the following program well-defined:

#include <iostream>
#include <vector>

int main()
{
  std::vector<int> v;
  v.reserve(4);
  v = { 1, 2, 3 };
  v.emplace(v.begin(), v.back());
  for (int x : v)
    std::cout << x << std::endl;
}

Nikolay Ivchenkov:

I think that an implementation of vector's 'emplace' should initialize an intermediate object with v.back() before any shifts take place, then perform all necessary shifts and finally replace the value pointed to by v.begin() with the value of the intermediate object. So, I would expect the following output:

3
1
2
3

GNU C++ 4.7.1 and GNU C++ 4.8.0 produce other results:

2
1
2
3

Howard Hinnant:

I believe Nikolay is correct that vector should initialize an intermediate object with v.back() before any shifts take place. As Nikolay pointed out in another email, this appears to be the only way to satisfy the strong exception guarantee when an exception is not thrown by T's copy constructor, move constructor, copy assignment operator, or move assignment operator as specified by 23.3.6.5 [vector.modifiers]/p1. I.e. if the emplace construction throws, the vector must remain unaltered.

That leads to an implementation that tolerates objects bound to the function parameter pack of the emplace member function may be elements or sub-objects of elements of the container.

My position is that the standard is correct as written, but needs a clarification in this area. Self-referencing emplace should be legal and give the result Nikolay expects. The proposed resolution of LWG 760 is not correct.

Proposed resolution:


2165. std::atomic<X> requires X to be nothrow default constructible

Section: 29.5 [atomics.types.generic], 29.6 [atomics.types.operations] Status: Core Submitter: Jonathan Wakely Opened: 2012-07-19 Last modified: 2012-11-14

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

View all issues with Core status.

Discussion:

As raised in c++std-lib-32781, this fails to compile even though the default constructor is not used:

#include <atomic>

struct X {
  X() noexcept(false) {}
  X(int) { }
};

std::atomic<X> x(3);

This is because atomic<T>'s default constructor is declared to be non-throwing and is explicitly-defaulted on its first declaration:

atomic() noexcept = default;

This is ill-formed if the implicitly-declared default constructor would not be non-throwing.

Possible solutions:

  1. Add nothrow default constructible to requirements for template argument of the generic atomic<T>
  2. Remove atomic<T>::atomic() from the overload set if T is not nothrow default constructible.
  3. Remove noexcept from atomic<T>::atomic(), allowing it to be deduced (but the default constructor is intended to be always noexcept)
  4. Do not default atomic<T>::atomic() on its first declaration (but makes the default constructor user-provided and so prevents atomic<T> being trivial)
  5. A core change to allow the mismatched exception specification if the default constructor isn't used (see c++std-core-21990)

[2012, Portland: move to Core]

Recommend referring to core to see if the constructor noexcept mismatch can be resolved there. The issue is not specific to concurrency.

Proposed resolution:


2166. Heap property underspecified?

Section: 25.4.6 [alg.heap.operations] Status: New Submitter: Peter Sommerlad Opened: 2012-07-09 Last modified: 2012-11-14

View all other issues in [alg.heap.operations].

View all issues with New status.

Discussion:

Another similar issue to the operator< vs greater in nth_element but not as direct occurs in 25.4.6 [alg.heap.operations]:

-1- A heap is a particular organization of elements in a range between two random access iterators [a,b). Its two key properties are:

  1. There is no element greater than *a in the range and
  2. *a may be removed by pop_heap(), or a new element added by push_heap(), in O(log(N)) time.

As noted by Richard Smith, it seems that the first bullet should read:

*a is not less than any element in the range

Even better the heap condition could be stated here directly, instead of leaving it unspecified, i.e.,

Each element at (a+2*i+1) and (a+2*i+2) is less than the element at (a+i), if those elements exist, for i>=0.

But may be that was may be intentional to allow other heap organizations?

See also follow-up discussion of c++std-lib-32780.

Proposed resolution:


2167. Copy assignment requirements of Containers

Section: 23.2.1 [container.requirements.general] Status: Tentatively NAD Submitter: Dean Michael Berris Opened: 2012-07-13 Last modified: 2012-11-14

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

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

Discussion:

Table 96 defines the general requirement for copy assignment (row 23, page 704) as:

Table 96 — Container requirements
Expression Return type Operational semantics Assertion/note pre-/post-condition Complexity
r = a X& post: r == a. linear

However there is no requirement that T is CopyInsertable into X.

[2012, Portland: Move to Tentatively NAD]

Howard notes that this may be a difficult requirement for std::array

We already have this requirement for allocator aware containers, and std::array already adds the appropriate extra requirement.

We say the necessary things in the necessary places, but the container requirements continue to cause confusion in where we sometimes say things. Consensus is that this issue remains NAD though.

Proposed resolution:

This wording is relative to N3376.

  1. Change Table 96 — "Container requirements" in 23.2.1 [container.requirements.general]:

    Table 96 — Container requirements
    Expression Return type Operational semantics Assertion/note pre-/post-condition Complexity
    r = a X& Requires: T is CopyInsertable into X.
    post: r == a.
    linear

2168. Inconsistent specification of uniform_real_distribution constructor

Section: 26.5.8.2.2 [rand.dist.uni.real] Status: New Submitter: Marshall Clow Opened: 2012-07-14 Last modified: 2012-11-14

View all issues with New status.

Discussion:

uniform_real says in 26.5.8.2.2 [rand.dist.uni.real] p1:

A uniform_real_distribution random number distribution produces random numbers x, a ≤ x < b,

but also that (26.5.8.2.2 [rand.dist.uni.real] p2):

explicit uniform_real_distribution(RealType a = 0.0, RealType b = 1.0);

-2- Requires: a ≤ b and b - a ≤ numeric_limits<RealType>::max().

If you construct a uniform_real_distribution<RealType>(a, b) where there are no representable numbers between 'a' and 'b' (using RealType's representation) then you cannot satisfy 26.5.8.2.2 [rand.dist.uni.real].

An obvious example is when a == b.

Proposed resolution:


2169. Missing reset() requirements in unique_ptr specialization

Section: 20.7.1.3.3 [unique.ptr.runtime.modifiers] Status: Ready Submitter: Geoffrey Romer Opened: 2012-07-16 Last modified: 2012-11-14

View all other issues in [unique.ptr.runtime.modifiers].

View all issues with Ready status.

Discussion:

In 20.7.1.3.3 [unique.ptr.runtime.modifiers]/p1-2 of N3376, the description of reset() in the array specialization of unique_ptr partially duplicates the description of the base template method (as specified in 20.7.1.2.5 [unique.ptr.single.modifiers]/p3-5), but lacks some significant requirements. Specifically, the text introduced in LWG 998, and item 13 of LWG 762, is present only in the base template, not the specialization.

This gives the appearance that these requirements specifically do not apply to the specialization, which I don't believe is correct or intended: the issue of reset() operation order addressed by LWG 998 applies just as much to the derived template as to the base template, and the derived template has just as much need to rely on get_deleter()(get()) being well-defined, well-formed, and not throwing exceptions (arguably some of those properties follow from the fact that T is required to be a complete type, but not all).

Assuming the derived template's reset() semantics are intended to be identical to the base template's, there is no need to explicitly specify the semantics of reset(pointer p) at all (since 20.7.1.3 [unique.ptr.runtime]/3 specifies "Descriptions are provided below only for member functions that have behavior different from the primary template."), and reset(nullptr_t p) can be specified by reference to the 'pointer' overload. This is more concise, and eliminates any ambiguity about intentional vs. accidental discrepancies.

[2012-10 Portland: Move to Ready]

This resolution looks blatantly wrong, as it seems to do nothing but defer to primary template where we should describe the contract here.

Ongoing discussion points out that the primary template has a far more carefully worded semantic for reset(p) that we would want to copy here.

STL points out that we need the nullptr overload for this dynamic-array form, as there is a deleted member function template that exists to steal overloads of pointer-to-derived, avoiding undifined behavior, so we need the extra overload.

Finally notice that there is blanket wording further up the clause saying we describe only changes from the primary template, so the proposed wording is in fact exactly correct. Move to Ready.

Proposed resolution:

This wording is relative to N3376.

Change 20.7.1.3.3 [unique.ptr.runtime.modifiers] as indicated:

void reset(pointer p = pointer()) noexcept;
void reset(nullptr_t p) noexcept;

-1- Effects: If get() == nullptr there are no effects. Otherwise get_deleter()(get()) Equivalent to reset(pointer()).

-2- Postcondition: get() == p.


2170. Aggregates cannot be DefaultConstructible

Section: 17.6.3.1 [utility.arg.requirements] Status: Core Submitter: Daniel Krügler Opened: 2012-07-19 Last modified: 2012-11-14

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

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

View all issues with Core status.

Discussion:

The lack of the definition of the DefaultConstructible requirements in C++03 was fixed by LWG 724 at a time where the core rules of list-initialization were slightly different than today, at that time value-initialization (shortly) was the primary rule for class types, i.e. just before applying CWG 1301, CWG 1324, and CWG 1368.

The order in 8.5.4 [dcl.init.list] p3 was changed to respect aggregate initialization, but that had the side-effect that formally aggregate types cannot satisfy the DefaultConstructible requirements anymore, because we require that

T u{};

value-initializes the object u.

Of-course exclusion of aggregates was not intended, therefore I suggest to extend the requirements in Table 19 (17.6.3.1 [utility.arg.requirements]) for empty aggregate-initialization as well.

[ 2012-10 Portland: Move to Core ]

We are not qualified to pick apart the Core rules quickly at this point, but the consensus is that if the core language has changed in this manner, then the fix should similarly be applied in Core - this is not something that we want users of the language to have to say every time they want to Value initialize (or aggregate initialize) an object.

More to Open until we get a clear response from Core, Alisdair to file an issue with Mike.

Proposed resolution:

This wording is relative to N3376.

Change Table 19 in 17.6.3.1 [utility.arg.requirements] as indicated:

Table 19 — DefaultConstructible requirements [defaultconstructible]
Expression Post-condition
T t; object t is default-initialized
T u{}; object u is value-initialized or aggregate-initialized
T()
T{}
a temporary object of type T is value-initialized or aggregate-initialized

2172. Does atomic_compare_exchange_* accept v == nullptr arguments?

Section: 20.7.2.5 [util.smartptr.shared.atomic] Status: Ready Submitter: Howard Hinnant Opened: 2012-07-28 Last modified: 2012-11-14

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

View all issues with Ready status.

Discussion:

Looking at 20.7.2.5 [util.smartptr.shared.atomic]/p31

template<class T>
  bool
  atomic_compare_exchange_strong_explicit(shared_ptr<T>* p,
                                          shared_ptr<T>* v,
                                          shared_ptr<T> w,
                                          memory_order success, memory_order failure);

-31- Requires: p shall not be null.

What about v? Can it be null? And if so, what happens?

This looks closely related to C++11 issue LWG 1030, where we gave every signature in this section a:

Requires: p shall not be null.

It looks like a simple oversight to me that we did not add for the atomic_compare_exchange_*:

Requires: p shall not be null and v shall not be null.

[2012-10 Portland: Move to Ready]

This is clearly the right thing to do, and Lawrence concurs.

Proposed resolution:

This wording is relative to N3376.

Change 20.7.2.5 [util.smartptr.shared.atomic] as indicated:

template<class T>
  bool atomic_compare_exchange_weak(
    shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);

-27- Requires: p shall not be null and v shall not be null.

[…]

template<class T>
  bool atomic_compare_exchange_weak_explicit(
    shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w,
    memory_order success, memory_order failure);
template<class T>
  bool atomic_compare_exchange_strong_explicit(
    shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w,
    memory_order success, memory_order failure);

-31- Requires: p shall not be null and v shall not be null.

[…]


2173. The meaning of operator + in the description of the algorithms

Section: 25 [algorithms] Status: New Submitter: Nikolay Ivchenkov Opened: 2012-08-01 Last modified: 2012-11-14

View all other issues in [algorithms].

View all issues with New 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.

Proposed resolution:


2174. wstring_convert::converted() should be noexcept

Section: 22.3.3.2.2 [conversions.string] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2012-08-02 Last modified: 2013-03-18

View other active issues in [conversions.string].

View all other issues in [conversions.string].

View all issues with Tentatively Ready status.

Discussion:

There is no reason wstring_convert::converted() shouldn't be noexcept.

It might be possible for wstring_convert::state() and wbuffer_convert::state() to be noexcept too, depending on the requirements on mbstate_t.

[2013-03-15 Issues Teleconference]

Moved to Tentatively Ready.

Defer the separate discsussion of state() to another issue, if anyone is ever motivated to file one.

Proposed resolution:

This wording is relative to N3376.

  1. Edit in the class template wstring_convert synopsis 22.3.3.2.2 [conversions.string] p2:

    size_t converted() const noexcept;
    
  2. Edit the signature before 22.3.3.2.2 [conversions.string] p6:

    size_t converted() const noexcept;
    

2175. wstring_convert and wbuffer_convert validity

Section: 22.3.3.2.2 [conversions.string], 22.3.3.2.3 [conversions.buffer] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2012-08-02 Last modified: 2013-03-18

View other active issues in [conversions.string].

View all other issues in [conversions.string].

View all issues with Tentatively Ready status.

Discussion:

See discussion following c++std-lib-32710.

It's not specified what happens if wstring_convert and wbuffer_convert objects are constructed with null Codecvt pointers.

Should the constructors have preconditions that the pointers are not null? If not, are conversions expected to fail, or is it undefined to attempt conversions if the pointers are null?

There are no observer functions to check whether objects were constructed with valid Codecvt pointers. If the types are made movable such observers would be necessary even if the constructors require non-null pointers (see also LWG 2176).

[2013-03-15 Issues Teleconference]

Moved to Tentatively Ready.

Proposed resolution:

This wording is relative to N3376.

  1. Insert a new paragraph before 22.3.3.2.2 [conversions.string] paragraph 16:

    wstring_convert(Codecvt *pcvt = new Codecvt);
    wstring_convert(Codecvt *pcvt, state_type state);
    wstring_convert(const byte_string& byte_err,
      const wide_string& wide_err = wide_string());
    

    -?- Requires: For the first and second constructors pcvt != nullptr.

    -16- Effects: The first constructor shall store pcvt in cvtptr and default values in cvtstate, byte_err_string, and wide_err_string. The second constructor shall store pcvt in cvtptr, state in cvtstate, and default values in byte_err_string and wide_err_string; moreover the stored state shall be retained between calls to from_bytes and to_bytes. The third constructor shall store new Codecvt in cvtptr, state_type() in cvtstate, byte_err in byte_err_string, and wide_err in wide_err_string.

  2. Insert a new paragraph before 22.3.3.2.3 [conversions.buffer] paragraph 10:

    wbuffer_convert(std::streambuf *bytebuf = 0,
      Codecvt *pcvt = new Codecvt, state_type state = state_type());
    

    -?- Requires: pcvt != nullptr.

    -10- Effects: The constructor constructs a stream buffer object, initializes bufptr to bytebuf, initializes cvtptr to pcvt, and initializes cvtstate to state.


2176. Special members for wstring_convert and wbuffer_convert

Section: 22.3.3.2.2 [conversions.string], 22.3.3.2.3 [conversions.buffer] Status: Review Submitter: Jonathan Wakely Opened: 2012-08-02 Last modified: 2013-03-18

View other active issues in [conversions.string].

View all other issues in [conversions.string].

View all issues with Review status.

Discussion:

See discussion following c++std-lib-32699.

The constructors for wstring_convert and wbuffer_convert should be explicit, to avoid implicit conversions which take ownership of a Codecvt pointer and delete it unexpectedly.

Secondly, 22.3.3.2.3 [conversions.buffer] p11 describes a destructor which is not declared in the class synopsis in p2.

Finally, and most importantly, the definitions in 22.3.3.2.2 [conversions.string] and 22.3.3.2.3 [conversions.buffer] imply implicitly-defined copy constructors and assignment operators, which would do shallow copies of the owned Codecvt objects and result in undefined behaviour in the destructors.

Codecvt is not required to be CopyConstructible, so deep copies are not possible. The wstring_convert and wstring_buffer types could be made move-only, but the proposed resolution below doesn't do so because of the lack of preconditions regarding null Codecvt pointers and the absence of observer functions that would allow users to check preconditions (see also LWG 2175).

[2013-03-15 Issues Teleconference]

Moved to Review.

Johnathan pointed out that you can have an implicit constructor that takes ownership of a heap reference, which wouldl result an unexpected deletion.

No-one really likes the 'naked new' in the interface here, either.

Proposed resolution:

This wording is relative to N3376.

  1. Edit the class template wstring_convert synopsis in 22.3.3.2.2 [conversions.string] p2:

    explicit wstring_convert(Codecvt *pcvt = new Codecvt);
    wstring_convert(Codecvt *pcvt, state_type state);
    explicit wstring_convert(const byte_string& byte_err,
                             const wide_string& wide_err = wide_string());
    ~wstring_convert();
    
    wstring_convert(const wstring_convert&) = delete;
    wstring_convert& operator=(const wstring_convert&) = delete;
    				 
    
  2. Edit the signatures before 22.3.3.2.2 [conversions.string] p16:

    explicit wstring_convert(Codecvt *pcvt = new Codecvt);
    wstring_convert(Codecvt *pcvt, state_type state);
    explicit wstring_convert(const byte_string& byte_err,
        const wide_string& wide_err = wide_string());
    
  3. Edit the class template wbuffer_convert synopsis in 22.3.3.2.3 [conversions.buffer] p2:

    explicit wbuffer_convert(std::streambuf *bytebuf = 0,
                             Codecvt *pcvt = new Codecvt,
                             state_type state = state_type());
    
    ~wbuffer_convert();
    
    wbuffer_convert(const wbuffer_convert&) = delete;
    wbuffer_convert& operator=(const wbuffer_convert&) = delete;
    						 
    
  4. Edit the signature before 22.3.3.2.3 [conversions.buffer] p10:

    explicit wbuffer_convert(std::streambuf *bytebuf = 0,
        Codecvt *pcvt = new Codecvt, state_type state = state_type());
    

2177. Requirements on Copy/MoveInsertable

Section: 23.2.1 [container.requirements.general] Status: Tentatively Ready Submitter: Loïc Joly Opened: 2012-08-10 Last modified: 2012-11-14

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

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

View all issues with Tentatively Ready status.

Discussion:

See also discussion following c++std-lib-32883 and c++std-lib-32897.

The requirements on CopyInsertable and MoveInsertable are either incomplete, or complete but hard to figure out.

From e-mail c++std-lib-32897:

Pablo Halpern:

I agree that we need semantic requirements for all of the *Insertable concepts analogous to the requirements we have on similar concepts.

Howard Hinnant:

I've come to believe that the standard is actually correct as written in this area. But it is really hard to read. I would have no objection whatsoever to clarifications to CopyInsertable as you suggest (such as the post-conditions on v). And I do agree with you that the correct approach to the clarifications is to confirm that CopyInsertable implies MoveInsertable.

[2012, Portland: Move to Tentatively Ready]

Move to Tentatively Ready by unanimous consent.

Proposed resolution:

This wording is relative to N3376.

  1. Edit 23.2.1 [container.requirements.general] p13 as indicated:

    -13- […] Given a container type X having an allocator_type identical to A and a value_type identical to T and given an lvalue m of type A, a pointer p of type T*, an expression v of type (possibly const) T, and an rvalue rv of type T, the following terms are defined. If X is not allocator-aware, the terms below are defined as if A were std::allocator<T> — no allocator object needs to be created and user specializations of std::allocator<T> are not instantiated:

    • T is DefaultInsertable into X means that the following expression is well-formed:

      allocator_traits<A>::construct(m, p);
      
    • An element of X is default-inserted if it is initialized by evaluation of the expression

      allocator_traits<A>::construct(m, p);
      

      where p is the address of the uninitialized storage for the element allocated within X.

    • T is CopyMoveInsertable into X means that the following expression is well-formed:

      allocator_traits<A>::construct(m, p, rv);
      

      and when evaluated the following postconditions hold: The value of *p is equivalent to the value of rv before the evaluation. [Note: rv remains a valid object. Its state is unspecified — end note]

    • T is MoveCopyInsertable into X means that, in addition to satisfying the MoveInsertable requirements, the following expression is well-formed:

      allocator_traits<A>::construct(m, p, rv);
      

      and when evaluated the following postconditions hold: The value of v is unchanged and is equivalent to *p.

    • T is EmplaceConstructible into X from args, for zero or more arguments args, means that the following expression is well-formed:

      allocator_traits<A>::construct(m, p, args);
      
    • T is Erasable from X means that the following expression is well-formed:

      allocator_traits<A>::destroy(m, p);
      

    [Note: A container calls allocator_traits<A>::construct(m, p, args) to construct an element at p using args. The default construct in std::allocator will call ::new((void*)p) T(args), but specialized allocators may choose a different definition. — end note]


2178. Allocator requirement changes not mentioned Annex C

Section: 17.6.3.5 [allocator.requirements], C.2 [diff.library] Status: Open Submitter: Nevin Liber Opened: 2012-08-14 Last modified: 2012-11-14

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with Open status.

Discussion:

Given that a number of things were removed from the allocator requirements (reference, const_reference, address() in 17.6.3.5 [allocator.requirements]), it seems that these incompatible changes should be mentioned in Annex C.2 [diff.library], more specifically in [diff.cpp03].

[ 2012-10 Portland: Move to Open ]

It was clearly pointed out by Bill during the C++11 process that our change to allocator requirements potentially broke 3rd party user containers written to expect C++03 allocators, or rather, an allocator written to the minimal requirements of C++11 might not be guaranteed to work with a container written to the previous rules. This was a trade-off in making allocaters easier to write by use of the allocator_traits framework.

This probably does merit a write-up in Annex C, and we look forward to seeing wording. Until then, the best we can do is move the issue to Open.

Proposed resolution:


2179. enable_shared_from_this and construction from raw pointers

Section: 20.7.2.4 [util.smartptr.enab], 20.7.2.2.1 [util.smartptr.shared.const] Status: Open Submitter: Daniel Krügler Opened: 2012-08-16 Last modified: 2013-03-18

View all issues with Open status.

Discussion:

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

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

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

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

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

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

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

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

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

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

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

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

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

[2013-03-15 Issues Teleconference]

Moved to Open.

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

Proposed resolution:


2180. Exceptions from std::seed_seq operations

Section: 26.5.7.1 [rand.util.seedseq] Status: New Submitter: Daniel Krügler Opened: 2012-08-18 Last modified: 2012-11-14

View all other issues in [rand.util.seedseq].

View all issues with New status.

Discussion:

26.5.7.1 [rand.util.seedseq] p1 says upfront:

No function described in this section 26.5.7.1 [rand.util.seedseq] throws an exception.

This constraint seems non-implementable to me when looking especially at the members

template<class T>
seed_seq(initializer_list<T> il);

template<class InputIterator>
seed_seq(InputIterator begin, InputIterator end);

which have the effect of invoking v.push_back() for the exposition-only member of type std::vector (or its equivalent) over all elements of the provided range, so out-of-memory exceptions are always possible and the seed_seq object doesn't seem to be constructible this way.

In addition to the potential lack-of-resources problem, the operations of InputIterator might also throw exceptions.

Aside to that it should me mentioned, that a default constructor of vector<uint_least32_t> in theory can also throw exceptions, even though this seems less of a problem to me in this context, because such an implementation could easily use a different internal container in seed_seq that can hold this no-throw exception guarantee.

Secondly, a slightly different problem category related to exceptions occurs for the member templates

template<class RandomAccessIterator>
void generate(RandomAccessIterator begin, RandomAccessIterator end);

template<class OutputIterator>
void param(OutputIterator dest) const;

where the actual operations performed by the implementation would never need to throw, but since they invoke operations of a user-provided customization point, the overall operation, like for example

copy(v.begin(), v.end(), dest);

could also throw exceptions. In this particular example we can just think of a std::back_insert_iterator applied to a container that needs to allocate its elements used as the type for OutputIterator.

Even though Clause 26 [numerics] has mostly stronger exception constraints than other parts of the library the here discussed are overrestrictive, especially since no operation of std::seed_seq except the template generate is actually needed within the library implementation, as mentioned in the discussion of LWG 2124.

I suggest to remove the general no-exception constraints for operations of std::seed_seq except for member size() and the default constructor and to provide specific wording for generate() and param() to ensure that the algorithm itself is a nothrow operation, which is especially for generate() important, because the templates specified in 26.5.3 [rand.eng] and 26.5.4 [rand.adapt] also depend on this property indirectly, which is further discussed in LWG 2181.

Howard:

I suggest to use a different form for the exception specification, something similar to 20.8.9.1.2 [func.bind.bind] p4:

Throws: Nothing unless an operation on RandomAccessIterator throws an exception.

Daniel:

The currently suggested "what and when" form seems a bit more specific and harmonizes with the form used for function template generate_canonical from 26.5.7.2 [rand.util.canonical].

Proposed resolution:

This wording is relative to N3376.

  1. Edit 26.5.7.1 [rand.util.seedseq] p1 as indicated:

    -1- No function described in this section 26.5.7.1 [rand.util.seedseq] throws an exception.

  2. Edit 26.5.7.1 [rand.util.seedseq] around p2 as indicated:

    seed_seq();
    

    -2- Effects: Constructs a seed_seq object as if by default-constructing its member v.

    -?- Throws: Nothing.

  3. Edit 26.5.7.1 [rand.util.seedseq] around p7 as indicated:

    template<class RandomAccessIterator>
      void generate(RandomAccessIterator begin, RandomAccessIterator end);
    

    -7- Requires: RandomAccessIterator shall meet the requirements of a mutable random access iterator (Table 111) type. Moreover, iterator_traits<class RandomAccessIterator>::value_type shall denote an unsigned integer type capable of accommodating 32-bit quantities.

    -8- Effects: Does nothing if begin == end. Otherwise, with s = v.size() and n = end - begin, fills the supplied range [begin, end) according to the following algorithm […]

    -?- Throws: What and when RandomAccessIterator operations of begin and end throw.

  4. Edit 26.5.7.1 [rand.util.seedseq] around p9 as indicated:

    size_t size() const;
    

    -9- Returns: The number of 32-bit units that would be returned by a call to param().

    -??- Throws: Nothing.

    -10- Complexity: constant time.

  5. Edit 26.5.7.1 [rand.util.seedseq] around p11 as indicated:

    template<class OutputIterator>
      void param(OutputIterator dest) const;
    

    -11- Requires: OutputIterator shall satisfy the requirements of an output iterator (Table 108) type. Moreover, the expression *dest = rt shall be valid for a value rt of type result_type.

    -12- Effects: Copies the sequence of prepared 32-bit units to the given destination, as if by executing the following statement:

    copy(v.begin(), v.end(), dest);
    

    -??- Throws: What and when OutputIterator operations of dest throw.


2181. Exceptions from seed sequence operations

Section: 26.5.1.2 [rand.req.seedseq], 26.5.3 [rand.eng], 26.5.4 [rand.adapt] Status: New Submitter: Daniel Krügler Opened: 2012-08-18 Last modified: 2012-11-14

View all other issues in [rand.req.seedseq].

View all issues with New status.

Discussion:

LWG issue 2180 points out some deficiences in regard to the specification of the library-provided type std::seed_seq regarding exceptions, but there is another specification problem in regard to general types satisfying the seed sequence constraints (named SSeq) as described in 26.5.1.2 [rand.req.seedseq].

26.5.3 [rand.eng] p3 and 26.5.4.1 [rand.adapt.general] p3 say upfront:

Except where specified otherwise, no function described in this section 26.5.3 [rand.eng]/26.5.4 [rand.adapt] throws an exception.

This constraint causes problems, because the described templates in these sub-clauses depend on operations of SSeq::generate() which is a function template, that depends both on operations provided by the implementor of SSeq (e.g. of std::seed_seq), and those of the random access iterator type provided by the caller. With class template linear_congruential_engine we have just one example for a user of SSeq::generate() via:

template<class Sseq> 
linear_congruential_engine<>::linear_congruential_engine(Sseq& q);

template<class Sseq> 
void linear_congruential_engine<>::seed(Sseq& q);

None of these operations has an exclusion rule for exceptions.

As described in 2180 the wording for std::seed_seq should and can be fixed to ensure that operations of seed_seq::generate() won't throw except from operations of the provided iterator range, but there is no corresponding "safety belt" for user-provided SSeq types, since 26.5.1.2 [rand.req.seedseq] does not impose no-throw requirements onto operations of seed sequences.

  1. A quite radical step to fix this problem would be to impose general no-throw requirements on the expression q.generate(rb,re) from Table 115, but this is not as simple as it looks initially, because this function again depends on general types that are mutable random access iterators. Typically, we do not impose no-throw requirements on iterator operations and this would restrict general seed sequences where exceptions are not a problem. Furthermore, we do not impose comparable constraints for other expressions, like that of the expression g() in Table 116 for good reasons, e.g. random_device::operator() explicitly states when it throws exceptions.

  2. A less radical variant of the previous suggestion would be to add a normative requirement on the expression q.generate(rb,re) from Table 115 that says: "Throws nothing if operations of rb and re do not throw exceptions". Nevertheless we typically do not describe conditional Throws elements in proper requirement sets elsewhere (Container requirements excluded, they just describe the containers from Clause 23) and this may exclude resonable implementations of seed sequences that could throw exceptions under rare situations.

  3. The iterator arguments provided to SSeq::generate() for operations in templates of 26.5.3 [rand.eng] and 26.5.4 [rand.adapt] are under control of implementations, so we could impose stricter exceptions requirements on SSeq::generate() for SSeq types that are used to instantiate member templates in 26.5.3 [rand.eng] and 26.5.4 [rand.adapt] solely.

  4. We simply add extra wording to the introductive parts of 26.5.3 [rand.eng] and 26.5.4 [rand.adapt] that specify that operations of the engine (adaptor) templates that depend on a template parameter SSeq throw no exception unless SSeq::generate() throws an exception.

Given these options I would suggest to apply the variant described in the fourth bullet.

The proposed resolution attempts to reduce a lot of the redundancies of requirements in the introductory paragraphs of 26.5.3 [rand.eng] and 26.5.4 [rand.adapt] by introducing a new intermediate sub-clause "Engine and engine adaptor class templates" following sub-clause 26.5.2 [rand.synopsis]. This approach also solves the problem that currently 26.5.3 [rand.eng] also describes requirements that apply for 26.5.4 [rand.adapt] (Constrained templates involving the Sseq parameters).

Proposed resolution:

This wording is relative to N3376.

  1. Add a new sub-clause titled "Engine and engine adaptor class templates" following sub-clause 26.5.2 [rand.synopsis] (but at the same level) and add one further sub-clause "General" as child of the new sub-clause as follows:

    Engine and engine adaptor class templates [rand.engadapt]

    General [rand.engadapt.general]

    -?- Throughout this sub-clause general requirements and conventions are described that apply to every class template specified in sub-clause 26.5.3 [rand.eng] and 26.5.4 [rand.adapt]. Phrases of the form "in those sub-clauses" shall be interpreted as equivalent to "in sub-clauses 26.5.3 [rand.eng] and 26.5.4 [rand.adapt]".

    -?- Except where specified otherwise, the complexity of each function specified in those sub-clauses is constant.

    -?- Except where specified otherwise, no function described in those sub-clauses throws an exception.

    -?- Every function described in those sub-clauses that has a function parameter q of type SSeq& for a template type parameter named SSeq that is different from type std::seed_seq throws what and when the invocation of q.generate throws.

    -?- Descriptions are provided in those sub-clauses only for engine operations that are not described in 26.5.1.4 [rand.req.eng], for adaptor operations that are not described in 26.5.1.5 [rand.req.adapt], or for operations where there is additional semantic information. In particular, declarations for copy constructors, for copy assignment operators, for streaming operators, and for equality and inequality operators are not shown in the synopses.

    -?- Each template specified in those sub-clauses requires one or more relationships, involving the value(s) of its non-type template parameter(s), to hold. A program instantiating any of these templates is ill-formed if any such required relationship fails to hold.

    -?- For every random number engine and for every random number engine adaptor X defined in those sub-clauses:

    • if the constructor

      template <class Sseq> explicit X(Sseq& q);
      

      is called with a type Sseq that does not qualify as a seed sequence, then this constructor shall not participate in overload resolution;

    • if the member function

      template <class Sseq> void seed(Sseq& q);
      

      is called with a type Sseq that does not qualify as a seed sequence, then this function shall not participate in overload resolution;

    The extent to which an implementation determines that a type cannot be a seed sequence is unspecified, except that as a minimum a type shall not qualify as a seed sequence if it is implicitly convertible to X::result_type.

  2. Edit the contents of sub-clause 26.5.3 [rand.eng] as indicated:

    -1- Each type instantiated from a class template specified in this section 26.5.3 [rand.eng] satisfies the requirements of a random number engine (26.5.1.4 [rand.req.eng]) type and the general implementation requirements specified in sub-clause [rand.engadapt.general].

    -2- Except where specified otherwise, the complexity of each function specified in this section 26.5.3 [rand.eng] is constant.

    -3- Except where specified otherwise, no function described in this section 26.5.3 [rand.eng] throws an exception.

    -4- Descriptions are provided in this section 26.5.3 [rand.eng] only for engine operations that are not described in 26.5.1.4 [rand.req.eng] […]

    -5- Each template specified in this section 26.5.3 [rand.eng] requires one or more relationships, involving the value(s) of its non-type template parameter(s), to hold. […]

    -6- For every random number engine and for every random number engine adaptor X defined in this subclause (26.5.3 [rand.eng]) and in sub-clause 26.5.3 [rand.eng]: […]

  3. Edit the contents of sub-clause 26.5.4.1 [rand.adapt.general] as indicated:

    -1- Each type instantiated from a class template specified in this section 26.5.3 [rand.eng]26.5.4 [rand.adapt] satisfies the requirements of a random number engine adaptor (26.5.1.5 [rand.req.adapt]) type and the general implementation requirements specified in sub-clause [rand.engadapt.general].

    -2- Except where specified otherwise, the complexity of each function specified in this section 26.5.4 [rand.adapt] is constant.

    -3- Except where specified otherwise, no function described in this section 26.5.4 [rand.adapt] throws an exception.

    -4- Descriptions are provided in this section 26.5.4 [rand.adapt] only for engine operations that are not described in 26.5.1.5 [rand.req.adapt] […]

    -5- Each template specified in this section 26.5.4 [rand.adapt] requires one or more relationships, involving the value(s) of its non-type template parameter(s), to hold. […]


2182. Container::[const_]reference types are misleadingly specified

Section: 23.2.1 [container.requirements.general] Status: Review Submitter: Daniel Krügler Opened: 2012-08-20 Last modified: 2013-03-18

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

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

View all issues with Review status.

Discussion:

According to Table 96 (Container requirements) the return type of X::reference and X::const_reference is "lvalue of T" and "const lvalue of T", respectively. This does not make much sense, because an lvalue is an expression category, not a type. It could also refer to an expression that has a type, but this doesn't make sense either in this context, because obviously X::[const_]reference are intended to refer to types.

Given the fact that vector<bool> has no real reference type for X::[const_]reference and this definition presumably is intended to cover such situations as well, one might think that the wording is just a sloppy form of "type that represents a [const] lvalue of T". But this is also problematic, because basically all proxy reference expressions are rvalues.

It is unclear what the intention is. A straightward way of fixing this wording could make X::[const_]reference identical to [const] T&. This holds for all Library containers except for vector<bool>.

Another way of solving this definition problem would be to impose a requirement that holds for both references and reference-like proxies. Both X::reference and X::const_reference would need to be convertible to const T&. Additionally X::reference would need to support for a mutable container an assignment expression of the form declval<X::reference>() = declval<T>() (this presentation intentionally does not require declval<X::reference&>() = declval<T>()).

Further, the Table 96 does not impose any relations between X::reference and X::const_reference. It seems that at least X::reference needs to be convertible to X::const_reference.

A related question is whether X::reference is supposed to be a mutable reference-like type, irrespective of whether the container is an immutable container or not. The way, type match_results defines reference identical to const_reference indicates one specific interpretation (similarly, the initializer_list template also defines member type reference equal to const value_type&). Note that this can be a different decision as that for iterator and const_iterator, e.g. for sets the type X::reference still is a mutable reference, even though iterator is described as constant iterator.

The proposed resolution is incomplete in regard to the last question.

[2013-03-15 Issues Teleconference]

Moved to Review.

Alisdair notes that this looks like wording in the right direction. Wonders about congruence of these typedefs and the similar ones for iterators.

Proposed resolution:

This wording is relative to N3376.

  1. Change Table 96 — "Container requirements" as indicated:

    Table p6 — Container requirements
    Expression Return type Operational
    Semantics
    Assertion/note
    pre-/post-condition
    Complexity
    X::reference lvalue oftype that behaves like a reference to T   convertible to X::const_reference
    and to const T&
    compile time
    X::const_reference const lvalue oftype that behaves like a reference to const T   convertible to const T& compile time

2183. Muddled allocator requirements for match_results constructors

Section: 28.10.1 [re.results.const], 28.10.6 [re.results.all] Status: New Submitter: Pete Becker Opened: 2012-08-29 Last modified: 2012-11-14

View other active issues in [re.results.const].

View all other issues in [re.results.const].

View all issues with New status.

Discussion:

28.10.1 [re.results.const] p1 says:

In all match_results constructors, a copy of the Allocator argument shall be used for any memory allocation performed by the constructor or member functions during the lifetime of the object.

There are three constructors:

match_results(const Allocator& = Allocator());
match_results(const match_results& m);
match_results(match_results&& m) noexcept;

The second and third constructors do no have an Allocator argument, so despite the "all match_results constructors", it is not possible to use "the Allocator argument" for the second and third constructors.

The requirements for those two constructors also does not give any guidance. The second constructor has no language about allocators, and the third states that the stored Allocator value is move constructed from m.get_allocator(), but doesn't require using that allocator to allocate memory.

The same basic problem recurs in 28.10.6 [re.results.all], which gives the required return value for get_allocator():

Returns: A copy of the Allocator that was passed to the object's constructor or, if that allocator has been replaced, a copy of the most recent replacement.

Again, the second and third constructors do not take an Allocator, so there is nothing that meets this requirement when those constructors are used.

Proposed resolution:


2184. Muddled allocator requirements for match_results assignments

Section: 28.10.1 [re.results.const], 28.10.6 [re.results.all] Status: New Submitter: Pete Becker Opened: 2012-08-29 Last modified: 2012-11-14

View other active issues in [re.results.const].

View all other issues in [re.results.const].

View all issues with New status.

Discussion:

The effects of the two assignment operators are specified in Table 141. Table 141 makes no mention of allocators, so, presumably, they don't touch the target object's allocator. That's okay, but it leaves the question: match_results::get_allocator() is supposed to return "A copy of the Allocator that was passed to the object's constructor or, if that allocator has been replaced, a copy of the most recent replacement"; if assignment doesn't replace the allocator, how can the allocator be replaced?

Proposed resolution:


2185. Missing throws clause for future/shared_future::wait_for/wait_until

Section: 30.6.6 [futures.unique_future], 30.6.7 [futures.shared_future] Status: Review Submitter: Vicente J. Botet Escriba Opened: 2012-09-20 Last modified: 2012-11-14

View all other issues in [futures.unique_future].

View all issues with Review status.

Discussion:

The functions future::wait_for, future::wait_until, shared_future::wait_for, and shared_future::wait_for can throw any timeout-related exceptions. It would be better if the wording could be more explicit. This is in line with the changes proposed in LWG 2093's Throws element of condition_variable::wait with predicate.

[2012, Portland: move to Review]

The phrase timeout-related exception does not exist.

2093 was put in review, and there is some dependency here with this issue.

If you provide a user-defined clock that throws, we need to put back an exception to allow that to be done.

We will put this in review and say that this cannot go in before 2093.

Proposed resolution:

[This resolution should not be adopted before resolving 2093]

[This wording is relative to N3376.]

  1. Change 30.6.6 [futures.unique_future] as indicated:

    template <class Rep, class Period>
    future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;
    

    -21- Effects: none if the shared state contains a deferred function (30.6.8 [futures.async]), otherwise blocks until the shared state is ready or until the relative timeout (30.2.4 [thread.req.timing]) specified by rel_time has expired.

    -22- Returns: […]

    -??- Throws: timeout-related exceptions (30.2.4 [thread.req.timing]).

    template <class Clock, class Duration>
    future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;
    

    -23- Effects: none if the shared state contains a deferred function (30.6.8 [futures.async]), otherwise blocks until the shared state is ready or until the absolute timeout (30.2.4 [thread.req.timing]) specified by abs_time has expired.

    -24- Returns: […]

    -??- Throws: timeout-related exceptions (30.2.4 [thread.req.timing]).

  2. Change 30.6.7 [futures.shared_future] as indicated:

    template <class Rep, class Period>
    future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;
    

    -23- Effects: none if the shared state contains a deferred function (30.6.8 [futures.async]), otherwise blocks until the shared state is ready or until the relative timeout (30.2.4 [thread.req.timing]) specified by rel_time has expired.

    -24- Returns: […]

    -??- Throws: timeout-related exceptions (30.2.4 [thread.req.timing]).

    template <class Clock, class Duration>
    future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;
    

    -25- Effects: none if the shared state contains a deferred function (30.6.8 [futures.async]), otherwise blocks until the shared state is ready or until the absolute timeout (30.2.4 [thread.req.timing]) specified by abs_time has expired.

    -26- Returns: […]

    -??- Throws: timeout-related exceptions (30.2.4 [thread.req.timing]).


2186. Incomplete action on async/launch::deferred

Section: 30.6.8 [futures.async] Status: Open Submitter: Vicente J. Botet Escriba Opened: 2012-09-20 Last modified: 2012-11-14

View other active issues in [futures.async].

View all other issues in [futures.async].

View all issues with Open status.

Discussion:

The description of the effects of async when the launch policy is launch::deferred doesn't state what is done with the result of the deferred function invocation and the possible exceptions as it is done for the asynchronous function when the policy is launch::async.

[2012, Portland: move to Open]

Detlef: agree with the problem but not with the resolution. The wording should be applied to all launch policies rather than having to be separately specified for each one.

Hans: we should redraft to factor out the proposed text outside the two bullets. Needs to be carefully worded to be compatible with the resolution of 2120 (see above).

Moved to open

Proposed resolution:

[This wording is relative to N3376.]

  1. Change 30.6.8 [futures.async] p3 bullet 2 as indicated:

    template <class F, class... Args>
    future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
    async(F&& f, Args&&... args);
    template <class F, class... Args>
    future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
    async(launch policy, F&& f, Args&&... args);
    

    -2- Requires: […]

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

    • if policy & launch::async is non-zero […]

    • if policy & launch::deferred is non-zero — Stores DECAY_COPY(std::forward<F>(f)) and DECAY_COPY(std::forward<Args>(args))... in the shared state. These copies of f and args constitute a deferred function. Invocation of the deferred function evaluates INVOKE(std::move(g), std::move(xyz)) where g is the stored value of DECAY_COPY(std::forward<F>(f)) and xyz is the stored copy of DECAY_COPY(std::forward<Args>(args)).... Any return value is stored as the result in the shared state. Any exception propagated from the execution of the deferred function is stored as the exceptional result in the shared state. The shared state is not made ready until the function has completed. The first call to a non-timed waiting function (30.6.4 [futures.state]) on an asynchronous return object referring to this shared state shall invoke the deferred function in the thread that called the waiting function. Once evaluation of INVOKE(std::move(g), std::move(xyz)) begins, the function is no longer considered deferred. [Note: If this policy is specified together with other policies, such as when using a policy value of launch::async | launch::deferred, implementations should defer invocation or the selection of the policy when no more concurrency can be effectively exploited. — end note]


2187. vector<bool> is missing emplace and emplace_back member functions

Section: 23.3.7 [vector.bool] Status: Tentatively Ready Submitter: Nevin Liber Opened: 2012-09-21 Last modified: 2012-11-14

View all other issues in [vector.bool].

View all issues with Tentatively Ready status.

Discussion:

It should have them so that it more closely matches the vector<T> interface, as this helps when writing generic code.

[2012, Portland: Move to Tentatively Ready]

Question on whether the variadic template is really needed, but it turns out to be needed to support emplace of no arguments.

Proposed resolution:

This wording is relative to N3376.

  1. Change the class template vector<bool> synopsis, 23.3.7 [vector.bool] p1, as indicated:

    namespace std {
      template <class Allocator> class vector<bool, Allocator> {
      public:
        […]
        // modifiers:
        template <class... Args> void emplace_back(Args&&... args);
        void push_back(const bool& x);
        void pop_back();
        template <class... Args> iterator emplace(const_iterator position, Args&&... args);
        iterator insert(const_iterator position, const bool& x);
        […]
      };
    }
    

2188. Reverse iterator does not fully support targets that overload operator&

Section: 24.5.1.3.5 [reverse.iter.opref] Status: New Submitter: Alisdair Meredith Opened: 2012-09-23 Last modified: 2013-03-15

View all other issues in [reverse.iter.opref].

View all issues with New status.

Discussion:

The specification for reverse_iterator::operator-> returns the address of the object yielded by dereferencing with operatator*, but does not have the usual wording about returning the true address of the object. As reverse_iterator requires the adapted iterator have at least the bidirectional iterator category, we know that the returned reference is a true reference, and not a proxy, hence we can use std::addressof on the reference to get the right answer.

This will most likely show itself as an issue with a list or vector of a type with such an overloaded operator, where algorithms are likely to work with a forward iteration, but not with reverse iteration.

Proposed resolution:

Revise 24.5.1.3.5 [reverse.iter.opref] p1, as indicated:

Returns: The true address of the object returned by &(operator*()).


2189. Throwing swap breaks unordered containers' state

Section: 23.2.5.1 [unord.req.except] Status: Open Submitter: Alisdair Meredith Opened: 2012-09-23 Last modified: 2013-03-18

View all issues with Open status.

Discussion:

The hash functor and key-comparison functor of unordered containers are allowed to throw on swap.

23.2.5.1 [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.

Proposed resolution:


2190. Condition variable specification

Section: 30.5 [thread.condition] Status: Review Submitter: Hans Boehm Opened: 2012-09-25 Last modified: 2012-11-14

View other active issues in [thread.condition].

View all other issues in [thread.condition].

View all issues with Review status.

Discussion:

The condition variable specification possibly leaves it unclear whether the effect of a notify_one() call can effectively be delayed, so that a call unblocks a wait() call that happens after the notify_one call. (For notify_all() this is not detectable, since it only results in spurious wake-ups.) Although this may at first glance seem like a contrived interpretation, it gains relevance since glibc in fact allows the analogous behavior (see here) and it is currently controversial whether this is correct and the Posix specification allows it (see here).

The following proposed resolution disallows the glibc implementation, remaining consistent with the believed intent of C++11. To make that clear, we require that the "unspecified total order" O from 30.5 [thread.condition] p4 be consistent with happens-before. We also intend that the 3 components of a wait occur in order in O, but stating that explicitly seems too pedantic. Since they are numbered, it appears clear enough that they are sequenced one after the other.

Another uncertainty with the current phrasing is whether there is a single total order that includes all c.v. accesses, or one total order per c.v. We believe it actually doesn't matter, because there is no way to tell the difference, but this requires a bit more thought. We resolved it one way, just to remove the potential ambiguity.

[2012, Portland: Move to Review]

This is linked to a glibc issue, and a POSIX specification issue.

We believe the proposed wording fixes the ambiguity in C++ and is compatible with the proposed resolution for Posix (which confirms the glibc behaviour as illegal).

Moved to review (Detlef hopes to send some improved wording to the reflector).

Proposed resolution:

This wording is relative to N3376.

  1. Change 30.5 [thread.condition] p4 as indicated:

    -4- The implementation shall behave as if all executions of notify_one, notify_all, and each part of the wait, wait_for, and wait_until executions are executed in somea single unspecified total order consistent with the "happens before" order.


2191. Incorrect specification of match_results(match_results&&)

Section: 28.10.1 [re.results.const] Status: New Submitter: Pete Becker Opened: 2012-10-02 Last modified: 2012-11-14

View other active issues in [re.results.const].

View all other issues in [re.results.const].

View all issues with New status.

Discussion:

28.10.1 [re.results.const]/3: "Move-constructs an object of class match_results satisfying the same postconditions as Table 141."

Table 141 lists various member functions and says that their results should be the results of the corresponding member function calls on m. But m has been moved from, so the actual requirement ought to be based on the value that m had before the move construction, not on m itself.

In addition to that, the requirements for the copy constructor should refer to Table 141.

Ganesh:

Also, the requirements for move-assignment should refer to Table 141. Further it seems as if in Table 141 all phrases of "for all integers n < m.size()" should be replaced by "for all unsigned integers n < m.size()".

Proposed resolution:


2192. Validity and return type of std::abs(0u) is unclear

Section: 26.8 [c.math] Status: New Submitter: Daniel Krügler Opened: 2012-10-02 Last modified: 2012-11-14

View other active issues in [c.math].

View all other issues in [c.math].

View all issues with New status.

Discussion:

In C++03 the following two programs are invalid:

  1. #include <cmath>
    
    int main() {
      std::abs(0u);
    }
    
  2. #include <cstdlib>
    
    int main() {
      std::abs(0u);
    }
    

because none of the std::abs() overloads is a best match.

In C++11 the additional "sufficient overload" rule from 26.8 [c.math] p11 (see also LWG 2086) can be read to be applicable to the std::abs() overloads as well, which can lead to the following possible conclusions:

  1. The program

    #include <type_traits>
    #include <cmath>
    
    static_assert(std::is_same<decltype(std::abs(0u)), double>(), "Oops");
    
    int main() {
      std::abs(0u); // Calls std::abs(double)
    }
    

    is required to be well-formed, because of sub-bullet 2 ("[..] or an integer type [..]") of 26.8 [c.math] p11 (Note that the current resolution of LWG 2086 doesn't fix this problem).

  2. Any translation unit including both <cmath> and <cstdlib> might be ill-formed because of two conflicting requirements for the return type of the overload std::abs(int).

It seems to me that at least the second outcome is not intended, personally I think that both are unfortunate: In contrast to all other floating-point functions explicitly listed in sub-clause 26.8 [c.math], the abs overloads have a special and well-defined meaning for signed integers and thus have explicit overloads returning a signed integral type. I also believe that there is no problem accepting that std::fabs(0u) is well-defined with return type double, because the leading 'f' clearly signals that we have a floating point function here. But the expected return type of std::abs(0u) seems less than clear to me. A very reasonable answer could be that this has the same type as its argument type, alternatively it could be a reasonably chosen signed integer type, or a floating point type. It should also be noted, that the corresponding "generic type function" rule set from C99/C1x in 7.25 p2+3 is restricted to the floating-point functions from <math.h> and <complex.h>, so cannot be applied to the abs functions (but to the fabs functions!).

Selecting a signed integer return type for unsigned input values can also problematic: The directly corresponding signed integer type would give half of the possible argument values an implementation-defined result value. Choosing the first signed integer value that can represent all positive values would solve this problem for unsigned int, but there would be no clear answer for the input type std::uintmax_t.

Based on this it seems to me that the C++03 state in regard to unsigned integer values was the better situation, alerting the user that this code is ambigious at the moment (This might be change with different core-language rules as described in N3387).

Proposed resolution:

This wording is relative to N3376.

  1. Change 26.8 [c.math] p11 as indicated:

    -11- Moreover, except for the abs functions, there shall be additional overloads sufficient to ensure:

    […]


2193. Default constructors for standard library containers are explicit

Section: 23 [containers] Status: EWG Submitter: Richard Smith Opened: 2012-10-04 Last modified: 2012-11-14

View all other issues in [containers].

Discussion:

Most (all?) of the standard library containers have explicit default constructors. Consequently:

std::set<int> s1 = { 1, 2 }; // ok
std::set<int> s2 = { 1 }; // ok
std::set<int> s3 = {}; // ill-formed, copy-list-initialization selected an explicit constructor

Note that Clang + libc++ rejects the declaration of s3 for this reason. This cannot possibly match the intent.

Suggested fix: apply this transformation throughout the standard library:

set() : set(Compare()) {}
explicit set(const Compare& comp = Compare(),
             const Allocator& = Allocator());

[ 2012-10-06: Daniel adds concrete wording. ]

[2012, Portland: Move to Open]

This may be an issue better solved by a core language tweak. Throw the issue over to EWG and see whether they believe the issue is better resolved in Core or Library.

AJM suggest we spawn a new status of 'EWG' to handle such issues - and will move this issue appropriately when the software can record such resolutions.

Proposed resolution:

This wording is relative to N3376.

The more general criterion for performing the suggested transformation was: Any type with an initializer-list constructor that also has an explicit default constructor.

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

    basic_string() : basic_string(Allocator()) {}
    explicit basic_string(const Allocator& a = Allocator());
    
  2. Change 21.4.2 [string.cons] before p1 as indicated:

    explicit basic_string(const Allocator& a = Allocator());
    
  3. Change class template deque synopsis, 23.3.3.1 [deque.overview] p2 as indicated:

    deque() : deque(Allocator()) {}
    explicit deque(const Allocator& = Allocator());
    
  4. Change 23.3.3.2 [deque.cons] before p1 as indicated:

    explicit deque(const Allocator& = Allocator());
    
  5. Change class template forward_list synopsis, 23.3.4.1 [forwardlist.overview] p3 as indicated:

    forward_list() : forward_list(Allocator()) {}
    explicit forward_list(const Allocator& = Allocator());
    
  6. Change 23.3.4.2 [forwardlist.cons] before p1 as indicated:

    explicit forward_list(const Allocator& = Allocator());
    
  7. Change class template list synopsis, 23.3.5.1 [list.overview] p2 as indicated:

    list() : list(Allocator()) {}
    explicit list(const Allocator& = Allocator());
    
  8. Change 23.3.5.2 [list.cons] before p1 as indicated:

    explicit list(const Allocator& = Allocator());
    
  9. Change class template vector synopsis, 23.3.6.1 [vector.overview] p2 as indicated:

    vector() : vector(Allocator()) {}
    explicit vector(const Allocator& = Allocator());
    
  10. Change 23.3.6.2 [vector.cons] before p1 as indicated:

    explicit vector(const Allocator& = Allocator());
    
  11. Change class template specialization vector<bool> synopsis, 23.3.7 [vector.bool] p1 as indicated:

    vector() : vector(Allocator()) {}
    explicit vector(const Allocator& = Allocator());
    
  12. Change class template map synopsis, 23.4.4.1 [map.overview] p2 as indicated:

    map() : map(Compare()) {}
    explicit map(const Compare& comp = Compare(),
                 const Allocator& = Allocator());
    
  13. Change 23.4.4.2 [map.cons] before p1 as indicated:

    explicit map(const Compare& comp = Compare(),
                 const Allocator& = Allocator());
    
  14. Change class template multimap synopsis, 23.4.5.1 [multimap.overview] p2 as indicated:

    multimap() : multimap(Compare()) {}
    explicit multimap(const Compare& comp = Compare(),
                      const Allocator& = Allocator());
    
  15. Change 23.4.5.2 [multimap.cons] before p1 as indicated:

    explicit multimap(const Compare& comp = Compare(),
                      const Allocator& = Allocator());
    
  16. Change class template set synopsis, 23.4.6.1 [set.overview] p2 as indicated:

    set() : set(Compare()) {}
    explicit set(const Compare& comp = Compare(),
                 const Allocator& = Allocator());
    
  17. Change 23.4.6.2 [set.cons] before p1 as indicated:

    explicit set(const Compare& comp = Compare(),
                 const Allocator& = Allocator());
    
  18. Change class template multiset synopsis, 23.4.7.1 [multiset.overview] p2 as indicated:

    multiset() : multiset(Compare()) {}
    explicit multiset(const Compare& comp = Compare(),
                      const Allocator& = Allocator());
    
  19. Change 23.4.7.2 [multiset.cons] before p1 as indicated:

    explicit multiset(const Compare& comp = Compare(),
                      const Allocator& = Allocator());
    
  20. Change class template unordered_map synopsis, 23.5.4.1 [unord.map.overview] p3 as indicated:

    unordered_map() : unordered_map(see below) {}
    explicit unordered_map(size_type n = see below,
                           const hasher& hf = hasher(),
                           const key_equal& eql = key_equal(),
                           const allocator_type& a = allocator_type());
    
  21. Change 23.5.4.2 [unord.map.cnstr] before p1 as indicated:

    unordered_map() : unordered_map(see below) {}
    explicit unordered_map(size_type n = see below,
                           const hasher& hf = hasher(),
                           const key_equal& eql = key_equal(),
                           const allocator_type& a = allocator_type());
    
  22. Change class template unordered_multimap synopsis, 23.5.5.1 [unord.multimap.overview] p3 as indicated:

    unordered_multimap() : unordered_multimap(see below) {}
    explicit unordered_multimap(size_type n = see below,
                                const hasher& hf = hasher(),
                                const key_equal& eql = key_equal(),
                                const allocator_type& a = allocator_type());
    
  23. Change 23.5.5.2 [unord.multimap.cnstr] before p1 as indicated:

    unordered_multimap() : unordered_multimap(see below) {}
    explicit unordered_multimap(size_type n = see below,
                                const hasher& hf = hasher(),
                                const key_equal& eql = key_equal(),
                                const allocator_type& a = allocator_type());
    
  24. Change class template unordered_set synopsis, 23.5.6.1 [unord.set.overview] p3 as indicated:

    unordered_set() : unordered_set(see below) {}
    explicit unordered_set(size_type n = see below,
                           const hasher& hf = hasher(),
                           const key_equal& eql = key_equal(),
                           const allocator_type& a = allocator_type());
    
  25. Change 23.5.6.2 [unord.set.cnstr] before p1 as indicated:

    unordered_set() : unordered_set(see below) {}
    explicit unordered_set(size_type n = see below,
                           const hasher& hf = hasher(),
                           const key_equal& eql = key_equal(),
                           const allocator_type& a = allocator_type());
    
  26. Change class template unordered_multiset synopsis, 23.5.7.1 [unord.multiset.overview] p3 as indicated:

    unordered_multiset() : unordered_multiset(see below) {}
    explicit unordered_multiset(size_type n = see below,
                                const hasher& hf = hasher(),
                                const key_equal& eql = key_equal(),
                                const allocator_type& a = allocator_type());
    
  27. Change 23.5.7.2 [unord.multiset.cnstr] before p1 as indicated:

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

2194. Impossible container requirements for adaptor types

Section: 23.6 [container.adaptors] Status: New Submitter: Sebastian Mach Opened: 2012-10-05 Last modified: 2012-11-14

View all other issues in [container.adaptors].

View all issues with New status.

Discussion:

The stack class template does not have an member type iterator, and therefore instantiations do not meet the general container requirements as described in 23.2.1 [container.requirements.general]. But 23.6.1 [container.adaptors.general] p1 says:

The headers <queue> and <stack> define the container adaptors queue, priority_queue, and stack. These container adaptors meet the requirements for sequence containers.

Since sequence containers is a subset of general containers, this imposes requirements on the container adaptors that are not satisfied.

Daniel Krügler: The wording change was performed as an editorial reorganization as requested by GB 116 occuring first in N3242, as a side-effect it does now make the previous implicit C++03 classification to [lib.sequences]/1 more obvious. As the NB comment noticed, the adaptors really are not sequences nor containers, so this wording needs to be fixed. The most simple way to realize that is to strike the offending sentence.

[ Daniel adds concrete wording. ]

Proposed resolution:

This wording is relative to N3376.

  1. Change 23.6.1 [container.adaptors.general] p1 as indicated:

    -1- The headers <queue> and <stack> define the container adaptors queue, priority_queue, and stack. These container adaptors meet the requirements for sequence containers.


2195. Missing constructors for match_results

Section: 28.10 [re.results] Status: New Submitter: Daniel Krügler Opened: 2012-10-06 Last modified: 2012-11-14

View all other issues in [re.results].

View all issues with New status.

Discussion:

The requirement expressed in 28.10 [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 23.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.

Proposed resolution:

This wording is relative to N3376.

  1. Change 28.10 [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 23.2.3 [sequence.reqmts], except that only operations defined for const-qualified sequence containers that are not constructors are supported.


2196. Specification of is_*[copy/move]_[constructible/assignable] unclear for non-referencable types

Section: 20.9.4.3 [meta.unary.prop] Status: Review Submitter: Daniel Krügler Opened: 2012-10-06 Last modified: 2012-11-14

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

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

View all issues with Review status.

Discussion:

The pre-conditions for the type is_copy_constructible allow for template argument types were the language forbids forming a reference, namely void types and function types that have cv-qualifiers or a ref-qualifier.

But the current wording in Table 49 defining the predicate condition,

is_constructible<T, const T&>::value is true.

leaves it open whether such argument types would (a) create a well-formed instantiation of the trait template or if so (b) what the outcome of the trait evaluation would be, as an example consider std::is_copy_constructible<void>.

Current implementations differ, e.g. gcc accepts the instantiation and returns a false result, VS 2012 also accepts the instantiation but returns true.

I would suggest that the wording clarifies that the instantiation would be valid for these types and I also would strongly prefer the outcome that the trait would always return false for these types. The latter seems rather natural to me, because there is no way to define a variable of void type or of function type at all, so it would be surprising to return a positive result for copy or move construction if no other construction could succeed. It is also not possible to assign to a any of these values (because there is no way to form lvalues of them), so the same argumentation can be applied to the is_copy/move_assignable traits as well.

To reduce the amount of wording changes and repetitions, I suggest to define the term referenceable type in sub-clause 17.3 [definitions] or alternatively in the core language to describe types to which references can be created via a typedef name. This definition corresponds to what the support concept ReferentType intended to describe during concept time.

In addition, LWG issue 2101 can also take advantage of the definition of a referenceable type.

If the proposed resolution for LWG issue 2101 would be accepted, there is an alternative solution possible with the same effects. Now we would be able to use the now always well-formed instantiation of std::add_lvalue_reference to modify the current definition of is_copy_constructible to

is_constructible<T,
typename add_lvalue_reference<
typename add_const<T>::type>::type>::value
is true.

and similar changes for the other affected traits.

[2012-10 Portland: Move to Open]

Referencable-type should be defined as "something that can be bound into a reference" or similar, rather than a list of types where that is true today. We can then provide the list of known types that cannot be bound as examples that do not qualify in a note.

Otherwise we are happy with the wording. AJM to redraft the definition and move to Review.

Proposed resolution:

This wording is relative to N3376.

  1. Add the following new definition to 17.3 [definitions] as indicated:

    referenceable type [defns.referenceable]

    An object type, a function type that does not have cv-qualifiers or a ref-qualifier, or a reference type. [Note: The term describes a type to which a reference can be created, including reference types. — end note]

  2. Change Table 49 as indicated:

    Table 49 — Type property predicates
    Template Condition Preconditions
    template <class T>
    struct is_copy_constructible;
    For a referenceable type T, the same result as
    is_constructible<T,
    const T&>::value is true, otherwise false.
    T shall be a complete type,
    (possibly cv-qualified) void, or an
    array of unknown bound.
    template <class T>
    struct is_move_constructible;
    For a referenceable type T, the same result as
    is_constructible<T,
    T&&>::value is true, otherwise false.
    T shall be a complete type,
    (possibly cv-qualified) void, or an
    array of unknown bound.
    template <class T>
    struct is_copy_assignable;
    For a referenceable type T, the same result as
    is_assignable<T&,
    const T&>::value is true, otherwise false.
    T shall be a complete type,
    (possibly cv-qualified) void, or an
    array of unknown bound.
    template <class T>
    struct is_move_assignable;
    For a referenceable type T, the same result as
    is_assignable<T&,
    T&&>::value is true, otherwise false.
    T shall be a complete type,
    (possibly cv-qualified) void, or an
    array of unknown bound.
    template <class T>
    struct is_trivially_copy_constructible;
    For a referenceable type T, the same result as
    is_trivially_constructible<T,
    const T&>::value is true, otherwise false.
    T shall be a complete type,
    (possibly cv-qualified) void, or an
    array of unknown bound.
    template <class T>
    struct is_trivially_move_constructible;
    For a referenceable type T, the same result as
    is_trivially_constructible<T,
    T&&>::value is true, otherwise false.
    T shall be a complete type,
    (possibly cv-qualified) void, or an
    array of unknown bound.
    template <class T>
    struct is_trivially_copy_assignable;
    For a referenceable type T, the same result as
    is_trivially_assignable<T&,
    const T&>::value is true, otherwise false.
    T shall be a complete type,
    (possibly cv-qualified) void, or an
    array of unknown bound.
    template <class T>
    struct is_trivially_move_assignable;
    For a referenceable type T, the same result as
    is_trivially_assignable<T&,
    T&&>::value is true, otherwise false.
    T shall be a complete type,
    (possibly cv-qualified) void, or an
    array of unknown bound.
    template <class T>
    struct is_nothrow_copy_constructible;
    For a referenceable type T, the same result as
    is_nothrow_constructible<T,
    const T&>::value is true, otherwise false.
    T shall be a complete type,
    (possibly cv-qualified) void, or an
    array of unknown bound.
    template <class T>
    struct is_nothrow_move_constructible;
    For a referenceable type T, the same result as
    is_nothrow_constructible<T,
    T&&>::value is true, otherwise false.
    T shall be a complete type,
    (possibly cv-qualified) void, or an
    array of unknown bound.
    template <class T>
    struct is_nothrow_copy_assignable;
    For a referenceable type T, the same result as
    is_nothrow_assignable<T&,
    const T&>::value is true, otherwise false.
    T shall be a complete type,
    (possibly cv-qualified) void, or an
    array of unknown bound.
    template <class T>
    struct is_nothrow_move_assignable;
    For a referenceable type T, the same result as
    is_nothrow_assignable<T&,
    T&&>::value is true, otherwise false.
    T shall be a complete type,
    (possibly cv-qualified) void, or an
    array of unknown bound.

2197. Specification of is_[un]signed unclear for non-arithmetic types

Section: 20.9.4.3 [meta.unary.prop] Status: Tentatively Ready Submitter: Daniel Krügler Opened: 2012-10-07 Last modified: 2013-03-18

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

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

View all issues with Tentatively Ready status.

Discussion:

The pre-conditions for the trait is_signed allow for any types as template arguments, including non-arithmetic ones.

But the current wording in Table 49 defining the predicate condition,

is_arithmetic<T>::value && T(-1) < T(0)

looks like real code and so leaves it open whether such argument types would create a well-formed instantiation of the trait template or not. As written this definition would lead to a hard instantiation error for a non-arithmetic type like e.g.

struct S {};

I would suggest that the wording clarifies that the instantiation would be valid for such types as well, by means of a specification that is not an exact code pattern. This also reflects how existing implementations behave.

[2013-03-15 Issues Teleconference]

Moved to Tentatively Ready.

Proposed resolution:

This wording is relative to N3376.

  1. Change Table 49 as indicated:

    Table 49 — Type property predicates
    Template Condition Preconditions
    template <class T>
    struct is_signed;
    If is_arithmetic<T>::value && is true, the same result as
    integral_constant<bool, T(-1) < T(0)>::value;
    otherwise, false.
     
    template <class T>
    struct is_unsigned;
    If is_arithmetic<T>::value && is true, the same result as
    integral_constant<bool, T(0) < T(-1)>::value;
    otherwise, false.
     

2198. max_load_factor(z) makes no strong guarantees, but bans useful behavior

Section: 23.2.5 [unord.req] Status: Open Submitter: Alisdair Meredith Opened: 2012-10-09 Last modified: 2013-03-18

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.

Proposed resolution:


2199. unordered containers are required to have an initial max load factor of 1.0

Section: 23.2.5 [unord.req] Status: Open Submitter: Alisdair Meredith Opened: 2012-10-09 Last modified: 2013-03-18

View other active issues in [unord.req].

View all other issues in [unord.req].

View all issues with Open status.

Discussion:

The default constructor, allocator-aware constructor, and range-based constructors for the unordered containers do not offer a means to control the initial max_load_factor, so the standard mandates the value 1.0. This seems overly restrictive, as there is plenty of research suggesting a value between 0.5 and 1.0 is more often optimal for unique-key containers, and perhaps a slightly higher value might be appropriate for multi-containers.

Rather than guess at the appropriate max_load_factor, it seems reasonable that the standard should allow vendors to pick a value at their discretion, with perhaps a note of advice. It is less clear whether the default value should be implementation-defined or unspecified, given the ease of a user determining this by querying this attribute immediately after construction.

[2013-03-15 Issues Teleconference]

Moved to Open.

Alisdair to provide wording.

Marshall: It seems to me that what you really want is to be able to pass a max load factor in the constructor, but that's a different issue.

Alisdair agrees in principle, but concerned with adding yet more constructors to these classes.

Proposed resolution:


2200. Data race avoidance for all containers, not only for sequences

Section: 23.2.2 [container.requirements.dataraces] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2012-10-17 Last modified: 2013-03-18

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

View all issues with Tentatively Ready status.

Discussion:

23.2.2 [container.requirements.dataraces]/2 says "[…] implementations are required to avoid data races when the contents of the contained object in different elements in the same sequence, excepting vector<bool>, are modified concurrently."

This should say "same container" instead of "same sequence", to avoid the interpretation that it only applies to sequence containers.

[2013-03-15 Issues Teleconference]

Moved to Tentatively Ready.

Proposed resolution:

This wording is relative to N3376.

  1. Change 23.2.2 [container.requirements.dataraces]/2 as indicated:

    -2- Notwithstanding (17.6.5.9 [res.on.data.races]), implementations are required to avoid data races when the contents of the contained object in different elements in the same sequencecontainer, excepting vector<bool>, are modified concurrently.

    -3- [Note: For a vector<int> x with a size greater than one, x[1] = 5 and *x.begin() = 10 can be executed concurrently without a data race, but x[0] = 5 and *x.begin() = 10 executed concurrently may result in a data race. As an exception to the general rule, for a vector<bool> y, y[0] = true may race with y[1] = true. — end note ]


2201. Missing macro entries from C standard library

Section: C.2 [diff.library] Status: New Submitter: Kevin McCarty Opened: 2012-02-03 Last modified: 2012-11-14

View all other issues in [diff.library].

View all issues with New status.

Discussion:

It seems that in C.2 [diff.library], Table 150 the following macros from 18.3.3 [c.limits], Table 31 are missing:

LLONG_MIN 
LLONG_MAX
ULLONG_MAX

In addition in C.2 [diff.library], Table 150 the following macros from 18.3.3 [c.limits], Table 32 are missing:

DECIMAL_DIG 
FLT_EVAL_METHOD

Furtheron it seems that in C.2 [diff.library], Table 149/150 further macros are missing as well, e.g. HUGE_VALF, INFINITY, etc.

Proposed resolution:


2202. Missing allocator support by async

Section: 30.6.8 [futures.async] Status: New Submitter: Detlef Vollmann Opened: 2012-10-19 Last modified: 2012-11-14

View other active issues in [futures.async].

View all other issues in [futures.async].

View all issues with New status.

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.

Proposed resolution:


2203. scoped_allocator_adaptor uses wrong argument types for piecewise construction

Section: 20.12.4 [allocator.adaptor.members] Status: Review Submitter: Jonathan Wakely Opened: 2012-10-19 Last modified: 2013-03-18

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

View all issues with Review status.

Discussion:

In 20.12.4 [allocator.adaptor.members] paragraph 11 the effects clause says a tuple should be constructed with inner_allocator_type(), but that creates an rvalue which cannot bind to inner_allocator_type&, and would also be wrong if this->inner_allocator() != inner_allocator_type(). This could be considered editorial, since the current wording doesn't even compile.

Secondly, in the same paragraph, the tuple objects xprime and yprime seem to be lvalues and might be constructed by copying x and y. This prevents using scoped_allocator to construct pairs from arguments of move-only types. I believe the tuple_cast() expressions should use std::move(x) and std::move(y) to move from the incoming arguments (which are passed by value to candidates for moving) and the final sentence of the paragraph should be:

then calls OUTERMOST_ALLOC_TRAITS(*this)::construct(OUTERMOST (*this), p, piecewise_construct, std::move(xprime), std::move(yprime)).

so that the objects are passed to std::pair's piecewise constructor as rvalues and are eligible for moving into the constructor arguments. This could also be considered editorial, as the current wording prevents certain uses which were intended to be supported.

I've implemented these changes and can confirm they allow code to work that can't be compiled according to the current wording.

[2013-03-15 Issues Teleconference]

Moved to Review.

The resolution looks good, with wording provided by a recent implementer. However, it will take more time than the telecon allows to review with confidence, and we would like Pablo to at least take a look over the resolution and confirm that it matches the design intent.

Proposed resolution:

This wording is relative to N3376.

  1. Change 20.12.4 [allocator.adaptor.members] paragraph 11 as indicated:

    -11- Effects: Constructs a tuple object xprime from x by the following rules:

    • If uses_allocator<T1, inner_allocator_type>::value is false and is_constructible<T1, Args1...>::value is true, then xprime is x.

    • Otherwise, if uses_allocator<T1, inner_allocator_type>::value is true and is_constructible<T1, allocator_arg_t, inner_allocator_type, Args1...>::value is true, then xprime is tuple_cat(tuple<allocator_arg_t, inner_allocator_type&>( allocator_arg, inner_allocator_type()), std::move(x)).

    • Otherwise, if uses_allocator<T1, inner_allocator_type>::value is true and is_constructible<T1, Args1..., inner_allocator_type>::value is true, then xprime is tuple_cat(std::move(x), tuple<inner_allocator_type&>(inner_allocator_type())).

    • Otherwise, the program is ill-formed.

    and constructs a tuple object yprime from y by the following rules:

    • If uses_allocator<T2, inner_allocator_type>::value is false and is_constructible<T2, Args2...>::value is true, then yprime is y.

    • Otherwise, if uses_allocator<T2, inner_allocator_type>::value is true and is_constructible<T2, allocator_arg_t, inner_allocator_type, Args2...>::value is true, then yprime is tuple_cat(tuple<allocator_arg_t, inner_allocator_type&>( allocator_arg, inner_allocator_type()), std::move(y)).

    • Otherwise, if uses_allocator<T2, inner_allocator_type>::value is true and is_constructible<T2, Args2..., inner_allocator_type>::value is true, then yprime is tuple_cat(std::move(y), tuple<inner_allocator_type&>(inner_allocator_type())).

    • Otherwise, the program is ill-formed.

    then calls OUTERMOST_ALLOC_TRAITS(*this)::construct(OUTERMOST(*this), p, piecewise_construct, std::move(xprime), std::move(yprime)).


2204. reverse_iterator should not require a second copy of the base iterator

Section: 24.5.1.3.4 [reverse.iter.op.star] Status: New Submitter: David Abrahams Opened: 2012-10-30 Last modified: 2012-11-14

View all issues with New status.

Discussion:

This note in 24.5.1.3.4 [reverse.iter.op.star]/2:

[ Note: This operation must use an auxiliary member variable rather than a temporary variable to avoid returning a reference that persists beyond the lifetime of its associated iterator. (See 24.2.) —end note ]

is incorrect because such iterator implementations are ruled out by 24.2.5 [forward.iterators]/6, where it says:

If a and b are both dereferenceable, then a == b if and only if *a and *b are bound to the same object.

Proposed resolution:

Strike the note, 24.5.1.3.4 [reverse.iter.op.star]/2:

[ Note: This operation must use an auxiliary member variable rather than a temporary variable to avoid returning a reference that persists beyond the lifetime of its associated iterator. (See 24.2.) —end note ]

2205. Problematic postconditions of regex_match and regex_search

Section: 28.11.2 [re.alg.match], 28.11.3 [re.alg.search] Status: New Submitter: Pete Becker Opened: 2012-10-24 Last modified: 2012-11-14

View all issues with New status.

Discussion:

Table 142 lists post-conditions on the match_results object when a call to regex_match succeeds. regex_match is required to match the entire target sequence. The post-condition for m[0].matched is "true if a full match was found." Since these are conditions for a successful search which is, by definition, a full match, the post-condition should be simply "true".

There's an analogous probem in Table 143: the condition for m[0].matched is "true if a match was found, false otherwise." But Table 143 gives post-conditions for a successful match, so the condition should be simply "true".

Furthermore, they have explicit requirements for m[0].first, m[0].second, and m[0].matched. They also have requirements for the other elements of m, described as m[n].first, m[n].second, and m[n].matched, in each case qualifying the value of n as "for n < m.size()". Since there is an explicit description for n == 0, this qualification should be "for 0 < n < m.size()" in all 6 places.

Proposed resolution:

This wording is relative to N3376.

  1. Change Table 142 as indicated:

    Table 142 — Effects of regex_match algorithm
    Element Value
    m[0].first first
    m[0].second last
    m[0].matched true if a full match was found.
    m[n].first For all integers 0 < n < m.size(), the start of the sequence that matched sub-expression n.
    Alternatively, if subexpression n did not participate in the match, then last.
    m[n].second For all integers 0 < n < m.size(), the end of the sequence that matched sub-expression n.
    Alternatively, if sub-expression n did not participate in the match, then last.
    m[n].matched For all integers 0 < n < m.size(), true if sub-expression n participated in the match, false otherwise.
  2. Change Table 143 as indicated:

    Table 143 — Effects of regex_search algorithm
    Element Value
    m[0].first The start of the sequence of characters that matched the regular expression
    m[0].second The end of the sequence of characters that matched the regular expression
    m[0].matched true if a match was found, and false otherwise.
    m[n].first For all integers 0 < n < m.size(), the start of the sequence that matched sub-expression n.
    Alternatively, if subexpression n did not participate in the match, then last.
    m[n].second For all integers 0 < n < m.size(), the end of the sequence that matched sub-expression n.
    Alternatively, if sub-expression n did not participate in the match, then last.
    m[n].matched For all integers 0 < n < m.size(), true if sub-expression n participated in the match, false otherwise.

2206. Inaccuracy in initializer_list constructor requirements

Section: 23.2.3 [sequence.reqmts], 23.2.4 [associative.reqmts], 23.2.5 [unord.req], 26.5.1.2 [rand.req.seedseq] Status: Open Submitter: Jeffrey Yasskin Opened: 2012-10-21 Last modified: 2013-03-18

View other active issues in [sequence.reqmts].

View all other issues in [sequence.reqmts].

View all issues with Open status.

Discussion:

In 23.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 23.2.4 [associative.reqmts], 23.2.5 [unord.req], and 26.5.1.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.

Proposed resolution:


2207. basic_string::at should not have a Requires clause

Section: 21.4.5 [string.access] Status: Review Submitter: Nevin Liber Opened: 2012-10-26 Last modified: 2013-03-18

View all other issues in [string.access].

View all issues with Review status.

Discussion:

basic_string::at() has a wide contract and should not have a "Requires" clause on it.

[2013-01-17, Juan Soulie comments]

This issue would also apply to every member function of basic_string that throws out_of_range, and to some cases where a length_error can be thrown.

[2013-03-15 Issues Teleconference]

Moved to Review.

While this could simply move to Ready on inspection, there is concern that this will not be the only such case. Alisdair volunteers to review clause 21/23 for more of such issues for Bristol, and update the proposed resolution as necessary.

Proposed resolution:

This wording is relative to N3376.

  1. Remove 21.4.5 [string.access] p5:

    const_reference at(size_type pos) const;
    reference at(size_type pos);
    

    -5- Requires: pos < size()

    -6- Throws: out_of_range if pos >= size().

    -7- Returns: operator[](pos).


2208. std::reverse_iterator should be a literal type

Section: 24.5.1 [reverse.iterators] Status: New Submitter: Jeffrey Yasskin Opened: 2012-10-30 Last modified: 2012-11-14

View all other issues in [reverse.iterators].

View all issues with New status.

Discussion:

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

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

Proposed resolution:


2209. assign() overspecified for sequence containers

Section: 23.3 [sequences] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2012-10-31 Last modified: 2013-03-18

View other active issues in [sequences].

View all other issues in [sequences].

View all issues with Tentatively Ready status.

Discussion:

DR 704 ensures allocator-aware containers can reuse existing elements during copy/move assignment, and sequence containers can do the same for assign().

But apart from std::list (which was changed by DR 320) the sequence containers define the Effects of assign() in terms of clear() followed by insert. A user-defined allocator can easily tell whether all old elements are cleared and then new elements inserted or whether existing elements are assigned to, so those Effects clauses cannot be ignored via the as-if rule.

The descriptions of the assign() members for deque, forward_list and vector should be removed. Their intended effects are entirely described by the sequence container requirements table, and the specific definitions of them are worse than redundant, they're contradictory (if the operations are defined in terms of erase and insert then there's no need for elements to be assignable.) The descriptions of assign() for list are correct but redundant, so should be removed too.

[2013-03-15 Issues Teleconference]

Moved to Tentatively Ready.

Proposed resolution:

This wording is relative to N3376.

  1. Edit 23.3.3.2 [deque.cons] to remove everything after paragraph 10:

    template <class InputIterator>
    void assign(InputIterator first, InputIterator last);
    

    -11- Effects:

    erase(begin(), end());
    insert(begin(), first, last);
    
    void assign(size_type n, const T& t);
    

    -12- Effects:

    erase(begin(), end());
    insert(begin(), n, t);
    
  2. Edit 23.3.4.2 [forwardlist.cons] to remove everything after paragraph 10:

    template <class InputIterator>
    void assign(InputIterator first, InputIterator last);
    

    -11- Effects: clear(); insert_after(before_begin(), first, last);

    void assign(size_type n, const T& t);
    

    -12- Effects: clear(); insert_after(before_begin(), n, t);

  3. Edit 23.3.5.2 [list.cons] to remove everything after paragraph 10:

    template <class InputIterator>
    void assign(InputIterator first, InputIterator last);
    

    -11- Effects: Replaces the contents of the list with the range [first, last).

    void assign(size_type n, const T& t);
    

    -12- Effects: Replaces the contents of the list with n copies of t.

  4. Edit 23.3.6.2 [vector.cons] to remove everything after paragraph 10:

    template <class InputIterator>
    void assign(InputIterator first, InputIterator last);
    

    -11- Effects:

    erase(begin(), end());
    insert(begin(), first, last);
    
    void assign(size_type n, const T& t);
    

    -12- Effects:

    erase(begin(), end());
    insert(begin(), n, t);
    

2210. Missing allocator-extended constructor for allocator-aware containers

Section: 23.3 [sequences], 23.4 [associative], 23.5 [unord] Status: Review Submitter: Jonathan Wakely Opened: 2012-11-01 Last modified: 2013-03-18

View other active issues in [sequences].

View all other issues in [sequences].

View all issues with Review status.

Discussion:

The forward_list(size_type) constructor has no allocator-extended equivalent, preventing the following code from compiling:

#include <forward_list>
#include <vector>
#include <scoped_allocator>

using namespace std;

int main()
{
  using list = forward_list<int>;
  vector<list, scoped_allocator_adaptor<list::allocator_type>> v;
  v.emplace_back(1u);
}

The very same problem exists for all allocator-aware sequence containers.

In addition it exists for associative containers. For example, it's possible to construct std::set<int>{0, 1, 2} but not std::set<int>{{0, 1, 2}, alloc}, and possible to construct std::set<int>{begin, end} but not std::set<int>{begin, end, alloc}.

This makes the following program fail when SCOPED is defined:

#include <set>
#include <vector>
#include <scoped_allocator>

#if SCOPED
using A = std::scoped_allocator_adaptor<std::allocator<int>>;
#else
using A = std::allocator<int>;
#endif

int main()
{
  int values[] = {0, 1, 2};
  std::vector<std::set<int>, A> v;
  v.emplace_back(std::begin(values), std::end(values));
}

[2013-03-15 Issues Teleconference]

Moved to Review.

Johnathon: There are lots of places where this is missing.

Howard: We should ping Pablo, this might be a deliberate design decision.

Proposed resolution:

This wording is relative to N3485.

  1. Edit the synopsis in 23.3.3.1 [deque.overview]/2:

    namespace std {
      template <class T, class Allocator = allocator<T> >
      class deque {
      public:
        […]
        explicit deque(const Allocator& = Allocator());
        explicit deque(size_type n, const Allocator& = Allocator());
        […]
      };
    }
    
  2. Edit 23.3.3.2 [deque.cons]/2:

    explicit deque(size_type n, const Allocator& = Allocator());
    

    -3- Effects: Constructs a deque with n default-inserted elements using the specified allocator.

  3. Edit the synopsis in 23.3.4.1 [forwardlist.overview]/3:

    namespace std {
      template <class T, class Allocator = allocator<T> >
      class forward_list {
      public:
        […]
        explicit forward_list(const Allocator& = Allocator());
        explicit forward_list(size_type n, const Allocator& = Allocator());
        […]
      };
    }
    
  4. Edit 23.3.4.2 [forwardlist.cons]/3:

    explicit forward_list(size_type n, const Allocator& = Allocator());
    

    -3- Effects: Constructs a forward_list object with n default-inserted elements using the specified allocator.

  5. Edit the synopsis in 23.3.5.1 [list.overview]/2:

    namespace std {
      template <class T, class Allocator = allocator<T> >
      class list {
      public:
        […]
        explicit list(const Allocator& = Allocator());
        explicit list(size_type n, const Allocator& = Allocator());
        […]
      };
    }
    
  6. Edit 23.3.5.2 [list.cons]/3:

    explicit list(size_type n, const Allocator& = Allocator());
    

    -3- Effects: Constructs a list with n default-inserted elements using the specified allocator.

  7. Edit the synopsis in 23.3.6.1 [vector.overview]/2:

    namespace std {
      template <class T, class Allocator = allocator<T> >
      class vector {
      public:
        […]
        explicit vector(const Allocator& = Allocator());
        explicit vector(size_type n, const Allocator& = Allocator());
        […]
      };
    }
    
  8. Edit 23.3.6.2 [vector.cons]/3:

    explicit vector(size_type n, const Allocator& = Allocator());
    

    -3- Effects: Constructs a vector with n default-inserted elements using the specified allocator.

  9. Edit the synopsis in 23.3.7 [vector.bool]/1:

    namespace std {
      template <class Allocator> class vector<bool, Allocator> {
      class vector {
      public:
        […]
        explicit vector(const Allocator& = Allocator());
        explicit vector(size_type n, const Allocator& = Allocator());
        explicit vector(size_type n, const bool& value = bool(),
                        const Allocator& = Allocator());
        […]
      };
    }
    
  10. Add to the synopsis in 23.4.4.1 [map.overview] p2:

    namespace std {
      template <class Key, class T, class Compare = less<Key>,
        class Allocator = allocator<pair<const Key, T> > > {
      class map {
      public:
        […]
        map(initializer_list<value_type>,
          const Compare& = Compare(),
          const Allocator& = Allocator());
        template <class InputIterator>
        map(InputIterator first, InputIterator last, const Allocator& a)
          : map(first, last, Compare(), a) { }
        map(initializer_list<value_type> il, const Allocator& a)
          : map(il, Compare(), a) { }
        ~map();
        […]
      };
    }
    
  11. Add to the synopsis in 23.4.5.1 [multimap.overview] p2:

    namespace std {
      template <class Key, class T, class Compare = less<Key>,
        class Allocator = allocator<pair<const Key, T> > > {
      class multimap {
      public:
        […]
        multimap(initializer_list<value_type>,
          const Compare& = Compare(),
          const Allocator& = Allocator());
        template <class InputIterator>
        multimap(InputIterator first, InputIterator last, const Allocator& a)
          : multimap(first, last, Compare(), a) { }
        multimap(initializer_list<value_type> il, const Allocator& a)
          : multimap(il, Compare(), a) { }
        ~multimap();
        […]
      };
    }
    
  12. Add to the synopsis in 23.4.6.1 [set.overview] p2:

    namespace std {
      template <class Key, class Compare = less<Key>,
        class Allocator = allocator<Key> > {
      class set {
      public:
        […]
        set(initializer_list<value_type>,
          const Compare& = Compare(),
          const Allocator& = Allocator());
        template <class InputIterator>
        set(InputIterator first, InputIterator last, const Allocator& a)
          : set(first, last, Compare(), a) { }
        set(initializer_list<value_type> il, const Allocator& a)
          : set(il, Compare(), a) { }
        ~set();
        […]
      };
    }
    
  13. Add to the synopsis in 23.4.7.1 [multiset.overview] p2:

    namespace std {
      template <class Key, class Compare = less<Key>,
        class Allocator = allocator<Key> > {
      class multiset {
      public:
        […]
        multiset(initializer_list<value_type>,
          const Compare& = Compare(),
          const Allocator& = Allocator());
        template <class InputIterator>
        multiset(InputIterator first, InputIterator last, const Allocator& a)
          : multiset(first, last, Compare(), a) { }
        multiset(initializer_list<value_type> il, const Allocator& a)
          : multiset(il, Compare(), a) { }
        ~multiset();
        […]
      };
    }
    
  14. Add to the synopsis in 23.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(initializer_list<value_type>,
          size_type = see below,
          const hasher& hf = hasher(),
          const key_equal& eql = key_equal(),
          const allocator_type& a = allocator_type());
        unordered_map(size_type n, const allocator_type& a)
          : unordered_map(n, hasher(), key_equal(), a) { }
        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, 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, size_type n, const allocator_type& a)
          : unordered_map(il, n, hasher(), key_equal(), a) { }
        unordered_map(initializer_list<value_type> il, size_type n, const hasher& hf, 
    	  const allocator_type& a)
          : unordered_map(il, n, hf, key_equal(), a) { }
        ~unordered_map();
        […]
      };
    }
    
  15. Add to the synopsis in 23.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(initializer_list<value_type>,
          size_type = see below,
          const hasher& hf = hasher(),
          const key_equal& eql = key_equal(),
          const allocator_type& a = allocator_type());
        unordered_multimap(size_type n, const allocator_type& a)
          : unordered_multimap(n, hasher(), key_equal(), a) { }
        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, 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, size_type n, const allocator_type& a)
          : unordered_multimap(il, n, hasher(), key_equal(), a) { }
        unordered_multimap(initializer_list<value_type> il, size_type n, const hasher& hf, 
    	  const allocator_type& a)
          : unordered_multimap(il, n, hf, key_equal(), a) { }
        ~unordered_multimap();
        […]
      };
    }
    
  16. Add to the synopsis in 23.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(initializer_list<value_type>,
          size_type = see below,
          const hasher& hf = hasher(),
          const key_equal& eql = key_equal(),
          const allocator_type& a = allocator_type());
        unordered_set(size_type n, const allocator_type& a)
          : unordered_set(n, hasher(), key_equal(), a) { }
        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, 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, size_type n, const allocator_type& a)
          : unordered_set(il, n, hasher(), key_equal(), a) { }
        unordered_set(initializer_list<value_type> il, size_type n, const hasher& hf, 
    	  const allocator_type& a)
          : unordered_set(il, n, hf, key_equal(), a) { }
        ~unordered_set();
        […]
      };
    }
    
  17. Add to the synopsis in 23.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(initializer_list<value_type>,
          size_type = see below,
          const hasher& hf = hasher(),
          const key_equal& eql = key_equal(),
          const allocator_type& a = allocator_type());
        unordered_multiset(size_type n, const allocator_type& a)
          : unordered_multiset(n, hasher(), key_equal(), a) { }
        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, 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, size_type n, const allocator_type& a)
          : unordered_multiset(il, n, hasher(), key_equal(), a) { }
        unordered_multiset(initializer_list<value_type> il, size_type n, const hasher& hf, 
    	  const allocator_type& a)
          : unordered_multiset(il, n, hf, key_equal(), a) { }
        ~unordered_multiset();
        […]
      };
    }
    

2211. Replace ambiguous use of "Allocator" in container requirements

Section: 23.2.1 [container.requirements.general] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2012-11-07 Last modified: 2013-03-18

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

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

View all issues with Tentatively Ready status.

Discussion:

23.2.1 [container.requirements.general]/7 says:

All other constructors for these container types take an Allocator& argument (17.6.3.5 [allocator.requirements]), an allocator whose value type is the same as the container's value type.

This is a strange place to state the requirement on the allocator's value_type, because the allocator is a property (and template parameter) of the container type not of some of its constructors. It's also unclear whether "Allocator&" refers to the concept (as implied by the cross-reference to the allocator requirements in Clause 17) or to the container's template parameter (as implied by the fact it's shown as an lvalue-reference type.) I believe the latter is intended, because those constructors can't take any model of the allocator concept, they can only take the container's allocator_type.

I think it would be clearer to remove the value type requirement earlier in the paragraph (Table 99 already imposes that requirement) and to make it clear the constructor arguments are the container's allocator_type. There is already a cross-reference to the allocator requirements earlier in the paragraph, so it doesn't need to be repeated in another place where it causes confusion.

[2013-03-15 Issues Teleconference]

Moved to Tentatively Ready.

Proposed resolution:

This wording is relative to N3485.

  1. Edit 23.2.1 [container.requirements.general] paragraph 7:

    Unless otherwise specified, all containers defined in this clause obtain memory using an allocator (see 17.6.3.5 [allocator.requirements]). Copy constructors for these container types obtain an allocator by calling allocator_traits<allocator_type>::select_on_container_copy_construction on their first parameters. Move constructors obtain an allocator by move construction from the allocator belonging to the container being moved. Such move construction of the allocator shall not exit via an exception. All other constructors for these container types take an Allocator& argument (17.6.3.5 [allocator.requirements]), an allocator whose value type is the same as the container's value typea const allocator_type& argument. [Note: If an invocation of a constructor uses the default value of an optional allocator argument, then the Allocator type must support value initialization. — end note] A copy of this allocator is used for any memory allocation performed, by these constructors and by all member functions, during the lifetime of each container object or until the allocator is replaced. […]


2212. tuple_size for const pair request <tuple> header

Section: 20.2 [utility] Status: Open Submitter: Alisdair Meredith Opened: 2012-11-09 Last modified: 2013-03-18

View all other issues in [utility].

View all issues with Open status.

Discussion:

The <utility> header declares sufficient of the tuple API to specialize the necessary templates for pair, notably tuple_size and tuple_element. However, it does not make available the partial specializations that support cv-qualified template arguments, so while I can write the following after including only <utility>:

#include <utility>

using TestType = std::pair<int, int>;
static_assert(2 == std::tuple_size<TestType>(), "Pairs have two elements");
std::tuple_element<0, TestType>::type var{1};

the following may fail to compile unless I also include <tuple>:

#include <utility>

using TestType = const std::pair<int, int>;
static_assert(2 == std::tuple_size<TestType>(), "Pairs have two elements");
std::tuple_element<0, TestType>::type var{1};

Note, however, that the latter may compile with some standard library implementations but not others, leading to subtle portability issues.

[2013-03-15 Issues Teleconference]

Moved to Open.

Howard notes that we have the same issue with array, so any resolution should apply to that header too.

Proposed resolution:


2213. Return value of std::regex_replace

Section: 28.11.4 [re.alg.replace] Status: New Submitter: Pete Becker Opened: 2012-11-08 Last modified: 2012-11-14

View other active issues in [re.alg.replace].

View all other issues in [re.alg.replace].

View all issues with New status.

Discussion:

In 28.11.4 [re.alg.replace], the first two variants of std::regex_replace take an output iterator named "out" as their first argument. Paragraph 2 of that section says that the functions return "out". When I first implemented this, many years ago, I wrote it to return the value of the output iterator after all the insertions (cf. std::copy), which seems like the most useful behavior. But looking at the requirement now, it like the functions should return the original value of "out" (i.e. they have to keep a copy of the iterator for no reason except to return it). Is that really what was intended?

Proposed resolution:

This wording is relative to N3485.

  1. Edit 28.11.4 [re.alg.replace] as indicated:

    template <class OutputIterator, class BidirectionalIterator,
      class traits, class charT, class ST, class SA>
    OutputIterator
    regex_replace(OutputIterator out, BidirectionalIterator first, BidirectionalIterator last,
      const basic_regex<charT, traits>& e, const basic_string<charT, ST, SA>& fmt,
      regex_constants::match_flag_type flags = regex_constants::match_default);
    template <class OutputIterator, class BidirectionalIterator,
      class traits, class charT>
    OutputIterator
    regex_replace(OutputIterator out, BidirectionalIterator first, BidirectionalIterator last,
      const basic_regex<charT, traits>& e, const charT* fmt,
      regex_constants::match_flag_type flags = regex_constants::match_default);
    

    -1- Effects: Constructs a regex_iterator object i as if by regex_iterator<BidirectionalIterator, charT, traits> i(first, last, e, flags), and uses i to enumerate through all of the matches m of type match_results<BidirectionalIterator> that occur within the sequence [first, last). If no such matches are found and !(flags & regex_constants ::format_no_copy) then calls out = std::copy(first, last, out). If any matches are found then, for each such match, if !(flags & regex_constants::format_no_copy), calls out = std::copy(m.prefix().first, m.prefix().second, out), and then calls out = m.format(out, fmt, flags) for the first form of the function and out = m.format(out, fmt, fmt + char_traits<charT>::length(fmt), flags) for the second. Finally, if such a match is found and !(flags & regex_constants ::format_no_copy), calls out = std::copy(last_m.suffix().first, last_m.suffix().second, out) where last_m is a copy of the last match found. If flags & regex_constants::format_first_only is non-zero then only the first match found is replaced.

    -2- Returns: out.


2214. Clarify basic_ios::init call restrictions

Section: 27.5.5.2 [basic.ios.cons] Status: New Submitter: Andrey Semashev Opened: 2012-11-09 Last modified: 2012-11-14

View all other issues in [basic.ios.cons].

View all issues with New status.

Discussion:

There is an ambiguity in how std::basic_ios::init method (27.5.5.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 (27.5.5.2 [basic.ios.cons]) there is this sentence:

Effects: Constructs an object of class basic_ios (27.5.3.7 [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 (27.5.3 [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 (27.5.3.7 [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.

Proposed resolution:

This wording is relative to N3485.

  1. Edit 27.5.5.2 [basic.ios.cons] as indicated:

    basic_ios();
    

    -2- Effects: Constructs an object of class basic_ios (27.5.3.7 [ios.base.cons]) leaving its member objects uninitializedinitializing 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. (unordered) associative container functors should be CopyConstructible

Section: 23.2.4 [associative.reqmts], 23.2.5 [unord.req] Status: Open Submitter: Alisdair Meredith Opened: 2012-11-14 Last modified: 2013-03-18

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

Proposed resolution:


2216. regex_replace(basic_string) allocator handling

Section: 28.11.4 [re.alg.replace] Status: New Submitter: Jeffrey Yasskin Opened: 2012-11-26 Last modified: 2012-11-29

View other active issues in [re.alg.replace].

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:


2217. operator==(sub_match, string) slices on embedded '\0's

Section: 28.9.2 [re.submatch.op] Status: New Submitter: Jeffrey Yasskin Opened: 2012-11-26 Last modified: 2012-11-29

View all other issues in [re.submatch.op].

View all issues with New status.

Discussion:

template <class BiIter, class ST, class SA>
  bool operator==(
    const basic_string<
      typename iterator_traits<BiIter>::value_type, ST, SA>& lhs,
    const sub_match<BiIter>& rhs);

is specified as:

Returns: rhs.compare(lhs.c_str()) == 0.

This is odd because sub_match::compare(basic_string) is defined to honor embedded '\0' characters. This could allow a sub_match to == or != a std::string unexpectedly.

[Daniel:]

This wording change was done intentionally as of LWG 1181, but the here mentioned slicing effect was not considered at that time. It seems best to use another overload of compare to fix this problem:

Returns: rhs.str().compare(0, rhs.length(), lhs.data(), lhs.size()) == 0.

or

Returns: rhs.compare(sub_match<BiIter>::string_type(lhs.data(), lhs.size())) == 0.

Proposed resolution:


2218. Unclear how containers use allocator_traits::construct()

Section: 23.2.1 [container.requirements.general] Status: Open Submitter: Jonathan Wakely Opened: 2012-11-27 Last modified: 2013-03-18

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

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

View all issues with Open status.

Discussion:

Firstly, 23.2.1 [container.requirements.general]/7 says a container's allocator is used to obtain memory, but it isn't stated explicitly that the same allocator is used to construct and destroy elements, as opposed to a value-initialized allocator of the same type.

Secondly, 23.2.1 [container.requirements.general]/3 says elements "shall be constructed using the allocator_traits<allocator_type>::construct function and destroyed using the allocator_traits<allocator_type>::destroy function" and 23.2.1 [container.requirements.general]/13 defines CopyInsertable etc. in terms of an allocator A which is identical to the container's allocator_type.

The intent of making construct() and destroy() function templates was that containers would be permitted to use allocator_traits<A>::construct() instead of allocator_traits<allocator_type>::construct(), where A is allocator_traits<allocator_type>::rebind_alloc<U> for some other type U. This allows node-based containers to store an allocator of the right type for allocating nodes and to use the same object to construct elements in aligned storage within those nodes, avoiding rebinding and copying the stored allocator every time an element needs to be constructed.

It should be made clear that possibly-rebound copy of the container's allocator is used for object construction.

[2013-03-15 Issues Teleconference]

Moved to Open.

Johnathan: point 2 in the proposed resolution is definitely needed.

Proposed resolution:

This wording is relative to N3485.

  1. Edit 23.2.1 [container.requirements.general] paragraph 3:

    For the components affected by this subclause that declare an allocator_type, objects stored in these components shall be constructed using the allocator_traits<allocator_type>::rebind_alloc<U>::construct function and destroyed using the allocator_traits<allocator_type>::rebind_alloc<U>::destroy function (20.6.8.2 [allocator.traits.members]), where U is either allocator_type::value_type or an internal type used by the container. These functions are called only for the container's element type, not for internal types used by the container. [ Note: This means, for example, that a node-based container might need to construct nodes containing aligned buffers and call construct to place the element into the buffer. — end note ]

  2. Edit 23.2.1 [container.requirements.general] paragraph 7:

    […] A copy of this allocator is used for any memory allocation and element construction performed, by these constructors and by all member functions, during the lifetime of each container object or until the allocator is replaced. […]

  3. Edit 23.2.1 [container.requirements.general] paragraph 13:

    […] Given an allocator type A and given a container type X having an allocator_type identical to A and a value_type identical to T and an allocator_type identical to allocator_traits<A>::rebind_alloc<T> and given an lvalue m of type A, a pointer p of type T*, an expression v of type (possibly const) T, and an rvalue rv of type T, the following terms are defined.

    […]

    [ Note: A container calls allocator_traits<A>::construct(m, p, args) to construct an element at p using args, with m == get_allocator(). The default construct in std::allocator will call ::new((void*)p) T(args), but specialized allocators may choose a different definition. — end note ]


2219. INVOKE-ing a pointer to member with a reference_wrapper as the object expression

Section: 20.8.2 [func.require] Status: Review Submitter: Jonathan Wakely Opened: 2012-11-28 Last modified: 2013-03-18

View all other issues in [func.require].

View all issues with Review status.

Discussion:

The standard currently requires this to be invalid:

#include <functional>

struct X { int i; } x;
auto f = &X::i;
auto t1 = std::ref(x);
int i = std::mem_fn(f)(t1);

The call expression on the last line is equivalent to INVOKE(f, std::ref(x)) which according to 20.8.2 [func.require]p1 results in the invalid expression (*t1).*f because reference_wrapper<X> is neither an object of type X nor a reference to an object of type X nor a reference to an object of a type derived from X.

The same argument applies to pointers to member functions, and if they don't work with INVOKE it becomes harder to do all sorts of things such as:

call_once(o, &std::thread::join, std::ref(thr))

or

async(&std::list<int>::sort, std::ref(list));

The definition of INVOKE should be extended to handle reference wrappers.

[2013-03-15 Issues Teleconference]

Moved to Review.

The wording seems accurate, but verbose. If possible, we would like to define the kind of thing being specified so carefully as one of a number of potential language constructs in a single place. It is also possible that this clause is that single place.

Proposed resolution:

This wording is relative to N3485.

  1. Edit 20.8.2 [func.require]:

    Define INVOKE(f, t1, t2, ..., tN) as follows:

    • (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T U or an object of type reference_wrapper<U> or a reference to an object of type reference_wrapper<U> where U is either the type T or a type derived from T;

    • ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of the types described in the previous item;

    • t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T U or an object of type reference_wrapper<U> or a reference to an object of type reference_wrapper<U> where U is either the type T or a type derived from T;

    • (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 is not one of the types described in the previous item;

    • f(t1, t2, ..., tN) in all other cases.


2220. Under-specification of operator== for regex_token_iterator

Section: 28.12.2.2 [re.tokiter.comp] Status: New Submitter: Pete Becker Opened: 2012-11-21 Last modified: 2012-12-25

View other active issues in [re.tokiter.comp].

View all other issues in [re.tokiter.comp].

View all issues with New 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

28.12.2.2 [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.

Proposed resolution:


2221. No formatted output operator for nullptr

Section: 28.12.2.2 [re.tokiter.comp] Status: New Submitter: Matt Austern Opened: 2012-12-07 Last modified: 2012-12-25

View other active issues in [re.tokiter.comp].

View all other issues in [re.tokiter.comp].

View all issues with New status.

Discussion:

When I write

std::cout << nullptr << std::endl;

I get a compilation error, "ambiguous overload for 'operator<<' in 'std::cout << nullptr'". As far as I can tell, the compiler is right to issue that error. There are inserters for const void*, const char*, const signed char*, and const unsigned char*, and none for nullptr_t, so the expression really is ambiguous.

Proposed resolution:

The obvious library solution is to add a nullptr_t overload, which would be defined something like

template<class C, class T>
basic_ostream<C, T>& operator<<(basic_ostream<C, T>& os, nullptr_t) 
{ 
  return os << (void*) nullptr; 
}

We might also consider addressing this at a core level: add a special-case language rule that addresses all cases where you write f(nullptr) and f is overloaded on multiple pointer types. (Perhaps a tiebreaker saying that void* is preferred in such cases.)

Proposed resolution:


2222. Inconsistency in description of forward_list::splice_after single-element overload

Section: 23.3.4.6 [forwardlist.ops] Status: Tentatively Ready Submitter: Edward Catmur Opened: 2012-12-11 Last modified: 2013-03-18

View all other issues in [forwardlist.ops].

View all issues with Tentatively Ready status.

Discussion:

23.3.4.6 [forwardlist.ops] p6 has

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

Effects: Inserts the element following i into *this, following position, and removes it from x. The result is unchanged if position == i or position == ++i. Pointers and references to *i continue to refer to the same element but as a member of *this. Iterators to *i (including i itself) continue to refer to the same element, but now behave as iterators into *this, not into x.

This overload splices the element following i from x to *this, so the language in the two latter sentences should refer to ++i:

Pointers and references to *++i continue to refer to the same element but as a member of *this. Iterators to *++i continue to refer to the same element, but now behave as iterators into *this, not into x.

[2013-03-15 Issues Teleconference]

Moved to Tentatively Ready.

Proposed resolution:

This wording is relative to N3485.

  1. Edit 23.3.4.6 [forwardlist.ops] p6 as indicated:

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

    -5- Requires: position is before_begin() or is a dereferenceable iterator in the range [begin(),end()). The iterator following i is a dereferenceable iterator in x. get_allocator() == x.get_allocator().

    -6- Effects: Inserts the element following i into *this, following position, and removes it from x. The result is unchanged if position == i or position == ++i. Pointers and references to *++i continue to refer to the same element but as a member of *this. Iterators to *++i (including i itself) continue to refer to the same element, but now behave as iterators into *this, not into x.


2223. shrink_to_fit effect on iterator validity

Section: 23.3.6.3 [vector.capacity] Status: Review Submitter: Juan Soulie Opened: 2012-12-17 Last modified: 2013-03-18

View other active issues in [vector.capacity].

View all other issues in [vector.capacity].

View all issues with Review status.

Discussion:

After the additions by 2033, it appears clear that the intended effect includes a reallocation and thus the potential effect on iterators should be explicitly added to the text in order to not contradict 23.2.1 [container.requirements.general]/11, or at the very least, explicitly state that a reallocation may happen.

Taking consistency with "reserve" into consideration, I propose:

BTW, while we are at it, I believe the effect on iterators should also be explicitly stated in the other instance a reallocation may happen: 23.3.6.5 [vector.modifiers]/1 — even if obvious, it only contradicts 23.2.1 [container.requirements.general]/11 implicitly.

I propose to also insert "Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence." at the appropriate location in its "Remarks".

[2012-12-19: Jonathan Wakely comments]

The described problem also affects std::basic_string and std::deque.

[2013-03-15 Issues Teleconference]

Moved to Review.

Proposed resolution:

This wording is relative to N3485.

  1. Edit 23.3.6.3 [vector.capacity] around p7 as indicated:

    void shrink_to_fit();
    

    -7- Requires: T shall be MoveInsertable into *this.

    -?- Effects: shrink_to_fit is a non-binding request to reduce capacity() to size(). [Note: The request is non-binding to allow latitude for implementation-specific optimizations. — end note ] Reallocation happens at this point if and only if the function effectively reduces the capacity. If an exception is thrown other than by the move constructor of a non-CopyInsertable T there are no effects.

    -8- Complexity: Linear in the size of the sequence.

    -9- Remarks: shrink_to_fit is a non-binding request to reduce capacity() to size(). [Note: The request is non-binding to allow latitude for implementation-specific optimizations. — end note ] If an exception is thrown other than by the move constructor of a non-CopyInsertable T there are no effects.Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence.

  2. Edit 23.3.6.5 [vector.modifiers] p1 as indicated:

    iterator insert(const_iterator position, const T& x);
    iterator insert(const_iterator position, T&& x);
    iterator insert(const_iterator position, size_type n, const T& x);
    template <class InputIterator>
    iterator insert(const_iterator position, InputIterator first, InputIterator last);
    iterator insert(const_iterator position, initializer_list<T>);
    template <class... Args> void emplace_back(Args&&... args);
    template <class... Args> iterator emplace(const_iterator position, Args&&... args);
    void push_back(const T& x);
    void push_back(T&& x);
    

    -1- Remarks: Causes reallocation if the new size is greater than the old capacity. Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence. 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 by the move constructor of a non-CopyInsertable T, the effects are unspecified.


2224. Ambiguous status of access to non-live objects

Section: 17.6.4.10 [res.on.objects] Status: Open Submitter: Geoffrey Romer Opened: 2012-12-17 Last modified: 2013-03-18

View all other issues in [res.on.objects].

View all issues with Open status.

Discussion:

The standard currently does not discuss when library objects may be accessed, except in a non-normative note pertaining to synchronization in [res.on.objects], leaving it ambiguous whether single-threaded code can access a library object during its construction or destruction. For example, there is a reasonable question as to what happens if the deleter supplied to a unique_ptr transitively accesses the unique_ptr itself during unique_ptr's destruction; a straightforward reading suggests that this is permitted, and that the deleter will see the unique_ptr still holding the originally stored pointer, but consensus on the LWG reflector indicates this was not the intent (see discussion beginning with c++std-lib-33362).

[2013-03-15 Issues Teleconference]

Moved to Open.

Geoffrey will provide an example that clearly highlights the issue.

Proposed resolution:

This wording is relative to N3485.

  1. Change the title of sub-clause 17.6.4.10 [res.on.objects] as indicated:

    Shared objects and the libraryLibrary object access [res.on.objects]

  2. Edit 17.6.4.10 [res.on.objects] p2 as indicated:

    -2- [Note: In particular, the program is required to ensure that completion of the constructor of any object of a class type defined in the standard library happens before any other member function invocation on that object and, unless otherwise specified, to ensure that completion of any member function invocation other than destruction on such an object happens before destruction of that object. This applies even to objects such as mutexes intended for thread synchronization. — end note] If an object of a standard library type is accessed outside of the object's lifetime (3.8 [basic.life]), the behavior is undefined unless otherwise specified.


2225. Unrealistic header inclusion checks required

Section: 17.6.2.2 [using.headers] Status: Tentatively Ready Submitter: Richard Smith Opened: 2012-12-18 Last modified: 2013-03-18

View all other issues in [using.headers].

View all issues with Tentatively Ready status.

Discussion:

17.6.2.2 [using.headers]/3 says:

A translation unit shall include a header only outside of any external declaration or definition, and shall include the header lexically before the first reference in that translation unit to any of the entities declared in that header.

Per 1.4 [intro.compliance]/1, programs which violate this rule are ill-formed, and a conforming implementation is required to produce a diagnostic. This does not seem to match reality. Presumably, this paragraph is missing a "no diagnostic is required".

[2013-03-15 Issues Teleconference]

Moved to Tentatively Ready.

Proposed resolution:

This wording is relative to N3485.

  1. Edit 17.6.2.2 [using.headers] p3 as indicated:

    -3- A translation unit shall include a header only outside of any external declaration or definition, and shall include the header lexically before the first reference in that translation unit to any of the entities declared in that header. No diagnostic is required.


2227. Stateful comparison objects in associative containers

Section: 23.2.4 [associative.reqmts] Status: Review Submitter: Juan Soulie Opened: 2012-12-19 Last modified: 2013-03-18

View other active issues in [associative.reqmts].

View all other issues in [associative.reqmts].

View all issues with Review status.

Discussion:

Table 102 in 23.2.4 [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, 23.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 23.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 23.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:

[2013-03-15 Issues Teleconference]

Moved to Review.

Proposed resolution:

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 rReturns thea's comparison object
    out of which a was constructed.
    constant

2228. Missing SFINAE rule in unique_ptr templated assignment

Section: 20.7.1.2.3 [unique.ptr.single.asgn] Status: Review Submitter: Geoffrey Romer Opened: 2012-12-20 Last modified: 2013-03-18

View other active issues in [unique.ptr.single.asgn].

View all other issues in [unique.ptr.single.asgn].

View all issues with Review status.

Discussion:

20.7.1.2.3 [unique.ptr.single.asgn]/5 permits unique_ptr's templated assignment operator to participate in overload resolution even when incompatibilities between D and E will render the result ill-formed, but the corresponding templated copy constructor is removed from the overload set in those situations (see the third bullet point of 20.7.1.2.1 [unique.ptr.single.ctor]/19). This asymmetry is confusing, and presumably unintended; it may lead to situations where constructing one unique_ptr from another is well-formed, but assigning from the same unique_ptr would be ill-formed.

There is a slight coupling between this and LWG 2118, in that my PR for LWG 2118 incorporates equivalent wording in the specification of the templated assignment operator for the array specialization; the two PRs are logically independent, but if my PR for 2118 is accepted but the above PR is not, the discrepancy between the base template and the specialization could be confusing.

[2013-03-15 Issues Teleconference]

Moved to Review.

The wording looks good, but we want a little more time than the telecon permits to be truly comfortable. We expect this issue to resolve fairly easily in Bristol.

Proposed resolution:

This wording is relative to N3485.

  1. Revise 20.7.1.2.3 [unique.ptr.single.asgn] p5 as follows:

    template <class U, class E> unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept;
    

    -4- Requires: If E is not a reference type, assignment of the deleter from an rvalue of type E shall be well-formed and shall not throw an exception. Otherwise, E is a reference type and assignment of the deleter from an lvalue of type E shall be well-formed and shall not throw an exception.

    -5- Remarks: This operator shall not participate in overload resolution unless:

    • unique_ptr<U, E>::pointer is implicitly convertible to pointer and

    • U is not an array type., and

    • either D is a reference type and E is the same type as D, or D is not a reference type and E is implicitly convertible to D.

    -6- Effects: Transfers ownership from u to *this as if by calling reset(u.release()) followed by an assignment from std::forward<E>(u.get_deleter()).

    -7- Returns: *this.


2229. Standard code conversion facets underspecified

Section: 22.5 [locale.stdcvt] Status: Review Submitter: Beman Dawes Opened: 2012-12-30 Last modified: 2013-03-18

View all issues with Review status.

Discussion:

The only specification for the non-inherited members of classes codecvt_utf8, codecvt_utf16, and codecvt_utf8_utf16 is a comment line in the synopsis that says // unspecified. There is no further indication of functionality, so a user does not know if one of these classes can be constructed or destroyed.

The proposed resolution adds a constructor that mimics the class codecvt constructor, and also adds a destructor. Following the practice of class codecvt, the semantics are not specified.

The only existing implementation I could find was libc++, and it does supply the proposed constructor and destructor for each of the three classes.

[2013-03-15 Issues Teleconference]

Moved to Review.

There was concern about the unspecified semantics - but that matches what is done in codecvt.

Jonathan: Should these constructor/destructors be public? Proposed wording is private. Base class constructor is public.

Howard noted that other facets do not have specified constructors.

Alisdair noted that this whole section was new in C++11.

Howard suggested looking at section 22.3.1.1.2 [locale.facet]p2/p3 for more info.

Proposed resolution:

In [locale.stdcvt] paragraph 2, Header codecvt synopsis:

template<class Elem, unsigned long Maxcode = 0x10ffff,
  codecvt_mode Mode = (codecvt_mode)0>
class codecvt_utf8
  : public codecvt<Elem, char, mbstate_t> {
  // unspecified
  explicit codecvt_utf8(size_t refs = 0);
  ~codecvt_utf8();
  };

template<class Elem, unsigned long Maxcode = 0x10ffff,
  codecvt_mode Mode = (codecvt_mode)0>
class codecvt_utf16
  : public codecvt<Elem, char, mbstate_t> {
  // unspecified
  explicit codecvt_utf16(size_t refs = 0);
  ~codecvt_utf16();
  };

template<class Elem, unsigned long Maxcode = 0x10ffff,
  codecvt_mode Mode = (codecvt_mode)0>
class codecvt_utf8_utf16
  : public codecvt<Elem, char, mbstate_t> {
  // unspecified
  explicit codecvt_utf8_utf16(size_t refs = 0);
  ~codecvt_utf8_utf16();
  };

2230. "see below" for initializer-list constructors of unordered containers

Section: 23.5 [unord] Status: New Submitter: Jonathan Wakely Opened: 2013-01-06 Last modified: 2013-01-15

View all other issues in [unord].

View all issues with New status.

Discussion:

The unordered_map class definition in 23.5.4.1 [unord.map.overview] declares an initializer-list constructor that says "see below":

unordered_map(initializer_list<value_type>,
    size_type = see below,
    const hasher& hf = hasher(),
    const key_equal& eql = key_equal(),
    const allocator_type& a = allocator_type());

But that constructor isn't defined below. The same problem exists for the other unordered associative containers.

Proposed resolution:

This wording is relative to N3485.

  1. Edit 23.5.4.2 [unord.map.cnstr] as follows:

    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());
    unordered_map(initializer_list<value_type> il,
      size_type = 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 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.

  2. Edit 23.5.5.2 [unord.multimap.cnstr] as follows:

    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());
    unordered_multimap(initializer_list<value_type> il,
      size_type = 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 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.

  3. Edit 23.5.6.2 [unord.set.cnstr] as follows:

    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());
    unordered_set(initializer_list<value_type> il,
      size_type = 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 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.

  4. Edit 23.5.7.2 [unord.multiset.cnstr] as follows:

    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());
    unordered_multiset(initializer_list<value_type> il,
      size_type = 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 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.


2231. DR 704 removes complexity guarantee for clear()

Section: 23.2.3 [sequence.reqmts] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2012-12-30 Last modified: 2013-03-18

View other active issues in [sequence.reqmts].

View all other issues in [sequence.reqmts].

View all issues with Tentatively Ready status.

Discussion:

From the question at stackoverflow.

Were we aware that the resolution to LWG 704 means there is no complexity guarantee for clear() on most sequence containers? Previously it was implied by defining it in terms of erase(begin(), end()) but we no longer do that.

There are explicit complexity requirements for std::list::clear(), but not the other sequence containers.

Daniel:

The idea was that the notion of "destroys all elements in a" would imply a linear complexity, but the wording needs to be clearer, because this doesn't say that this step is the actual complexity bound.

[2013-03-15 Issues Teleconference]

Moved to Tentatively Ready.

Proposed resolution:

This wording is relative to N3485.

  1. Change Table 100 as indicated:

    Table 100 — Sequence container requirements (in addition to container) (continued)
    Expression Return type Assertion/note pre-/post-condition
    a.clear() void Destroys all elements in a. Invalidates all
    references, pointers, and iterators referring to
    the elements of a and may invalidate the
    past-the-end iterator.
    post: a.empty() returns true
    complexity: linear

2232. The char_traits specializations should declare their length(), compare(), and find() members constexpr

Section: 21.2.3 [char.traits.specializations] Status: Open Submitter: Jeffrey Yasskin Opened: 2012-12-24 Last modified: 2013-03-18

View all other issues in [char.traits.specializations].

View all issues with Open status.

Discussion:

These functions have easy recursive constexpr implementations that, unfortunately, aren't efficient at runtime. EWG is still figuring out how to solve this problem in general (e.g., N3444 isn't sufficient to avoid stack overflows in debug builds or to get the optimal assembly-based implementations at runtime), so users can't portably solve this problem for themselves, but implementations can use compiler-specific techniques to choose the right implementation inside their standard libraries.

The LWG is still undecided about whether individual implementations can add constexpr to these functions, so we need to add constexpr to the standard here for implementations to be able to improve this.

[2013-03-15 Issues Teleconference]

Moved to Open.

There are a number of people who have a strong interest in this issue not available for the telecon.

It also plays at the heart of a discussion about library freedoms for constexpr and specifying a library that may depend on unspecified compiler intrinsics to be implementable.

Proposed resolution:

This wording is relative to N3485.

  1. In 21.2.3.1 [char.traits.specializations.char], 21.2.3.2 [char.traits.specializations.char16_t], 21.2.3.3 [char.traits.specializations.char32_t], and 21.2.3.4 [char.traits.specializations.wchar.t]:

    static constexpr int compare(const char_type* s1, const char_type* s2, size_t n);
    static constexpr size_t length(const char_type* s);
    static constexpr const char_type* find(const char_type* s, size_t n, const char_type& a);
    

2233. bad_function_call::what() unhelpful

Section: 20.8.11.1 [func.wrap.badcall] Status: Open Submitter: Jonathan Wakely Opened: 2013-01-05 Last modified: 2013-03-18

View all issues with Open status.

Discussion:

A strict reading of the standard implies std::bad_function_call{}.what() returns the same string as std::exception{}.what() which doesn't help to know what happened if you catch an exception by reference to std::exception.

For consistency with bad_weak_ptr::what() it should return "bad_function_call".

See c++std-lib-33515 for other details.

There was a considerable support on the reflector to instead change the specification of both bad_weak_ptr::what() and bad_function_call::what() to return an implementation-defined string instead.

[2013-03-15 Issues Teleconference]

Moved to Open.

Consensus that we want consistency in how this is treated. Less consensus on what the common direction should be.

Alisdair to provide wording proposing that all string literals held by standard exception objects are either unspecified, or implmentation defined.

Proposed resolution:

This wording is relative to N3485.

  1. Edit 20.8.11.1.1 [func.wrap.badcall.const]:

    bad_function_call() noexcept;
    

    -1- Effects: constructs a bad_function_call object.

    -?- Postconditions: what() returns "bad_function_call".


2234. assert() should allow usage in constant expressions

Section: 19.3 [assertions] Status: Open Submitter: Daniel Krügler Opened: 2013-01-12 Last modified: 2013-03-18

View all issues with Open status.

Discussion:

It is unclear from the current specification whether assert() expressions can be used in (potential) constant expressions. As an example consider the implementation of a constexpr function:

#include <cassert>

template<class T, unsigned N>
struct array {
  T data[N];
  constexpr const T& operator[](unsigned i) const {
    return assert(i < N), data[i];
  }
};

int main() {
  constexpr array<int, 3> ai = {1, 2, 3};
  constexpr int i = ai[0];
  int j = ai[0];
  // constexpr int k = ai[5];
}

The first question is whether this program is guaranteed well-formed? A second question is whether is would guaranteed to be ill-formed, if we uncomment the last code line in main()?

The wording in 19.3 [assertions] doesn't add anything significant to the C99 wording. From the C99 specification (7.2 p1 and 7.2.1.1 p2) we get already some valuable guarantees:

The current wording does not yet guarantee that assert expressions can be used in constant expressions, but all tested implementations (gcc, MSVC) would already support this use-case. It seems to me that this should be possible without giving assert a special meaning for the core language.

As a related comment it should be added, that there is a core language proposal that intents to relax some current constraints for constexpr functions and literal types. The most interessting one (making void a literal types and allowing for expression-statements) would simplify the motivating example implementation of operator[] to:

constexpr const T& operator[](unsigned i) const {
  assert(i < N);
  return data[i];
};

[2013-03-15 Issues Teleconference]

Moved to Open.

We are still gaining experience with constexpr as a language feature, and there may be work in Evolution that would help address some of these concerns. Defer discussion until we have a group familiar with any evolutionary direction.

Proposed resolution:


2235. Undefined behavior without proper requirements on basic_string constructors

Section: 21.4.2 [string.cons] Status: Review Submitter: Juan Soulie Opened: 2013-01-17 Last modified: 2013-03-18

View all other issues in [string.cons].

View all issues with Review status.

Discussion:

In 21.4.2 [string.cons], I believe tighter requirements should be imposed on basic_string's constructors taking an s argument (or, a behavior should be provided for the undefined cases). These requirements are properly stated in the other members functions taking s arguments (append, assign, insert,...).

basic_string(const charT* s, size_type n, const Allocator& a = Allocator());

Relative to N3485, 21.4.2 [string.cons]/6 says "Requires: s shall not be a null pointer and n < npos", where it should say: "Requires: s points to an array of at least n elements of charT"

basic_string(const charT* s, const Allocator& a = Allocator());

21.4.2 [string.cons]/8 says "Requires: s shall not be a null pointer.", where it should say: "Requires: s points to an array of at least traits::length(s) + 1 elements of charT"

Daniel:

I think that 17.6.4.9 [res.on.arguments] p1 b2 basically requires this already, but the wording is indeed worth improving it.

[2013-03-15 Issues Teleconference]

Moved to Review.

The resolution could be worded more cleanly, and there is some concern about redundancy between Requirements and Effects clauses. Consensus that we do want to say something like this for the Requirements though.

Proposed resolution:

This wording is relative to N3485.

  1. Change 21.4.2 [string.cons]/6 as indicated:

    basic_string(const charT* s, size_type n, const Allocator& a = Allocator());
    

    -6- Requires: s shall not be a null pointer and n < npospoints to an array of at least n elements of charT.

  2. Change 21.4.2 [string.cons]/8 as indicated:

    basic_string(const charT* s, const Allocator& a = Allocator());
    

    -8- Requires: s shall not be a null pointerpoints to an array of at least traits::length(s) + 1 elements of charT.


2236. kill_dependency unconditionally noexcept

Section: 29.2 [atomics.syn], 29.3 [atomics.order] Status: New Submitter: Daniel Krügler Opened: 2013-01-19 Last modified: 2013-03-18

View all other issues in [atomics.syn].

View all issues with New 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.

Proposed resolution:


2237. <cuchar> macros

Section: 21.7 [c.strings] Status: New Submitter: Jason Merrill Opened: 2013-01-29 Last modified: 2013-03-18

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. Problematic iterator-pair constructor of containers

Section: 21.7 [c.strings] Status: New Submitter: Johannes Schaub Opened: 2013-02-02 Last modified: 2013-03-18

View other active issues in [c.strings].

View all other issues in [c.strings].

View all issues with New 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 meassage here.

Proposed resolution:


2239. min/max/minmax requirements

Section: 25.4.7 [alg.min.max] Status: New Submitter: Juan Soulie Opened: 2013-01-26 Last modified: 2013-03-18

View all other issues in [alg.min.max].

View all issues with New status.

Discussion:

25.4.7 [alg.min.max] requires type T in min, max, and minmax to be LessThanComparable, but I don't believe this should be required for the versions that take a Compare argument.

Paragraphs 1 to 4 of 25.4 [alg.sorting] should apply anyway, although I'm not sure about Compare being required to induce a strict weak ordering here.

Further, min and max also lack formal complexity guarantees.

Proposed resolution:


2240. Probable misuse of term "function scope" in [thread.condition]

Section: 30.5.1 [thread.condition.condvar], 30.5.2 [thread.condition.condvarany] Status: New Submitter: FrankHB1989 Opened: 2013-02-03 Last modified: 2013-03-18

View other active issues in [thread.condition.condvar].

View all other issues in [thread.condition.condvar].

View all issues with New status.

Discussion:

All usages of "function scope" in 30.5.1 [thread.condition.condvar] and 30.5.2 [thread.condition.condvarany], such as 30.5.1 [thread.condition.condvar] p10 b4:

If the function exits via an exception, lock.lock() shall be called prior to exiting the function scope.

seem to be inappropriate compared to the actual core language definition of 3.3.5 [basic.funscope]:

Labels (6.1) have function scope and may be used anywhere in the function in which they are declared. Only labels have function scope.

Probably the intended meaning is "outermost block scope of the function".

Proposed resolution:


2241. <cstdalign> and #define of alignof

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

View other active issues in [support.runtime].

View all other issues in [support.runtime].

View all issues with New status.

Discussion:

According to 18.10 [support.runtime] p2:

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

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

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

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

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

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

Proposed resolution:


2242. [uninitialized_]copy_n() defect

Section: 25.3.1 [alg.copy], 20.6.12.2 [uninitialized.copy] Status: New Submitter: Sean Parent Opened: 2013-02-14 Last modified: 2013-03-18

View all other issues in [alg.copy].

View all issues with New status.

Discussion:

copy_n() and uninitialized_copy_n() only return the output iterator, and not the input iterator. Likely the interface was simply copied from the original STL. Unfortunately the interface in the original STL contains a bug.

copy_n() and uninitialized_copy_n() must return the resulting input iterator as well as the output iterator (I would suggest returning a pair). Without this, there is no way to continue reading from an actual input iterator — and if it is really a forward iterator, it will cost n increments to get back to where you were.

Proposed resolution:


2243. istream::putback problem

Section: 27.7.2.3 [istream.unformatted] Status: New Submitter: Juan Soulie Opened: 2013-03-01 Last modified: 2013-03-18

View other active issues in [istream.unformatted].

View all other issues in [istream.unformatted].

View all issues with New status.

Discussion:

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

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

Proposed resolution:


2244. Issue on basic_istream::seekg

Section: 27.7.2.3 [istream.unformatted] Status: New Submitter: Juan Soulie Opened: 2013-03-04 Last modified: 2013-03-18

View other active issues in [istream.unformatted].

View all other issues in [istream.unformatted].

View all issues with New status.

Discussion:

When issue 1445 was resolved by adopting N3168, it exposed the need to modify both overloads of basic_istream::seekg (by inserting "the function clears eofbit," after "except that"), but the fix applied to the text apparently forgets the second overload at 27.7.2.3 [istream.unformatted] p43.

Proposed resolution:


2245. packaged_task::reset() memory allocation

Section: 27.7.2.3 [istream.unformatted] Status: New Submitter: Jonathan Wakely Opened: 2013-03-05 Last modified: 2013-03-18

View other active issues in [istream.unformatted].

View all other issues in [istream.unformatted].

View all issues with New status.

Discussion:

The effects of packaged_task::reset() result in memory allocation, but don't allow a user to provide an allocator.

packaged_task::reset() needs to be overloaded like so:

template<class Alloc>  
void reset(const Alloc&);

Alternatively, the effects of reset() need to require the same allocator is used as at construction, which would require the constructor to store the allocator for later use.

I like to remark that GCC at the moment uses the second option, i.e. the allocator passed to the constructor (if any) is used to create the new shared state, because this didn't require any change to the interface.

Proposed resolution:


2246. unique_ptr assignment effects w.r.t. deleter

Section: 20.7.1.2.3 [unique.ptr.single.asgn] Status: New Submitter: Jonathan Wakely Opened: 2013-03-13 Last modified: 2013-03-18

View other active issues in [unique.ptr.single.asgn].

View all other issues in [unique.ptr.single.asgn].

View all issues with New status.

Discussion:

The Effects clauses for unique_ptr assignment don't make sense, what is the target of "an assignment from std::forward<D>(u.get_deleter())"?

Obviously it's intended to be the deleter, but that isn't stated clearly.

Proposed resolution:

This wording is relative to N3485.

  1. Edit 20.7.1.2.3 [unique.ptr.single.asgn] paragraph 2:

    unique_ptr& operator=(unique_ptr&& u) noexcept;
    

    […]

    -2- Effects: Transfers ownership from u to *this as if by calling reset(u.release()) followed by an assignment fromget_deleter() = std::forward<D>(u.get_deleter()).

  2. Edit 20.7.1.2.3 [unique.ptr.single.asgn] paragraph 6:

    template <class U, class E> unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept;
    

    […]

    -6- Effects: Transfers ownership from u to *this as if by calling reset(u.release()) followed by an assignment fromget_deleter() = std::forward<E>(u.get_deleter()).


2247. Type traits and std::nullptr_t

Section: 20.9.4.1 [meta.unary.cat] Status: New Submitter: Joe Gottman Opened: 2013-03-15 Last modified: 2013-03-18

View all issues with New status.

Discussion:

According to 20.9.4.1 [meta.unary.cat], for every type T, exactly one of the primary type traits is true. So which is true for the type std::nullptr_t? By 2.14.7 [lex.nullptr] std::nullptr_t is not a pointer type or a pointer-to-member type, so is_pointer, is_member_object_pointer and is_member_function_pointer can't be true for std::nullptr_t, and none of the other primary type traits seem to apply.

Proposed resolution:

This wording is relative to N3485.

  1. Edit 20.9.2 [meta.type.synop], header <type_traits> synopsis:

    namespace std {
      […]
      // 20.9.4.1, primary type categories:
      template <class T> struct is_void;
      template <class T> struct is_nullptr;
      template <class T> struct is_integral;
      template <class T> struct is_floating_point;
      […]
    }
    
  2. Edit Table 47 — "Primary type category predicates" as indicated:

    Table 47 — Primary type category predicates
    Template Condition Comments
    template <class T>
    struct is_nullptr;
    T is std::nullptr_t ([basic.fundamental])  

2248. numeric_limits::is_iec559 misnamed

Section: 18.3.2 [limits] Status: New Submitter: Pete Becker Opened: 2013-03-08 Last modified: 2013-03-18

View all other issues in [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.

Proposed resolution: