Doc. no. N3285=11-0055
Date: 2011-03-28
Project: Programming Language C++
Reply to: Alisdair Meredith <lwgchair@gmail.com>

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

Revised 2011-04-11 at 13:04:34 UTC

Reference ISO/IEC IS 14882:2003(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:2003(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:2003(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

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.

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.

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 Concepts - The LWG has reached consensus that the issue is NAD for now, but represents a real issue when the library is done with language-supported concepts.

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

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

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.

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.

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.

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.

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.

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.

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 J16 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 (TC), or are closed without action other than a Record of Response (RR ). 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: Deferred Submitter: Cosmin Truta Opened: 2009-07-04 Last modified: 2011-03-24

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

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

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: Deferred Submitter: Pablo Halpern Opened: 2009-07-17 Last modified: 2011-03-24

View all other issues in [unord.req].

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

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

    2 Complexity: Constant if n is not provided, otherwise linear in n to construct the 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 implementation-definedimpldefdefault 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 quadraticConstant if n is not provided, else linear in n to construct the 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 distance(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 implementation-definedimpldefdefault number of buckets in unordered_multimap. max_load_factor() returns 1.0.

    2 Complexity: Constant if n is not provided, otherwise linear in n to construct the 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 implementation-definedimpldefdefault 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 quadraticConstant if n is not provided, else linear in n to construct the 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 distance(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 implementation-definedimpldefdefault number of buckets in unordered_set. max_load_factor() returns 1.0.

    2 Complexity: Constant if n is not provided, otherwise linear in n to construct the 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 implementation-definedimpldefdefault 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 quadraticConstant if n is not provided, else linear in n to construct the 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 distance(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 implementation-definedimpldefdefault number of buckets in unordered_multiset. max_load_factor() returns 1.0.

    2 Complexity: Constant if n is not provided, otherwise linear in n to construct the 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 implementation-definedimpldefdefault 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 quadraticConstant if n is not provided, else linear in n to construct the 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 distance(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: 2011-03-24

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.


1214. Insufficient/inconsistent key immutability requirements for associative containers

Section: 23.2.4 [associative.reqmts] Status: Deferred Submitter: Daniel Krügler Opened: 2009-09-20 Last modified: 2011-03-24

View all other issues in [associative.reqmts].

View all issues with Deferred status.

Discussion:

Scott Meyers' mentions on a recent posting on c.s.c++ some arguments that point to an incomplete resolution of 103 and to an inconsistency of requirements on keys in ordered and unordered associative containers:

1) 103 introduced the term immutable without defining it in a unique manner in 23.2.4 [associative.reqmts]/5:

[..] Keys in an associative container are immutable.

According to conventional dictionaries immutable is an unconditional way of saying that something cannot be changed. So without any further explicit allowance a user always runs into undefined behavior if (s)he attempts to modify such a key. IMO this was not the intend of the committee to resolve 103 in that way because the comments suggest an interpretation that should give any user the freedom to modify the key in an explicit way provided it would not affect the sort order in that container.

2) Another observation was that surprisingly no similar 'safety guards' exists against unintentional key changes for the unordered associative containers, specifically there is no such requirement as in 23.2.4 [associative.reqmts]/6 that "both iterator and const_iterator are constant iterators". But the need for such protection against unintentional changes as well as the constraints in which manner any explicit changes may be performed are both missing and necessary, because such changes could potentially change the equivalence of keys that is measured by the hasher and key_equal.

I suggest to fix the unconditional wording involved with "immutable keys" by at least adding a hint for the reader that users may perform such changes in an explicit manner and to perform similar wording changes as 103 did for the ordered associative containers also for the unordered containers.

[ 2010-03-27 Daniel provides wording. ]

This update attempts to provide normative wording that harmonizes the key and function object constraints of associative and unordered containers.

[ 2010 Batavia: ]

We're uncomfortable with the first agenda item, and we can live with the second agenda item being applied before or after Madrid.

Proposed resolution:

  1. Change 23.2.4 [associative.reqmts]/2 as indicated: [This ensures that associative containers make better clear what this "arbitrary" type is, as the unordered containers do in 23.2.5 [unord.req]/3]

    2 Each associative container is parameterized on Key and an ordering relation Compare that induces a strict weak ordering (25.4) on elements of Key. In addition, map and multimap associate an arbitrary mapped typetype T with the Key. The object of type Compare is called the comparison object of a container.

  2. Change 23.2.4 [associative.reqmts]/5 as indicated: [This removes the too strong requirement that keys must not be changed at all and brings this line in sync with 23.2.5 [unord.req]/7. We take care about the real constraints by the remaining suggested changes. The rationale provided by LWG 103 didn't really argue why that addition is necessary, and I believe the remaining additions make it clear that any user changes have strong restrictions]:

    5 For set and multiset the value type is the same as the key type. For map and multimap it is equal to pair<const Key, T>. Keys in an associative container are immutable.

  3. Change 23.2.5 [unord.req]/3+4 as indicated: [The current sentence of p.4 has doesn't say something really new and this whole subclause misses to define the concepts of the container-specific hasher object and predicate object. We introduce the term key equality predicate which is already used in the requirements table. This change does not really correct part of this issue, but is recommended to better clarify the nomenclature and the difference between the function objects and the function object types, which is important, because both can potentially be stateful.]

    3 Each unordered associative container is parameterized by Key, by a function object type Hash that meets the Hash requirements (20.2.4) and acts as a hash function for argument values of type Key, and by a binary predicate Pred that induces an equivalence relation on values of type Key. Additionally, unordered_map and unordered_multimap associate an arbitrary mapped type T with the Key.

    4 The container's object of type Hash - denoted by hash - is called the hash function of the container. The container's object of type Pred - denoted by pred - is called the key equality predicate of the container.A hash function is a function object that takes a single argument of type Key and returns a value of type std::size_t.

  4. Change 23.2.5 [unord.req]/5 as indicated: [This adds a similar safe-guard as the last sentence of 23.2.4 [associative.reqmts]/3]

    5 Two values k1 and k2 of type Key are considered equivalent if the container's key equality predicatekey_equal function object returns true when passed those values. If k1 and k2 are equivalent, the container's hash function shall return the same value for both. [Note: thus, when an unordered associative container is instantiated with a non-default Pred parameter it usually needs a non-default Hash parameter as well. — end note] For any two keys k1 and k2 in the same container, calling pred(k1, k2) shall always return the same value. For any key k in a container, calling hash(k) shall always return the same value.

  5. After 23.2.5 [unord.req]/7 add the following new paragraph: [This ensures the same level of compile-time protection that we already require for associative containers. It is necessary for similar reasons, because any change in the stored key which would change it's equality relation to others or would change it's hash value such that it would no longer fall in the same bucket, would break the container invariants]

    7 For unordered_set and unordered_multiset the value type is the same as the key type. For unordered_map and unordered_multimap it is std::pair<const Key, T>.

    For unordered containers where the value type is the same as the key type, both iterator and const_iterator are constant iterators. It is unspecified whether or not iterator and const_iterator are the same type. [Note: iterator and const_iterator have identical semantics in this case, and iterator is convertible to const_iterator. Users can avoid violating the One Definition Rule by always using const_iterator in their function parameter lists. — end note]


1330. Move container requirements into requirements tables

Section: 23.2 [container.requirements] Status: Deferred Submitter: Nicolai Josuttis Opened: 2010-03-10 Last modified: 2011-03-24

View all other issues in [container.requirements].

View all issues with Deferred status.

Discussion:

Abstract:

In general, it seems that in a couple of places container behavior is not described in requirement tables although it is a general behavior.

History:

Issue 676 added move semantics to unordered containers. For the added insert functions the Editor requested to put their semantic description into a requirements table rather than describing them for each container individually. The text however was taken from the associative containers, where we also have the semantics for each container described. Also, 1034 is to some extend requesting a clarification of the requirement tables and it turned out that in other places we have the same problem (e.g. we have no general requirement for type pointer and const_pointer although each container has them with issue 1306).

From my personal list of functions in requirement tables and containers, the following types/functions are missing in requirement tables:

As a special case, we lack the following requirements for all sequence containers BUT array (so special wording or a new container category is required):

Note that we also might have to add additional requirements on other places for sequence containers because having an allocator requires additional statements for the treatment of the allocators. E.g. swap for containers with allocators is not specified in any requirement table.

And finally, if we have the requirements in the requirements tables, we can remove the corresponding descriptions for the individual container. However, note that sequence container requirements have NO complexity column, so that we still need container specific descriptions for the functions listed there.

[ 2010 Batavia ]

While there is consensus that further cleaning up the container requirement tables would be a good thing, there is no feeling that this must be done in time for 0x. The issue remains open, but Deferred.

Proposed resolution:


1450. [FCD] Contradiction in regex_constants

Section: 28.5.2 [re.matchflag] Status: Deferred Submitter: BSI Opened: 2010-08-25 Last modified: 2011-03-24

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

Proposed resolution:

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.


1521. Requirements on internal pointer representations in containers

Section: 23.2.1 [container.requirements.general] Status: Deferred Submitter: Mike Spertus Opened: 2010-10-16 Last modified: 2011-03-24

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

View all issues with Deferred status.

Discussion:

Addresses US-104, US-141

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

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

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

[ Pre-batavia ]

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

[2011-03-23 Madrid meeting]

Deferred

Proposed resolution:

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

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


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

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

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

Rationale:

No consensus to make a change at this time

Proposed resolution:


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: 2011-03-24

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.


2005. unordered_map::insert(T&&) protection should apply to map too

Section: 23.4.4.4 [map.modifiers], 23.4.5.3 [multimap.modifiers] Status: Review Submitter: P.J. Plauger Opened: 2010-10-14 Last modified: 2011-03-24

View all issues with Review status.

Discussion:

In [unord.map.modifiers], the signature:

template <class P>
    pair<iterator, bool> insert(P&& obj);

now has an added Remarks paragraph:

Remarks: This signature shall not participate in overload resolution unless P is implicitly convertible to value_type.

The same is true for unordered_multimap.

But neither map nor multimap have this constraint, even though it is a Good Thing(TM) in those cases as well.

[ The submitter suggests: Add the same Remarks clause to [map.modifiers] and [multimap.modifiers]. ]

[ 2010-10-29 Daniel comments: ]

I believe both paragraphs need more cleanup: First, the current Requires element conflict with the Remark; second, it seems to me that the whole single Requires element is intended to be split into a Requires and an Effects element; third, the reference to tuple is incorrect (noticed by Paolo Carlini); fourth, it refers to some non-existing InputIterator parameter relevant for a completely different overload; sixth, the return type of the overload with hint is wrong. The following proposed resolution tries to solve these issues as well and uses similar wording as for the corresponding unordered containers. Unfortunately it has some redundancy over Table 99, but I did not remove the specification because of the more general template parameter P - the Table 99 requirements apply only for an argument identical to value_type.

Proposed resolution:

  1. Change 23.4.4.4 [map.modifiers] around p. 1 as indicated:
    template <class P> pair<iterator, bool> insert(P&& x);
    template <class P> pair<iterator, bool> insert(const_iterator position, P&& x);
    

    1 Requires: P shall be convertible to value_type is constructible from std::forward<P>(x)..

    If P is instantiated as a reference type, then the argument x is copied from. Otherwise x is considered to be an rvalue as it is converted to value_type and inserted into the map. Specifically, in such cases CopyConstructible is not required of key_type or mapped_type unless the conversion from P specifically requires it (e.g., if P is a tuple<const key_type, mapped_type>, then key_type must be CopyConstructible). The signature taking InputIterator parameters does not require CopyConstructible of either key_type or mapped_type if the dereferenced InputIterator returns a non-const rvalue pair<key_type,mapped_type>. Otherwise CopyConstructible is required for both key_type and mapped_type.
    ? Effects: Inserts x converted to value_type if and only if there is no element in the container with key equivalent to the key of value_type(x). For the second form, the iterator position is a hint pointing to where the search should start.

    ? Returns: For the first form, the bool component of the returned pair object indicates whether the insertion took place and the iterator component - or for the second form the returned iterator - points to the element with key equivalent to the key of value_type(x).

    ? Complexity: Logarithmic in general, but amortized constant if x is inserted right before position.

    ? Remarks: These signatures shall not participate in overload resolution unless P is implicitly convertible to value_type.

  2. Change 23.4.5.3 [multimap.modifiers] around p. 1 as indicated:
    template <class P> iterator insert(P&& x);
    template <class P> iterator insert(const_iterator position, P&& x);
    

    1 Requires: P shall be convertible to value_type is constructible from std::forward<P>(x).

    If P is instantiated as a reference type, then the argument x is copied from. Otherwise x is considered to be an rvalue as it is converted to value_type and inserted into the map. Specifically, in such cases CopyConstructible is not required of key_type or mapped_type unless the conversion from P specifically requires it (e.g., if P is a tuple<const key_type, mapped_type>, then key_type must be CopyConstructible). The signature taking InputIterator parameters does not require CopyConstructible of either key_type or mapped_type if the dereferenced InputIterator returns a non-const rvalue pair<key_type, mapped_type>. Otherwise CopyConstructible is required for both key_type and mapped_type.
    ? Effects: Inserts x converted to value_type. For the second form, the iterator position is a hint pointing to where the search should start.

    ? Returns: An iterator that points to the element with key equivalent to the key of value_type(x).

    ? Complexity: Logarithmic in general, but amortized constant if x is inserted right before position.

    ? Remarks: These signatures shall not participate in overload resolution unless P is implicitly convertible to value_type.

[ 2010 Batavia: ]

We need is_convertible, not is_constructible, both in ordered and unordered containers.

Proposed resolution:

  1. Add a new Remarks element after 23.4.4.4 [map.modifiers] p. 1:
    template <class P> pair<iterator, bool> insert(P&& x);
    template <class P> pair<iterator, bool> insert(const_iterator position, P&& x);
    

    1 Requires: P shall be convertible to value_type.

    If P is instantiated as a reference type, then the argument x is copied from. Otherwise x is considered to be an rvalue as it is converted to value_type and inserted into the map. Specifically, in such cases CopyConstructible is not required of key_type or mapped_type unless the conversion from P specifically requires it (e.g., if P is a tuple<const key_type, mapped_type>, then key_type must be CopyConstructible). The signature taking InputIterator parameters does not require CopyConstructible of either key_type or mapped_type if the dereferenced InputIterator returns a non-const rvalue pair<key_type,mapped_type>. Otherwise CopyConstructible is required for both key_type and mapped_type.

    ? Remarks: These signatures shall not participate in overload resolution unless P is implicitly convertible to value_type.

  2. Change 23.4.5.3 [multimap.modifiers] around p. 1 as indicated:
    template <class P> iterator insert(P&& x);
    template <class P> iterator insert(const_iterator position, P&& x);
    

    1 Requires: P shall be convertible to value_type.

    If P is instantiated as a reference type, then the argument x is copied from. Otherwise x is considered to be an rvalue as it is converted to value_type and inserted into the map. Specifically, in such cases CopyConstructible is not required of key_type or mapped_type unless the conversion from P specifically requires it (e.g., if P is a tuple<const key_type, mapped_type>, then key_type must be CopyConstructible). The signature taking InputIterator parameters does not require CopyConstructible of either key_type or mapped_type if the dereferenced InputIterator returns a non-const rvalue pair<key_type, mapped_type>. Otherwise CopyConstructible is required for both key_type and mapped_type.

    ? Remarks: These signatures shall not participate in overload resolution unless P is implicitly convertible to value_type.


2009. Reporting out-of-bound values on numeric string conversions

Section: 21.5 [string.conversions] Status: Ready Submitter: Alisdair Meredith Opened: 2010-07-19 Last modified: 2011-03-24

View all other issues in [string.conversions].

View all issues with Ready status.

Discussion:

The functions (w)stoi and (w)stof are specified in terms of calling C library APIs for potentially wider types. The integer and floating-point versions have subtly different behaviour when reading values that are too large to convert. The floating point case will throw out_of_bound if the read value is too large to convert to the wider type used in the implementation, but behaviour is undefined if the converted value cannot narrow to a float. The integer case will throw out_of_bounds if the converted value cannot be represented in the narrower type, but throws invalid_argument, rather than out_of_range, if the conversion to the wider type fails due to overflow.

Suggest that the Throws clause for both specifications should be consistent, supporting the same set of fail-modes with the matching set of exceptions.

Proposed resolution:

21.5p3 [string.conversions]

int stoi(const string& str, size_t *idx = 0, int base = 10);
long stol(const string& str, size_t *idx = 0, int base = 10);
unsigned long stoul(const string& str, size_t *idx = 0, int base = 10);
long long stoll(const string& str, size_t *idx = 0, int base = 10);
unsigned long long stoull(const string& str, size_t *idx = 0, int base = 10);

...

3 Throws: invalid_argument if strtol, strtoul, strtoll, or strtoull reports that no conversion could be performed. Throws out_of_range if strtol, strtoul, strtoll or strtoull sets errno to ERANGE, or if the converted value is outside the range of representable values for the return type.

21.5p6 [string.conversions]

float stof(const string& str, size_t *idx = 0);
double stod(const string& str, size_t *idx = 0);
long double stold(const string& str, size_t *idx = 0);

...

6 Throws: invalid_argument if strtod or strtold reports that no conversion could be performed. Throws out_of_range if strtod or strtold sets errno to ERANGE or if the converted value is outside the range of representable values for the return type.


2010. is_* traits for binding operations can't be meaningfully specialized

Section: 20.8.9.1.1 [func.bind.isbind] Status: Open Submitter: Sean Hunt Opened: 2010-07-19 Last modified: 2011-03-24

View all other issues in [func.bind.isbind].

View all issues with Open status.

Discussion:

20.8.9.1.1 [func.bind.isbind] says for is_bind_expression:

Users may specialize this template to indicate that a type should be treated as a subexpression in a bind call.

But it also says:

If T is a type returned from bind, is_bind_expression<T> shall be publicly derived from integral_constant<bool, true>, otherwise from integral_constant<bool, false>.

This means that while the user is free to specialize, any specialization would have to be false to avoid violating the second requirement. A similar problem exists for is_placeholder.

[ 2010 Batavia (post meeting session) ]

Alisdair recognises this is clearly a bug introduced by some wording he wrote, the sole purpose of this metafunction is as a customization point for users to write their own bind-expression types that participate in the standard library bind protocol. The consensus was that this should be fixed in Madrid, moved to Open.

Proposed resolution:


2011. unexpected output required of strings

Section: 21.4.8.9 [string.io] Status: Open Submitter: James Kanze Opened: 2010-07-23 Last modified: 2011-03-24

View all other issues in [string.io].

View all issues with Open status.

Discussion:

What should the following code output?

#include <string>
#include <iostream>
#include <iomanip>

int 
main() 
{ 
   std::string test("0X1Y2Z"); 
   std::cout.fill('*'); 
   std::cout.setf(std::ios::internal, std::ios::adjustfield); 
   std::cout << std::setw(8) << test << std::endl; 
} 

I would expect "**0X1Y2Z", and this is what the compilers I have access to (VC++, g++ and Sun CC) do. But according to the standard, it should be "0X**1Y2Z":

21.4.8.9 [string.io]/5:

template<class charT, class traits, class Allocator>
  basic_ostream<charT, traits>&
    operator<<(basic_ostream<charT, traits>& os, const basic_string<charT,traits,Allocator>& str);

Effects: Behaves as a formatted output function (27.7.3.6.1 [ostream.formatted.reqmts]). After constructing a sentry object, if this object returns true when converted to a value of type bool, determines padding as described in 22.4.2.2.2 [facet.num.put.virtuals], then inserts the resulting sequence of characters seq as if by calling os.rdbuf()->sputn(seq, n), where n is the larger of os.width() and str.size(); then calls os.width(0).

22.4.2.2.2 [facet.num.put.virtuals]/5:

[...]

Stage 3: A local variable is initialized as

fmtflags adjustfield= (flags & (ios_base::adjustfield));

The location of any padding is determined according to Table 88.

If str.width() is nonzero and the number of charT's in the sequence after stage 2 is less than str.width(), then enough fill characters are added to the sequence at the position indicated for padding to bring the length of the sequence to str.width(). str.width(0) is called.

Table 88 — Fill padding
State Location
adjustfield == ios_base::left pad after
adjustfield == ios_base::right pad before
adjustfield == internal and a sign occurs in the representation pad after the sign
adjustfield == internal and representation after stage 1 began with 0x or 0X pad after x or X
otherwise pad before

Although it's not 100% clear what "the sequence after stage 2" should mean here, when there is no stage 2, the only reasonable assumption is that it is the contents of the string being output. In the above code, the string being output is "0X1Y2Z", which starts with "0X", so the padding should be inserted "after x or X", and not before the string. I believe that this is a defect in the standard, and not in the three compilers I tried.

[ 2010 Batavia (post meeting session) ]

Consensus that all known implementations are consistent, and disagree with the standard. Preference is to fix the standard before implementations start trying to conform to the current spec, as the current implementations have the preferred form. Howard volunteered to drught for Madrid, move to Open.

[2011-03-24 Madrid meeting]

Daniel Krügler volunteered to provide wording, interacting with Dietmar and Bill.

Proposed resolution:


2012. Associative maps should insert pair, not tuple

Section: 23.4 [associative] Status: Open Submitter: Paolo Carlini Opened: 2010-10-29 Last modified: 2011-03-24

View all other issues in [associative].

View all issues with Open status.

Discussion:

I'm seeing something strange in the paragraphs 23.4.4.4 [map.modifiers] and 23.4.5.3 [multimap.modifiers]: they both talk about tuple<const key_type, mapped_type> but I think they should be talking about pair<const key_type, mapped_type> because, among other reasons, a tuple is not convertible to a pair. If I replace tuple with pair everything makes sense to me.

The proposed resolution is obvious.

[ 2010-11-07 Daniel comments ]

This is by far not the only necessary fix within both sub-clauses. For details see the 2010-10-29 comment in 2005.

[2011-03-24 Madrid meeting]

Paolo: Don't think we can do it now.

Daniel K: Agrees.

Proposed resolution:

Apply the resolution proposed by the 2010-10-29 comment in 2005.


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

Section: 17.6.5.6 [constexpr.functions] Status: New Submitter: Matt Austern Opened: 2010-11-12 Last modified: 2011-03-24

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

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.


2015. Incorrect pre-conditions for some type traits

Section: 20.9.4 [meta.unary] Status: New Submitter: Nikolay Ivchenkov Opened: 2010-11-08 Last modified: 2011-03-24

View all other issues in [meta.unary].

View all issues with New status.

Discussion:

According to N3126 ‑ 3.9/9,

"Scalar types, trivial class types (Clause 9), arrays of such types and cv‑qualified versions of these types (3.9.3) are collectively called trivial types."

Thus, an array (possibly of unknown bound) can be trivial type, non‑trivial type, or an array type whose triviality cannot be determined because its element type is incomplete.

According to N3126 ‑ Table 45, preconditions for std::is_trivial are defined as follows:

"T shall be a complete type, (possibly cv-qualified) void, or an array of unknown bound"

It seems that "an array of unknown bound" should be changed to "an array of unknown bound of a complete element type". Preconditions for some other templates (e.g., std::is_trivially_copyable, std::is_standard_layout, std::is_pod, and std::is_literal_type) should be changed similarly.

On the other hand, some preconditions look too restrictive. For example, std::is_empty and std::is_polymorphic might accept any incomplete non‑class type.

[2011-02-18: Daniel provides wording proposal]

While reviewing the individual preconditions I could find three different groups of either too weakening or too strengthening constraints:

  1. is_empty/is_polymorphic/is_abstract/has_virtual_destructor:

    These traits can only apply for non‑union class types, otherwise the result must always be false

  2. is_base_of:

    Similar to the previous bullet, but the current wording comes already near to that ideal, it only misses to add the non‑union aspect.

  3. is_trivial/is_trivially_copyable/is_standard_layout/is_pod/is_literal_type:

    These traits always require that std::remove_all_extents<T>::type to be cv void or a complete type.

Proposed resolution:

  1. Modify the pre-conditions of the following type traits in 20.9.4.3 [meta.unary.prop], Table 48 — Type property predicates:

    Table 48 — Type property predicates
    Template Condition Preconditions
    ...
    template <class T>
    struct is_trivial;
    T is a trivial type (3.9) remove_all_extents<T>::type
    shall be a complete type, or (possibly
    cv-qualified) void, or an array of
    unknown bound
    .
    template <class T>
    struct is_trivially_copyable;
    T is a trivially copyable
    type (3.9)
    remove_all_extents<T>::type
    shall be a complete type, or (possibly
    cv-qualified) void, or an array of
    unknown bound
    .
    template <class T>
    struct is_standard_layout;
    T is a standard-layout
    type (3.9)
    remove_all_extents<T>::type
    shall be a complete type, or (possibly
    cv-qualified) void, or an array of
    unknown bound
    .
    template <class T>
    struct is_pod;
    T is a POD type (3.9) remove_all_extents<T>::type
    shall be a complete type, or (possibly
    cv-qualified) void, or an array of
    unknown bound
    .
    template <class T>
    struct is_literal_type;
    T is a literal type (3.9) remove_all_extents<T>::type
    shall be a complete type, or (possibly
    cv-qualified) void, or an array of
    unknown bound
    .
    template <class T>
    struct is_empty;
    T is a class type, but not a
    union type, with no
    non-static data members
    other than bit-fields of
    length 0, no virtual
    member functions, no
    virtual base classes, and
    no base class B for which
    is_empty<B>::value is
    false.
    T shall be a complete type,
    (possibly cv-qualified) void, or
    an array of unknown bound
    If T
    is a non‑union class type, T
    shall be a complete type
    .
    template <class T>
    struct is_polymorphic;
    T is a polymorphic
    class (10.3)
    T shall be a complete type,
    type, (possibly cv-qualified) void, or
    an array of unknown bound
    If T
    is a non‑union class type, T
    shall be a complete type
    .
    template <class T>
    struct is_abstract;
    T is an abstract
    class (10.4)
    T shall be a complete type,
    type, (possibly cv-qualified) void, or
    an array of unknown bound
    If T
    is a non‑union class type, T
    shall be a complete type
    .
    ...
    template <class T>
    struct has_virtual_destructor;
    T has a virtual
    destructor (12.4)
    T shall be a complete type,
    (possibly cv-qualified) void, or
    an array of unknown bound
    If T
    is a non‑union class type, T
    shall be a complete type
    .
  2. Modify the pre-conditions of the following type traits in 20.9.6 [meta.rel], Table 50 — Type relationship predicates:

    Table 50 — Type relationship predicates
    Template Condition Comments
    ...
    template <class Base, class
    Derived>
    struct is_base_of;
    Base is a base class of
    Derived (10) without
    regard to cv-qualifiers
    or Base and Derived
    are not unions and
    name the same class
    type without regard to
    cv-qualifiers
    If Base and Derived are
    non‑union class types
    and are different types
    (ignoring possible cv-qualifiers)
    then Derived shall be a complete
    type. [ Note: Base classes that
    are private, protected, or
    ambigious are, nonetheless, base
    classes. — end note ]
    ...

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: 2011-03-24

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.

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]). 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: 2011-03-24

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.

Proposed resolution:

Replace the Returns clause with a description in terms of ctype categories, rather than pseudocode in terms of bitwise operations. (full replacement wording to follow)


2021. Further incorrect usages of result_of

Section: 20.8.9.1.2 [func.bind.bind], 30.6.1 [futures.overview], 30.6.8 [futures.async] Status: Review Submitter: Daniel Krügler Opened: 2010-12-07 Last modified: 2011-03-24

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

View all issues with Review status.

Discussion:

Issue 2017 points out some incorrect usages of result_of in the declaration of the function call operator overload of reference_wrapper, but there are more such specification defects:

  1. According to 20.8.9.1.2 [func.bind.bind] p. 3:

    [..] The effect of g(u1, u2, ..., uM) shall be INVOKE(fd, v1, v2, ..., vN, result_of<FD cv (V1, V2, ..., VN)>::type) [..]

    but fd is defined as "an lvalue of type FD constructed from std::forward<F>(f)". This means that the above usage must refer to result_of<FD cv & (V1, V2, ..., VN)> instead.

  2. Similar in 20.8.9.1.2 [func.bind.bind] p. 10 bullet 2 we have:

    if the value of is_bind_expression<TiD>::value is true, the argument is tid(std::forward<Uj>(uj)...) and its type Vi is result_of<TiD cv (Uj...)>::type

    Again, tid is defined as "lvalue of type TiD constructed from std::forward<Ti>(ti)". This means that the above usage must refer to result_of<TiD cv & (Uj...)> instead. We also have similar defect as in 2017 in regard to the argument types, this leads us to the further corrected form result_of<TiD cv & (Uj&&...)>. This is not the end: Since the Vi are similar sensitive to the argument problem, the last part must say:

    "[..] its type Vi is result_of<TiD cv & (Uj&&...)>::type &&"

    (The bound arguments Vi can never be void types, therefore we don't need to use the more defensive std::add_rvalue_reference type trait)

  3. The function template async is declared as follows (the other overload has the same problem):

    template <class F, class... Args>
    future<typename result_of<F(Args...)>::type>
    async(F&& f, Args&&... args);
    

    This usage has the some same problems as we have found in reference_wrapper (2017) and more: According to the specification in 30.6.8 [futures.async] the effective result type is that of the call of

    INVOKE(decay_copy(std::forward<F>(f)), decay_copy(std::forward<Args>(args))...)
    

    First, decay_copy potentially modifies the effective types to decay<F>::type and decay<Args>::type.... Second, the current specification is not really clear, what the value category of callable type or the arguments shall be: According to the second bullet of 30.6.8 [futures.async] p. 3:

    Invocation of the deferred function evaluates INVOKE(g, 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))....

    This seems to imply that lvalues are provided in contrast to the direct call expression of 30.6.8 [futures.async] p. 2 which implies rvalues instead. The specification needs to be clarified.

Proposed resolution:

The suggested wording changes are against the working draft N3242.

  1. Change 20.8.9.1.2 [func.bind.bind] p. 3 as indicated:

    Returns: A forwarding call wrapper g with a weak result type (20.8.2). The effect of g(u1, u2, ..., uM) shall be INVOKE(fd, v1, v2, ..., vN, result_of<FD cv & (V1, V2, ..., VN)>::type), where cv represents the cv-qualifiers of g and the values and types of the bound arguments v1, v2, ..., vN are determined as specified below. [..]

  2. Change 20.8.9.1.2 [func.bind.bind] p. 10 bullet 2 as indicated:

    if the value of is_bind_expression<TiD>::value is true, the argument is tid(std::forward<Uj>(uj)...) and its type Vi is result_of<TiD cv & (Uj&&...)>::type&&;

  3. This resolution assumes that the wording of 30.6.8 [futures.async] is incorrectly implying rvalues as arguments of INVOKE, those should be lvalues instead.

    Change the function signatures in header <future> synopsis 30.6.1 [futures.overview] p. 1 and in 30.6.8 [futures.async] p. 1 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);
    
  4. Change 30.6.8 [futures.async] p. 4 as indicated: [Note: There is one tiny editorial correction that completes one :: scope specifier] [Note: This sub-section need more wording: The call expressions used imply a different value category]

    Returns: an object of type future<typename result_of<typename decay<F>::type&(typename decay<Args>::type&...)>::type> that refers to the associated asynchronous state created by this call to async.


2028. messages_base::catalog overspecified

Section: 22.4.7.1 [locale.messages] Status: Ready Submitter: Howard Hinnant Opened: 2011-02-14 Last modified: 2011-03-24

View all issues with Ready status.

Discussion:

In 22.4.7.1 [locale.messages], messages_base::catalog is specified to be a typedef to int. This type is subsequently used to open, access and close catalogs.

However, an OS may have catalog/messaging services that are indexed and managed by types other than int. For example POSIX, publishes the following messaging API:

typedef unspecified nl_catd;

nl_catd catopen(const char* name , int oflag);
char*   catgets(nl_catd catd, int set_id, int msg_id, const char* s);
int     catclose(nl_catd catd);

I.e., the catalog is managed with an unspecified type, not necessarily an int. Mac OS uses a void* for nl_catd (which is conforming to the POSIX standard). The current messages_base spec effectively outlaws using the built-in OS messaging service supplied for this very purpose!

[2011-02-24: Chris Jefferson updates the proposed wording, changing unspecified to unspecified signed integral type]

[2011-03-02: Daniel updates the proposed wording, changing unspecified signed integral type to unspecified signed integer type (We don't want to allow for bool or char)]

[2011-03-24 Madrid meeting]

Consensus that this resolution is the direction we would like to see.

Proposed resolution:

  1. Modify 22.4.7.1 [locale.messages]:

    namespace std {
      class messages_base {
      public:
        typedef intunspecified signed integer type catalog;
      };
      ...
    }
    

2033. Preconditions of reserve, shrink_to_fit, and resize functions

Section: 23.3.6.3 [vector.capacity], 23.3.3.3 [deque.capacity] Status: Open Submitter: Nikolay Ivchenkov Opened: 2011-02-20 Last modified: 2011-03-24

View all other issues in [vector.capacity].

View all issues with Open status.

Discussion:

I have several questions with regard to the working paper N3225 (C++0x working draft):

  1. Where the working draft specifies preconditions for shrink_to_fit member function of std::vector and std::deque?

  2. Where the working draft specifies preconditions for 'void reserve(size_type n)' member function of std::vector?

  3. Does a call to 'void resize(size_type sz)' of std::vector require the element type to be DefaultConstructible? If yes, why such requirement is not listed in the Requires paragraph?

  4. 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?

  5. Why CopyInsertable requirement is used for 'void resize(size_type sz)' of std::vector instead of MoveInsertable requirement?

Proposed resolution:


2035. Output iterator requirements are broken

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

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.

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] p. 5:

      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 &mdash> "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:

    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:

    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.
    post: r is incrementable.
    ++r X&   pre: r is incrementable.
    &r == &++r.
    Remark: After this operation
    r is not required to be
    dereferenceable or incrementable.
    post: r is incrementable.
    r++ convertible to const X& { X tmp = r;
    ++r;
    return tmp; }
    Remark: After this operation
    r is not required to be
    dereferenceable or incrementable.
    post: r is incrementable.
    *r++ = o result is not used { *r = o; ++r; } Remark: After this operation
    r is not required to be
    dereferenceable or incrementable.
    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: 2011-03-24

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.

Proposed resolution:


2039. Issues with std::reverse and std::copy_if

Section: 25.3.1 [alg.copy], 25.3.10 [alg.reverse] Status: Ready Submitter: Nikolay Ivchenkov Opened: 2011-03-02 Last modified: 2011-03-24

View all issues with Ready status.

Discussion:

  1. In the description of std::reverse

    Effects: For each non-negative integer i <= (last - first)/2, applies iter_swap to all pairs of iterators first + i, (last - i) - 1.

    should be changed to

    Effects: For each non-negative integer i < (last - first)/2, applies iter_swap to all pairs of iterators first + i, (last - i) - 1.

    Here i shall be strictly less than (last - first)/2.

  2. In the description of std::copy_if Returns paragraph is missing.

[2011-03-02: Daniel drafts wording]

Proposed resolution:

  1. Modify 25.3.10 [alg.reverse] p. 1 as indicated:

    1 Effects: For each non-negative integer i <= (last - first)/2, applies iter_swap to all pairs of iterators first + i, (last - i) - 1.

  2. Add the following Returns element after 25.3.1 [alg.copy] p. 9:

    template<class InputIterator, class OutputIterator, class Predicate>
    OutputIterator copy_if(InputIterator first, InputIterator last,
       OutputIterator result, Predicate pred);
    

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

    9 Effects: Copies all of the elements referred to by the iterator i in the range [first,last) for which pred(*i) is true.

    ?? Returns: The end of the resulting range.

    10 Complexity: Exactly last - first applications of the corresponding predicate.

    11 Remarks: Stable.


2040. Missing type traits related to is_convertible

Section: 20.9 [meta] Status: Open Submitter: Daniel Krügler Opened: 2011-03-03 Last modified: 2011-03-24

View all other issues in [meta].

View all issues with Open status.

Discussion:

When n3142 was suggested, it concentrated on constructions, assignments, and destructions, but overlooked to complement the single remaining compiler-support trait

template <class From, class To> struct is_convertible;

with the no-throw and triviality related aspects as it had been done with the other expression-based traits. Specifically, the current specification misses to add the following traits:

template <class From, class To> struct is_nothrow_convertible;
template <class From, class To> struct is_trivially_convertible;

In particular the lack of is_nothrow_convertible is severly restricting. This was recently recognized when the proposal for decay_copy was prepared by n3255. There does not exist a portable means to define the correct conditional noexcept specification for the decay_copy function template, which is declared as:

template <class T> 
typename decay<T>::type decay_copy(T&& v) noexcept(???);

The semantics of decay_copy bases on an implicit conversion which again influences the overload set of functions that are viable here. In most circumstances this will have the same effect as comparing against the trait std::is_nothrow_move_constructible, but there is no guarantee for that being the right answer. It is possible to construct examples, where this would lead to the false result, e.g.

struct S {
  S(const S&) noexcept(false);
 
  template<class T>
  explicit S(T&&) noexcept(true);
};

std::is_nothrow_move_constructible will properly honor the explicit template constructor because of the direct-initialization context which is part of the std::is_constructible definition and will in this case select it, such that std::is_nothrow_move_constructible<S>::value == true, but if we had the traits is_nothrow_convertible, is_nothrow_convertible<S, S>::value would evaluate to false, because it would use the copy-initialization context that is part of the is_convertible definition, excluding any explicit constructors and giving the opposite result.

The decay_copy example is surely not one of the most convincing examples, but is_nothrow_convertible has several use-cases, and can e.g. be used to express whether calling the following implicit conversion function could throw an exception or not:

template<class T, class U>
T implicit_cast(U&& u) noexcept(is_nothrow_convertible<U, T>::value) 
{
  return std::forward<U>(u);
}

Therefore I suggest to add the missing trait is_nothrow_convertible and for completeness also the missing trait is_trivially_convertible to 20.9 [meta].

[2011-03-24 Madrid meeting]

Daniel K: This is a new feature so out of scope.

Pablo: Any objections to moving 2040 to Open?

No objections.

Proposed resolution:

  1. Ammend the following declarations to the header <type_traits> synopsis in 20.9.2 [meta.type.synop]:

    namespace std {
      …
      // 20.9.6, type relations:
      template <class T, class U> struct is_same;
      template <class Base, class Derived> struct is_base_of;
      template <class From, class To> struct is_convertible;
      template <class From, class To> struct is_trivially_convertible;
      template <class From, class To> struct is_nothrow_convertible;
    
      …
    }
    
  2. Modify Table 51 — "Type relationship predicates" as indicated. The removal of the remaining traces of the trait is_explicitly_convertible is an editorial step, it was removed by n3047:

    Table 51 — Type relationship predicates
    Template Condition Comments
    template <class From, class To>
    struct is_convertible;
    see below From and To shall be complete
    types, arrays of unknown bound, or
    (possibly cv-qualified) void
    types.
    template <class From, class To>
    struct is_explicitly_convertible;
    is_constructible<To, From>::value a synonym for a two-argument
    version of is_constructible.
    An implementation may define it
    as an alias template.
    template <class From, class To>
    struct is_trivially_convertible;
    is_convertible<From,
    To>::value
    is true and the
    conversion, as defined by
    is_convertible, is known
    to call no operation that is
    not trivial ([basic.types], [special]).
    From and To shall be complete
    types, arrays of unknown bound,
    or (possibly cv-qualified) void
    types.
    template <class From, class To>
    struct is_nothrow_convertible;
    is_convertible<From,
    To>::value
    is true and the
    conversion, as defined by
    is_convertible, is known
    not to throw any
    exceptions ([expr.unary.noexcept]).
    From and To shall be complete
    types, arrays of unknown bound,
    or (possibly cv-qualified) void
    types.