| Doc. no. | N3054=10-0044 |
| Date: | 2010-03-12 |
| Project: | Programming Language C++ |
| Reply to: | Howard Hinnant <howard.hinnant@gmail.com> |
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 ANSI (J16) 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.
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.
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).
DR - (Defect Report) - The full J16 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 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 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 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.
Section: 20.3.4 [pairs] Status: Ready Submitter: Martin Sebor Opened: 2001-01-14 Last modified: 2009-10-26
View other active issues in [pairs].
View all other issues in [pairs].
View all issues with Ready status.
Discussion:
The synopsis of the header <utility> in 20.3 [utility] lists the complete set of equality and relational operators for pair but the section describing the template and the operators only describes operator==() and operator<(), and it fails to mention any requirements on the template arguments. The remaining operators are not mentioned at all.
[ 2009-09-27 Alisdair reopens. ]
The issue is a lack of wording specifying the semantics of std::pair relational operators. The rationale is that this is covered by catch-all wording in the relops component, and that as relops directly precedes pair in the document this is an easy connection to make.
Reading the current working paper I make two observations:
- relops no longer immediately precedes pair in the order of specification. However, even if it did, there is a lot of pair specification itself between the (apparently) unrelated relops and the relational operators for pair. (The catch-all still requires operator== and operator< to be specified explicitly)
- No other library component relies on the catch-all clause. The following all explicitly document all six relational operators, usually in a manner that could have deferred to the relops clause.
tuple unique_ptr duration time_point basic_string queue stack move_iterator reverse_iterator regex submatch thread::idThe container components provide their own (equivalent) definition in 23.2.1 [container.requirements.general] Table 90 -- Container requirements and do so do not defer to relops.
Shared_ptr explicitly documents operator!= and does not supply the other 3 missing operators (>,>=,<=) so does not meet the reqirements of the relops clause.
Weak_ptr only supports operator< so would not be covered by relops.
At the very least I would request a note pointing to the relops clause we rely on to provide this definition. If this route is taken, I would recommend reducing many of the above listed clauses to a similar note rather than providing redundant specification.
My preference would be to supply the 4 missing specifications consistent with the rest of the library.
[ 2009-10-11 Daniel opens 1233 which deals with the same issue as it pertains to unique_ptr. ]
[ 2009-10 Santa Cruz: ]
Move to Ready
Proposed resolution:
After p20 20.3.4 [pairs] add:
template <class T1, class T2> bool operator!=(const pair<T1,T2>& x, const pair<T1,T2>& y);Returns: !(x==y)template <class T1, class T2> bool operator> (const pair<T1,T2>& x, const pair<T1,T2>& y);Returns: y < xtemplate <class T1, class T2> bool operator>=(const pair<T1,T2>& x, const pair<T1,T2>& y);Returns: !(x < y)template <class T1, class T2> bool operator<=(const pair<T1,T2>& x, const pair<T1,T2>& y);Returns: !(y < x)
Rationale:
20.3.1 [operators] paragraph 10 already specifies the semantics. That paragraph says that, if declarations of operator!=, operator>, operator<=, and operator>= appear without definitions, they are defined as specified in 20.3.1 [operators]. There should be no user confusion, since that paragraph happens to immediately precede the specification of pair.
Section: 24.2.4 [bidirectional.iterators], 24.2.5 [random.access.iterators] Status: Open Submitter: John Potter Opened: 2001-01-22 Last modified: 2009-10-26
View all other issues in [bidirectional.iterators].
View all issues with Open status.
Discussion:
In section 24.2.4 [bidirectional.iterators], Table 75 gives the return type of *r-- as convertible to T. This is not consistent with Table 74 which gives the return type of *r++ as T&. *r++ = t is valid while *r-- = t is invalid.
In section 24.2.5 [random.access.iterators], Table 76 gives the return type of a[n] as convertible to T. This is not consistent with the semantics of *(a + n) which returns T& by Table 74. *(a + n) = t is valid while a[n] = t is invalid.
Discussion from the Copenhagen meeting: the first part is uncontroversial. The second part, operator[] for Random Access Iterators, requires more thought. There are reasonable arguments on both sides. Return by value from operator[] enables some potentially useful iterators, e.g. a random access "iota iterator" (a.k.a "counting iterator" or "int iterator"). There isn't any obvious way to do this with return-by-reference, since the reference would be to a temporary. On the other hand, reverse_iterator takes an arbitrary Random Access Iterator as template argument, and its operator[] returns by reference. If we decided that the return type in Table 76 was correct, we would have to change reverse_iterator. This change would probably affect user code.
History: the contradiction between reverse_iterator and the Random Access Iterator requirements has been present from an early stage. In both the STL proposal adopted by the committee (N0527==94-0140) and the STL technical report (HPL-95-11 (R.1), by Stepanov and Lee), the Random Access Iterator requirements say that operator[]'s return value is "convertible to T". In N0527 reverse_iterator's operator[] returns by value, but in HPL-95-11 (R.1), and in the STL implementation that HP released to the public, reverse_iterator's operator[] returns by reference. In 1995, the standard was amended to reflect the contents of HPL-95-11 (R.1). The original intent for operator[] is unclear.
In the long term it may be desirable to add more fine-grained iterator requirements, so that access method and traversal strategy can be decoupled. (See "Improved Iterator Categories and Requirements", N1297 = 01-0011, by Jeremy Siek.) Any decisions about issue 299 should keep this possibility in mind.
Further discussion: I propose a compromise between John Potter's resolution, which requires T& as the return type of a[n], and the current wording, which requires convertible to T. The compromise is to keep the convertible to T for the return type of the expression a[n], but to also add a[n] = t as a valid expression. This compromise "saves" the common case uses of random access iterators, while at the same time allowing iterators such as counting iterator and caching file iterators to remain random access iterators (iterators where the lifetime of the object returned by operator*() is tied to the lifetime of the iterator).
Note that the compromise resolution necessitates a change to reverse_iterator. It would need to use a proxy to support a[n] = t.
Note also there is one kind of mutable random access iterator that will no longer meet the new requirements. Currently, iterators that return an r-value from operator[] meet the requirements for a mutable random access iterartor, even though the expression a[n] = t will only modify a temporary that goes away. With this proposed resolution, a[n] = t will be required to have the same operational semantics as *(a + n) = t.
[ 2009-07-28 Reopened by Alisdair. No longer solved by concepts. ]
[ 2009-09-18 Alisdair adds: ]
Why can't we write through the reference returned from operator[] on a random access iterator?
Recommended solution:
In table Table 104 -- Random access iterator requirements, replace
a[n] : convertible toconst T &T& if X is mutable, otherwise convertible to const T&
[ 2009-10 Santa Cruz: ]
Leave Open. Alisdair to spearhead a paper on revivification.
Proposed resolution:
In section 24.1.4 [lib.bidirectdional.iterators], change the return type in table 75 from "convertible to T" to T&.
In section 24.1.5 [lib.random.access.iterators], change the operational semantics for a[n] to " the r-value of a[n] is equivalent to the r-value of *(a + n)". Add a new row in the table for the expression a[n] = t with a return type of convertible to T and operational semantics of *(a + n) = t.
[Lillehammer: Real problem, but should be addressed as part of iterator redesign]
Rationale:
[ San Francisco: ]
Solved by N2758.
Section: 24.2 [iterator.requirements] Status: Open Submitter: Nathan Myers Opened: 2003-06-03 Last modified: 2009-11-03
View other active issues in [iterator.requirements].
View all other issues in [iterator.requirements].
View all issues with Open status.
Discussion:
I've been discussing iterator semantics with Dave Abrahams, and a surprise has popped up. I don't think this has been discussed before.
X [iterator.concepts] says that the only operation that can be performed on "singular" iterator values is to assign a non-singular value to them. (It doesn't say they can be destroyed, and that's probably a defect.) Some implementations have taken this to imply that there is no need to initialize the data member of a reverse_iterator<> in the default constructor. As a result, code like
std::vector<std::reverse_iterator<char*> > v(7); v.reserve(1000);
invokes undefined behavior, because it must default-initialize the vector elements, and then copy them to other storage. Of course many other vector operations on these adapters are also left undefined, and which those are is not reliably deducible from the standard.
I don't think that 24.1 was meant to make standard-library iterator types unsafe. Rather, it was meant to restrict what operations may be performed by functions which take general user- and standard iterators as arguments, so that raw pointers would qualify as iterators. However, this is not clear in the text, others have come to the opposite conclusion.
One question is whether the standard iterator adaptors have defined copy semantics. Another is whether they have defined destructor semantics: is
{ std::vector<std::reverse_iterator<char*> > v(7); }
undefined too?
Note this is not a question of whether algorithms are allowed to rely on copy semantics for arbitrary iterators, just whether the types we actually supply support those operations. I believe the resolution must be expressed in terms of the semantics of the adapter's argument type. It should make clear that, e.g., the reverse_iterator<T> constructor is actually required to execute T(), and so copying is defined if the result of T() is copyable.
Issue 235, which defines reverse_iterator's default constructor more precisely, has some relevance to this issue. However, it is not the whole story.
The issue was whether
reverse_iterator() { }
is allowed, vs.
reverse_iterator() : current() { }
The difference is when T is char*, where the first leaves the member uninitialized, and possibly equal to an existing pointer value, or (on some targets) may result in a hardware trap when copied.
8.5 paragraph 5 seems to make clear that the second is required to satisfy DR 235, at least for non-class Iterator argument types.
But that only takes care of reverse_iterator, and doesn't establish a policy for all iterators. (The reverse iterator adapter was just an example.) In particular, does my function
template <typename Iterator>
void f() { std::vector<Iterator> v(7); }
evoke undefined behavior for some conforming iterator definitions? I think it does, now, because vector<> will destroy those singular iterator values, and that's explicitly disallowed.
24.1 shouldn't give blanket permission to copy all singular iterators, because then pointers wouldn't qualify as iterators. However, it should allow copying of that subset of singular iterator values that are default-initialized, and it should explicitly allow destroying any iterator value, singular or not, default-initialized or not.
[ We don't want to require all singular iterators to be copyable, because that is not the case for pointers. However, default construction may be a special case. Issue: is it really default construction we want to talk about, or is it something like value initialization? We need to check with core to see whether default constructed pointers are required to be copyable; if not, it would be wrong to impose so strict a requirement for iterators. ]
[ 2009-05-10 Alisdair provided wording. ]
The comments regarding destroying singular iterators have already been resolved. That just leaves copying (with moving implied).
[ 2009-07 Frankfurt ]
This is related to LWG 1012.
Note that there is a bug in the proposed resolution to LWG 1012. The change to [reverse.iter.con] should be modified so that the word "default" in the second sentence of the Effects clause is replaced by "value."
We believe that the proposed fix to LWG 1012 (now corrected) is sufficient to solve the problem for reverse_iterator. However, Alisdair pointed out that LWG 1012 does not solve the general problem for authors of iterator adaptors.
There are some problems with the proposed resolution. The phrase "safely copyable" is not a term of art. Also, it mentions a DefaultConstructible? concept.
Move to Review after Alisdair updates the wording.
[ 2009-07-31 Alisdair revised wording: ]
[ 2009-08-17 Alisdair and Daniel collaborate on slightly revised wording. This issue depends upon 724 ]
[ 2009-10-14 Daniel adds: ]
There is a clear dependency on 1213, because the term "singular", which is used as part of the resolution, is not properly defined yet.
[ 2009-10 Santa Cruz: ]
Moved to Open. Alisdair will provide improved wording to make this have "value semantics" and otherwise behave like a valid iterator.
Proposed resolution:
Add a new paragrpah to Iterator concepts 24.2 [iterator.requirements] after para 5 (the one describing singular iterators)
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 container. 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. [Example: After the declaration of an uninitialized pointer x (as with int* x;), x must always be assumed to have a singular value of a pointer. — end example] 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. In this case the singular value is overwritten the same way as any other value. Dereferenceable values are always non-singular.
After value-initialization, any iterator that satisfies the DefaultConstructible requirements ([defaultconstructible]) shall not introduce undefined behaviour when used as the source of a copy or move operation, even if it would otherwise be singular. [Note: This guarantee is not offered for default-initialization (8.5 [dcl.init]), although the distinction only matters for types with trivial default constructors such as pointers. — end note]
Section: 22.4.2.1.2 [facet.num.get.virtuals] Status: Ready Submitter: Martin Sebor Opened: 2003-09-18 Last modified: 2010-03-09
View other active issues in [facet.num.get.virtuals].
View all other issues in [facet.num.get.virtuals].
View all issues with Ready status.
Discussion:
The requirements specified in Stage 2 and reiterated in the rationale of DR 221 (and echoed again in DR 303) specify that num_get<charT>:: do_get() compares characters on the stream against the widened elements of "012...abc...ABCX+-"
An implementation is required to allow programs to instantiate the num_get template on any charT that satisfies the requirements on a user-defined character type. These requirements do not include the ability of the character type to be equality comparable (the char_traits template must be used to perform tests for equality). Hence, the num_get template cannot be implemented to support any arbitrary character type. The num_get template must either make the assumption that the character type is equality-comparable (as some popular implementations do), or it may use char_traits<charT> to do the comparisons (some other popular implementations do that). This diversity of approaches makes it difficult to write portable programs that attempt to instantiate the num_get template on user-defined types.
[Kona: the heart of the problem is that we're theoretically supposed to use traits classes for all fundamental character operations like assignment and comparison, but facets don't have traits parameters. This is a fundamental design flaw and it appears all over the place, not just in this one place. It's not clear what the correct solution is, but a thorough review of facets and traits is in order. The LWG considered and rejected the possibility of changing numeric facets to use narrowing instead of widening. This may be a good idea for other reasons (see issue 459), but it doesn't solve the problem raised by this issue. Whether we use widen or narrow the num_get facet still has no idea which traits class the user wants to use for the comparison, because only streams, not facets, are passed traits classes. The standard does not require that two different traits classes with the same char_type must necessarily have the same behavior.]
Informally, one possibility: require that some of the basic character operations, such as eq, lt, and assign, must behave the same way for all traits classes with the same char_type. If we accept that limitation on traits classes, then the facet could reasonably be required to use char_traits<charT>.
[ 2009-07 Frankfurt ]
There was general agreement that the standard only needs to specify the behavior when the character type is char or wchar_t.
Beman: we don't need to worry about C++1x because there is a non-zero possibility that we would have a replacement facility for iostreams that would solve these problems.
We need to change the following sentence in [locale.category], paragraph 6 to specify that C is char and wchar_t:
"A template formal parameter with name C represents the set of all possible specializations on a parameter that satisfies the requirements for a character on which any member of the iostream components can be instantiated."
We also need to specify in 27 that the basic character operations, such as eq, lt, and assign use std::char_traits.
Daniel volunteered to provide wording.
[ 2009-09-19 Daniel provided wording. ]
[ 2009-10 Santa Cruz: ]
Leave as Open. Alisdair and/or Tom will provide wording based on discussions. We want to clearly state that streams and locales work just on char and wchar_t (except where otherwise specified).
[ 2010-02-06 Tom updated the proposed wording. ]
[ The original proposed wording is preserved here: ]
Change 22.3.1.1.1 [locale.category]/6:
[..] A template formal parameter with name C represents the set of all possible specializations on a char or wchar_t parameterthat satisfies the requirements for a character on which any of the iostream components can be instantiated. [..]Add the following sentence to the end of 22.4.2 [category.numeric]/2:
[..] These specializations refer to [..], and also for the ctype<> facet to perform character classification. Implementations are encouraged but not required to use the char_traits<charT> functions for all comparisons and assignments of characters of type charT that do not belong to the set of required specializations.Change 22.4.2.1.2 [facet.num.get.virtuals]/3:
Stage 2: If in==end then stage 2 terminates. Otherwise a charT is taken from in and local variables are initialized as if by
char_type ct = *in; using tr = char_traits<char_type>; const char_type* pos = tr::find(atoms, sizeof(src) - 1, ct); char c = src[find(atoms, atoms + sizeof(src) - 1, ct) - atomspos ? pos - atoms : sizeof(src) - 1]; if (tr::eq(ct,ct ==use_facet<numpunct<charT>(loc).decimal_point())) c = '.'; bool discard = tr::eq(ct,ct ==use_facet<numpunct<charT>(loc).thousands_sep()) && use_facet<numpunct<charT> >(loc).grouping().length() != 0;where the values src and atoms are defined as if by: [..]
[Remark of the author: I considered to replace the initialization "char_type ct = *in;" by the sequence "char_type ct; tr::assign(ct, *in);", but decided against it, because it is a copy-initialization context, not an assignment]
Add the following sentence to the end of 22.4.5 [category.time]/1:
[..] Their members use [..] , to determine formatting details. Implementations are encouraged but not required to use the char_traits<charT> functions for all comparisons and assignments of characters of type charT that do not belong to the set of required specializations.Change 22.4.5.1.1 [locale.time.get.members]/8 bullet 4:
The next element of fmt is equal to '%'For the next element c of fmt char_traits<char_type>::eq(c, use_facet<ctype<char_type>>(f.getloc()).widen('%')) == true, [..]Add the following sentence to the end of 22.4.6 [category.monetary]/2:
Their members use [..] to determine formatting details. Implementations are encouraged but not required to use the char_traits<charT> functions for all comparisons and assignments of characters of type charT that do not belong to the set of required specializations.Change 22.4.6.1.2 [locale.money.get.virtuals]/4:
[..] The value units is produced as if by:
for (int i = 0; i < n; ++i) buf2[i] = src[char_traits<charT>::find(atoms,atoms+sizeof(src), buf1[i]) - atoms]; buf2[n] = 0; sscanf(buf2, "%Lf", &units);Change 22.4.6.2.2 [locale.money.put.virtuals]/1:
[..] for character buffers buf1 and buf2. If for the first character c in digits or buf2is equal to ct.widen('-')char_traits<charT>::eq(c, ct.widen('-')) == true, [..]Add a footnote to the first sentence of 27.7.1.2.2 [istream.formatted.arithmetic]/1:
As in the case of the inserters, these extractors depend on the locale's num_get<> (22.4.2.1) object to perform parsing the input stream data.(footnote) [..]
footnote) If the traits of the input stream has different semantics for lt(), eq(), and assign() than char_traits<char_type>, this may give surprising results.
Add a footnote to the second sentence of 27.7.2.6.2 [ostream.inserters.arithmetic]/1:
Effects: The classes num_get<> and num_put<> handle locale-dependent numeric formatting and parsing. These inserter functions use the imbued locale value to perform numeric formatting.(footnote) [..]
footnote) If the traits of the output stream has different semantics for lt(), eq(), and assign() than char_traits<char_type>, this may give surprising results.
Add a footnote after the first sentence of 27.7.4 [ext.manip]/4:
Returns: An object of unspecified type such that if in is an object of type basic_istream<charT, traits> then the expression in >> get_money(mon, intl) behaves as if it called f(in, mon, intl), where the function f is defined as:(footnote) [..]
footnote) If the traits of the input stream has different semantics for lt(), eq(), and assign() than char_traits<char_type>, this may give surprising results.
Add a footnote after the first sentence of 27.7.4 [ext.manip]/5:
Returns: An object of unspecified type such that if out is an object of type basic_ostream<charT, traits> then the expression out << put_money(mon, intl) behaves as a formatted input function that calls f(out, mon, intl), where the function f is defined as:(footnote) [..]
footnote) If the traits of the output stream has different semantics for lt(), eq(), and assign() than char_traits<char_type>, this may give surprising results.
13) Add a footnote after the first sentence of 27.7.4 [ext.manip]/8:
Returns: An object of unspecified type such that if in is an object of type basic_istream<charT, traits> then the expression in >>get_time(tmb, fmt) behaves as if it called f(in, tmb, fmt), where the function f is defined as:(footnote) [..]
footnote) If the traits of the input stream has different semantics for lt(), eq(), and assign() than char_traits<char_type>, this may give surprising results.
Add a footnote after the first sentence of 27.7.4 [ext.manip]/10:
Returns: An object of unspecified type such that if out is an object of type basic_ostream<charT, traits> then the expression out <<put_time(tmb, fmt) behaves as if it called f(out, tmb, fmt), where the function f is defined as:(footnote) [..]
footnote) If the traits of the output stream has different semantics for lt(), eq(), and assign() than char_traits<char_type>, this may give surprising results.
[ 2010 Pittsburgh: ]
Moved to Ready with only two of the bullets. The original wording is preserved here:
Change 22.3.1.1.1 [locale.category]/6:
[..] A template formal parameter with name C represents the setof all possible specializations on aof types containing char, wchar_t, and any other implementation-defined character typeparameterthat satisfies the requirements for a character on which any of the iostream components can be instantiated. [..]Add the following sentence to the end of 22.4.2 [category.numeric]/2:
[..] These specializations refer to [..], and also for the ctype<> facet to perform character classification. [Note: Implementations are encouraged but not required to use the char_traits<charT> functions for all comparisons and assignments of characters of type charT that do not belong to the set of required specializations - end note].Change 22.4.2.1.2 [facet.num.get.virtuals]/3:
Stage 2: If in==end then stage 2 terminates. Otherwise a charT is taken from in and local variables are initialized as if by
char_type ct = *in; using tr = char_traits<char_type>; const char_type* pos = tr::find(atoms, sizeof(src) - 1, ct); char c = src[find(atoms, atoms + sizeof(src) - 1, ct) - atomspos ? pos - atoms : sizeof(src) - 1]; if (tr::eq(ct,ct ==use_facet<numpunct<charT>(loc).decimal_point())) c = '.'; bool discard = tr::eq(ct,ct ==use_facet<numpunct<charT>(loc).thousands_sep()) && use_facet<numpunct<charT> >(loc).grouping().length() != 0;where the values src and atoms are defined as if by: [..]
[Remark of the author: I considered to replace the initialization "char_type ct = *in;" by the sequence "char_type ct; tr::assign(ct, *in);", but decided against it, because it is a copy-initialization context, not an assignment]
Add the following sentence to the end of 22.4.5 [category.time]/1:
[..] Their members use [..] , to determine formatting details. [Note: Implementations are encouraged but not required to use the char_traits<charT> functions for all comparisons and assignments of characters of type charT that do not belong to the set of required specializations - end note].Change 22.4.5.1.1 [locale.time.get.members]/8 bullet 4:
The next element of fmt is equal to '%'For the next element c of fmt char_traits<char_type>::eq(c, use_facet<ctype<char_type>>(f.getloc()).widen('%')) == true, [..]Add the following sentence to the end of 22.4.6 [category.monetary]/2:
Their members use [..] to determine formatting details. [Note: Implementations are encouraged but not required to use the char_traits<charT> functions for all comparisons and assignments of characters of type charT that do not belong to the set of required specializations - end note].Change 22.4.6.1.2 [locale.money.get.virtuals]/4:
[..] The value units is produced as if by:
for (int i = 0; i < n; ++i) buf2[i] = src[char_traits<charT>::find(atoms,atoms+sizeof(src), buf1[i]) - atoms]; buf2[n] = 0; sscanf(buf2, "%Lf", &units);Change 22.4.6.2.2 [locale.money.put.virtuals]/1:
[..] for character buffers buf1 and buf2. If for the first character c in digits or buf2is equal to ct.widen('-')char_traits<charT>::eq(c, ct.widen('-')) == true, [..]Add a new paragraph after the first paragraph of 27.2.2 [iostreams.limits.pos]/1:
In the classes of clause 27, a template formal parameter with name charT represents one of the set of types containing char, wchar_t, and any other implementation-defined character type that satisfies the requirements for a character on which any of the iostream components can be instantiated.Add a footnote to the first sentence of 27.7.1.2.2 [istream.formatted.arithmetic]/1:
As in the case of the inserters, these extractors depend on the locale's num_get<> (22.4.2.1) object to perform parsing the input stream data.(footnote) [..]
footnote) If the traits of the input stream has different semantics for lt(), eq(), and assign() than char_traits<char_type>, this may give surprising results.
Add a footnote to the second sentence of 27.7.2.6.2 [ostream.inserters.arithmetic]/1:
Effects: The classes num_get<> and num_put<> handle locale-dependent numeric formatting and parsing. These inserter functions use the imbued locale value to perform numeric formatting.(footnote) [..]
footnote) If the traits of the output stream has different semantics for lt(), eq(), and assign() than char_traits<char_type>, this may give surprising results.
Add a footnote after the first sentence of 27.7.4 [ext.manip]/4:
Returns: An object of unspecified type such that if in is an object of type basic_istream<charT, traits> then the expression in >> get_money(mon, intl) behaves as if it called f(in, mon, intl), where the function f is defined as:(footnote) [..]
footnote) If the traits of the input stream has different semantics for lt(), eq(), and assign() than char_traits<char_type>, this may give surprising results.
Add a footnote after the first sentence of 27.7.4 [ext.manip]/5:
Returns: An object of unspecified type such that if out is an object of type basic_ostream<charT, traits> then the expression out << put_money(mon, intl) behaves as a formatted input function that calls f(out, mon, intl), where the function f is defined as:(footnote) [..]
footnote) If the traits of the output stream has different semantics for lt(), eq(), and assign() than char_traits<char_type>, this may give surprising results.
Add a footnote after the first sentence of 27.7.4 [ext.manip]/8:
Returns: An object of unspecified type such that if in is an object of type basic_istream<charT, traits> then the expression in >>get_time(tmb, fmt) behaves as if it called f(in, tmb, fmt), where the function f is defined as:(footnote) [..]
footnote) If the traits of the input stream has different semantics for lt(), eq(), and assign() than char_traits<char_type>, this may give surprising results.
Add a footnote after the first sentence of 27.7.4 [ext.manip]/10:
Returns: An object of unspecified type such that if out is an object of type basic_ostream<charT, traits> then the expression out <<put_time(tmb, fmt) behaves as if it called f(out, tmb, fmt), where the function f is defined as:(footnote) [..]
footnote) If the traits of the output stream has different semantics for lt(), eq(), and assign() than char_traits<char_type>, this may give surprising results.
Proposed resolution:
Change 22.3.1.1.1 [locale.category]/6:
[..] A template formal parameter with name C represents the setof all possible specializations on aof types containing char, wchar_t, and any other implementation-defined character typeparameterthat satisfies the requirements for a character on which any of the iostream components can be instantiated. [..]
Add a new paragraph after the first paragraph of 27.2.2 [iostreams.limits.pos]/1:
In the classes of clause 27, a template formal parameter with name charT represents one of the set of types containing char, wchar_t, and any other implementation-defined character type that satisfies the requirements for a character on which any of the iostream components can be instantiated.
Section: 26.6.2.4 [valarray.sub] Status: Ready Submitter: Martin Sebor Opened: 2003-09-18 Last modified: 2010-03-12
View all issues with Ready status.
Discussion:
The standard fails to specify the behavior of valarray::operator[](slice) and other valarray subset operations when they are passed an "invalid" slice object, i.e., either a slice that doesn't make sense at all (e.g., slice (0, 1, 0) or one that doesn't specify a valid subset of the valarray object (e.g., slice (2, 1, 1) for a valarray of size 1).
[Kona: the LWG believes that invalid slices should invoke undefined behavior. Valarrays are supposed to be designed for high performance, so we don't want to require specific checking. We need wording to express this decision.]
[ Bellevue: ]
Please note that the standard also fails to specify the behavior of slice_array and gslice_array in the valid case. Bill Plauger will endeavor to provide revised wording for slice_array and gslice_array.
[ post-Bellevue: Bill provided wording. ]
[ 2009-07 Frankfurt ]
Move to Ready.
[ 2009-11-04 Pete opens: ]
The resolution to LWG issue 430 has not been applied --- there have been changes to the underlying text, and the resolution needs to be reworked.
[ 2010-03-09 Matt updated wording. ]
[ 2010 Pittsburgh: Moved to Ready for Pittsburgh. ]
Proposed resolution:
Replace 26.6.2.4 [valarray.sub], with the following:
The member operator is overloaded to provide several ways to select sequences of elements from among those controlled by *this. Each of these operations returns a subset of the array. The const-qualified versions return this subset as a new valarray. The non-const versions return a class template object which has reference semantics to the original array, working in conjunction with various overloads of operator= (and other assigning operators) to allow selective replacement (slicing) of the controlled sequence. In each case the selected element(s) must exist.
valarray<T> operator[](slice slicearr) const;This function returns an object of class valarray<T> containing those elements of the controlled sequence designated by slicearr. [Example:
valarray<char> v0("abcdefghijklmnop", 16); valarray<char> v1("ABCDE", 5); v0[slice(2, 5, 3)] = v1; // v0 == valarray<char>("abAdeBghCjkDmnEp", 16)end example]
valarray<T> operator[](slice slicearr);This function selects those elements of the controlled sequence designated by slicearr. [Example:
valarray<char> v0("abcdefghijklmnop", 16); valarray<char> v1("ABCDE", 5); v0[slice(2, 5, 3)] = v1; // v0 == valarray<char>("abAdeBghCjkDmnEp", 16)end example]
valarray<T> operator[](const gslice& gslicearr) const;This function returns an object of class valarray<T> containing those elements of the controlled sequence designated by gslicearr. [Example:
valarray<char> v0("abcdefghijklmnop", 16); const size_t lv[] = {2, 3}; const size_t dv[] = {7, 2}; const valarray<size_t> len(lv, 2), str(dv, 2); // v0[gslice(3, len, str)] returns // valarray<char>("dfhkmo", 6)end example]
gslice_array<T> operator[](const gslice& gslicearr);This function selects those elements of the controlled sequence designated by gslicearr. [Example:
valarray<char> v0("abcdefghijklmnop", 16); valarray<char> v1("ABCDEF", 6); const size_t lv[] = {2, 3}; const size_t dv[] = {7, 2}; const valarray<size_t> len(lv, 2), str(dv, 2); v0[gslice(3, len, str)] = v1; // v0 == valarray<char>("abcAeBgCijDlEnFp", 16)end example]
valarray<T> operator[](const valarray<bool>& boolarr) const;This function returns an object of class valarray<T> containing those elements of the controlled sequence designated by boolarr. [Example:
valarray<char> v0("abcdefghijklmnop", 16); const bool vb[] = {false, false, true, true, false, true}; // v0[valarray<bool>(vb, 6)] returns // valarray<char>("cdf", 3)end example]
mask_array<T> operator[](const valarray<bool>& boolarr);This function selects those elements of the controlled sequence designated by boolarr. [Example:
valarray<char> v0("abcdefghijklmnop", 16); valarray<char> v1("ABC", 3); const bool vb[] = {false, false, true, true, false, true}; v0[valarray<bool>(vb, 6)] = v1; // v0 == valarray<char>("abABeCghijklmnop", 16)end example]
valarray<T> operator[](const valarray<size_t>& indarr) const;This function returns an object of class valarray<T> containing those elements of the controlled sequence designated by indarr. [Example:
valarray<char> v0("abcdefghijklmnop", 16); const size_t vi[] = {7, 5, 2, 3, 8}; // v0[valarray<size_t>(vi, 5)] returns // valarray<char>("hfcdi", 5)end example]
indirect_array<T> operator[](const valarray<size_t>& indarr);This function selects those elements of the controlled sequence designated by indarr. [Example:
valarray<char> v0("abcdefghijklmnop", 16); valarray<char> v1("ABCDE", 5); const size_t vi[] = {7, 5, 2, 3, 8}; v0[valarray<size_t>(vi, 5)] = v1; // v0 == valarray<char>("abCDeBgAEjklmnop", 16)end example]
Section: 24.2 [iterator.requirements], 23.2 [container.requirements] Status: Open Submitter: Andy Koenig Opened: 2003-12-16 Last modified: 2009-11-03
View other active issues in [iterator.requirements].
View all other issues in [iterator.requirements].
View all issues with Open status.
Discussion:
What requirements does the standard place on equality comparisons between iterators that refer to elements of different containers. For example, if v1 and v2 are empty vectors, is v1.end() == v2.end() allowed to yield true? Is it allowed to throw an exception?
The standard appears to be silent on both questions.
[Sydney: The intention is that comparing two iterators from different containers is undefined, but it's not clear if we say that, or even whether it's something we should be saying in clause 23 or in clause 24. Intuitively we might want to say that equality is defined only if one iterator is reachable from another, but figuring out how to say it in any sensible way is a bit tricky: reachability is defined in terms of equality, so we can't also define equality in terms of reachability. ]
[ 2009-07 Frankfurt ]
Daniel volunteered to work on this.
[ 2009-09-20 Daniel provided wording. ]
[ 2009-10 Santa Cruz: ]
Leave as Open. Alisdair has volunteered to refine the wording.
Proposed resolution:
Insert a new paragraph between 24.2 [iterator.requirements]/7+8:
[..] The result of the application of functions in the library to invalid ranges is undefined.
The result of directly or indirectly evaluating any comparison function or the binary - operator with two iterator values as arguments that were obtained from two different ranges r1 and r2 (including their past-the-end values) which are not subranges of one common range is undefined, unless explicitly described otherwise.
Section: 18.8.1 [exception] Status: Ready Submitter: Martin Sebor Opened: 2004-06-28 Last modified: 2009-10-26
View all issues with Ready status.
Discussion:
[lib.exception] specifies the following:
exception (const exception&) throw();
exception& operator= (const exception&) throw();
-4- Effects: Copies an exception object.
-5- Notes: The effects of calling what() after assignment
are implementation-defined.
First, does the Note only apply to the assignment operator? If so, what are the effects of calling what() on a copy of an object? Is the returned pointer supposed to point to an identical copy of the NTBS returned by what() called on the original object or not?
Second, is this Note intended to extend to all the derived classes in section 19? I.e., does the standard provide any guarantee for the effects of what() called on a copy of any of the derived class described in section 19?
Finally, if the answer to the first question is no, I believe it constitutes a defect since throwing an exception object typically implies invoking the copy ctor on the object. If the answer is yes, then I believe the standard ought to be clarified to spell out exactly what the effects are on the copy (i.e., after the copy ctor was called).
[Redmond: Yes, this is fuzzy. The issue of derived classes is fuzzy too.]
[ Batavia: Howard provided wording. ]
[ Bellevue: ]
Eric concerned this is unimplementable, due to nothrow guarantees. Suggested implementation would involve reference counting.
Is the implied reference counting subtle enough to call out a note on implementation? Probably not.
If reference counting required, could we tighten specification further to require same pointer value? Probably an overspecification, especially if exception classes defer evalutation of final string to calls to what().
Remember issue moved open and not resolved at Batavia, but cannot remember who objected to canvas a disenting opinion - please speak up if you disagree while reading these minutes!
Move to Ready as we are accepting words unmodified.
[ Sophia Antipolis: ]
The issue was pulled from Ready. It needs to make clear that only homogenous copying is intended to be supported, not coping from a derived to a base.
[ Batavia (2009-05): ]
Howard supplied the following replacement wording for paragraph 7 of the proposed resolution:
-7- Postcondition: what() shall return the same NTBS as would be obtained by using static_cast to cast the rhs to the same types as the lhs and then calling what() on that possibly sliced object.Pete asks what "the same NTBS" means.
[ 2009-07-30 Niels adds: ]
Further discussion in the thread starting with c++std-lib-24512.
[ 2009-09-24 Niels provided updated wording: ]
I think the resolution should at least guarantee that the result of what() is independent of whether the compiler does copy-elision. And for any class derived from std::excepion that has a constructor that allows specifying a what_arg, it should make sure that the text of a user-provided what_arg is preserved, when the object is copied. Note that all the implementations I've tested already appear to satisfy the proposed resolution, including MSVC 2008 SP1, Apache stdcxx-4.2.1, GCC 4.1.2, GCC 4.3.2, and CodeGear C++ 6.13.
The proposed resolution was updated with help from Daniel Krügler; the update aims to clarify that the proposed postcondition only applies to homogeneous copying.
[ 2009-10 Santa Cruz: ]
Moved to Ready after inserting "publicly accessible" in two places.
Proposed resolution:
Change 18.8.1 [exception] to:
-1- The class exception defines the base class for the types of objects thrown as exceptions by C++ standard library components, and certain expressions, to report errors detected during program execution.
Each standard library class T that derives from class exception shall have a publicly accessible copy constructor and a publicly accessible copy assignment operator that do not exit with an exception. These member functions shall preserve the following postcondition: If two objects lhs and rhs both have dynamic type T, and lhs is a copy of rhs, then strcmp(lhs.what(), rhs.what()) == 0.
...
exception(const exception& rhs) throw(); exception& operator=(const exception& rhs) throw();-4- Effects: Copies an exception object.
-5- Remarks: The effects of calling what() after assignment are implementation-defined.-5- Postcondition: If *this and rhs both have dynamic type exception then strcmp(what(), rhs.what()) == 0.
Section: 22.4.1.1 [locale.ctype] Status: Ready Submitter: Martin Sebor Opened: 2004-07-01 Last modified: 2009-10-21
View all issues with Ready status.
Discussion:
Most ctype member functions come in two forms: one that operates on a single character at a time and another form that operates on a range of characters. Both forms are typically described by a single Effects and/or Returns clause.
The Returns clause of each of the single-character non-virtual forms suggests that the function calls the corresponding single character virtual function, and that the array form calls the corresponding virtual array form. Neither of the two forms of each virtual member function is required to be implemented in terms of the other.
There are three problems:
1. One is that while the standard does suggest that each non-virtual member function calls the corresponding form of the virtual function, it doesn't actually explicitly require it.
Implementations that cache results from some of the virtual member functions for some or all values of their arguments might want to call the array form from the non-array form the first time to fill the cache and avoid any or most subsequent virtual calls. Programs that rely on each form of the virtual function being called from the corresponding non-virtual function will see unexpected behavior when using such implementations.
2. The second problem is that either form of each of the virtual functions can be overridden by a user-defined function in a derived class to return a value that is different from the one produced by the virtual function of the alternate form that has not been overriden.
Thus, it might be possible for, say, ctype::widen(c) to return one value, while for ctype::widen(&c, &c + 1, &wc) to set wc to another value. This is almost certainly not intended. Both forms of every function should be required to return the same result for the same character, otherwise the same program using an implementation that calls one form of the functions will behave differently than when using another implementation that calls the other form of the function "under the hood."
3. The last problem is that the standard text fails to specify whether one form of any of the virtual functions is permitted to be implemented in terms of the other form or not, and if so, whether it is required or permitted to call the overridden virtual function or not.
Thus, a program that overrides one of the virtual functions so that it calls the other form which then calls the base member might end up in an infinite loop if the called form of the base implementation of the function in turn calls the other form.
Lillehammer: Part of this isn't a real problem. We already talk about caching. 22.1.1/6 But part is a real problem. ctype virtuals may call each other, so users don't know which ones to override to avoid avoid infinite loops.
This is a problem for all facet virtuals, not just ctype virtuals, so we probably want a blanket statement in clause 22 for all facets. The LWG is leaning toward a blanket prohibition, that a facet's virtuals may never call each other. We might want to do that in clause 27 too, for that matter. A review is necessary. Bill will provide wording.
[ 2009-07 Frankfurt, Howard provided wording directed by consensus. ]
[ 2009-10 Santa Cruz: ]
Move to Ready.
Proposed resolution:
Add paragraph 3 to 22.4 [locale.categories]:
-3- Within this clause it is unspecified if one virtual function calls another virtual function.
Rationale:
We are explicitly not addressing bullet item #2, thus giving implementors more latitude. Users will have to override both virtual functions, not just one.
Section: 26.7.3 [partial.sum] Status: Ready Submitter: Marc Schoolderman Opened: 2006-02-06 Last modified: 2009-10-24
View all issues with Ready status.
Discussion:
There are some problems in the definition of partial_sum and adjacent_difference in 26.4 [lib.numeric.ops]
Unlike accumulate and inner_product, these functions are not parametrized on a "type T", instead, 26.4.3 [lib.partial.sum] simply specifies the effects clause as;
Assigns to every element referred to by iterator i in the range [result,result + (last - first)) a value correspondingly equal to
((...(* first + *( first + 1)) + ...) + *( first + ( i - result )))
And similarly for BinaryOperation. Using just this definition, it seems logical to expect that:
char i_array[4] = { 100, 100, 100, 100 };
int o_array[4];
std::partial_sum(i_array, i_array+4, o_array);
Is equivalent to
int o_array[4] = { 100, 100+100, 100+100+100, 100+100+100+100 };
i.e. 100, 200, 300, 400, with addition happening in the result type, int.
Yet all implementations I have tested produce 100, -56, 44, -112, because they are using an accumulator of the InputIterator's value_type, which in this case is char, not int.
The issue becomes more noticeable when the result of the expression *i + *(i+1) or binary_op(*i, *i-1) can't be converted to the value_type. In a contrived example:
enum not_int { x = 1, y = 2 };
...
not_int e_array[4] = { x, x, y, y };
std::partial_sum(e_array, e_array+4, o_array);
Is it the intent that the operations happen in the input type, or in the result type?
If the intent is that operations happen in the result type, something like this should be added to the "Requires" clause of 26.4.3/4 [lib.partial.sum]:
The type of *i + *(i+1) or binary_op(*i, *(i+1)) shall meet the requirements of CopyConstructible (20.1.3) and Assignable (23.1) types.
(As also required for T in 26.4.1 [lib.accumulate] and 26.4.2 [lib.inner.product].)
The "auto initializer" feature proposed in N1894 is not required to implement partial_sum this way. The 'narrowing' behaviour can still be obtained by using the std::plus<> function object.
If the intent is that operations happen in the input type, then something like this should be added instead;
The type of *first shall meet the requirements of CopyConstructible (20.1.3) and Assignable (23.1) types. The result of *i + *(i+1) or binary_op(*i, *(i+1)) shall be convertible to this type.
The 'widening' behaviour can then be obtained by writing a custom proxy iterator, which is somewhat involved.
In both cases, the semantics should probably be clarified.
26.4.4 [lib.adjacent.difference] is similarly underspecified, although all implementations seem to perform operations in the 'result' type:
unsigned char i_array[4] = { 4, 3, 2, 1 };
int o_array[4];
std::adjacent_difference(i_array, i_array+4, o_array);
o_array is 4, -1, -1, -1 as expected, not 4, 255, 255, 255.
In any case, adjacent_difference doesn't mention the requirements on the value_type; it can be brought in line with the rest of 26.4 [lib.numeric.ops] by adding the following to 26.4.4/2 [lib.adjacent.difference]:
The type of *first shall meet the requirements of CopyConstructible (20.1.3) and Assignable (23.1) types."
[ Berlin: Giving output iterator's value_types very controversial. Suggestion of adding signatures to allow user to specify "accumulator". ]
[ Bellevue: ]
The intent of the algorithms is to perform their calculations using the type of the input iterator. Proposed wording provided.
[ Sophia Antipolis: ]
We did not agree that the proposed resolution was correct. For example, when the arguments are types (float*, float*, double*), the highest-quality solution would use double as the type of the accumulator. If the intent of the wording is to require that the type of the accumulator must be the input_iterator's value_type, the wording should specify it.
[ 2009-05-09 Alisdair adds: ]
Now that we have the facility, the 'best' accumulator type could probably be deduced as:
std::common_type<InIter::value_type, OutIter::reference>::typeThis type would then have additional requirements of constructability and incrementability/assignability.
If this extracting an accumulator type from a pair/set of iterators (with additional requirements on that type) is a problem for multiple functions, it might be worth extracting into a SharedAccumulator concept or similar.
I'll go no further in writing up wording now, until the group gives a clearer indication of preferred direction.
[ 2009-07 Frankfurt ]
The proposed resolution isn't quite right. For example, "the type of *first" should be changed to "iterator::value_type" or similar. Daniel volunteered to correct the wording.
[ 2009-07-29 Daniel corrected wording. ]
[ 2009-10 Santa Cruz: ]
Move to Ready.
Proposed resolution:
Change 26.7.3 [partial.sum]/1 as indicated:
Effects: Let VT be InputIterator's value type. For a nonempty range, initializes an accumulator acc of type VT with *first and performs *result = acc. For every iterator i in [first + 1, last) in order, acc is then modified by acc = acc + *i or acc = binary_op(acc, *i) and is assigned to *(result + (i - first)).
Assigns to every element referred to by iterator i in the range [result,result + (last - first)) a value correspondingly equal to((...(*first + *(first + 1)) + ...) + *(first + (i - result)))
orbinary_op(binary_op(..., binary_op(*first, *(first + 1)),...), *(first + (i - result)))
Change 26.7.3 [partial.sum]/3 as indicated:
Complexity: Exactly max((last - first) - 1, 0) applications ofbinary_opthe binary operation.
Change 26.7.3 [partial.sum]/4 as indicated:
Requires: VT shall be constructible from the type of *first, the result of acc + *i or binary_op(acc, *i) shall be implicitly convertible to VT, and the result of the expression acc shall be writable to the result output iterator. In the ranges [first,last] and [result,result + (last - first)] [..]
Change 26.7.4 [adjacent.difference]/1 as indicated:
Effects: Let VT be InputIterator's value type. For a nonempty range, initializes an accumulator acc of type VT with *first and performs *result = acc. For every iterator i in [first + 1, last) in order, initializes a value val of type VT with *i, assigns the result of val - acc or binary_op(val, acc) to *(result + (i - first)) and modifies acc = std::move(val).
Assigns to every element referred to by iterator i in the range [result + 1, result + (last - first)) a value correspondingly equal to*(first + (i - result)) - *(first + (i - result) - 1)
orbinary_op(*(first + (i - result)), *(first + (i - result) - 1)).
result gets the value of *first.
Change 26.7.4 [adjacent.difference]/2 as indicated:
Requires: VT shall be MoveAssignable ([moveassignable]) and shall be constructible from the type of *first. The result of the expression acc and the result of the expression val - acc or binary_op(val, acc) shall be writable to the result output iterator. In the ranges [first,last] [..]
Change 26.7.4 [adjacent.difference]/5 as indicated:
Complexity: Exactly max((last - first) - 1, 0) applications ofbinary_opthe binary operation.
Section: 25.4 [alg.sorting] Status: Ready Submitter: Martin Sebor Opened: 2006-02-05 Last modified: 2010-03-08
View all other issues in [alg.sorting].
View all issues with Ready status.
Discussion:
In 25, p8 we allow BinaryPredicates to return a type that's convertible to bool but need not actually be bool. That allows predicates to return things like proxies and requires that implementations be careful about what kinds of expressions they use the result of the predicate in (e.g., the expression in if (!pred(a, b)) need not be well-formed since the negation operator may be inaccessible or return a type that's not convertible to bool).
Here's the text for reference:
...if an algorithm takes BinaryPredicate binary_pred as its argument and first1 and first2 as its iterator arguments, it should work correctly in the construct if (binary_pred(*first1, first2)){...}.
In 25.3, p2 we require that the Compare function object return true of false, which would seem to preclude such proxies. The relevant text is here:
Compare is used as a function object which returns true if the first argument is less than the second, and false otherwise...
[ Portland: Jack to define "convertible to bool" such that short circuiting isn't destroyed. ]
[ 2009-07-28 Reopened by Alisdair. No longer solved by concepts. ]
[ 2009-10 Santa Cruz: ]
Move to Review once wording received. Stefanus to send proposed wording.
[ 2009-10 Santa Cruz: ]
Move to Review once wording received. Stefanus to send proposed wording.
[ 2009-10-24 Stefanus supplied wording. ]
Move to Review once wording received. Stefanus to send proposed wording. Old proposed wording here:I think we could fix this by rewording 25.3, p2 to read somthing like:
-2- Compare is
used as a function object which returns true if the first argumenta BinaryPredicate. The return value of the function call operator applied to an object of type Compare, when converted to type bool, yields true if the first argument of the call is less than the second, and false otherwise. Compare comp is used throughout for algorithms assuming an ordering relation. It is assumed that comp will not apply any non-constant function through the dereferenced iterator.
[ 2010-01-17: ]
Howard expresses concern that the current direction of the proposed wording outlaws expressions such as:
if (!comp(x, y))Daniel provides wording which addresses that concern.
The previous wording is saved here:
Change 25.4 [alg.sorting] p2:
Compare is used as a function object. The return value of the function call operator applied to an object of type Compare, when converted to type bool, yields true if the first argument of the callwhich returns true if the first argumentis less than the second, and false otherwise. Compare comp is used throughout for algorithms assuming an ordering relation. It is assumed that comp will not apply any non-constant function through the dereferenced iterator.
[ 2010-01-22 Moved to Tentatively Ready after 5 positive votes on c++std-lib. ]
Proposed resolution:
Change 25.1 [algorithms.general]/7+8 as indicated. [This change is recommended to bring the return value requirements of BinaryPredicate and Compare in sync.]
7 The Predicate parameter is used whenever an algorithm expects a function object that when applied to the result of dereferencing the corresponding iterator returns a value testable as true. In other words, if an algorithm takes Predicate pred as its argument and first as its iterator argument, it should work correctly in the construct
if (pred(*first)){...}pred(*first) contextually converted to bool (4 [conv]). The function object pred shall not apply any nonconstant function through the dereferenced iterator. This function object may be a pointer to function, or an object of a type with an appropriate function call operator.8 The BinaryPredicate parameter is used whenever an algorithm expects a function object that when applied to the result of dereferencing two corresponding iterators or to dereferencing an iterator and type T when T is part of the signature returns a value testable as true. In other words, if an algorithm takes BinaryPredicate binary_pred as its argument and first1 and first2 as its iterator arguments, it should work correctly in the construct
if (binary_pred(*first1, *first2)){...}binary_pred(*first1, *first2) contextually converted to bool (4 [conv]). BinaryPredicate always takes the first iterator type as its first argument, that is, in those cases when T value is part of the signature, it should work correctly in thecontext of if (binary_pred(*first1, value)){...}construct binary_pred(*first1, value) contextually converted to bool (4 [conv]). binary_pred shall not apply any non-constant function through the dereferenced iterators.
Change 25.4 [alg.sorting]/2 as indicated:
2 Compare isused asa function object type (20.8 [function.objects]). The return value of the function call operation applied to an object of type Compare, when contextually converted to type bool (4 [conv]), yields true if the first argument of the callwhich returns true if the first argumentis less than the second, and false otherwise. Compare comp is used throughout for algorithms assuming an ordering relation. It is assumed that comp will not apply any non-constant function through the dereferenced iterator.
Section: 23.2.5 [unord.req] Status: Ready Submitter: Joaquín M López Muñoz Opened: 2006-06-13 Last modified: 2010-03-11
View other active issues in [unord.req].
View all other issues in [unord.req].
View all issues with Ready status.
Discussion:
See N2023 for full discussion.
[ 2009-12-11 Paolo opens: ]
I'm asking for DR 579 to be re-opened, basing on recent discussions on the library reflector, see Message c++std-lib-26040 and replies.
[ 2010-02-07 Paolo updates wording. ]
As pointed out by Chris in c++std-lib-26040, that an erase(unordered_container, iterator) returning an iterator can easily implemented in user code, if needed; that actually returning an iterator costs nothing for the overload taking two iterators, thus that proposed change is only for consistency; that forward_list::erase_after also returns void (for different reasons, granted, but isn't that any "erase" function in the containers uniformly returns an iterator); that, also in thread started by Chris' message, Alberto pointed out that the proxy idea isn't a good one; that users both of the GNU and Boost implementations are reporting serious performance problems with the current version returning an iterator.
[ 2010-02-07 Original wording saved here: ]
Option 1:
The problem can be eliminated by omitting the requirement that a.erase(q) return an iterator. This is, however, in contrast with the equivalent requirements for other standard containers.
Option 2:
a.erase(q) can be made to compute the next iterator only when explicitly requested: the technique consists in returning a proxy object implicitly convertible to iterator, so that
iterator q1=a.erase(q);works as expected, while
a.erase(q);does not ever invoke the conversion-to-iterator operator, thus avoiding the associated computation. To allow this technique, some sections of TR1 along the line "return value is an iterator..." should be changed to "return value is an unspecified object implicitly convertible to an iterator..." Although this trick is expected to work transparently, it can have some collateral effects when the expression a.erase(q) is used inside generic code.
[ 2010-02-09 Moved to Tentatively Ready after 6 positive votes on c++std-lib. ]
[ 2010 Pittsburgh: ]
There was no concensus for moving this to Ready. However there was concensus for moving this to NAD.
Rationale updated below.
[ 2010 Pittsburgh: ]
Reopened and proposed wording updated by Beman.
[ 2010 Pittsburgh: ]
Moved to Ready for Pittsburgh.
Rationale:
N2023 was discussed in Portland and the consensus was that there appears to be no need for either change proposed in the paper. The consensus opinion was that since the iterator could serve as its own proxy, there appears to be no need for the change. In general, "converts to" is undesirable because it interferes with template matching.
Post Toronto: There does not at this time appear to be consensus with the Portland consensus.
[ Bellevue: ]
The Bellevue review of this issue reached consensus with the Portland consensus, in contravention of the Toronto non-consensus. Common implementations have the iterator readily available, and most common uses depend on the iterator being returned.
****
The rationale for the change in direction here is best summarized by Paolo's 2010-02-07 comment.
Pittsburgh: Issue is wrong because we believe the standard is consistent as written and the complexity is achievable.
Pittsburgh: We want to enable both existing unordred container implementations.
Proposed resolution:
In 23.2.5 [unord.req], Table 98, change the following as indicated:
Table 98 — Unordered associative container requirements (in addition to container) Expression Return type Assertion/note pre-/post-condition Complexity a.erase(q) iterator Erases the element pointed to by q. Return value is the iterator immediately following q prior to the erasure. Average case O(1)O(max(1, 1/a.load_factor()), worst caseO(a.size())O(max(a.size(), a.bucket_count()).a.erase(q1, q2) iterator Erases all elements in the range [q1, q2). Return value is the iterator immediately following the erased elements prior to the erasure. Average case linear in distance(q1, q2)O(max(distance(q1,q2), 1/a.load_factor())), worst caseO(a.size())O(max(a.size(), a.bucket_count()).a.quick_erase(q) void Erases the element pointed to by q. Average case O(1), worst case O(a.size()). a.quick_erase(q1, q2) void Erases all elements in the range [q1, q2). Average case linear in distance(q1, q2), worst case O(a.size()).
Adjust the declarations accordingly in 23.5.1 [unord.map], 23.5.2 [unord.multimap], 23.5.3 [unord.set], and 23.5.4 [unord.multiset].
iterator erase(const_iterator position); void quick_erase(const_iterator position); ... iterator erase(const_iterator first, const_iterator last); void quick_erase(const_iterator first, const_iterator last);
Section: 22.4.2.2.2 [facet.num.put.virtuals] Status: Ready Submitter: John Salmon Opened: 2007-04-20 Last modified: 2009-10-21
View other active issues in [facet.num.put.virtuals].
View all other issues in [facet.num.put.virtuals].
View all issues with Ready status.
Discussion:
I am trying to understand how TR1 supports hex float (%a) output.
As far as I can tell, it does so via the following:
8.15 Additions to header <locale> [tr.c99.locale]
In subclause 22.4.2.2.2 [facet.num.put.virtuals], Table 58 Floating-point conversions, after the line: floatfield == ios_base::scientific %E
add the two lines:
floatfield == ios_base::fixed | ios_base::scientific && !uppercase %a floatfield == ios_base::fixed | ios_base::scientific %A 2
[Note: The additional requirements on print and scan functions, later in this clause, ensure that the print functions generate hexadecimal floating-point fields with a %a or %A conversion specifier, and that the scan functions match hexadecimal floating-point fields with a %g conversion specifier. end note]
Following the thread, in 22.4.2.2.2 [facet.num.put.virtuals], we find:
For conversion from a floating-point type, if (flags & fixed) != 0 or if str.precision() > 0, then str.precision() is specified in the conversion specification.
This would seem to imply that when floatfield == fixed|scientific, the precision of the conversion specifier is to be taken from str.precision(). Is this really what's intended? I sincerely hope that I'm either missing something or this is an oversight. Please tell me that the committee did not intend to mandate that hex floats (and doubles) should by default be printed as if by %.6a.
[ Howard: I think the fundamental issue we overlooked was that with %f, %e, %g, the default precision was always 6. With %a the default precision is not 6, it is infinity. So for the first time, we need to distinguish between the default value of precision, and the precision value 6. ]
[ 2009-07 Frankfurt ]
Leave this open for Robert and Daniel to work on.
Straw poll: Disposition?
- Default is %.6a (i.e. NAD): 2
- Always %a (no precision): 6
- precision(-1) == %a: 3
Daniel and Robert have direction to write up wording for the "always %a" solution.
[ 2009-07-15 Robert provided wording. ]
[ 2009-10 Santa Cruz: ]
Move to Ready.
Proposed resolution:
Change 22.4.2.2.2 [facet.num.put.virtuals], Stage 1, under p5 (near the end of Stage 1):
For conversion from a floating-point type, str.precision() is specified as precision in the conversion specification if floatfield != (ios_base::fixed | ios_base::scientific), else no precision is specified.
[ Kona (2007): Robert volunteers to propose wording. ]
Section: 23.5 [unord] Status: Ready Submitter: Howard Hinnant Opened: 2007-05-05 Last modified: 2010-03-09
View other active issues in [unord].
View all other issues in [unord].
View all issues with Ready status.
Discussion:
Move semantics are missing from the unordered containers. The proposed resolution below adds move-support consistent with N1858 and the current working draft.
The current proposed resolution simply lists the requirements for each function. These might better be hoisted into the requirements table for unordered associative containers. Futhermore a mild reorganization of the container requirements could well be in order. This defect report is purposefully ignoring these larger issues and just focusing on getting the unordered containers "moved".
[ 2009-07-28 Reopened by Alisdair. No longer solved by concepts. ]
[ 2009-10-17 Removed rvalue-swaps from wording. ]
[ 2009-10 Santa Cruz: ]
Move to Review. Alisdair will review proposed wording.
[ 2009-10-29 Daniel updates wording. ]
[ 2010-01-26 Alisdair updates wording. ]
[ 2010-02-10 Howard updates wording to reference the unordered container requirements table (modified by 704) as much as possible. ]
[ Voted to WP in Bellevue. ]
[ post Bellevue, Pete notes: ]
Please remind people who are reviewing issues to check that the text modifications match the current draft. Issue 676, for example, adds two overloads for unordered_map::insert taking a hint. One takes a const_iterator and returns a const_iterator, and the other takes an iterator and returns an iterator. This was correct at the time the issue was written, but was changed in Toronto so there is only one hint overload, taking a const_iterator and returning an iterator.
This issue is not ready. In addition to the relatively minor signature problem I mentioned earlier, it puts requirements in the wrong places. Instead of duplicating requirements throughout the template specifications, it should put them in the front matter that talks about requirements for unordered containers in general. This presentation problem is editorial, but I'm not willing to do the extensive rewrite that it requires. Please put it back into Open status.
[ 2010-02-11 Moved to Tentatively Ready after 5 positive votes on c++std-lib. ]
[ 2010-02-24 Pete moved to Open: ]
The descriptions of the semantics of the added insert functions belong in the requirements table. That's where the rest of the insert functions are.
[ 2010 Pittsburgh: ]
Move issue 676 to Ready for Pittsburgh. Nico to send Howard an issue for the broader problem.
Rationale:
[ San Francisco: ]
Solved by N2776.
[ Rationale is obsolete. ]
Proposed resolution:
unordered_map
Change 23.5.1 [unord.map]:
class unordered_map
{
...
unordered_map(const unordered_map&);
unordered_map(unordered_map&&);
unordered_map(const Allocator&);
unordered_map(const unordered_map&, const Allocator&);
unordered_map(unordered_map&&, const Allocator&);
...
unordered_map& operator=(const unordered_map&);
unordered_map& operator=(unordered_map&&);
...
// modifiers
...
std::pair<iterator, bool> insert(const value_type& obj);
template <class P> pair<iterator, bool> insert(P&& obj);
iterator insert(const_iterator hint, const value_type& obj);
template <class P> iterator insert(const_iterator hint, P&& obj);
...
mapped_type& operator[](const key_type& k);
mapped_type& operator[](key_type&& k);
...
};
Add to 23.5.1.2 [unord.map.elem]:
mapped_type& operator[](const key_type& k);...
Requires: key_type shall be CopyConstructible and mapped_type shall be DefaultConstructible.
Complexity: Average case O(1), worst case O(size()).
mapped_type& operator[](key_type&& k);Requires: key_type shall be MoveConstructible and mapped_type shall be DefaultConstructible.
Effects: If the unordered_map does not already contain an element whose key is equivalent to k , inserts the value value_type(std::move(k), mapped_type()).
Returns: A reference to x.second, where x is the (unique) element whose key is equivalent to k.
Complexity: Average case O(1), worst case O(size()).
Add new section [unord.map.modifiers]:
template <class P> pair<iterator, bool> insert(P&& x);Requires: value_type is constructible from std::forward<P>(x).
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).
Returns: The bool component of the returned pair indicates whether the insertion takes place, and the iterator component points to the element with key equivalent to the key of value_type(x).
Complexity: Average case O(1), worst case O(size()).
Remarks: P shall be implicitly convertible to value_type, else this signature shall not participate in overload resolution.
template <class P> iterator insert(const_iterator hint, P&& x);Requires: value_type is constructible from std::forward<P>(x).
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). The iterator hint is a hint pointing to where the search should start. Implementations are permitted to ignore the hint.
Returns: An iterator pointing to the element with key equivalent to the key of value_type(x).
Complexity: Average case O(1), worst case O(size()).
Remarks: P shall be implicitly convertible to value_type, else this signature shall not participate in overload resolution.
unordered_multimap
Change 23.5.2 [unord.multimap]:
class unordered_multimap
{
...
unordered_multimap(const unordered_multimap&);
unordered_multimap(unordered_multimap&&);
unordered_multimap(const Allocator&);
unordered_multimap(const unordered_multimap&, const Allocator&);
unordered_multimap(unordered_multimap&&, const Allocator&);
...
unordered_multimap& operator=(const unordered_multimap&);
unordered_multimap& operator=(unordered_multimap&&);
...
// modifiers
...
iterator insert(const value_type& obj);
template <class P> iterator insert(P&& obj);
iterator insert(const_iterator hint, const value_type& obj);
template <class P> iterator insert(const_iterator hint, P&& obj);
...
};
Add new section [unord.multimap.modifiers]:
template <class P> iterator insert(P&& x);Requires: value_type is constructible from std::forward<P>(x).
Effects: Inserts x converted to value_type.
Returns: An iterator pointing to the element with key equivalent to the key of value_type(x).
Complexity: Average case O(1), worst case O(size()).
Remarks: P shall be implicitly convertible to value_type, else this signature shall not participate in overload resolution.
template <class P> iterator insert(const_iterator hint, P&& x);Requires: value_type is constructible from std::forward<P>(x).
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). The iterator hint is a hint pointing to where the search should start. Implementations are permitted to ignore the hint.
Returns: An iterator pointing to the element with key equivalent to the key of value_type(x).
Complexity: Average case O(1), worst case O(size()).
Remarks: P shall be implicitly convertible to value_type, else this signature shall not participate in overload resolution.
unordered_set
Change 23.5.3 [unord.set]:
class unordered_set
{
...
unordered_set(const unordered_set&);
unordered_set(unordered_set&&);
unordered_set(const Allocator&);
unordered_set(const unordered_set&, const Allocator&);
unordered_set(unordered_set&&, const Allocator&);
...
unordered_set& operator=(const unordered_set&);
unordered_set& operator=(unordered_set&&);
...
// modifiers
...
std::pair<iterator, bool> insert(const value_type& obj);
pair<iterator, bool> insert(value_type&& obj);
iterator insert(const_iterator hint, const value_type& obj);
iterator insert(const_iterator hint, value_type&& obj);
...
};
unordered_multiset
Change 23.5.4 [unord.multiset]:
class unordered_multiset
{
...
unordered_multiset(const unordered_multiset&);
unordered_multiset(unordered_multiset&&);
unordered_multiset(const Allocator&);
unordered_multiset(const unordered_multiset&, const Allocator&);
unordered_multiset(unordered_multiset&&, const Allocator&);
...
unordered_multiset& operator=(const unordered_multiset&);
unordered_multiset& operator=(unordered_multiset&&);
...
// modifiers
...
iterator insert(const value_type& obj);
iterator insert(value_type&& obj);
iterator insert(const_iterator hint, const value_type& obj);
iterator insert(const_iterator hint, value_type&& obj);
...
};
Section: 23.2 [container.requirements] Status: Ready Submitter: Howard Hinnant Opened: 2007-05-20 Last modified: 2010-03-10
View other active issues in [container.requirements].
View all other issues in [container.requirements].
View all issues with Ready status.
Discussion:
The move-related changes inadvertently overwrote the intent of 276. Issue 276 removed the requirement of CopyAssignable from most of the member functions of node-based containers. But the move-related changes unnecessarily introduced the MoveAssignable requirement for those members which used to require CopyAssignable.
We also discussed (c++std-lib-18722) the possibility of dropping MoveAssignable from some of the sequence requirements. Additionally the in-place construction work may further reduce requirements. For purposes of an easy reference, here are the minimum sequence requirements as I currently understand them. Those items in requirements table in the working draft which do not appear below have been purposefully omitted for brevity as they do not have any requirements of this nature. Some items which do not have any requirements of this nature are included below just to confirm that they were not omitted by mistake.
| X u(a) | value_type must be CopyConstructible |
| X u(rv) | array requires value_type to be CopyConstructible |
| a = u | Sequences require value_type to be CopyConstructible and CopyAssignable. Associative containers require value_type to be CopyConstructible. |
| a = rv | array requires value_type to be CopyAssignable. Sequences containers with propagate_on_container_move_assignment == false allocators require value_type to be MoveConstructible and MoveAssignable. Associative containers with propagate_on_container_move_assignment == false allocators require value_type to be MoveConstructible. |
| swap(a,u) | array requires value_type to be Swappable. |
| X(n) | value_type must be DefaultConstructible |
| X(n, t) | value_type must be CopyConstructible |
| X(i, j) | Sequences require value_type to be constructible from *i. Additionally if input_iterators are used, vector and deque require MoveContructible and MoveAssignable. |
| a.insert(p, t) | The value_type must be CopyConstructible. The sequences vector and deque also require the value_type to be CopyAssignable. |
| a.insert(p, rv) | The value_type must be MoveConstructible. The sequences vector and deque also require the value_type to be MoveAssignable. |
| a.insert(p, n, t) | The value_type must be CopyConstructible. The sequences vector and deque also require the value_type to be CopyAssignable. |
| a.insert(p, i, j) | If the iterators return an lvalue the value_type must be CopyConstructible. The sequences vector and deque also require the value_type to be CopyAssignable when the iterators return an lvalue. If the iterators return an rvalue the value_type must be MoveConstructible. The sequences vector and deque also require the value_type to be MoveAssignable when the iterators return an rvalue. |
| a.erase(p) | The sequences vector and deque require the value_type to be MoveAssignable. |
| a.erase(q1, q2) | The sequences vector and deque require the value_type to be MoveAssignable. |
| a.clear() | |
| a.assign(i, j) | If the iterators return an lvalue the value_type must be CopyConstructible and CopyAssignable. If the iterators return an rvalue the value_type must be MoveConstructible and MoveAssignable. |
| a.assign(n, t) | The value_type must be CopyConstructible and CopyAssignable. |
| a.resize(n) | The value_type must be DefaultConstructible. The sequence vector also requires the value_type to be MoveConstructible. |
| a.resize(n, t) | The value_type must be CopyConstructible. |
| a.front() | |
| a.back() | |
| a.push_front(t) | The value_type must be CopyConstructible. |
| a.push_front(rv) | The value_type must be MoveConstructible. |
| a.push_back(t) | The value_type must be CopyConstructible. |
| a.push_back(rv) | The value_type must be MoveConstructible. |
| a.pop_front() | |
| a.pop_back() | |
| a[n] | |
| a.at[n] |
| X(i, j) | If the iterators return an lvalue the value_type must be CopyConstructible. If the iterators return an rvalue the value_type must be MoveConstructible. |
| a_uniq.insert(t) | The value_type must be CopyConstructible. |
| a_uniq.insert(rv) | The key_type and the mapped_type (if it exists) must be MoveConstructible. |
| a_eq.insert(t) | The value_type must be CopyConstructible. |
| a_eq.insert(rv) | The key_type and the mapped_type (if it exists) must be MoveConstructible. |
| a.insert(p, t) | The value_type must be CopyConstructible. |
| a.insert(p, rv) | The key_type and the mapped_type (if it exists) must be MoveConstructible. |
| a.insert(i, j) | If the iterators return an lvalue the value_type must be CopyConstructible. If the iterators return an rvalue the key_type and the mapped_type (if it exists) must be MoveConstructible.. |
| X(i, j, n, hf, eq) | If the iterators return an lvalue the value_type must be CopyConstructible. If the iterators return an rvalue the value_type must be MoveConstructible. |
| a_uniq.insert(t) | The value_type must be CopyConstructible. |
| a_uniq.insert(rv) | The key_type and the mapped_type (if it exists) must be MoveConstructible. |
| a_eq.insert(t) | The value_type must be CopyConstructible. |
| a_eq.insert(rv) | The key_type and the mapped_type (if it exists) must be MoveConstructible. |
| a.insert(p, t) | The value_type must be CopyConstructible. |
| a.insert(p, rv) | The key_type and the mapped_type (if it exists) must be MoveConstructible. |
| a.insert(i, j) | If the iterators return an lvalue the value_type must be CopyConstructible. If the iterators return an rvalue the key_type and the mapped_type (if it exists) must be MoveConstructible.. |
| map[lvalue-key] | The key_type must be CopyConstructible. The mapped_type must be DefaultConstructible and MoveConstructible. |
| map[rvalue-key] | The key_type must be MoveConstructible. The mapped_type must be DefaultConstructible and MoveConstructible. |
[ Kona (2007): Howard and Alan to update requirements table in issue with emplace signatures. ]
[ Bellevue: This should be handled as part of the concepts work. ]
[ 2009-07-20 Reopened by Howard: ]
This is one of the issues that was "solved by concepts" and is now no longer solved.
In a nutshell, concepts adopted the "minimum requirements" philosophy outlined in the discussion of this issue, and enforced it. My strong suggestion is that we translate the concepts specification into documentation for the containers.
What this means for vendors is that they will have to implement container members being careful to only use those characteristics of a type that the concepts specification formally allowed. Note that I am not talking about enable_if'ing everything. I am simply suggesting that (for example) we tell the vendor he can't call T's copy constructor or move constructor within the emplace member function, etc.
What this means for customers is that they will be able to use types within C++03 containers which are sometimes not CopyConstructible, and sometimes not even MoveConstructible, etc.
[ 2009-10 Santa Cruz: ]
Leave open. Howard to provide wording.
[ 2010-02-06 Howard provides wording. ]
[ 2010-02-08 Moved to Tentatively Ready after 5 positive votes on c++std-lib. ]
[ 2010-02-10 Howard opened. I neglected to reduce the requirements on value_type for the insert function of the ordered and unordered associative containers when the argument is an rvalue. Fixed it. ]
[ 2010-02-11 Moved to Tentatively Ready after 5 positive votes on c++std-lib. ]
[ 2010-03-08 Nico opens: ]
I took the task to see whether 868 is covered by 704 already. However, by doing that I have the impression that 704 is a big mistake.
Take e.g. the second change of 868:
Change 23.3.2.1 [deque.cons] para 5:
Effects: Constructs a deque with n default constructed elements.where "default constructed" should be replaced by "value-initialized". This is the constructor out of a number of elements:
ContType c(num)704 says:
Remove the entire section 23.3.2.1 [deque.cons].
[ This section is already specified by the requirements tables. ]BUT, there is no requirement table that lists this constructor at all, which means that we would lose the entire specification of this function !!!
In fact, I found with further investigation, if we follow 704 to remove 23.3.2.1 we
- have no semantics for ContType c(num)
- have no complexity and no allocator specification for ContType c(num,val)
- have no semantics for ContType c(num,val,alloc)
- - have no complexity and no allocator specification for ContType c(beg,end)
- - have no semantics for ContType c(beg,end,alloc)
- - have different wording (which might or might not give the same guarantees) for the assign functions
because all these guarantees are given in the removed section but nowhere else (as far as I saw).
Looks to me that 704 need a significant review before we take that change, because chances are high that there are similar flaws in other proposed changes there (provided I am not missing anything).
[ 2010 Pittsburgh: ]
Removed the parts from the proposed wording that removed existing sections, and set to Ready for Pittsburgh.
Rationale:
[ post San Francisco: ]
Solved by N2776.
This rationale is obsolete.
Proposed resolution:
Change 23.2.1 [container.requirements.general]/4:
4 In Tables 91 and 92, X denotes a container class containing objects of type T, a and b denote values of type X, u denotes an identifier, r denotesan lvalue or a const rvaluea non-const value of type X, and rv denotes a non-const rvalue of type X.
Change the following rows in Table 91 — Container requirements 23.2.1 [container.requirements.general]:
Table 91 — Container requirements Expression Return type Assertion/note
pre-/post-conditionComplexity X::value_type T Requires: T is Destructible. compile time
Change 23.2.1 [container.requirements.general]/10:
Unless otherwise specified (see 23.2.4.1, 23.2.5.1, 23.3.2.3, and 23.3.6.4) all container types defined in this Clause meet the following additional requirements:
- ..
- no erase(), clear(), pop_back() or pop_front() function throws an exception.
- ...
Insert a new paragraph prior to 23.2.1 [container.requirements.general]/14:
The descriptions of the requirements of the type T in this section use the terms CopyConstructible, MoveConstructible, constructible from *i, and constructible from args. These terms are equivalent to the following expression using the appropriate arguments:
allocator_traits<allocator_type>::construct(x.get_allocator(), q, args...);where x is a non-const lvalue of some container type X and q has type X::value_type*.
[Example: The container is going to move construct a T, so will call:
allocator_traits<allocator_type>::construct(get_allocator(), q, std::move(t));The default implementation of construct will call:
::new (q) T(std::forward<T>(t)); // where forward is the same as move here, cast to rvalueBut the allocator author may override the above definition of construct and do the construction of T by some other means. — end example]
14 ...
Add to 23.2.1 [container.requirements.general]/14:
14 In Table 93, X denotes an allocator-aware container class with a value_type of T using allocator of type A, u denotes a variable, a and b denote non-const lvalues of type X, t denotes an lvalue or a const rvalue of type X, rv denotes a non-const rvalue of type X, m is a value of type A, and Q is an allocator type.
Change or add the following rows in Table 93 — Allocator-aware container requirements in 23.2.1 [container.requirements.general]:
Table 93 — Allocator-aware container requirements Expression Return type Assertion/note
pre-/post-conditionComplexity X(t, m)
X u(t, m);Requires: T is CopyConstructible.
post: u == t,
get_allocator() == mlinear X(rv, m)
X u(rv, m);Requires: T is MoveConstructible.
post: u shall have the same elements, or copies of the elements, that rv had before this construction,
get_allocator() == mconstant if m == rv.get_allocator(), otherwise linear a = t X& Requires: T is CopyConstructible and CopyAssignable
post: a == t.linear a = rv X& Requires: If allocator_traits< allocator_type > ::propagate_on_container_move_assignment ::value is false, T is MoveConstructible and MoveAssignable.
All existing elements of a are either move assigned to or destroyed.
a shall be equal to the value that rv had before this assignmentlinear a.swap(b); void exchanges the contents of a and b constant
Change the following rows in Table 94 — Sequence container requirements (in addition to container) in 23.2.3 [sequence.reqmts]:
Table 94 — Sequence container requirements (in addition to container) Expression Return type Assertion/note
pre-/post-conditionX(i, j)
X a(i, j)Requires: If the iterator's dereference operation returns an lvalue or a const rvalue, T shall be CopyConstructible.T shall be constructible from *i.
If the iterator does not meet the forward iterator requirements (24.2.3 [forward.iterators]), then vector also requires T to be MoveConstructible.
Each iterator in the range [i,j) shall be dereferenced exactly once.
post: size() == distance between i and j
Constructs a sequence container equal to the range [i, j)a = il; X& Requires: T is CopyConstructible and CopyAssignable.
a = X(il);
Assigns the range [il.begin(), il.end()) into a. All existing elements of a are either assigned or destroyed.
rReturns *this;a.emplace(p, args); iterator Requires: ConstructibleAsElement<A, T, Args>.T is constructible from args. vector and deque also require T to be MoveConstructible and MoveAssignable. Inserts an object of type T constructed with std::forward<Args>(args)... before p.a.insert(p, t); iterator Requires: ConstructibleAsElement<A, T, Args> and T shall be CopyAssignable.T shall be CopyConstructible. vector and deque also require T to be CopyAssignable. Inserts a copy t before p.a.insert(p, rv); iterator Requires: ConstructibleAsElement<A, T, T&&> and T shall be MoveAssignable.T shall be MoveConstructible. vector and deque also require T to be MoveAssignable. Inserts a copy rv before p.a.insert(p, i, j) iterator Requires: If the iterator's dereference operation returns an lvalue or a const rvalue, T shall be CopyConstructible.T shall be constructible from *i.
If the iterator does not meet the forward iterator requirements (24.2.3 [forward.iterators]), then vector also requires T to be MoveConstructible and MoveAssignable.
Each iterator in the range [i,j) shall be dereferenced exactly once.
pre: i and j are not iterators into a.
Inserts copies of elements in [i, j) before pa.erase(q); iterator Requires: T and T shall be MoveAssignable.vector and deque require T to be MoveAssignable. Erases the element pointed to by q.a.erase(q1, q2); iterator Requires: T and T shall be MoveAssignable.vector and deque require T to be MoveAssignable. Erases the elements in the range [q1, q2).a.clear(); void erase(begin(), end())
Destroys all elements in a. Invalidates all references, pointers, and iterators referring to the elements of a and may invalidate the past-the-end iterator.
post:size() == 0a.empty() == truea.assign(i, j) void Requires: If the iterator's dereference operation returns an lvalue or a const rvalue, T shall be CopyConstructible and CopyAssignable.T shall be constructible and assignable from *i. If the iterator does not meet the forward iterator requirements (24.2.3 [forward.iterators]), then vector also requires T to be MoveConstructible.
Each iterator in the range [i,j) shall be dereferenced exactly once.
pre: i, j are not iterators into a.
Replaces elements in a with a copy of [i, j).
Change the following rows in Table 95 — Optional sequence container operations in 23.2.3 [sequence.reqmts]:
Table 95 — Optional sequence container operations Expression Return type Operational semantics Container a.emplace_front(args) void a.emplace(a.begin(), std::forward<Args>(args)...)
Prepends an object of type T constructed with std::forward<Args>(args)....
Requires:ConstructibleAsElement<A, T, Args>T shall be constructible from args.list, deque, forward_list a.emplace_back(args) void a.emplace(a.end(), std::forward<Args>(args)...)
Appends an object of type T constructed with std::forward<Args>(args)....
Requires:ConstructibleAsElement<A, T, Args>T shall be constructible from args. vector also requires T to be MoveConstructible.list, deque, vector a.push_front(t) void a.insert(a.begin(), t)
Prepends a copy of t.
Requires:ConstructibleAsElement<A, T, T> and T shall be CopyAssignable.T shall be CopyConstructible.list, deque, forward_list a.push_front(rv) void a.insert(a.begin(), t)
Prepends a copy of rv.
Requires:ConstructibleAsElement<A, T, T&&> and T shall be MoveAssignable.T shall be MoveConstructible.list, deque, forward_list a.push_back(t) void a.insert(a.end(), t)
Appends a copy of t.
Requires:ConstructibleAsElement<A, T, T> and T shall be CopyAssignable.T shall be CopyConstructible.vector, list, deque, basic_string a.push_back(rv) void a.insert(a.end(), t)
Appends a copy of rv.
Requires:ConstructibleAsElement<A, T, T&&> and T shall be MoveAssignable.T shall be MoveConstructible.vector, list, deque, basic_string a.pop_front() void a.erase(a.begin())
Destroys the first element.
Requires: a.empty() shall be false.list, deque, forward_list a.pop_back() void { iterator tmp = a.end();
--tmp;
a.erase(tmp); }
Destroys the last element.
Requires: a.empty() shall be false.vector, list, deque, basic_string
Insert a new paragraph prior to 23.2.4 [associative.reqmts]/7, and edit paragraph 7:
The associative containers meet all of the requirements of Allocator-aware containers (23.2.1 [container.requirements.general]), except for the containers map and multimap, the requirements placed on value_type in Table 93 apply instead directly to key_type and mapped_type. [Note: For example key_type and mapped_type are sometimes required to be CopyAssignable even though the value_type (pair<const key_type, mapped_type>) is not CopyAssignable. — end note]
7 In Table 96, X denotes an associative container class, a denotes a value of X, a_uniq denotes a value of X when X supports unique keys, a_eq denotes a value of X when X supports multiple keys, u denotes an identifier,
r denotes an lvalue or a const rvalue of type X, rv denotes a non-const rvalue of type X,i and j satisfy input iterator requirements and refer to elements implicitly convertible to value_type, [i,j) denotes a valid range, p denotes a valid const iterator to a, q denotes a valid dereferenceable const iterator to a, [q1, q2) denotes a valid range of const iterators in a, il designates an object of type initializer_list<value_type>, t denotes a value of X::value_type, k denotes a value of X::key_type and c denotes a value of type X::key_compare. A denotes the storage allocator used by X, if any, or std::allocator<X::value_type> otherwise, and m denotes an allocator of a type convertible to A.
Change or add the following rows in Table 96 — Associative container requirements (in addition to container) in 23.2.4 [associative.reqmts]:
Table 96 — Associative container requirements (in addition to container) Expression Return type Assertion/note
pre-/post-conditionComplexity X::key_type Key Requires: Key is CopyConstructible and CopyAssignableDestructiblecompile time X::mapped_type (map and multimap only) T Requires: T is Destructible compile time X(c)
X a(c);Requires: ConstructibleAsElement<A, key_compare, key_compare>.
key_compare is CopyConstructible.
Constructs an empty container.
Uses a copy of c as a comparison object.constant X()
X a;Requires: ConstructibleAsElement<A, key_compare, key_compare>.
key_compare is DefaultConstructible.
Constructs an empty container.
Uses Compare() as a comparison object.constant X(i, j, c)
X a(i, j, c);Requires: ConstructibleAsElement<A, key_compare, key_compare>.
key_compare is CopyConstructible. value_type shall be constructible from *i.
Constructs an empty container ans inserts elements from the range [i, j) into it; uses c as a comparison object.N log N in general (N is the distance from i to j); linear if [i, j) is sorted with value_comp() X(i, j)
X a(i, j);Requires: ConstructibleAsElement<A, key_compare, key_compare>.
value_type shall be constructible from *i. key_compare is DefaultConstructible.
Same as above, but uses Compare() as a comparison object.same as above a = il X& a = X(il);
return *this;
Requires: T is CopyConstructible and CopyAssignable.
Assigns the range [il.begin(), il.end()) into a. All existing elements of a are either assigned or destroyed.Same as a = X(il).N log N in general (N is il.size() added to the existing size of a); linear if [il.begin(), il.end()) is sorted with value_comp()a_uniq.emplace(args) pair<iterator, bool> Requires: T shall be constructible from args
inserts a T object t constructed with std::forward<Args>(args)... if and only if there is no element in the container with key equivalent to the key of t. The bool component of the returned pair is true if and only if the insertion takes place, and the iterator component of the pair points to the element with key equivalent to the key of t.logarithmic a_eq.emplace(args) iterator Requires: T shall be constructible from args
inserts a T object t constructed with std::forward<Args>(args)... and returns the iterator pointing to the newly inserted element.logarithmic a_uniq.insert(t) pair<iterator, bool> Requires: T shall be MoveConstructible if t is a non-const rvalue expression, else T shall be CopyConstructible.
inserts t if and only if there is no element in the container with key equivalent to the key of t. The bool component of the returned pair is true if and only if the insertion takes place, and the iterator component of the pair points to the element with key equivalent to the key of t.logarithmic a_eq.insert(t) iterator Requires: T shall be MoveConstructible if t is a non-const rvalue expression, else T shall be CopyConstructible.
inserts t and returns the iterator pointing to the newly inserted element. If a range containing elements equivalent to t exists in a_eq, t is inserted at the end of that range.logarithmic a.insert(p, t) iterator Requires: T shall be MoveConstructible if t is a non-const rvalue expression, else T shall be CopyConstructible.
inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys; always returns the iterator pointing to the element with key equivalent to the key of t. t is inserted as close as possible to the position just prior to p.logarithmic in general, but amortized constant if t is inserted right before p. a.insert(i, j) void Requires: T shall be constructible from *i.
pre: i, j are not iterators into a. inserts each element from the range [i,j) if and only if there is no element with key equivalent to the key of that element in containers with unique keys; always inserts that element in containers with equivalent keys.N log(size() + N ) (N is the distance from i to j)
Insert a new paragraph prior to 23.2.5 [unord.req]/9:
The unordered associative containers meet all of the requirements of Allocator-aware containers (23.2.1 [container.requirements.general]), except for the containers unordered_map and unordered_multimap, the requirements placed on value_type in Table 93 apply instead directly to key_type and mapped_type. [Note: For example key_type and mapped_type are sometimes required to be CopyAssignable even though the value_type (pair<const key_type, mapped_type>) is not CopyAssignable. — end note]
9 ...
Change or add the following rows in Table 98 — Unordered associative container requirements (in addition to container) in 23.2.5 [unord.req]:
Table 98 — Unordered associative container requirements (in addition to container) Expression Return type Assertion/note
pre-/post-conditionComplexity X::key_type Key Requires: Key shall be CopyAssignable and CopyConstructibleDestructiblecompile time X::mapped_type (unordered_map and unordered_multimap only) T Requires:T is Destructible compile time X(n, hf, eq)
X a(n, hf, eq)X Requires: hasher and key_equal are CopyConstructible. Constructs an empty container with at least n buckets, using hf as the hash function and eq as the key equality predicate. O(N) X(n, hf)
X a(n, hf)X Requires: hasher is CopyConstructible and key_equal is DefaultConstructible. Constructs an empty container with at least n buckets, using hf as the hash function and key_equal() as the key equality predicate. O(N) X(n)
X a(n)X Requires: hasher and key_equal are DefaultConstructible. Constructs an empty container with at least n buckets, using hasher() as the hash function and key_equal() as the key equality predicate. O(N) X()
X aX Requires: hasher and key_equal are DefaultConstructible. Constructs an empty container an unspecified number of buckets, using hasher() as the hash function and key_equal() as the key equality predicate. constant X(i, j, n, hf, eq)
X a(i, j, n, hf, eq)X Requires: value_type is constructible from *i. hasher and key_equal are CopyConstructible.
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 O(N) (N is distance(i, j)), worst case O(N2) X(i, j, n, hf)
X a(i, j, n, hf)X Requires: value_type is constructible from *i. hasher is CopyConstructible and key_equal is DefaultConstructible.
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 O(N) (N is distance(i, j)), worst case O(N2) X(i, j, n)
X a(i, j, n)X Requires: value_type is constructible from *i. hasher and key_equal are DefaultConstructible.
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 O(N) (N is distance(i, j)), worst case O(N2) X(i, j)
X a(i, j)X Requires: value_type is constructible from *i. hasher and key_equal are DefaultConstructible.
Constructs an empty container with an unspecified number of buckets, using hasher() as the hash function and key_equal() as the key equality predicate, and inserts elements from [i, j) into it.Average case O(N) (N is distance(i, j)), worst case O(N2) X(b)
X a(b)X Copy constructor. In addition to the contained elementsrequirements of Table 93 (23.2.1 [container.requirements.general]), copies the hash function, predicate, and maximum load factor.Average case linear in b.size(), worst case quadratic. a = b X& Copy assignment operator. In addition to the contained elementsrequirements of Table 93 (23.2.1 [container.requirements.general]), copies the hash function, predicate, and maximum load factor.Average case linear in b.size(), worst case quadratic. a = il X& a = X(il); return *this;
Requires: T is CopyConstructible and CopyAssignable.
Assigns the range [il.begin(), il.end()) into a. All existing elements of a are either assigned or destroyed.Average case linear in il.size(), worst case quadratic. a_uniq.emplace(args) pair<iterator, bool> Requires: T shall be constructible from args
inserts a T object t constructed with std::forward<Args>(args)... if and only if there is no element in the container with key equivalent to the key of t. The bool component of the returned pair is true if and only if the insertion takes place, and the iterator component of the pair points to the element with key equivalent to the key of t.Average case O(1), worst case O(a_uniq.size()). a_eq.emplace(args) iterator Requires: T shall be constructible from args
inserts a T object t constructed with std::forward<Args>(args)... and returns the iterator pointing to the newly inserted element.Average case O(1), worst case O(a_eq.size()). a.emplace_hint(p, args) iterator Requires: T shall be constructible from args
equivalent to a.emplace( std::forward<Args>(args)...). Return value is an iterator pointing to the element with the key equivalent to the newly inserted element. The const_iterator p is a hint pointing to where the search should start. Implementations are permitted to ignore the hint.Average case O(1), worst case O(a.size()). a_uniq.insert(t) pair<iterator, bool> Requires: T shall be MoveConstructible if t is a non-const rvalue expression, else T shall be CopyConstructible.
Inserts t if and only if there is no element in the container with key equivalent to the key of t. The bool component of the returned pair indicates whether the insertion takes place, and the iterator component points to the element with key equivalent to the key of t.Average case O(1), worst case O(a_uniq.size()). a_eq.insert(t) iterator Requires: T shall be MoveConstructible if t is a non-const rvalue expression, else T shall be CopyConstructible.
Inserts t, and returns an iterator pointing to the newly inserted element.Average case O(1), worst case O(a_uniq.size()). a.insert(q, t) iterator Requires: T shall be MoveConstructible if t is a non-const rvalue expression, else T shall be CopyConstructible.
Equivalent to a.insert(t). Return value is an iterator pointing to the element with the key equivalent to that of t. The iterator q is a hint pointing to where the search should start. Implementations are permitted to ignore the hint.Average case O(1), worst case O(a_uniq.size()). a.insert(i, j) void Requires: T shall be constructible from *i.
Pre: i and j are not iterators in a. Equivalent to a.insert(t) for each element in [i,j).Average case O(N), where N is distance(i, j). Worst case O(N * a.size()).
Change 23.3.3 [forwardlist]/2:
2 A forward_list satisfies all of the requirements of a container (table 91), except that the size() member function is not provided. A forward_list also satisfies all of the requirements of an allocator-aware container (table 93). And forward_list provides the assign member functions as specified in Table 94, Sequence container requirements, and several of the optional sequence container requirements (Table 95). Descriptions are provided here only for operations on forward_list that are not described in that table or for operations where there is additional semantic information.
Add a new paragraph after 23.3.3.4 [forwardlist.modifiers]/23:
void clear();23 Effects: Erases all elements in the range [begin(),end()).
Remarks: Does not invalidate past-the-end iterators.
Change 23.3.6.2 [vector.capacity]/13:
void resize(size_type sz, const T& c);13 Requires: T shall be CopyConstructible. If value_type has a move constructor, that constructor shall not throw any exceptions.
In 23.5.3 [unord.set] and 23.5.4 [unord.multiset] substitute "Key" for "Value".
[ The above substitution is normative as it ties into the requirements table. ]
Section: 20.2.1 [utility.arg.requirements] Status: Ready Submitter: Pablo Halpern Opened: 2007-09-12 Last modified: 2010-03-08
View other active issues in [utility.arg.requirements].
View all other issues in [utility.arg.requirements].
View all issues with Ready status.
Discussion:
The DefaultConstructible requirement is referenced in several places in the August 2007 working draft N2369, but is not defined anywhere.
[ Bellevue: ]
Walking into the default/value-initialization mess...
Why two lines? Because we need both expressions to be valid.
AJM not sure what the phrase "default constructed" means. This is unfortunate, as the phrase is already used 24 times in the library!
Example: const int would not accept first line, but will accept the second.
This is an issue that must be solved by concepts, but we might need to solve it independantly first.
It seems that the requirements are the syntax in the proposed first column is valid, but not clear what semantics we need.
A table where there is no post-condition seems odd, but appears to sum up our position best.
At a minimum an object is declared and is destuctible.
Move to open, as no-one happy to produce wording on the fly.
[ 2009-07-28 Reopened by Alisdair. No longer solved by concepts. ]
[ 2009-08-17 Daniel adds "[defaultconstructible]" to table title. 408 depends upon this issue. ]
[ 2009-08-18 Alisdair adds: ]
Looking at the proposed table in this issue, it really needs two rows:
Table 33: DefaultConstructible requirements [defaultconstructible] expression post-condition T t; t is default-initialized. T{} Object of type T is value-initialized. Note I am using the new brace-initialization syntax that is unambiguous in all use cases (no most vexing parse.)
[ 2009-10-03 Daniel adds: ]
The suggested definition T{} describing it as value-initialization is wrong, because it belongs to list-initialization which would - as the current rules are - always prefer a initializer-list constructor over a default-constructor. I don't consider this as an appropriate definition of DefaultConstructible. My primary suggestion is to ask core, whether the special case T{} (which also easily leads to ambiguity situations for more than one initializer-list in a class) would always prefer a default-constructor - if any - before considering an initializer-list constructor or to provide another syntax form to prefer value-initialization over list-initialization. If that fails I would fall back to suggest to use the expression T() instead of T{} with all it's disadvantages for the meaning of the expression
T t();
[ 2009-10 Santa Cruz: ]
Leave Open. Core is looking to make Alisdair's proposed resolution correct.
[ 2010-01-24 At Alisdiar's request, moved his proposal into the proposed wording seciton. The old wording is preserved here: ]
In section 20.2.1 [utility.arg.requirements], before table 33, add the following table:
Table 33: DefaultConstructible requirements [defaultconstructible]
expression
post-condition
T t;
T()T is default constructed.
[ 2010-02-04: Moved to Tentatively Ready after 5 positive votes on c++std-lib. ]
Rationale:
[ San Francisco: ]
We believe concepts will solve this problem (N2774).
[ Rationale is obsolete. ]
Proposed resolution:
In section 20.2.1 [utility.arg.requirements], before table 33, add the following table:
Table 33: DefaultConstructible requirements [defaultconstructible] expression post-condition T t; Object t is default-initialized. T u{}; Object u is value-initialized. T()
T{}A temporary object of type T is value-initialized.
Section: 28.11.4 [re.alg.replace] Status: Ready Submitter: Stephan T. Lavavej Opened: 2007-09-22 Last modified: 2010-03-08
View all other issues in [re.alg.replace].
View all issues with Ready status.
Discussion:
regex_match() and regex_search() take const basic_string<charT, ST, SA>&. regex_replace() takes const basic_string<charT>&. This prevents regex_replace() from accepting basic_strings with custom traits and allocators.
Overloads of regex_replace() taking basic_string should be additionally templated on class ST, class SA and take const basic_string<charT, ST, SA>&. Consistency with regex_match() and regex_search() would place class ST, class SA as the first template arguments; compatibility with existing code using TR1 and giving explicit template arguments to regex_replace() would place class ST, class SA as the last template arguments.
[ Batavia (2009-05): ]
Bill comments, "We need to look at the depth of this change."
Pete remarks that we are here dealing with a convenience function that saves a user from calling the iterato-based overload.
Move to Open.
[ 2009-07 Frankfurt: ]
Howard to ask Stephan Lavavej to provide wording.
[ 2009-07-17 Stephan provided wording. ]
[ 2009-07-25 Daniel tweaks both this issue and 726. ]
One relevant part of the proposed resolution below suggests to add a new overload of the format member function in the match_results class template that accepts two character pointers defining the begin and end of a format range. A more general approach could have proposed a pair of iterators instead, but the used pair of char pointers reflects existing practice. If the committee strongly favors an iterator-based signature, this could be simply changed. I think that the minimum requirement should be a BidirectionalIterator, but current implementations take advantage (at least partially) of the RandomAccessIterator sub interface of the char pointers.
Suggested Resolution:
[Moved into the proposed resloution]
[ 2009-07-30 Stephan agrees with Daniel's wording. Howard places Daniel's wording in the Proposed Resolution. ]
[ 2009-10 Santa Cruz: ]
Move to Review. Chair is anxious to move this to Ready in Pittsburgh.
[ 2010-01-27 Moved to Tentatively Ready after 5 positive votes on c++std-lib. ]
Proposed resolution:
Change 28.4 [re.syn] as indicated:
// 28.11.4, function template regex_replace:
template <class OutputIterator, class BidirectionalIterator,
class traits, class charT, class ST, class SA>
OutputIterator
regex_replace(OutputIterator out,
BidirectionalIterator first, BidirectionalIterator last,
const basic_regex<charT, traits>& e,
const basic_string<charT, ST, SA>& fmt,
regex_constants::match_flag_type flags =
regex_constants::match_default);
template <class OutputIterator, class BidirectionalIterator,
class traits, class charT>
OutputIterator
regex_replace(OutputIterator out,
BidirectionalIterator first, BidirectionalIterator last,
const basic_regex<charT, traits>& e,
const charT* fmt,
regex_constants::match_flag_type flags =
regex_constants::match_default);
template <class traits, class charT, class ST, class SA,
class FST, class FSA>
basic_string<charT, ST, SA>
regex_replace(const basic_string<charT, ST, SA>& s,
const basic_regex<charT, traits>& e,
const basic_string<charT, FST, FSA>& fmt,
regex_constants::match_flag_type flags =
regex_constants::match_default);
template <class traits, class charT, class ST, class SA>
basic_string<charT, ST, SA>
regex_replace(const basic_string<charT, ST, SA>& s,
const basic_regex<charT, traits>& e,
const charT* fmt,
regex_constants::match_flag_type flags =
regex_constants::match_default);
template <class traits, class charT, class ST, class SA>
basic_string<charT>
regex_replace(const charT* s,
const basic_regex<charT, traits>& e,
const basic_string<charT, ST, SA>& fmt,
regex_constants::match_flag_type flags =
regex_constants::match_default);
template <class traits, class charT>
basic_string<charT>
regex_replace(const charT* s,
const basic_regex<charT, traits>& e,
const charT* fmt,
regex_constants::match_flag_type flags =
regex_constants::match_default);
Change 28.10 [re.results]/3, class template match_results as indicated:
template <class OutputIter>
OutputIter
format(OutputIter out,
const char_type* fmt_first, const char_type* fmt_last,
regex_constants::match_flag_type flags =
regex_constants::format_default) const;
template <class OutputIter, class ST, class SA>
OutputIter
format(OutputIter out,
const string_typebasic_string<char_type, ST, SA>& fmt,
regex_constants::match_flag_type flags =
regex_constants::format_default) const;
template <class ST, class SA>
string_typebasic_string<char_type, ST, SA>
format(const string_typebasic_string<char_type, ST, SA>& fmt,
regex_constants::match_flag_type flags =
regex_constants::format_default) const;
string_type
format(const char_type* fmt,
regex_constants::match_flag_type flags =
regex_constants::format_default) const;
Insert at the very beginning of 28.10.4 [re.results.form] the following:
template <class OutputIter> OutputIter format(OutputIter out, const char_type* fmt_first, const char_type* fmt_last, regex_constants::match_flag_type flags = regex_constants::format_default) const;1 Requires: The type OutputIter shall satisfy the requirements for an Output Iterator (24.2.2 [output.iterators]).
2 Effects: Copies the character sequence [fmt_first,fmt_last) to OutputIter out. Replaces each format specifier or escape sequence in the copied range with either the character(s) it represents or the sequence of characters within *this to which it refers. The bitmasks specified in flags determine which format specifiers and escape sequences are recognized.
3 Returns: out.
Change 28.10.4 [re.results.form], before p. 1 until p. 3 as indicated:
template <class OutputIter, class ST, class SA> OutputIter format(OutputIter out, conststring_typebasic_string<char_type, ST, SA>& fmt, regex_constants::match_flag_type flags = regex_constants::format_default) const;
1 Requires: The type OutputIter shall satisfy the requirements for an Output Iterator (24.2.3).2 Effects:
Copies the character sequence [fmt.begin(),fmt.end()) to OutputIter out. Replaces each format specifier or escape sequence in fmt with either the character(s) it represents or the sequence of characters within *this to which it refers. The bitmasks specified in flags determines what format specifiers and escape sequences are recognizedEquivalent to return format(out, fmt.data(), fmt.data() + fmt.size(), flags).
3 Returns: out.
Change 28.10.4 [re.results.form], before p. 4 until p. 4 as indicated:
template <class ST, class SA>string_typebasic_string<char_type, ST, SA> format(conststring_typebasic_string<char_type, ST, SA>& fmt, regex_constants::match_flag_type flags = regex_constants::format_default) const;Effects:
Returns a copy of the string fmt. Replaces each format specifier or escape sequence in fmt with either the character(s) it represents or the sequence of characters within *this to which it refers. The bitmasks specified in flags determines what format specifiers and escape sequences are recognized.Constructs an empty string result of type basic_string<char_type, ST, SA>, and calls format(back_inserter(result), fmt, flags).Returns: result
At the end of 28.10.4 [re.results.form] insert as indicated:
string_type format(const char_type* fmt, regex_constants::match_flag_type flags = regex_constants::format_default) const;Effects: Constructs an empty string result of type string_type, and calls format(back_inserter(result), fmt, fmt + char_traits<char_type>::length(fmt), flags).
Returns: result
Change 28.11.4 [re.alg.replace] before p. 1 as indicated:
template <class OutputIterator, class BidirectionalIterator, class traits, class charT, class ST, class SA> OutputIterator regex_replace(OutputIterator out, BidirectionalIterator first, BidirectionalIterator last, const basic_regex<charT, traits>& e, const basic_string<charT, ST, SA>& fmt, regex_constants::match_flag_type flags = regex_constants::match_default); template <class OutputIterator, class BidirectionalIterator, class traits, class charT> OutputIterator regex_replace(OutputIterator out, BidirectionalIterator first, BidirectionalIterator last, const basic_regex<charT, traits>& e, const charT* fmt, regex_constants::match_flag_type flags = regex_constants::match_default);Effects: [..]. If any matches are found then, for each such match, if !(flags & regex_constants::format_no_copy) calls std::copy(m.prefix().first, m.prefix().second, out), and then calls m.format(out, fmt, flags) for the first form of the function and m.format(out, fmt, fmt + char_traits<charT>::length(fmt), flags) for the second form. [..].
Change 28.11.4 [re.alg.replace] before p. 3 as indicated:
template <class traits, class charT, class ST, class SA, class FST, class FSA> basic_string<charT, ST, SA> regex_replace(const basic_string<charT, ST, SA>& s, const basic_regex<charT, traits>& e, const basic_string<charT, FST, FSA>& fmt, regex_constants::match_flag_type flags = regex_constants::match_default); template <class traits, class charT, class ST, class SA> basic_string<charT, ST, SA> regex_replace(const basic_string<charT, ST, SA>& s, const basic_regex<charT, traits>& e, const charT* fmt, regex_constants::match_flag_type flags = regex_constants::match_default);Effects: Constructs an empty string result of type basic_string<charT, ST, SA>, calls regex_replace(back_inserter(result), s.begin(), s.end(), e, fmt, flags), and then returns result.
At the end of 28.11.4 [re.alg.replace] add the following new prototype description:
template <class traits, class charT, class ST, class SA> basic_string<charT> regex_replace(const charT* s, const basic_regex<charT, traits>& e, const basic_string<charT, ST, SA>& fmt, regex_constants::match_flag_type flags = regex_constants::match_default); template <class traits, class charT> basic_string<charT> regex_replace(const charT* s, const basic_regex<charT, traits>& e, const charT* fmt, regex_constants::match_flag_type flags = regex_constants::match_default);Effects: Constructs an empty string result of type basic_string<charT>, calls regex_replace(back_inserter(result), s, s + char_traits<charT>::length(s), e, fmt, flags), and then returns result.
Section: 23 [containers] Status: Ready Submitter: Alisdair Meredith Opened: 2008-01-14 Last modified: 2010-03-12
View other active issues in [containers].
View all other issues in [containers].
View all issues with Ready status.
Discussion:
It appears most containers declare but do not define a member-swap function.
This is unfortunate, as all overload the swap algorithm to call the member-swap function! (required for swappable guarantees [Table 37] and Container Requirements [Table 87])
Note in particular that Table 87 gives semantics of a.swap(b) as swap(a,b), yet for all containers we define swap(a,b) to call a.swap(b) - a circular definition.
A quick survey of clause 23 shows that the following containers provide a definition for member-swap:
array queue stack vector
Whereas the following declare it, but do not define the semantics:
deque list map multimap multiset priority_queue set unordered_map unordered_multi_map unordered_multi_set unordered_set
Suggested resolution:
Provide a definition for each of the affected containers...
[ Bellevue: ]
Move to Open and ask Alisdair to provide wording.
[ 2009-07 Frankfurt: ]
Daniel to provide wording. N2590 is no longer applicable.
[ 2009-07-28 Daniel provided wording. ]
- It assumes that the proposed resolution for 883 is applied, which breaks the circularity of definition between member swap and free swap.
- It uses the notation of the pre-concept allocator trait allocator_propagation_map, which might be renamed after the next refactoring phase of generalized allocators.
- It requires that compare objects, key equal functions and hash functions in containers are swapped via unqualified free swap according to 594.
[ 2009-09-30 Daniel adds: ]
The outcome of this issue should be considered with the outcome of 1198 both in style and in content (e.g. bullet 9 suggests to define the semantic of void priority_queue::swap(priority_queue&) in terms of the member swap of the container).
[ 2009-10 Santa Cruz: ]
Looked at, but took no action on as it overlaps too much with N2982. Waiting for a new draft WP.
[ 2009-10 Santa Cruz: ]
Leave as open. Pablo to provide wording.
[ 2009-10-26 Pablo updated wording. Here is the wording he replaced: ]
Add a new Throws clause just after X [allocator.propagation.map]/5:
static void swap(Alloc& a, Alloc& b);Effects: [..]
Throws: Nothing.
[ This exception requirement is added, such that it's combination with the general container requirements of N2723 [container.requirements.general]/9 make it unambiguously clear that the following descriptions of "swaps the allocators" have the following meaning: (a) This swap is done by calling allocator_propagation_map<allocator_type>::swap and (b) This allocator swap does never propagate an exception ]
Change 23.2.4.1 [associative.reqmts.except]/3 as indicated:
For associative containers, no swap function throws an exception unless that exception is thrown by thecopy constructor or copy assignment operatorswap of the container's Pred objects(if any).Change 23.2.5.1 [unord.req.except]/3 as indicated:
For unordered associative containers, no swap function throws an exception unless that exception is thrown by thecopy constructor or copy assignment operatorswap of the container's Hash or Pred objects, respectively(if any).Insert a new paragraph just after 23.3 [sequences]/1:
In addition to being available via inclusion of the <algorithm> header, the swap function templates in 25.3.3 [alg.swap] are also available when the header <queue> is included.[ There is a new issue in process that will suggest a minimum header for swap and move. If this one is provided, this text can be removed and the header dependency should be added to <queue> ]
Add one further clause at the end of 23.3.1.2 [array.special]:
[This part is added, because otherwise array::swap would otherwise contradict the general contract of 23.2.1 [container.requirements.general] p. 10 b. 5]
Throws: Nothing, unless one of the element-wise swap calls throws an exception.
In 23.3.2 [deque], class template deque synopsis change as indicated:
void swap(deque<T,Alloc>&);At the end of 23.3.2.3 [deque.modifiers] add as indicated:
void swap(deque& x);Effects: Exchanges the contents and swaps the allocators of *this with that of x.
Complexity: Constant time.
In 23.3.3 [forwardlist], class template forward_list synposis change as indicated:
void swap(forward_list<T,Allocator>&);At the end of 23.3.3.4 [forwardlist.modifiers] add as indicated:
void swap(forward_list& x);Effects: Exchanges the contents and swaps the allocators of *this with that of x.
Complexity: Constant time.
In 23.3.4 [list], class template list synopsis change as indicated:
void swap(list<T,Allocator>&);At the end of 23.3.4.3 [list.modifiers] add as indicated:
void swap(list& x);Effects: Exchanges the contents and swaps the allocators of *this with that of x.
Complexity: Constant time.
At the end of 23.3.5.2.2 [priqueue.members] add a new prototype description:
void swap(priority_queue& q);Requires: Compare shall satisfy the Swappable requirements ( [swappable]).
[ This requirement is added to ensure that even a user defined swap which is found by ADL for Compare satisfies the Swappable requirements ]
Effects: this->c.swap(q.c); swap(this->comp, q.comp);
Throws: What and if c.swap(q.c) and swap(comp, q.comp) throws.
[ This part is added, because otherwise priority_queue::swap would otherwise contradict the general contract of 23.2.1 [container.requirements.general] p. 10 b. 5 ]
In 23.3.6 [vector], class template vector synopsis change as indicated:
void swap(vector<T,Allocator>&);Change 23.3.6.2 [vector.capacity]/8 as indicated:
void swap(vector<T,Allocator>& x);Effects: Exchanges the contents and capacity() and swaps the allocators of *this with that of x.Insert a new paragraph just before 23.4 [associative]/1:
In addition to being available via inclusion of the <algorithm> header, the swap function templates in 25.3.3 [alg.swap] are also available when any of the headers <map> or <set> are included.
In 23.4.1 [map], class template map synopsis change as indicated:
void swap(map<Key,T,Compare,Allocator>&);At the end of 23.4.1.3 [map.modifiers] add as indicated:
void swap(map& x);Requires: Compare shall satisfy the Swappable requirements ( [swappable]).
[ This requirement is added to ensure that even a user defined swap which is found by ADL for Compare satisfies the Swappable requirements ]
Effects: Exchanges the contents and swaps the allocators of *this with that of x, followed by an unqualified swap of the comparison objects of *this and x.
Complexity: Constant time
In 23.4.2 [multimap], class template multimap synopsis change as indicated:
void swap(multimap<Key,T,Compare,Allocator>&);At the end of 23.4.2.2 [multimap.modifiers] add as indicated:
void swap(multimap& x);Requires: Compare shall satisfy the Swappable requirements ( [swappable]).
Effects: Exchanges the contents and swaps the allocators of *this with that of x, followed by an unqualified swap of the comparison objects of *this and x.
Complexity: Constant time
In 23.4.3 [set], class template set synopsis change as indicated:
void swap(set<Key,Compare,Allocator>&);After section 23.4.3.1 [set.cons] add a new section set modifiers [set.modifiers] and add the following paragraphs:
void swap(set& x);Requires: Compare shall satisfy the Swappable requirements ( [swappable]).
Effects: Exchanges the contents and swaps the allocators of *this with that of x, followed by an unqualified swap of the comparison objects of *this and x.
Complexity: Constant time
In 23.4.4 [multiset], class template multiset synosis, change as indicated:
void swap(multiset<Key,Compare,Allocator>&);After section 23.4.4.1 [multiset.cons] add a new section multiset modifiers [multiset.modifiers] and add the following paragraphs:
void swap(multiset& x);Requires: Compare shall satisfy the Swappable requirements ( [swappable]).
Effects: Exchanges the contents and swaps the allocators of *this with that of x, followed by an unqualified swap of the comparison objects of *this and x.
Complexity: Constant time
Insert a new paragraph just before 23.5 [unord]/1:
In addition to being available via inclusion of the <algorithm> header, the swap function templates in 25.3.3 [alg.swap] are also available when any of the headers <unordered_map> or <unordered_set> are included.After section 23.5.1.2 [unord.map.elem] add a new section unordered_map modifiers [unord.map.modifiers] and add the following paragraphs:
void swap(unordered_map& x);Requires: Hash and Pred shall satisfy the Swappable requirements ( [swappable]).
[ This requirement is added to ensure that even a user defined swap which is found by ADL for Hash and Pred satisfies the Swappable requirements ]
Effects: Exchanges the contents and hash policy and swaps the allocators of *this with that of x, followed by an unqualified swap of the Pred objects and an unqualified swap of the Hash objects of *this and x.
Complexity: Constant time
After section 23.5.2.1 [unord.multimap.cnstr] add a new section unordered_multimap modifiers [unord.multimap.modifiers] and add the following paragraphs:
void swap(unordered_multimap& x);Requires: Hash and Pred shall satisfy the Swappable requirements ( [swappable]).
Effects: Exchanges the contents and hash policy and swaps the allocators of *this with that of x, followed by an unqualified swap of the Pred objects and an unqualified swap of the Hash objects of *this and x
Complexity: Constant time
After section 23.5.3.1 [unord.set.cnstr] add a new section unordered_set modifiers [unord.set.modifiers] and add the following paragraphs:
void swap(unordered_set& x);Requires: Hash and Pred shall satisfy the Swappable requirements ( [swappable]).
Effects: Exchanges the contents and hash policy and swaps the allocators of *this with that of x, followed by an unqualified swap of the Pred objects and an unqualified swap of the Hash objects of *this and x
Complexity: Constant time
After section 23.5.4.1 [unord.multiset.cnstr] add a new section unordered_multiset modifiers [unord.multiset.modifiers] and add the following paragraphs:
void swap(unordered_multiset& x);Requires: Hash and Pred shall satisfy the Swappable requirements ( [swappable]).
Effects: Exchanges the contents and hash policy and swaps the allocators of *this with that of x, followed by an unqualified swap of the Pred objects and an unqualified swap of the Hash objects of *this and x
Complexity: Constant time
[ 2009-10-30 Pablo and Daniel updated wording. ]
[ 2010 Pittsburgh: Ready for Pittsburgh. ]
Proposed resolution:
[ This resolution is based on the September 2009 WP, N2960, except that it assumes that N2982 and issues 883 and 1232 have already been applied. Note in particular that Table 91 in N2960 is refered to as Table 90 because N2982 removed the old Table 90. This resolution also addresses issue 431. ]
In 23.2.1 [container.requirements.general], replace the a.swap(b) row in table 90, "container requirements" (was table 91 before the application of N2982 to the WP):
a.swap(b)voidswap(a,b)Exchange the contents of a and b.(Note A) swap(a,b)voida.swap(b)(Note A)
Modify the notes immediately following Table 90 in 23.2.1 [container.requirements.general] as follows (The wording below is after the application of N2982 to N2960. The editor might also want to combine Notes A and B into one.):
Notes: the algorithms
swap(),equal() and lexicographical_compare() are defined in Clause 25. Those entries marked "(Note A)" or "(Note B)"shouldhave linear complexity for array and constant complexity for all other standard containers.
In 23.2.1 [container.requirements.general], before paragraph 8, add:
The expression
a.swap(b), for containersaandbof a standard container type other thanarray, exchanges the values ofaandbwithout invoking any move, copy, or swap operations on the individual container elements. AnyCompare,Pred, orHashfunction objects belonging toaandbshall beswappableand are exchanged by unqualified calls to non-memberswap. Ifallocator_traits<allocator_type>::propagate_on_container_swap::value == true, then the allocators ofaandbare also exchanged using an unqualified call to non-memberswap. Otherwise, the behavior is undefined unlessa.get_allocator() == b.get_allocator(). Each iterator refering 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 valuea.end()before the swap will have valueb.end()after the swap. In addition to being available via inclusion of the<utility>header, theswapfunction template in 25.3.3 [alg.swap] is also available within the definition of every standard container'sswapfunction.
[ Note to the editor: Paragraph 2 starts with a sentence fragment, clearly from an editing or source-control error. ]
Modify 23.2.4.1 [associative.reqmts.except] as follows:
23.2.4.1 Exception safety guarantees 23.2.4.1 [associative.reqmts.except]
For associative containers, no
clear()function throws an exception.erase(k)does not throw an exception unless that exception is thrown by the container'sobject (if any).PredCompareFor associative containers, if an exception is thrown by any operation from within an
insert()function inserting a single element, theinsert()function has no effect.For associative containers, no
swapfunction throws an exception unless that exception is thrown by thecopy constructor or copy assignment operatorswap of the container'sobject (if any).PredCompare
Modify 23.2.5.1 [unord.req.except], paragraph 3 as follows:
For unordered associative containers, no
swapfunction throws an exception unless that exception is thrown by thecopy constructor or copy assignment operatorswap of the container'sHashorPredobject (if any).
Modify section 23.3.1.2 [array.special]:
array specialized algorithms 23.3.1.2 [array.special]
template <class T, size_t N> void swap(array<T,N>& x,array<T,N>& y);Effects:
swap_ranges(x.begin(), x.end(), y.begin() );x.swap(y);
Add a new section after 23.3.1.5 [array.fill] (Note to the editor: array::fill make use of a concept requirement that must be removed or changed to text.):
array::swap [array.swap]
void swap(array& y);Effects:
swap_ranges(this->begin(), this->end(), y.begin() );Throws: Nothing unless one of the element-wise swap calls throws an exception.
[Note: Unlike other containers'
swapfunctions,array::swaptakes linear, not constant, time, may exit via an exception, and does not cause iterators to become associated with the other container. — end note]
Insert a new paragraph just after 23.3.5 [container.adaptors]/1:
For container adaptors, no
swapfunction throws an exception unless that exception is thrown by the swap of the adaptor'sContainerorCompareobject (if any).
Section: 25.4.4 [alg.merge] Status: Ready Submitter: Daniel Krügler Opened: 2008-01-25 Last modified: 2010-03-08
View all issues with Ready status.
Discussion:
Though issue 283 has fixed many open issues, it seems that some are still open:
Both 25.3.4 [lib.alg.merge] in 14882:2003 and 25.4.4 [alg.merge] in N2461 have no Requires element and the Effects element contains some requirements, which is probably editorial. Worse is that:
[ Post Summit Alisdair adds: ]
Suggest:
(where last is equal to next(result, distance(first1, last1) + distance(first2, last2)), such that resulting range will be sorted in non-decreasing order; that is, for every iterator i in [result,last) other than result, the condition *i < *prev(i) or, respectively, comp(*i, *prev(i)) will be false.Note that this might still not be technically accurate in the case of InputIterators, depending on other resolutions working their way through the system (1011).
[ Post Summit Daniel adds: ]
If we want to use prev and next here (Note: merge is sufficiently satisfied with InputIterator) we should instead *add* more to 25 [algorithms]/6, but I can currently not propose any good wording for this.
[ Batavia (2009-05): ]
Pete points out the existing wording in [algorithms]/4 that permits the use of + in algorithm specifications.
Alisdair points out that that wording may not apply to input iterators.
Move to Review.
[ 2009-07 Frankfurt: ]
Move to Ready.
[ 2009-08-23 Daniel reopens: ]
The proposed wording must be rephrased, because the part
for every iterator i in [result,last) other than result, the condition *i < *(i - 1) or, respectively, comp(*i, *(i - 1)) will be false"isn't meaningful, because the range [result,last) is that of a pure OutputIterator, which is not readable in general.
[Howard: Proposed wording updated by Daniel, status moved from Ready to Review.]
[ 2009-10 Santa Cruz: ]
Matt has some different words to propose. Those words have been moved into the proposed wording section, and the original proposed wording now appears here:
In 25.4.4 [alg.merge] replace p.1+ 2:
Effects:
MergesCopies all the elements of the two sorted ranges [first1,last1) and [first2,last2) into the range [result,result + (last1 - first1) + (last2 - first2)) , such that resulting range will be sorted in non-decreasing order; that is for every pair of iterators i and j of either input ranges, where *i was copied to the output range before *j was copied to the output range, the condition *j < *i or, respectively, comp(*j, *i) will be false.Requires:The resulting range shall not overlap with either of the original ranges.
The list will be sorted in non-decreasing order according to the ordering defined by comp; that is, for every iterator i in [first,last) other than first, the condition *i < *(i - 1) or comp(*i, *(i - 1)) will be false.
[ 2010-02-10 Moved to Tentatively Ready after 5 positive votes on c++std-lib. ]
Proposed resolution:
Change 25.4.4 [alg.merge] 1 and 2:
1
Effects: Merges two sorted ranges [first1,last1) and [first2,last2) into the range [result, result + (last1 - first1) + (last2 - first2)).Effects: Copies all the elements of the two ranges [first1,last1) and [first2,last2) into the range [result, result_last), where result_last is result + (last1 - first1) + (last2 - first2), such that the resulting range satisfies is_sorted(result, result_last) or is_sorted(result, result_last, comp), respectively.
2 Requires: The ranges [first1,last1) and [first2,last2) shall be sorted with respect to operator< or comp. The resulting range shall not overlap with either of the original ranges.
The list will be sorted in non-decreasing order according to the ordering defined by comp; that is, for every iterator i in [first,last) other than first, the condition *i < *(i - 1) or comp(*i, *(i - 1)) will be false.
Change 25.4.4 [alg.merge]/6+7 as indicated [This ensures harmonization between inplace_merge and merge]
6 Effects: Merges two
sortedconsecutive ranges [first,middle) and [middle,last), putting the result of the merge into the range [first,last). The resulting range will be in non-decreasing order; that is, for every iterator i in [first,last) other than first, the condition *i < *(i - 1) or, respectively, comp(*i, *(i - 1)) will be false.7 Requires: The ranges [first,middle) and [middle,last) shall be sorted with respect to operator< or comp. The type of *first shall satisfy the Swappable requirements (37), the MoveConstructible requirements (Table 33), and the the MoveAssignable requirements (Table 35).
Section: 20.4 [tuple] Status: Open Submitter: Lawrence Crowl Opened: 2008-02-18 Last modified: 2010-03-10
View all other issues in [tuple].
View all issues with Open status.
Discussion:
Classes with trivial special member functions are inherently more efficient than classes without such functions. This efficiency is particularly pronounced on modern ABIs that can pass small classes in registers. Examples include value classes such as complex numbers and floating-point intervals. Perhaps more important, though, are classes that are simple collections, like pair and tuple. When the parameter types of these classes are trivial, the pairs and tuples themselves can be trivial, leading to substantial performance wins.
The current working draft make specification of trivial functions (where possible) much easer through defaulted and deleted functions. As long as the semantics of defaulted and deleted functions match the intended semantics, specification of defaulted and deleted functions will yield more efficient programs.
There are at least two cases where specification of an explicitly defaulted function may be desirable.
First, the std::pair template has a non-trivial default constructor, which prevents static initialization of the pair even when the types are statically initializable. Changing the definition to
pair() = default;
would enable such initialization. Unfortunately, the change is not semantically neutral in that the current definition effectively forces value initialization whereas the change would not value initialize in some contexts.
** Does the committee confirm that forced value initialization was the intent? If not, does the committee wish to change the behavior of std::pair in C++0x?
Second, the same default constructor issue applies to std::tuple. Furthermore, the tuple copy constructor is current non-trivial, which effectively prevents passing it in registers. To enable passing tuples in registers, the copy constructor should be make explicitly defaulted. The new declarations are:
tuple() = default; tuple(const tuple&) = default;
This changes is not implementation neutral. In particular, it prevents implementations based on pointers to the parameter types. It does however, permit implementations using the parameter types as bases.
** How does the committee wish to trade implementation efficiency versus implementation flexibility?
[ Bellevue: ]
General agreement; the first half of the issue is NAD.
Before voting on the second half, it was agreed that a "Strongly Favor" vote meant support for trivial tuples (assuming usual requirements met), even at the expense of other desired qualities. A "Weakly Favor" vote meant support only if not at the expense of other desired qualities.
Concensus: Go forward, but not at expense of other desired qualities.
It was agreed to Alisdair should fold this work in with his other pair/tuple action items, above, and that issue 801 should be "open", but tabled until Alisdair's proposals are disposed of.
[ 2009-05-27 Daniel adds: ]
This is partly solved by 1117.
[ 2009-07 Frankfurt: ]
Wait for dust to settle from fixing exception safety problem with rvalue refs.
[ 2009-07-20 Alisdair adds: ]
Basically, this issue is what should we do with the default constructor for pairs and tuples of trivial types. The motivation of the issue was to force static initialization rather than dynamic initialization, and was rejected in the case of pair as it would change the meaning of existing programs. The advice was "do the best we can" for tuple without changing existing meaning.
Frankfurt seems to simply wait and see the resolution on no-throw move constructors, which (I believe) is only tangentially related to this issue, but as good as any to defer until Santa Cruz.
Looking again now, I think constant (static) initialization for pair can be salvaged by making the default construct constexpr. I have a clarification from Core that this is intended to work, even if the constructor is not trivial/constexpr, so long as no temporaries are implied in the process (even if elided).
[ 2009-10 Santa Cruz: ]
Leave as open. Alisdair to provide wording.
[ 2010 Pittsburgh: ]
We believe this may be NAD Editorial since both pair and tuple now have constexpr default constructors, but we're not sure.
Proposed resolution:
Section: 20.3.4 [pairs] Status: Ready Submitter: Doug Gregor Opened: 2008-03-14 Last modified: 2010-03-08
View other active issues in [pairs].
View all other issues in [pairs].
View all issues with Ready status.
Discussion:
#include <utility>
int main()
{
std::pair<char *, char *> p (0,0);
}
I just got a bug report about that, because it's valid C++03, but not C++0x. The important realization, for me, is that the emplace proposal---which made push_back variadic, causing the push_back(0) issue---didn't cause this break in backward compatibility. The break actually happened when we added this pair constructor as part of adding rvalue references into the language, long before variadic templates or emplace came along:
template<class U, class V> pair(U&& x, V&& y);
Now, concepts will address this issue by constraining that pair constructor to only U's and V's that can properly construct "first" and "second", e.g. (from N2322):
template<class U , class V > requires Constructible<T1, U&&> && Constructible<T2, V&&> pair(U&& x , V&& y );
[ San Francisco: ]
Suggested to resolve using pass-by-value for that case.
Side question: Should pair interoperate with tuples? Can construct a tuple of a pair, but not a pair from a two-element tuple.
Related to 885.
[ 2009-07-28 Reopened by Alisdair. No longer solved by concepts. ]
[ 2009-10 Santa Cruz: ]
Leave as open. Howard to provide wording.
[ 2010-02-06 Howard provided wording. ]
[ 2010-02-09 Moved to Tentatively Ready after 6 positive votes on c++std-lib. ]
Rationale:
[ San Francisco: ]
Solved by N2770.
[ The rationale is obsolete. ]
Proposed resolution:
Add a paragraph to 20.3.4 [pairs]:
template<class U, class V> pair(U&& x, V&& y);6 Effects: The constructor initializes first with std::forward<U>(x) and second with std::forward<V>(y).
Remarks: U shall be implicitly convertible to first_type and V shall be implicitly convertible to second_type, else this constructor shall not participate in overload resolution.
Section: 20.8.11.1.3 [func.bind.bind] Status: Ready Submitter: Howard Hinnant Opened: 2008-03-17 Last modified: 2010-03-08
View all other issues in [func.bind.bind].
View all issues with Ready status.
Discussion:
Addresses US 72, JP 38 and DE 21
The functor returned by bind() should have a move constructor that requires only move construction of its contained functor and bound arguments. That way move-only functors can be passed to objects such as thread.
This issue is related to issue 816.
US 72:
bind should support move-only functors and bound arguments.
JP 38:
add the move requirement for bind's return type.
For example, assume following th1 and th2,
void f(vector<int> v) { } vector<int> v{ ... }; thread th1([v]{ f(v); }); thread th2(bind(f, v));When function object are set to thread, v is moved to th1's lambda expression in a Move Constructor of lambda expression because th1's lambda expression has a Move Constructor. But bind of th2's return type doesn't have the requirement of Move, so it may not moved but copied.
Add the requirement of move to get rid of this useless copy.
And also, add the MoveConstructible as well as CopyConstructible.
DE 21
The specification for bind claims twice that "the values and types for the bound arguments v1, v2, ..., vN are determined as specified below". No such specification appears to exist.
[ San Francisco: ]
Howard to provide wording.
[ Post Summit Alisdair and Howard provided wording. ]
Several issues are being combined in this resolution. They are all touching the same words so this is an attempt to keep one issue from stepping on another, and a place to see the complete solution in one place.
- bind needs to be "moved".
- 20.8.11.1.3 [func.bind.bind]/p3, p6 and p7 were accidently removed from N2798.
- Issue 929 argues for a way to pass by && for efficiency but retain the decaying behavior of pass by value for the thread constructor. That same solution is applicable here.
[ Batavia (2009-05): ]
We were going to recommend moving this issue to Tentatively Ready until we noticed potential overlap with issue 816 (q.v.).
Move to Open, and recommend both issues be considered together (and possibly merged).
[ 2009-07 Frankfurt: ]
The proposed resolution uses concepts. Leave Open.
[ 2009-10 Santa Cruz: ]
Leave as Open. Howard to provide deconceptified wording.
[ 2009-11-07 Howard updates wording. ]
[ 2009-11-15 Further updates by Peter, Chris and Daniel. ]
[ Moved to Tentatively Ready after 6 positive votes on c++std-lib. ]
Proposed resolution:
Change 20.8 [function.objects] p2:
template<class Fn, class...TypesBoundArgs> unspecified bind(Fn&&,TypesBoundArgs&&...); template<class R, class Fn, class...TypesBoundArgs> unspecified bind(Fn&&,TypesBoundArgs&&...);
Change 20.8.2 [func.require]:
4 Every call wrapper (20.8.1 [func.def]) shall be
CopyMoveConstructible. A simple call wrapper is a call wrapper that is CopyConstructible and CopyAssignable and whose copy constructor, move constructor and assignment operator do not throw exceptions. A forwarding call wrapper is a call wrapper that can be called with an argument list. [Note: in a typical implementation forwarding call wrappers have an overloaded function call operator of the formtemplate<class...ArgTypesUnBoundsArgs> R operator()(ArgTypesUnBoundsArgs&&... unbound_args) cv-qual;— end note]
Change 20.8.11.1.3 [func.bind.bind]:
Within this clause:
- Let FD be a synonym for the type decay<F>::type.
- Let fd be an lvalue of type FD constructed from std::forward<F>(f).
- Let Ti be a synonym for the ith type in the template parameter pack BoundArgs.
- Let TiD be a synonym for the type decay<Ti>::type.
- Let ti be the ith argument in the function parameter pack bound_args.
- Let tid be an lvalue of type TiD constructed from std::forward<Ti>(ti).
- Let Uj be the jth deduced type of the UnBoundArgs&&... parameter of the operator() of the forwarding call wrapper.
- Let uj be the jth argument associated with Uj.
template<class F, class... BoundArgs> unspecified bind(F&& f, BoundArgs&&... bound_args);-1- Requires: is_constructible<FD, F>::value shall be true. For each Ti in BoundArgs, is_constructible<TiD, Ti>::value shall be true.
F and each Ti in BoundArgs shall be CopyConstructible.INVOKE(fd, w1, w2, ..., wN) (20.8.2 [func.require]) shall be a valid expression for some values w1, w2, ..., wN, where N == sizeof...(bound_args).-2- Returns: A forwarding call wrapper g with a weak result type (20.8.2 [func.require]). 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. The copy constructor and move constructor of the forwarding call wrapper shall throw an exception if and only if the corresponding constructor of FD or of any of the types TiD throws an exception.
-3- Throws: Nothing unless the
copyconstructionorofFfd or of one of the values tidtypes in the BoundArgs... pack expansionthrows an exception.Remarks: The unspecified return type shall satisfy the requirements of MoveConstructible. If all of FD and TiD satisfy the requirements of CopyConstructible then the unspecified return type shall satisfy the requirements of CopyConstructible. [Note: This implies that all of FD and TiD shall be MoveConstructible — end note]
template<class R, class F, class... BoundArgs> unspecified bind(F&& f, BoundArgs&&... bound_args);-4- Requires: is_constructible<FD, F>::value shall be true. For each Ti in BoundArgs, is_constructible<TiD, Ti>::value shall be true.
F and each Ti in BoundArgs shall be CopyConstructible.INVOKE(fd, w1, w2, ..., wN) shall be a valid expression for some values w1, w2, ..., wN, where N == sizeof...(bound_args).-5- Returns: A forwarding call wrapper g with a nested type result_type defined as a synonym for R. The effect of g(u1, u2, ..., uM) shall be INVOKE(fd, v1, v2, ..., vN, R), where the values and types of the bound arguments v1, v2, ..., vN are determined as specified below. The copy constructor and move constructor of the forwarding call wrapper shall throw an exception if and only if the corresponding constructor of FD or of any of the types TiD throws an exception.
-6- Throws: Nothing unless the
copyconstructionorofFfd or of one of the values tidtypes in the BoundArgs... pack expansionthrows an exception.Remarks: The unspecified return type shall satisfy the requirements of MoveConstructible. If all of FD and TiD satisfy the requirements of CopyConstructible then the unspecified return type shall satisfy the requirements of CopyConstructible. [Note: This implies that all of FD and TiD shall be MoveConstructible — end note]
-7- The values of the bound arguments v1, v2, ..., vN and their corresponding types V1, V2, ..., VN depend on the types TiD derived from
of the corresponding argument ti in bound_args of type Ti in BoundArgs inthe call to bind and the cv-qualifiers cv of the call wrapper g as follows:
- if
tiTiD isof typereference_wrapper<T> the argument is tid.get() and its type Vi is T&;- if the value of
std::is_bind_expression<TiD>::value is true the argument is tid(std::forward<Uj>(uj)...u1, u2, ..., uM) and its type Vi is result_of<TiD cv (Uj...U1&, U2&, ..., UM&)>::type;- if the value j of
std::is_placeholder<TiD>::value is not zero the argument is std::forward<Uj>(uj) and its type Vi is Uj&&;- otherwise the value is tid and its type Vi is TiD cv &.
Section: 18.8.6 [except.nested] Status: Ready Submitter: Alisdair Meredith Opened: 2008-03-25 Last modified: 2010-03-11
View other active issues in [except.nested].
View all other issues in [except.nested].
View all issues with Ready status.
Discussion:
Looking at the wording I submitted for rethrow_if_nested, I don't think I got it quite right.
The current wording says:
template <class E> void rethrow_if_nested(const E& e);Effects: Calls e.rethrow_nested() only if e is publicly derived from nested_exception.
This is trying to be a bit subtle, by requiring e (not E) to be publicly derived from nested_exception the idea is that a dynamic_cast would be required to be sure. Unfortunately, if e is dynamically but not statically derived from nested_exception, e.rethrow_nested() is ill-formed.
[ San Francisco: ]
Alisdair was volunteered to provide wording.
[ 2009-10 Santa Cruz: ]
Leave as Open. Alisdair to provide wording.
[ 2009-11-09 Alisdair provided wording. ]
[ 2010-03-10 Dietmar updated wording. ]
[ 2010 Pittsburgh: ]
Moved to Ready for Pittsburgh.
Proposed resolution:
Change 18.8.6 [except.nested], p8:
template <class E> void rethrow_if_nested(const E& e);-8- Effects:Calls e.rethrow_nested() oOnly if the dynamic type of e is publicly and unambiguously derived from nested_exception this calls dynamic_cast<const nested_exception&>(e).rethrow_nested().
Section: 20.9.10.2 [unique.ptr.single] Status: Open Submitter: Daniel Krügler Opened: 2008-05-14 Last modified: 2010-01-16
View other active issues in [unique.ptr.single].
View all other issues in [unique.ptr.single].
View all issues with Open status.
Discussion:
Issue 673 (including recent updates by 821) proposes a useful extension point for unique_ptr by granting support for an optional deleter_type::pointer to act as pointer-like replacement for element_type* (In the following: pointer).
Unfortunately no requirements are specified for the type pointer which has impact on at least two key features of unique_ptr:
Unique_ptr specification makes great efforts to require that essentially *all* operations cannot throw and therefore adds proper wording to the affected operations of the deleter as well. If user-provided pointer-emulating types ("smart pointers") will be allowed, either *all* throw-nothing clauses have to be replaced by weaker "An exception is thrown only if pointer's {op} throws an exception"-clauses or it has to be said explicitly that all used operations of pointer are required *not* to throw. I understand the main focus of unique_ptr to be as near as possible to the advantages of native pointers which cannot fail and thus strongly favor the second choice. Also, the alternative position would make it much harder to write safe and simple template code for unique_ptr. Additionally, I assume that a general statement need to be given that all of the expressions of pointer used to define semantics are required to be well-formed and well-defined (also as back-end for 762).
[ Sophia Antipolis: ]
Howard: We maybe need a core concept PointerLike, but we don't need the arithmetic (see shared_ptr vs. vector<T>::iterator.
Howard will go through and enumerate the individual requirements wrt. pointer for each member function.
[ 2009-07 Frankfurt: ]
Move to Ready.
[ 2009-10-15 Alisdair pulls from Ready: ]
I hate to pull an issue out of Ready status, but I don't think 834 is fully baked yet.
For reference the proposed resolution is to add the following words:
unique_ptr<T, D>::pointer's operations shall be well-formed, shall have well defined behavior, and shall not throw exceptions.This leaves me with a big question : which operations?
Are all pointer operations required to be nothrow, including operations that have nothing to do with interactions with unique_ptr? This was much simpler with concepts where we could point to operations within a certain concept, and so nail down the interactions.
[ 2009-10-15 Daniel adds: ]
I volunteer to prepare a more fine-grained solution, but I would like to ask for feedback that helps me doing so. If this question is asked early in the meeting I might be able to fix it within the week, but I cannot promise that now.
[ 2009-10 Santa Cruz: ]
Leave in open. Daniel to provide wording as already suggested.
[ 2009-12-22 Daniel provided wording and rationale. ]
Rationale:
The here proposed resolution has considerable overlap with the requirements that are used in the allocator requirements.
This might be a convincing argument to isolate the common subset into one requirement. The reason I did not do that is basically because we might find out that they are either over-constraining or under-constraining at this late point of specification. Note also that as a result of the idea of a general requirement set I added the requirement
A default-initialized object may have a singular value
even though this does not play a relevant role for unique_ptr.
One further characteristics of the resolution is that availability of relational operators of unique_ptr<T, D>::pointer is not part of the basic requirements, which is in sync with the allocator requirements on pointer-like (this means that unique_ptr can hold a void_pointer or const_void_pointer).
Proposed resolution:
Change 20.9.10.2 [unique.ptr.single]/1 as indicated: [The intent is to replace the coupling between T* and the deleter's operator() by a coupling between unique_ptr<T, D>::pointer and this operator()]
1 - The default type for the template parameter D is default_delete. A client-supplied template argument D shall be a function pointer or functor for which, given a value d of type D and apointervalue ptr of typeT*unique_ptr<T, D>::pointer, the expression d(ptr) is valid and has the effect of deallocating the pointer as appropriate for that deleter. D may also be an lvalue-reference to a deleter.
Change 20.9.10.2 [unique.ptr.single]/3 as indicated:
3 - If the type remove_reference<D>::type::pointer exists, then unique_ptr<T, D>::pointer shall be a synonym for remove_reference<D>::type::pointer. Otherwise unique_ptr<T, D>::pointer shall be a synonym for T*. The type unique_ptr<T, D>::pointer shall
besatisfy the requirements of EqualityComparable, DefaultConstructible, CopyConstructible(Table 34) and, CopyAssignable(Table 36), Swappable, and Destructible (20.2.1 [utility.arg.requirements]). A default-initialized object may have a singular value. A value-initialized object produces the null value of the type. The null value shall be equivalent only to itself. An object of this type can be copy-initialized with a value of type nullptr_t, compared for equality with a value of type nullptr_t, and assigned a value of type nullptr_t. The effect shall be as if a value-initialized object had been used in place of the null pointer constant. An object p of this type can be contextually converted to bool. The effect shall be as if p != nullptr had been evaluated in place of p. No operation on this type which is part of the above mentioned requirements shall exit via an exception.[Note: Given an allocator type X (20.2.2 [allocator.requirements]), the types X::pointer, X::const_pointer, X::void_pointer, and X::const_void_pointer may be used as unique_ptr<T, D>::pointer — end note]
In addition to being available via inclusion of the <utility> header, the swap function template in 20.3.2 [utility.swap] is also available within the definition of unique_ptr's swap function.
Change 20.9.10.2.1 [unique.ptr.single.ctor]/2+3 as indicated: [The first change ensures that we explicitly say, how the stored pointer is initialized. This is important for a constexpr function, because this may make a difference for user-defined pointer-like types]
constexpr unique_ptr();...
2 - Effects: Constructs a unique_ptr which owns nothing, value-initializing the stored pointer.
3 - Postconditions: get() ==
0nullptr.
Change 20.9.10.2.1 [unique.ptr.single.ctor]/6+7 as indicated: [This is a step-by-fix to ensure consistency to the changes of N2976]
unique_ptr(pointer p);...
6 - Effects: Constructs a unique_ptr which owns p, initializing the stored pointer with p.
7 - Postconditions: get() == p. get_deleter() returns a reference to a
default constructedvalue-initialized deleter D.
Insert a new effects clause in 20.9.10.2.1 [unique.ptr.single.ctor] just before p. 14: [The intent is to fix the current lack of specification in which way the stored pointer is initialized]
unique_ptr(pointer p,implementation-definedsee below d1); unique_ptr(pointer p,implementation-definedsee below d2);...
Effects: Constructs a unique_ptr which owns p, initializing the stored pointer with p and the initializing the deleter as described above.
14 - Postconditions: get() == p. get_deleter() returns a reference to the internally stored deleter. If D is a reference type then get_deleter() returns a reference to the lvalue d.
Change 20.9.10.2.1 [unique.ptr.single.ctor]/18+22 as indicated: [The intent is to clarify that the moved-from source must contain a null pointer, there is no other choice left]
unique_ptr(unique_ptr&& u);[..]
18 - Postconditions: get() == value u.get() had before the construction and u.get() == nullptr. get_deleter() returns a reference to the internally stored deleter which was constructed from u.get_deleter(). If D is a reference type then get_deleter() and u.get_deleter() both reference the same lvalue deleter.
template <class U, class E> unique_ptr(unique_ptr<U, E>&& u);[..]
22 - Postconditions: get() == value u.get() had before the construction, modulo any required offset adjustments resulting from the cast from unique_ptr<U, E>::pointer to pointer and u.get() == nullptr. get_deleter() returns a reference to the internally stored deleter which was constructed from u.get_deleter().
Change 20.9.10.2.1 [unique.ptr.single.ctor]/20 as indicated: [With the possibility of user-defined pointer-like types the implication does only exist, if those are built-in pointers. Note that this change should also be applied with the acceptance of 950]
template <class U, class E> unique_ptr(unique_ptr<U, E>&& u);20 - Requires: If D is not a reference type, construction of the deleter D from an rvalue of type E shall be well formed and shall not throw an exception. If D is a reference type, then E shall be the same type as D (diagnostic required). unique_ptr<U, E>::pointer shall be implicitly convertible to pointer.[Note: These requirements imply that T and U are complete types. — end note]
Change 20.9.10.2.2 [unique.ptr.single.dtor]/2 as indicated:
~unique_ptr();...
2 - Effects: If get() ==
0nullptr there are no effects. Otherwise get_deleter()(get()).
Change 20.9.10.2.3 [unique.ptr.single.asgn]/3+8 as indicated: [The intent is to clarify that the moved-from source must contain a null pointer, there is no other choice left]
unique_ptr& operator=(unique_ptr&& u);[..]
3 - Postconditions: This unique_ptr now owns the pointer which u owned, and u no longer owns it, u.get() == nullptr. [Note: If D is a reference type, then the referenced lvalue deleters are move assigned. — end note]
template <class U, class E> unique_ptr& operator=(unique_ptr<U, E>&& u);[..]
8 - Postconditions: This unique_ptr now owns the pointer which u owned, and u no longer owns it, u.get() == nullptr.
Change 20.9.10.2.3 [unique.ptr.single.asgn]/6 as indicated: [With the possibility of user-defined pointer-like types the implication does only exist, if those are built-in pointers. Note that this change should also be applied with the acceptance of 950]
template <class U, class E> unique_ptr& operator=(unique_ptr<U, E>&& u);[..]
6 - Requires: Assignment of the deleter D from an rvalue D shall not throw an exception. unique_ptr<U, E>::pointer shall be implicitly convertible to pointer.
[Note: These requirements imply that T and U are complete types. — end note]
Change 20.9.10.2.3 [unique.ptr.single.asgn] before p. 11 and p. 12 as indicated: [The first change is a simple typo fix]
unique_ptr& operator=(nullptr_t});11 - Effects: reset().
12 - Postcondition: get() ==
0nullptr
Change 20.9.10.2.4 [unique.ptr.single.observers]/1+4+12 as indicated:
typename add_lvalue_reference<T>::type operator*() const;1 - Requires: get() !=
0nullptr. The variable definition add_lvalue_reference<T>::type t = *get() shall be well formed, shall have well-defined behavior, and shall not exit via an exception.[..]
pointer operator->() const;4 - Requires: get() !=
0nullptr.[..]
explicit operator bool() const;12 - Returns: get() !=0nullptr.
Change 20.9.10.2.5 [unique.ptr.single.modifiers]/1 as indicated:
pointer release();1 - Postcondition: get() ==0nullptr.
Change 20.9.10.2.5 [unique.ptr.single.modifiers]/9 as indicated: [The intent is to ensure that potentially user-defined swaps are used. A side-step fix and harmonization with the specification of the the deleter is realized. Please note the additional requirement in bullet 2 of this proposed resolution regarding the availability of the generic swap templates within the member swap function.]
void swap(unique_ptr& u);8 - Requires: The deleter D shall be Swappable and shall not throw an exception under swap.
9 - Effects: The stored pointers of *this and u are exchanged by an unqualified call to non-member swap. The stored deleters are
swap'd (unqualified)exchanged by an unqualified call to non-member swap.
Change 20.9.10.3.2 [unique.ptr.runtime.observers]/1 as indicated:
T& operator[](size_t i) const;Requires: i < the size of the array to which the stored pointer points. The variable definition T& t = get()[i] shall be well formed, shall have well-defined behavior, and shall not exit via an exception.
Change 20.9.10.3.3 [unique.ptr.runtime.modifiers]/1 as indicated:
void reset(pointer p = pointer()); void reset(nullptr_t p);1 - Effects: If get() ==0nullptr there are no effects. Otherwise get_deleter()(get()).
Change 20.9.10.4 [unique.ptr.special] as indicated: [We don't add the relational operators to the basic requirement set, therefore we need special handling here]
template <class T1, class D1, class T2, class D2> bool operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);Requires: The variable definition bool b = x.get() == y.get(); shall be well formed, shall have well-defined behavior, and shall not exit via an exception.
2 - Returns: x.get() == y.get().
Throws: nothing.
template <class T1, class D1, class T2, class D2> bool operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);Requires: The variable definition bool b = x.get() != y.get(); shall be well formed, shall have well-defined behavior, and shall not exit via an exception.
3 - Returns: x.get() != y.get().
Throws: nothing.
template <class T1, class D1, class T2, class D2> bool operator<(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);Requires: The variable definition bool b = x.get() < y.get(); shall be well formed, shall have well-defined behavior, and shall not exit via an exception.
4 - Returns: x.get() < y.get().
Throws: nothing.
template <class T1, class D1, class T2, class D2> bool operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);Requires: The variable definition bool b = x.get() <= y.get(); shall be well formed, shall have well-defined behavior, and shall not exit via an exception.
5 - Returns: x.get() <= y.get().
Throws: nothing.
template <class T1, class D1, class T2, class D2> bool operator>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);Requires: The variable definition bool b = x.get() > y.get(); shall be well formed, shall have well-defined behavior, and shall not exit via an exception.
6 - Returns: x.get() > y.get().
Throws: nothing.
template <class T1, class D1, class T2, class D2> bool operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);Requires: The variable definition bool b = x.get() >= y.get(); shall be well formed, shall have well-defined behavior, and shall not exit via an exception.
7 - Returns: x.get() >= y.get().
Throws: nothing.
Section: 27.5.4.2 [basic.ios.members] Status: Ready Submitter: Martin Sebor Opened: 2008-05-17 Last modified: 2010-03-09
View other active issues in [basic.ios.members].
View all other issues in [basic.ios.members].
View all issues with Ready status.
Discussion:
The fix for issue 581, now integrated into the working paper, overlooks a couple of minor problems.
First, being an unformatted function once again, flush()
is required to create a sentry object whose constructor must, among
other things, flush the tied stream. When two streams are tied
together, either directly or through another intermediate stream
object, flushing one will also cause a call to flush() on
the other tied stream(s) and vice versa, ad infinitum. The program
below demonstrates the problem.
Second, as Bo Persson notes in his
comp.lang.c++.moderated post,
for streams with the unitbuf flag set such
as std::stderr, the destructor of the sentry object will
again call flush(). This seems to create an infinite
recursion for std::cerr << std::flush;
#include <iostream>
int main ()
{
std::cout.tie (&std::cerr);
std::cerr.tie (&std::cout);
std::cout << "cout\n";
std::cerr << "cerr\n";
}
[ Batavia (2009-05): ]
We agree with the proposed resolution. Move to Review.
[ 2009-05-26 Daniel adds: ]
I think that the most recently suggested change in 27.7.2.4 [ostream::sentry] need some further word-smithing. As written, it would make the behavior undefined, if under conditions when pubsync() should be called, but when in this scenario os.rdbuf() returns 0.
This case is explicitly handled in flush() and needs to be taken care of. My suggested fix is:
If ((os.flags() & ios_base::unitbuf) && !uncaught_exception() && os.rdbuf() != 0) is true, callsos.flush()os.rdbuf()->pubsync().Two secondary questions are:
- Should pubsync() be invoked in any case or shouldn't a base requirement for this trial be that os.good() == true as required in the original flush() case?
- Since uncaught_exception() is explicitly tested, shouldn't a return value of -1 of pubsync() produce setstate(badbit) (which may throw ios_base::failure)?
[ 2009-07 Frankfurt: ]
Daniel volunteered to modify the proposed resolution to address his two questions.
Move back to Open.
[ 2009-07-26 Daniel provided wording. Moved to Review. ]
[ 2009-10-13 Daniel adds: ]
This proposed wording is written to match the outcome of 397.
[ 2009 Santa Cruz: ]
Move to Open. Martin to propose updated wording that will also resolve issue 397 consistently.
[ 2010-02-15 Martin provided wording. ]
[ 2010 Pittsburgh: ]
Moved to Ready for Pittsburgh.
Proposed resolution:
Just before 27.5.4.2 [basic.ios.members]/2 insert a new paragraph:
Requires: If (tiestr != 0) is true, tiestr must not be reachable by traversing the linked list of tied stream objects starting from tiestr->tie().
Change 27.7.2.4 [ostream::sentry]/4 as indicated:
If ((os.flags() & ios_base::unitbuf) && !uncaught_exception() && os.good()) is true, callsos.flush()os.rdbuf()->pubsync(). If that function returns -1 sets badbit in os.rdstate() without propagating an exception.
Add after 27.7.2.4 [ostream::sentry] p17, the following paragraph:
Throws: Nothing.
money_base::space and
money_base::none on money_get
Section: 22.4.6.1.2 [locale.money.get.virtuals] Status: Ready Submitter: Martin Sebor Opened: 2008-05-17 Last modified: 2009-10-21
View all other issues in [locale.money.get.virtuals].
View all issues with Ready status.
Duplicate of: 670
Discussion:
In paragraph 2, 22.4.6.1.2 [locale.money.get.virtuals] specifies the following:
Wherespaceornoneappears in the format pattern, except at the end, optional white space (as recognized byct.is) is consumed after any required space.
This requirement can be (and has been) interpreted two mutually exclusive ways by different readers. One possible interpretation is that:
- where
money_base::spaceappears in the format, at least one space is required, and- where
money_base::noneappears in the format, space is allowed but not required.
The other is that:
where eithermoney_base::spaceormoney_base::noneappears in the format, white space is optional.
[ San Francisco: ]
Martin will revise the proposed resolution.
[ 2009-07 Frankfurt: ]
There is a noun missing from the proposed resolution. It's not clear that the last sentence would be helpful, even if the word were not missing:
In either case, any required MISSINGWORD followed by all optional whitespace (as recognized by ct.is()) is consumed.Strike this sentence and move to Review.
[ Howard: done. ]
[ 2009-10 Santa Cruz: ]
Move to Ready.
Proposed resolution:
I propose to change the text to make it clear that the first interpretation is intended, that is, to make following change to 22.4.6.1.2 [locale.money.get.virtuals], p2:
Whenmoney_base::spaceormoney_base::noneappears as the last element in the format pattern,except at the end, optional white space (as recognized byno white space is consumed. Otherwise, wherect.is) is consumed after any required space.money_base::spaceappears in any of the initial elements of the format pattern, at least one white space character is required. Wheremoney_base::noneappears in any of the initial elements of the format pattern, white space is allowed but not required. If(str.flags() & str.showbase)isfalse, ...
Section: 20.9.10.1.1 [unique.ptr.dltr.dflt] Status: Ready Submitter: Howard Hinnant Opened: 2008-06-18 Last modified: 2009-10-21
View all issues with Ready status.
Discussion:
No relationship between U and T in the converting constructor for default_delete template.
Requirements: U* is convertible to T* and has_virtual_destructor<T>; the latter should also become a concept.
Rules out cross-casting.
The requirements for unique_ptr conversions should be the same as those on the deleter.
[ Howard adds 2008-11-26: ]
I believe we need to be careful to not outlaw the following use case, and I believe the current proposed wording (requires Convertible<U*, T*> && HasVirtualDestructor<T>) does so:
#include <memory> int main() { std::unique_ptr<int> p1(new int(1)); std::unique_ptr<const int> p2(move(p1)); int i = *p2; // *p2 = i; // should not compile }I've removed "&& HasVirtualDestructor<T>" from the requires clause in the proposed wording.
[ Post Summit: ]
Alisdair: This issue has to stay in review pending a paper constraining unique_ptr.
Consensus: We agree with the resolution, but unique_ptr needs to be constrained, too.
Recommend Keep in Review.
[ Batavia (2009-05): ]
Keep in Review status for the reasons cited.
[ 2009-07 Frankfurt: ]
The proposed resolution uses concepts. Howard needs to rewrite the proposed resolution.
Move back to Open.
[ 2009-07-26 Howard provided rewritten proposed wording and moved to Review. ]
[ 2009-10 Santa Cruz: ]
Move to Ready.
Proposed resolution:
Add after 20.9.10.1.1 [unique.ptr.dltr.dflt], p1:
template <class U> default_delete(const default_delete<U>& other);-1- Effects: ...
Remarks: This constructor shall participate in overload resolution if and only if U* is implicitly convertible to T*.
Section: 26 [numerics] Status: Ready Submitter: Lawrence Crowl Opened: 2008-06-23 Last modified: 2009-10-23
View all other issues in [numerics].
View all issues with Ready status.
Discussion:
There are a number of functions that affect the floating point state. These function need to be thread-safe, but I'm unsure of the right approach in the standard, as we inherit them from C.
[ San Francisco: ]
Nick: I think we already say that these functions do not introduce data races; see 17.6.5.6/20
Pete: there's more to it than not introducing data races; are these states maintained per thread?
Howard: 21.5/14 says that strtok and strerror are not required to avoid data races, and 20.9/2 says the same about asctime, gmtime, ctime, and gmtime.
Nick: POSIX has a list of not-safe functions. All other functions are implicitly thread safe.
Lawrence is to form a group between meetings to attack this issue. Nick and Tom volunteered to work with Lawrence.
Move to Open.
[ Post Summit: ]
Hans: Sane oses seem ok. Sensible thing is implementable and makes sense.
Nick: Default wording seems to cover this? Hole in POSIX, these functions need to be added to list of thread-unsafe functions.
Lawrence: Not sufficient, not "thread-safe" per our definition, but think of state as a thread-local variable. Need something like "these functions only affect state in the current thread."
Hans: Suggest the following wording: "The floating point environment is maintained per-thread."
Walter: Any other examples of state being thread safe that are not already covered elsewhere?
Have thread unsafe functions paper which needs to be updated. Should just fold in 26.3 [cfenv] functions.
Recommend Open. Lawrence instead suggests leaving it open until we have suitable wording that may or may not include the thread local commentary.
[ 2009-09-23 Hans provided wording. ]
If I understand the history correctly, Nick, as the Posix liaison, should probably get a veto on this, since I think it came from Posix (?) via WG14 and should probably really be addressed there (?). But I think we are basically in agreement that there is no other sane way to do this, and hence we don't have to worry too much about stepping on toes. As far as I can tell, this same issue also exists in the latest Posix standard (?).
[ 2009-10 Santa Cruz: ]
Moved to Ready.
Proposed resolution:
Add at the end of 26.3.1 [cfenv.syn]:
2 The header defines all functions, types, and macros the same as C99 7.6.
A separate floating point environment shall be maintained for each thread. Each function accesses the environment corresponding to its calling thread.
Section: 23.2 [container.requirements] Status: Ready Submitter: Daniel Krügler Opened: 2008-06-24 Last modified: 2010-03-10
View other active issues in [container.requirements].
View all other issues in [container.requirements].
View all issues with Ready status.
Discussion:
Table 89, Container requirements, defines operator== in terms of the container member function size() and the algorithm std::equal:
== is an equivalence relation. a.size() == b.size() && equal(a.begin(), a.end(), b.begin()
The new container forward_list does not provide a size member function by design but does provide operator== and operator!= without specifying it's semantic.
Other parts of the (sequence) container requirements do also depend on size(), e.g. empty() or clear(), but this issue explicitly attempts to solve the missing EqualityComparable specification, because of the special design choices of forward_list.
I propose to apply one of the following resolutions, which are described as:
Both proposal choices are discussed, the preferred choice of the author is to apply (A).
[ San Francisco: ]
There's an Option C: change the requirements table to use distance().
LWG found Option C acceptable.
Martin will draft the wording for Option C.
[ post San Francisco: ]
Martin provided wording for Option C.
[ 2009-07 Frankfurt ]
Other operational semantics (see, for example, Tables 82 and 83) are written in terms of a container's size() member. Daniel to update proposed resolution C.
[ Howard: Commented out options A and B. ]
[ 2009-07-26 Daniel updated proposed resolution C. ]
[ 2009-10 Santa Cruz: ]
Mark NAD Editorial. Addressed by N2986.
[ 2009-10 Santa Cruz: ]
Reopened. N2986 was rejected in full committee on procedural grounds.
[ 2010-01-30 Howard updated Table numbers. ]
[ 2010 Pittsburgh: ]
Moved to Ready for Pittsburgh.
Proposed resolution:
Option (C):
In 23.2.1 [container.requirements.general] change Table 90 -- Container requirements as indicated:
Change the text in the Assertion/note column in the row for "X u;" as follows:
post: u.size() == 0empty() == trueChange the text in the Assertion/note column in the row for "X();" as follows:
X().size() == 0empty() == trueChange the text in the Operational Semantics column in the row for "a == b" as follows:
== is an equivalence relation.a.size()distance(a.begin(), a.end()) ==b.size()distance(b.begin(), b.end()) && equal(a.begin(), a.end(), b.begin())Add text in the Ass./Note/pre-/post-condition column in the row for "a == b" as follows:
Requires: T is EqualityComparableChange the text in the Operational Semantics column in the row for "a.size()" as follows:
a.end() - a.begin()distance(a.begin(), a.end())Change the text in the Operational Semantics column in the row for "a.max_size()" as follows:
size()distance(begin(), end()) of the largest possible containerChange the text in the Operational Semantics column in the row for "a.empty()" as follows:
a.size() == 0a.begin() == a.end()In 23.2.1 [container.requirements.general] change Table 93 -- Allocator-aware container requirements as indicated:
Change the text in the Assertion/note column in the row for "X() / X u;" as follows:
Requires: A is DefaultConstructible post:u.size() == 0u.empty() == true, get_allocator() == A()Change the text in the Assertion/note column in the row for "X(m) / X u(m);" as follows:
post:u.size() == 0u.empty() == true, get_allocator() == mIn 23.2.3 [sequence.reqmts] change Table 94 -- Sequence container requirements as indicated:
Change the text in the Assertion/note column in the row for "X(n, t) / X a(n, t)" as follows:
post:size()distance(begin(), end()) == n [..]Change the text in the Assertion/note column in the row for "X(i, j) / X a(i, j)" as follows:
[..] post:size() == distance between i and jdistance(begin(), end()) == distance(i, j) [..]Change the text in the Assertion/note column in the row for "a.clear()" as follows:
a.erase(a.begin(), a.end()) post:size() == 0a.empty() == trueIn 23.2.4 [associative.reqmts] change Table 96 -- Associative container requirements as indicated:
[ Not every occurrence of size() was replaced, because all current associative containers have a size. The following changes ensure consistency regarding the semantics of "erase" for all tables and adds some missing objects ]
Change the text in the Complexity column in the row for X(i,j,c)/X a(i,j,c); as follows:
N log N in general (N == distance(i, j)is the distance from i to j); ...Change the text in the Complexity column in the row for "a.insert(i, j)" as follows:
N log(a.size() + N)(N is the distance from i to j)where N == distance(i, j)Change the text in the Complexity column in the row for "a.erase(k)" as follows:
log(a.size()) + a.count(k)Change the text in the Complexity column in the row for "a.erase(q1, q2)" as follows:
log(a.size()) + N where Nis the distance from q1 to q2== distance(q1, q2).Change the text in the Assertion/note column in the row for "a.clear()" as follows:
a.erase(a.begin(),a.end()) post:size() == 0a.empty() == trueChange the text in the Complexity column in the row for "a.clear()" as follows:
linear in a.size()Change the text in the Complexity column in the row for "a.count(k)" as follows:
log(a.size()) + a.count(k)In 23.2.5 [unord.req] change Table 98 -- Unordered associative container requirements as indicated:
[ The same rational as for Table 96 applies here ]
Change the text in the Assertion/note column in the row for "a.clear()" as follows:
[..] Post: a.size() == 0empty() == true
Section: 25.3.6 [alg.fill], 25.3.7 [alg.generate] Status: Ready Submitter: Daniel Krügler Opened: 2008-07-13 Last modified: 2009-10-23
View all issues with Ready status.
Discussion:
In regard to library defect 488 I found some more algorithms which unnecessarily throw away information. These are typically algorithms, which sequentially write into an OutputIterator, but do not return the final value of this output iterator. These cases are:
template<class OutputIterator, class Size, class T> void fill_n(OutputIterator first, Size n, const T& value);
template<class OutputIterator, class Size, class Generator> void generate_n(OutputIterator first, Size n, Generator gen);
In both cases the minimum requirements on the iterator are OutputIterator, which means according to the requirements of 24.2.2 [output.iterators]/2 that only single-pass iterations are guaranteed. So, if users of fill_n and generate_n have *only* an OutputIterator available, they have no chance to continue pushing further values into it, which seems to be a severe limitation to me.
[ Post Summit Daniel "conceptualized" the wording. ]
[ Batavia (2009-05): ]
Alisdair likes the idea, but has concerns about the specific wording about the returns clauses.
Alan notes this is a feature request.
Bill notes we have made similar changes to other algorithms.
Move to Open.
[ 2009-07 Frankfurt ]
We have a consensus for moving forward on this issue, but Daniel needs to deconceptify it.
[ 2009-07-25 Daniel provided non-concepts wording. ]
[ 2009-10 Santa Cruz: ]
Moved to Ready.
Proposed resolution:
Replace the current declaration of fill_n in 25 [algorithms]/2, header <algorithm> synopsis and in 25.3.6 [alg.fill] by
template<class OutputIterator, class Size, class T>voidOutputIterator fill_n(OutputIterator first, Size n, const T& value);
Just after the effects clause add a new returns clause saying:
Returns: For fill_n and positive n, returns first + n. Otherwise returns first for fill_n.
Replace the current declaration of generate_n in 25 [algorithms]/2, header <algorithm> synopsis and in 25.3.7 [alg.generate] by
template<class OutputIterator, class Size, class Generator>voidOutputIterator generate_n(OutputIterator first, Size n, Generator gen);
Just after the effects clause add a new returns clause saying:
For generate_n and positive n, returns first + n. Otherwise returns first for generate_n.
Section: 23 [containers] Status: Review Submitter: Alberto Ganesh Barbati Opened: 2008-07-22 Last modified: 2010-03-08
View other active issues in [containers].
View all other issues in [containers].
Discussion:
The term "default constructed" is often used in wording that predates the introduction of the concept of value-initialization. In a few such places the concept of value-initialization is more correct than the current wording (for example when the type involved can be a built-in) so a replacement is in order. Two of such places are already covered by issue 867. This issue deliberately addresses the hopefully non-controversial changes in the attempt of being approved more quickly. A few other occurrences (for example in std::tuple, std::reverse_iterator and std::move_iterator) are left to separate issues. For std::reverse_iterator, see also issue 408. This issue is related with issue 724.
[ San Francisco: ]
The list provided in the proposed resolution is not complete. James Dennett will review the library and provide a complete list and will double-check the vocabulary.
This issue relates to Issue 886 tuple construction
[ 2009-07 Frankfurt ]
The proposed resolution is incomplete.
Move to Tentatively NAD Future. Howard will contact Ganesh for wording. If wording is forthcoming, Howard will move it back to Review.
[ 2009-07-18 Ganesh updated the proposed wording. ]
Howard: Moved back to Review. Note that 20.2.1 [utility.arg.requirements] refers to a section that is not in the current working paper, but does refer to a section that we expect to reappear after the de-concepts merge. This was a point of confusion we did not recognize when we reviewed this issue in Frankfurt.
Howard: Ganesh also includes a survey of places in the WP surveyed for changes of this nature and purposefully not treated:
Places where changes are not being proposed
In the following paragraphs, we are not proposing changes because it's not clear whether we actually prefer value-initialization over default-initialization (now partially covered by 1012):
20.9.10.2.1 [unique.ptr.single.ctor] para 3 e 7
24.5.1.3.1 [reverse.iter.cons] para 1
24.5.3.3.1 [move.iter.op.const] para 1
In the following paragraphs, the expression "default constructed" need not be changed, because the relevant type does not depend on a template parameter and has a user-provided constructor:
[func.referenceclosure.invoke] para 12, type: reference_closure
30.3.1.2 [thread.thread.constr] para 30, type: thread
30.3.1.5 [thread.thread.member] para 52, type: thread_id
30.3.2 [thread.thread.this], para 1, type: thread_id
[ 2009-08-18 Daniel adds: ]
I have no objections against the currently suggested changes, but I also cross-checked with the list regarding intentionally excluded changes, and from this I miss the discussion of
21.4.1 [string.require]/2:
"[..] The Allocator object used shall be a copy of the Allocator> object passed to the basic_string object's constructor or, if the constructor does not take an Allocator argument, a copy of a default-constructed Allocator object."N2723, X [rand.req.eng], Table 109, expression "T()":
Pre-/post-condition: "Creates an engine with the same initial state as all other default-constructed engines of type X."as well as in 26.5.5 [rand.predef]/1-9 (N2914), 26.5.7.1 [rand.util.seedseq]/3, 27.7.1.1.1 [istream.cons]/3, 27.7.2.2 [ostream.cons]/9 (N2914), 28.13 [re.grammar]/2, 30.3.1.4 [thread.thread.assign]/1 (N2914),
[ Candidates for the "the expression "default constructed" need not be changed" list ]
I'm fine, if these would be added to the intentionally exclusion list, but mentioning them makes it easier for other potential reviewers to decide on the relevance or not-relevance of them for this issue.
I suggest to remove the reference of [func.referenceclosure.invoke] in the "it's not clear" list, because this component does no longer exist.
I also suggest to add a short comment that all paragraphs in the resolution whether they refer to N2723 or to N2914 numbering, because e.g. "Change 23.3.2.1 [deque.cons] para 5" is an N2723 coordinate, while "Change 23.3.2.2 [deque.capacity] para 1" is an N2914 coordinate. Even better would be to use one default document for the numbering (probably N2914) and mention special cases (e.g. "Change 20.2.1 [utility.arg.requirements] para 2" as referring to N2723 numbering).
[ 2009-08-18 Alisdair adds: ]
I strongly believe the term "default constructed" should not appear in the library clauses unless we very clearly define a meaning for it, and I am not sure what that would be.
In those cases where we do not want to replace "default constructed" with "vale initialized" we should be using "default initialized". If we have a term that could mean either, we reduce portability of programs.
I have not done an exhaustive review to clarify if that is a vendor freedom we have reason to support (e.g. value-init in debug, default-init in release) so I may yet be convinced that LWG has reason to define this new term of art, but generally C++ initialization is confusing enough without supporting further ill-defined terms.
[ 2009-10 Santa Cruz: ]
Move to Ready.
[ 2010 Pittsburgh: ]
Moved to review in order to enable conflict resolution with 704.
Proposed resolution:
Change 20.2.1 [utility.arg.requirements] para 2:
In general, a default constructor is not required. Certain container class member function signatures specifythe default constructorT() as a default argument. T() shall be a well-defined expression (8.5) if one of those signatures is called using the default argument (8.3.6).
Change 23.3.2.1 [deque.cons] para 5:
Effects: Constructs a deque with ndefault constructedvalue-initialized elements.
Change 23.3.2.2 [deque.capacity] para 1:
Effects: If sz < size(), equivalent to erase(begin() + sz, end());. If size() < sz, appends sz - size()default constructedvalue-initialized elements to the sequence.
Change 23.3.3.1 [forwardlist.cons] para 5:
Effects: Constructs a forward_list object with ndefault constructedvalue-initialized elements.
Change 23.3.3.4 [forwardlist.modifiers] para 21:
Effects: [...] For the first signature the inserted elements aredefault constructedvalue-initialized, and for the second signature they are copies of c.
Change 23.3.4.1 [list.cons] para 5:
Effects: Constructs a list with ndefault constructedvalue-initialized elements.
Change 23.3.4.2 [list.capacity] para 15:
Effects: If sz < size(), equivalent to list<T>::iterator it = begin(); advance(it, sz); erase(it, end());. If size() < sz, appends sz - size()default constructedvalue-initialized elements to the sequence.
Change 23.3.6.1 [vector.cons] para 3:
Effects: Constructs a vector with ndefault constructedvalue-initialized elements.
Change 23.3.6.2 [vector.capacity] para 24:
Effects: If sz < size(), equivalent to erase(begin() + sz, end());. If size() < sz, appends sz - size()default constructedvalue-initialized elements to the sequence.
Section: 23.2.5 [unord.req] Status: Ready Submitter: Daniel Krügler Opened: 2008-08-17 Last modified: 2010-03-08
View other active issues in [unord.req].
View all other issues in [unord.req].
View all issues with Ready status.
Discussion:
Good ol' associative containers allow both function pointers and function objects as feasible comparators, as described in 23.2.4 [associative.reqmts]/2:
Each associative container is parameterized on Key and an ordering relation Compare that induces a strict weak ordering (25.3) on elements of Key. [..]. The object of type Compare is called the comparison object of a container. This comparison object may be a pointer to function or an object of a type with an appropriate function call operator.[..]
The corresponding wording for unordered containers is not so clear, but I read it to disallow function pointers for the hasher and I miss a clear statement for the equality predicate, see 23.2.5 [unord.req]/3+4+5:
Each unordered associative container is parameterized by Key, by a function object Hash that acts as a hash function for values of type Key, and by a binary predicate Pred that induces an equivalence relation on values of type Key.[..]
A hash function is a function object that takes a single argument of type Key and returns a value of type std::size_t.
Two values k1 and k2 of type Key are considered equal if the container's equality function object returns true when passed those values.[..]
and table 97 says in the column "assertion...post-condition" for the expression X::hasher:
Hash shall be a unary function object type such that the expression hf(k) has type std::size_t.
Note that 20.8 [function.objects]/1 defines as "Function objects are objects with an operator() defined.[..]"
Does this restriction exist by design or is it an oversight? If an oversight, I suggest that to apply the following
[ 2009-07-28 Reopened by Alisdair. No longer solved by concepts. ]
[ 2009-10 Santa Cruz: ]
Ask Daniel to provide proposed wording that: makes it explicit that function pointers are function objects at the beginning of 20.8 [function.objects]; fixes the "requirements" for typedefs in 20.8.5 [refwrap] to instead state that the function objects defined in that clause have these typedefs, but not that these typedefs are requirements on function objects; remove the wording that explicitly calls out that associative container comparators may be function pointers.
[ 2009-12-19 Daniel updates wording and rationale. ]
[ 2010-02-11 Moved to Tentatively Ready after 5 positive votes on c++std-lib. ]
Rationale:
The below provided wording also affects some part of the library which is involved with callable types (20.8.1 [func.def]/3). Reason for this is that callable objects do have a lot in common with function objects. A simple formula seems to be:
callable objects = function objects + pointers to member
The latter group is excluded from function objects because of the expression-based usage of function objects in the algorithm clause, which is incompatible with the notation to dereference pointers to member without a concept map available in the language.
This analysis showed some currently existing normative definition differences between the above subset of callable objects and function objects which seem to be unintended: Backed by the Santa Cruz outcome function objects should include both function pointers and "object[s] with an operator() defined". This clearly excludes class types with a conversion function to a function pointer or all similar conversion function situations described in 13.3 [over.match]/2 b. 2. In contrast to this, the wording for callable types seems to be less constrained (20.8.1 [func.def]/3):
A callable type is a [..] class type whose objects can appear immediately to the left of a function call operator.
The rationale given in N1673 and a recent private communication with Peter Dimov revealed that the intention of this wording was to cover the above mentioned class types with conversion functions as well. To me the current wording of callable types can be read either way and I suggest to make the intention more explicit by replacing
[..] class type whose objects can appear immediately to the left of a function call operatorby
[..] class type whose objects can appear as the leftmost subexpression of a function call expression 5.2.2 [expr.call].
and to use the same definition for the class type part of function objects, because there is no reason to exclude class types with a conversion function to e.g. pointer to function from being used in algorithms.
Now this last term "function objects" itself brings us to a third unsatisfactory state: The term is used both for objects (e.g. "Function objects are objects[..]" in 20.8 [function.objects]/1) and for types (e.g. "Each unordered associative container is parameterized [..] by a function object Hash that acts as a hash function [..]" in 23.2.5 [unord.req]/3). This impreciseness should be fixed and I suggest to introduce the term function object type as the counter part to callable type. This word seems to be a quite natural choice, because the library already uses it here and there (e.g. "Hash shall be a unary function object type such that the expression hf(k) has type std::size_t." in Table 98, "X::hasher" or "Requires: T shall be a function object type [..]" in 20.8.15.2.5 [func.wrap.func.targ]/3).
Finally I would like to add that part of the issue 870 discussion related to the requirements for typedefs in 20.8.5 [refwrap] during the Santa Cruz meeting is now handled by the new issue 1290.
Obsolete rationale:
[ San Francisco: ]
This is fixed by N2776.
Proposed resolution:
Change 20.8 [function.objects]/1 as indicated:
1
Function objects are objects with an operator() defined.An object type (3.9 [basic.types]) that can be the type of the postfix-expression in a function call (5.2.2 [expr.call], 13.3.1.1 [over.match.call]) is called a function object type*. A function object is an object of a function object type. In the places where one would expect to pass a pointer to a function to an algorithmic template (Clause 25 [algorithms]), the interface is specified to acceptan object with an operator() defineda function object. This not only makes algorithmic templates work with pointers to functions, but also enables them to work with arbitrary function objects.* Such a type is either a function pointer or a class type which often has a member operator(), but in some cases it can omit that member and provide a conversion to a pointer to function.
Change 20.8.1 [func.def]/3 as indicated: [The intent is to make the commonality of callable types and function object types more explicit and to get rid of wording redundancies]
3 A callable type isa pointer to function,a pointer to memberfunction, a pointer to member data,or aclass type whose objects can appear immediately to the left of a function call operatorfunction object type (20.8 [function.objects]).
Change 20.8.11 [bind]/1 as indicated:
1 The function template bind returns an object that binds afunctioncallable object passed as an argument to additional arguments.
Change 20.8.11.1 [func.bind]/1 as indicated:
1 This subclause describes a uniform mechanism for binding arguments offunctioncallable objects.
Change 20.8.15 [func.wrap]/1 as indicated:
1 This subclause describes a polymorphic wrapper class that encapsulates arbitraryfunctioncallable objects.
Change 20.8.15.2 [func.wrap.func]/2 as indicated [The reason for this change is that 20.8.15.2 [func.wrap.func]/1 clearly says that all callable types may be wrapped by std::function and current implementations indeed do provide support for pointer to members as well. One further suggested improvement is to set the below definition of Callable in italics]:
2 Afunctioncallable object f of type F isCallableCallable for argument typesT1, T2, ..., TN inArgTypes andareturn type R,if, given lvalues t1, t2, ..., tN of types T1, T2, ..., TN, respectively,the expression INVOKE(f, declval<ArgTypes>()..., Rt1, t2, ..., tN), considered as an unevaluated operand (5 [expr]), is well formed (20.7.2)and, if R is not void, convertible to R.
Change 20.8.15.2.1 [func.wrap.func.con]/7 as indicated:
function(const function& f); template <class A> function(allocator_arg_t, const A& a, const function& f);...
7 Throws: shall not throw exceptions if f's target is a function pointer or a
functioncallable object passed via reference_wrapper. Otherwise, may throw bad_alloc or any exception thrown by the copy constructor of the storedfunctioncallable object. [Note: Implementations are encouraged to avoid the use of dynamically allocated memory for smallfunctioncallable objects, e.g., where f's target is an object holding only a pointer or reference to an object and a member function pointer. — end note]
Change 20.8.15.2.1 [func.wrap.func.con]/11 as indicated:
template<class F> function(F f); template <class F, class A> function(allocator_arg_t, const A& a, F f);...
11 [..] [Note: implementations are encouraged to avoid the use of dynamically allocated memory for small
functioncallable objects, for example, where f's target is an object holding only a pointer or reference to an object and a member function pointer. — end note]
Change 20.8.15.2.4 [func.wrap.func.inv]/3 as indicated:
R operator()(ArgTypes... args) const...
3 Throws: bad_function_call if !*this; otherwise, any exception thrown by the wrapped
functioncallable object.
Change 20.8.15.2.5 [func.wrap.func.targ]/3 as indicated:
template<typename T> T* target(); template<typename T> const T* target() const;...
3 Requires: T shall be a
function objecttype that is Callable (20.8.15.2 [func.wrap.func]) for parameter types ArgTypes and return type R.
Change 23.2.4 [associative.reqmts]/2 as indicated: [The suggested removal seems harmless, because 25.4 [alg.sorting]1 already clarifies that Compare is a function object type. Nevertheless it is recommended, because the explicit naming of "pointer to function" is misleading]
2 Each associative container is parameterized on Key and an ordering relation Compare that induces a strict weak ordering (25.4 [alg.sorting]) on elements of Key. In addition, map and multimap associate an arbitrary type T with the Key. The object of type Compare is called the comparison object of a container.This comparison object may be a pointer to function or an object of a type with an appropriate function call operator.
Change 23.2.5 [unord.req]/3 as indicated:
3 Each unordered associative container is parameterized by Key, by a function object type Hash that acts as a hash function for values of type Key, and by a binary predicate Pred that induces an equivalence relation on values of type Key. [..]
Change 25.1 [algorithms.general]/7 as indicated: [The intent is to bring this part in sync with 20.8 [function.objects]]
7 The Predicate parameter is used whenever an algorithm expects a function object (20.8 [function.objects]) that when applied to the result of dereferencing the corresponding iterator returns a value testable as true. In other words, if an algorithm takes Predicate pred as its argument and first as its iterator argument, it should work correctly in the construct if (pred(*first)){...}. The function object pred shall not apply any nonconstant function through the dereferenced iterator.This function object may be a pointer to function, or an object of a type with an appropriate function call operator.
Change 20.9.10.2 [unique.ptr.single]/1 as indicated:
1 The default type for the template parameter D is default_delete. A client-supplied template argument D shall be a functionpointer or functorobject type for which, given a value d of type D and a pointer ptr of type T*, the expression d(ptr) is valid and has the effect of deallocating the pointer as appropriate for that deleter. D may also be an lvalue-reference to a deleter.
Section: 26.7.5 [numeric.iota] Status: Ready Submitter: Daniel Krügler Opened: 2008-08-20 Last modified: 2009-10-22
View all issues with Ready status.
Discussion:
According to the recent WP N2691, 26.7.5 [numeric.iota]/1, the requires clause of std::iota says:
T shall meet the requirements of CopyConstructible and Assignable types, and shall be convertible to ForwardIterator's value type.[..]
Neither CopyConstructible nor Assignable is needed, instead MoveConstructible seems to be the correct choice. I guess the current wording resulted as an artifact from comparing it with similar numerical algorithms like accumulate.
Note: If this function will be conceptualized, the here proposed MoveConstructible requirement can be removed, because this is an implied requirement of function arguments, see N2710/[temp.req.impl]/3, last bullet.
[ post San Francisco: ]
Issue pulled by author prior to review.
[ 2009-07-30 Daniel reopened: ]
with the absence of concepts, this issue (closed) is valid again and I suggest to reopen it. I also revised by proposed resolution based on N2723 wording:
[ 2009-10 Santa Cruz: ]
Change 'convertible' to 'assignable', Move To Ready.
Proposed resolution:
Change the first sentence of 26.7.5 [numeric.iota]/1:
Requires: T shallmeet the requirements of CopyConstructible and Assignable types, and shallbe assignable to ForwardIterator's value type. [..]
Section: 24.5.3.3.12 [move.iter.op.index] Status: Ready Submitter: Doug Gregor Opened: 2008-08-21 Last modified: 2009-10-23
View all issues with Ready status.
Discussion:
move_iterator's operator[] is declared as:
reference operator[](difference_type n) const;
This has the same problem that reverse_iterator's operator[] used to have: if the underlying iterator's operator[] returns a proxy, the implicit conversion to value_type&& could end up referencing a temporary that has already been destroyed. This is essentially the same issue that we dealt with for reverse_iterator in DR 386.
[ 2009-07-28 Reopened by Alisdair. No longer solved by concepts. ]
[ 2009-08-15 Howard adds: ]
I recommend closing this as a duplicate of 1051 which addresses this issue for both move_iterator and reverse_iterator.
[ 2009-10 Santa Cruz: ]
Move to Ready. Note that if 1051 is reopened, it may yield a better resolution, but 1051 is currently marked NAD.
Proposed resolution:
In 24.5.3.1 [move.iterator] and 24.5.3.3.12 [move.iter.op.index], change the declaration of move_iterator's operator[] to:
referenceunspecified operator[](difference_type n) const;
Rationale:
[ San Francisco: ]
NAD Editorial, see N2777.
Section: 20.3.4 [pairs] Status: Ready Submitter: Alisdair Meredith Opened: 2008-09-15 Last modified: 2010-03-12
View other active issues in [pairs].
View all other issues in [pairs].
View all issues with Ready status.
Discussion:
20.2.3 pairs
Missing assignemnt operator:
template<class U , class V>
requires CopyAssignable<T1, U> && CopyAssignable<T2, V>
pair& operator=(pair<U , V> const & p );
Well, that's interesting. This assignment operator isn't in the current working paper, either. Perhaps we deemed it acceptable to build a temporary of type pair from pair<U, V>, then move-assign from that temporary?
It sounds more like an issue waiting to be opened, unless you want to plug it now. As written we risk moving from lvalues.
[ San Francisco: ]
Would be NAD if better ctors fixed it.
Related to 811.
[ post San Francisco: ]
Possibly NAD Editorial, solved by N2770.
[ 2009-05-25 Alisdair adds: ]
Issue 885 was something I reported while reviewing the library concepts documents ahead of San Francisco. The missing operator was added as part of the paper adopted at that meeting (N2770) and I can confirm this operator is present in the current working paper. I recommend NAD.
[ 2009-07 Frankfurt ]
We agree with the intent, but we need to wait for the dust to settle on concepts.
[ 2010-03-11 Stefanus provided wording. ]
[ 2010 Pittsburgh: Moved to Ready for Pittsburgh. ]
Proposed resolution:
Add the following declaration 20.3.4.2 [pairs.pair], before the declaration of pair& operator=(pair&& p);:
template<class U, class V> pair& operator=(const pair<U, V>& p);
Add the following description to 20.3.4.2 [pairs.pair] after paragraph 11 (before the description of pair& operator=(pair&& p);):
template<class U, class V> pair& operator=(const pair<U, V>& p);Requires: T1 shall satisfy the requirements of CopyAssignable from U. T2 shall satisfy the requirements of CopyAssignable from V.
Effects: Assigns p.first to first and p.second to second.
Returns: *this.
Section: 30.3.1.2 [thread.thread.constr], 30.4.5.2 [thread.once.callonce] Status: Ready Submitter: Peter Dimov Opened: 2008-09-15 Last modified: 2010-03-08
View other active issues in [thread.thread.constr].
View all other issues in [thread.thread.constr].
View all issues with Ready status.
Discussion:
I notice that the vararg overloads of std::thread and std::call_once (N2723 30.3.1.2 [thread.thread.constr] and 30.4.5.2 [thread.once.callonce]) are no longer specified in terms of std::bind; instead, some of the std::bind wording has been inlined into the specification.
There are two problems with this.
First, the specification (and implementation) in terms of std::bind allows, for example:
std::thread th( f, 1, std::bind( g ) );
which executes f( 1, g() ) in a thread. This can be useful. The "inlined" formulation changes it to execute f( 1, bind(g) ) in a thread.
Second, assuming that we don't want the above, the specification has copied the wording
INVOKE(func, w1, w2, ..., wN) (20.6.2) shall be a valid expression for some values w1, w2, ..., wN
but this is not needed since we know that our argument list is args; it should simply be
INVOKE(func, args...) (20.6.2) shall be a valid expression
[ Summit: ]
Move to open.
[ Post Summit Anthony provided proposed wording. ]
[ 2009-07 Frankfurt ]
Leave Open. Await decision for thread variadic constructor.
[ 2009-10 Santa Cruz: ]
See proposed wording for 929 for this, for the formulation on how to solve this. 929 modifies the thread constructor to have "pass by value" behavior with pass by reference efficiency through the use of the decay trait. This same formula would be useful for call_once.
[ 2010-02-11 Anthony updates wording. ]
[ 2010-02-12 Moved to Tentatively Ready after 5 postive votes on c++std-lib. ]
Proposed resolution:
Modify 30.4.5.2 [thread.once.callonce] p1-p2 with the following:
template<class Callable, class ...Args> void call_once(once_flag& flag, Callable&& func, Args&&... args);Given a function as follows:
template<typename T> typename decay<T>::type decay_copy(T&& v) { return std::forward<T>(v); }1 Requires:
The template parametersCallable and each Ti in Args shallbe CopyConstructible if an lvalue and otherwisesatisfy the MoveConstructible requirements. INVOKE(decay_copy(std::forward<Callable>(func),w1, w2, ..., wNdecay_copy(std::forward<Args>(args))...) (20.8.2 [func.require]) shall be a valid expressionfor some values w1, w2, ..., wN, where N == sizeof...(Args).2 Effects: Calls to call_once on the same once_flag object are serialized. If there has been a prior effective call to call_once on the same once_flag object, the call to call_once returns without invoking func. If there has been no prior effective call to call_once on the same once_flag object,
the argument func (or a copy thereof) is called as if by invoking func(args)INVOKE(decay_copy(std::forward<Callable>(func)), decay_copy(std::forward<Args>(args))...) is executed. The call to call_once is effective if and only iffunc(args)INVOKE(decay_copy(std::forward<Callable>(func)), decay_copy(std::forward<Args>(args))...) returns without throwing an exception. If an exception is thrown it is propagated to the caller.
Section: 30.4.1.1 [thread.mutex.class] Status: Ready Submitter: Peter Dimov Opened: 2008-09-15 Last modified: 2010-03-08
View all other issues in [thread.mutex.class].
View all issues with Ready status.
Duplicate of: 905
Discussion:
30.4.1.1 [thread.mutex.class]/27 (in N2723) says that the behavior is undefined if:
I don't believe that this is right. Calling lock() or try_lock() on a locked mutex is well defined in the general case. try_lock() is required to fail and return false. lock() is required to either throw an exception (and is allowed to do so if it detects deadlock) or to block until the mutex is free. These general requirements apply regardless of the current owner of the mutex; they should apply even if it's owned by the current thread.
Making double lock() undefined behavior probably can be justified (even though I'd still disagree with the justification), but try_lock() on a locked mutex must fail.
[ Summit: ]
Move to open. Proposed resolution:
- In 30.4.1 [thread.mutex.requirements] paragraph 12, change the error condition for resource_deadlock_would_occur to: "if the implementation detects that a deadlock would occur"
- Strike 30.4.1.1 [thread.mutex.class] paragraph 3 bullet 2 "a thread that owns a mutex object calls lock() or try_lock() on that object, or"
[ 2009-07 Frankfurt ]
Move to Review. Alisdair to provide note.
[ 2009-07-31 Alisdair provided note. ]
[ 2009-10 Santa Cruz: ]
Moved to Ready.
[ 2009-11-18 Peter Opens: ]
I don't believe that the proposed note:
[Note: a program may deadlock if the thread that owns a mutex object calls lock() or try_lock() on that object. If the program can detect the deadlock, a resource_deadlock_would_occur error condition may be observed. — end note]is entirely correct. "or try_lock()" should be removed, because try_lock is non-blocking and doesn't deadlock; it just returns false when it fails to lock the mutex.
[ Howard: I've set to Open and updated the wording per Peter's suggestion. ]
[ 2009-11-18 Moved to Tentatively Ready after 5 positive votes on c++std-lib. ]
Proposed resolution:
In 30.4.1 [thread.mutex.requirements] paragraph 12 change:
- ...
- resource_deadlock_would_occur -- if the
current thread already owns the mutex and is able to detect itimplementation detects that a deadlock would occur.- ...
Strike 30.4.1.1 [thread.mutex.class] paragraph 3 bullet 2:
-3- The behavior of a program is undefined if:
- ...
a thread that owns a mutex object calls lock() or try_lock() on that object, or- ...
Add the following note after p3 30.4.1.1 [thread.mutex.class]
[Note: a program may deadlock if the thread that owns a mutex object calls lock() on that object. If the implementation can detect the deadlock, a resource_deadlock_would_occur error condition may be observed. — end note]
Section: 20.9.11.2 [util.smartptr.shared] Status: Ready Submitter: Hans Boehm Opened: 2008-09-16 Last modified: 2010-03-12
View all other issues in [util.smartptr.shared].
View all issues with Ready status.
Discussion:
It is unclear whether shared_ptr is thread-safe in the sense that multiple threads may simultaneously copy a shared_ptr. However this is a critical piece of information for the client, and it has significant impact on usability for many applications. (Detlef Vollman thinks it is currently clear that it is not thread-safe. Hans Boehm thinks it currently requires thread safety, since the use_count is not an explicit field, and constructors and assignment take a const reference to an existing shared_ptr.)
Pro thread-safety:
Many multi-threaded usages are impossible. A thread-safe version can be used to destroy an object when the last thread drops it, something that is often required, and for which we have no other easy mechanism.
Against thread-safety:
The thread-safe version is well-known to be far more expensive, even if used by a single thread. Many applications, including all single-threaded ones, do not care.
[ San Francisco: ]
Beman: this is a complicated issue, and would like to move this to Open and await comment from Peter Dimov; we need very careful and complete rationale for any decision we make; let's go slow
Detlef: I think that shared_ptr should not be thread-safe.
Hans: When you create a thread with a lambda, it in some cases makes it very difficult for the lambda to reference anything in the heap. It's currently ambiguous as to whether you can use a shared_ptr to get at an object.
Leave in Open. Detlef will submit an alternative proposed resolution that makes shared_ptr explicitly unsafe.
A third option is to support both threadsafe and non-safe share_ptrs, and to let the programmer decide which behavior they want.
Beman: Peter, do you support the PR?
Peter:
Yes, I support the proposed resolution, and I certainly oppose any attempts to make shared_ptr thread-unsafe.
I'd mildly prefer if
[Note: This is true in spite of that fact that such functions often modify use_count() --end note]is changed to
[Note: This is true in spite of that fact that such functions often cause a change in use_count() --end note](or something along these lines) to emphasise that use_count() is not, conceptually, a variable, but a return value.
[ 2009-07 Frankfurt ]
Vote: Do we want one thread-safe shared pointer or two? If two, one would allow concurrent construction and destruction of shared pointers, and one would not be thread-safe. If one, then it would be thread-safe.
No concensus on that vote.
Hans to improve wording in consultation with Pete. Leave Open.
[ 2009-10 Santa Cruz: ]
Move to Ready. Ask Editor to clear up wording a little when integrating to make it clear that the portion after the first comma only applies for the presence of data races.
[ 2009-10-24 Hans adds: ]
I think we need to pull 896 back from ready, unfortunately. My wording doesn't say the right thing.
I suspect we really want to say something along the lines of:
For purposes of determining the presence of a data race, member functions access and modify only the shared_ptr and weak_ptr objects themselves and not objects they refer to. Changes in use_count() do not reflect modifications that can introduce data races.But I think this needs further discussion by experts to make sure this is right.
Detlef and I agree continue to disagree on the resolution, but I think we agree that it would be good to try to expedite this so that it can be in CD2, since it's likely to generate NB comments no matter what we do. And lack of clarity of intent is probably the worst option. I think it would be good to look at this between meetings.
[ 2010-01-20 Howard: ]
I've moved Hans' suggested wording above into the proposed resolution section and preserved the previous wording here:
Make it explicitly thread-safe, in this weak sense, as I believe was intended:
Insert in 20.9.11.2 [util.smartptr.shared], before p5:
For purposes of determining the presence of a data race, member functions do not modify const shared_ptr and const weak_ptr arguments, nor any objects they refer to. [Note: This is true in spite of that fact that such functions often cause a change in use_count() --end note]
On looking at the text, I'm not sure we need a similar disclaimer anywhere else, since nothing else has the problem with the modified use_count(). I think Howard arrived at a similar conclusion.
[ 2010 Pittsburgh: Moved to Ready for Pittsburgh ]
Proposed resolution:
Insert a new paragraph at the end of 20.9.11.2 [util.smartptr.shared]:
For purposes of determining the presence of a data race, member functions access and modify only the shared_ptr and weak_ptr objects themselves and not objects they refer to. Changes in use_count() do not reflect modifications that can introduce data races.
Section: 27.9.1.8 [ifstream.assign] Status: Ready Submitter: Niels Dekker Opened: 2008-09-20 Last modified: 2010-03-10
View all issues with Ready status.
Discussion:
It appears that we have an issue similar to issue 675 regarding the move-assignment of stream types. For example, when assigning to an std::ifstream, ifstream1, it seems preferable to close the file originally held by ifstream1:
ifstream1 = std::move(ifstream2);
The current Draft (N2723) specifies that the move-assignment of stream types like ifstream has the same effect as a swap:
Assign and swap 27.9.1.8 [ifstream.assign]
basic_ifstream& operator=(basic_ifstream&& rhs);Effects: swap(rhs).
[ Batavia (2009-05): ]
Howard agrees with the analysis and the direction proposed.
Move to Open pending specific wording to be supplied by Howard.
[ 2009-07 Frankfurt: ]
Howard is going to write wording.
[ 2009-07-26 Howard provided wording. ]
[ 2009-09-13 Niels adds: ]
Note: The proposed change of 27.9.1.3 [filebuf.assign]/1 depends on the resolution of LWG 1204, which allows implementations to assume that *this and rhs refer to different objects.
[ 2009 Santa Cruz: ]
Leave as Open. Too closely related to 911 to move on at this time.
[ 2010 Pittsburgh: ]
Moved to Ready for Pittsburgh.
Proposed resolution:
Change 27.8.1.2 [stringbuf.assign]/1:
basic_stringbuf& operator=(basic_stringbuf&& rhs);-1- Effects:swap(rhs).After the move assignment *this reflects the same observable state it would have if it had been move constructed from rhs (27.8.1.1 [stringbuf.cons]).
Change 27.8.2.2 [istringstream.assign]/1:
basic_istringstream& operator=(basic_istringstream&& rhs);-1- Effects:swap(rhs).Move assigns the base and members of *this with the respective base and members of rhs.
Change 27.8.3.2 [ostringstream.assign]/1:
basic_ostringstream& operator=(basic_ostringstream&& rhs);-1- Effects:swap(rhs).Move assigns the base and members of *this with the respective base and members of rhs.
Change 27.8.5.1 [stringstream.assign]/1:
basic_stringstream& operator=(basic_stringstream&& rhs);-1- Effects:swap(rhs).Move assigns the base and members of *this with the respective base and members of rhs.
Change 27.9.1.3 [filebuf.assign]/1:
basic_filebuf& operator=(basic_filebuf&& rhs);-1- Effects:swap(rhs).Begins by calling this->close(). After the move assignment *this reflects the same observable state it would have if it had been move constructed from rhs (27.9.1.2 [filebuf.cons]).
Change 27.9.1.8 [ifstream.assign]/1:
basic_ifstream& operator=(basic_ifstream&& rhs);-1- Effects:swap(rhs).Move assigns the base and members of *this with the respective base and members of rhs.
Change 27.9.1.12 [ofstream.assign]/1:
basic_ofstream& operator=(basic_ofstream&& rhs);-1- Effects:swap(rhs).Move assigns the base and members of *this with the respective base and members of rhs.
Change 27.9.1.16 [fstream.assign]/1:
basic_fstream& operator=(basic_fstream&& rhs);-1- Effects:swap(rhs).Move assigns the base and members of *this with the respective base and members of rhs.
Section: 27.7.1 [input.streams], 27.7.2 [output.streams] Status: Ready Submitter: Alberto Ganesh Barbati Opened: 2008-09-29 Last modified: 2010-03-10
View all issues with Ready status.
Discussion:
Class template basic_istream, basic_ostream and basic_iostream implements public move constructors, move assignment operators and swap method and free functions. This might induce both the user and the compiler to think that those types are MoveConstructible, MoveAssignable and Swappable. However, those class templates fail to fulfill the user expectations. For example:
std::ostream os(std::ofstream("file.txt"));
assert(os.rdbuf() == 0); // buffer object is not moved to os, file.txt has been closed
std::vector<std::ostream> v;
v.push_back(std::ofstream("file.txt"));
v.reserve(100); // causes reallocation
assert(v[0].rdbuf() == 0); // file.txt has been closed!
std::ostream&& os1 = std::ofstream("file1.txt");
os1 = std::ofstream("file2.txt");
os1 << "hello, world"; // still writes to file1.txt, not to file2.txt!
std::ostream&& os1 = std::ofstream("file1.txt");
std::ostream&& os2 = std::ofstream("file2.txt");
std::swap(os1, os2);
os1 << "hello, world"; // writes to file1.txt, not to file2.txt!
This is because the move constructor, the move assignment operator and swap are all implemented through calls to std::basic_ios member functions move() and swap() that do not move nor swap the controlled stream buffers. That can't happen because the stream buffers may have different types.
Notice that for basic_streambuf, the member function swap() is protected. I believe that is correct and all of basic_istream, basic_ostream, basic_iostream should do the same as the move ctor, move assignment operator and swap member function are needed by the derived fstreams and stringstreams template. The free swap functions for basic_(i|o|io)stream templates should be removed for the same reason.
[ Batavia (2009-05): ]
We note that the rvalue swap functions have already been removed.
Bill is unsure about making the affected functions protected; he believes they may need to be public.
We are also unsure about removing the lvalue swap functions as proposed.
Move to Open.
[ 2009-07 Frankfurt: ]
It's not clear that the use case is compelling.
Howard: This needs to be implemented and tested.
[ 2009-07-26 Howard adds: ]
I started out thinking I would recommend NAD for this one. I've turned around to agree with the proposed resolution (which I've updated to the current draft). I did not fully understand Ganesh's rationale, and attempt to describe my improved understanding below.
The move constructor, move assignment operator, and swap function are different for basic_istream, basic_ostream and basic_iostream than other classes. A timely conversation with Daniel reminded me of this long forgotten fact. These members are sufficiently different that they would be extremely confusing to use in general, but they are very much needed for derived clients.
- The move constructor moves everything but the rdbuf pointer.
- The move assignment operator moves everything but the rdbuf pointer.
- The swap function swaps everything but the rdbuf pointer.
The reason for this behavior is that for the std-derived classes (stringstreams, filestreams), the rdbuf pointer points back into the class itself (self referencing). It can't be swapped or moved. But this fact isn't born out at the stream level. Rather it is born out at the fstream/sstream level. And the lower levels just need to deal with that fact by not messing around with the rdbuf pointer which is stored down at the lower levels.
In a nutshell, it is very confusing for all of those who are not so intimately related with streams that they've implemented them. And it is even fairly confusing for some of those who have (including myself). I do not think it is safe to swap or move istreams or ostreams because this will (by necessary design) separate stream state from streambuffer state. Derived classes (such as fstream and stringstream must be used to keep the stream state and stream buffer consistently packaged as one unit during a move or swap.
I've implemented this proposal and am living with it day to day.
[ 2009 Santa Cruz: ]
Leave Open. Pablo expected to propose alternative wording which would rename move construction, move assignment and swap, and may or may not make them protected. This will impact issue 900.
[ 2010 Pittsburgh: ]
Moved to Ready for Pittsburgh.
Proposed resolution:
27.7.1.1 [istream]: make the following member functions protected:
basic_istream(basic_istream&& rhs); basic_istream& operator=(basic_istream&& rhs); void swap(basic_istream& rhs);
Ditto: remove the swap free function signature
// swap: template <class charT, class traits> void swap(basic_istream<charT, traits>& x, basic_istream<charT, traits>& y);
27.7.1.1.2 [istream.assign]: remove paragraph 4
template <class charT, class traits> void swap(basic_istream<charT, traits>& x, basic_istream<charT, traits>& y);Effects: x.swap(y).
27.7.1.5 [iostreamclass]: make the following member function protected:
basic_iostream(basic_iostream&& rhs); basic_iostream& operator=(basic_iostream&& rhs); void swap(basic_iostream& rhs);
Ditto: remove the swap free function signature
template <class charT, class traits> void swap(basic_iostream<charT, traits>& x, basic_iostream<charT, traits>& y);
27.7.1.5.3 [iostream.assign]: remove paragraph 3
template <class charT, class traits> void swap(basic_iostream<charT, traits>& x, basic_iostream<charT, traits>& y);Effects: x.swap(y).
27.7.2.1 [ostream]: make the following member function protected:
basic_ostream(basic_ostream&& rhs); basic_ostream& operator=(basic_ostream&& rhs); void swap(basic_ostream& rhs);
Ditto: remove the swap free function signature
// swap: template <class charT, class traits> void swap(basic_ostream<charT, traits>& x, basic_ostream<charT, traits>& y);
27.7.2.3 [ostream.assign]: remove paragraph 4
template <class charT, class traits> void swap(basic_ostream<charT, traits>& x, basic_ostream<charT, traits>& y);Effects: x.swap(y).
Section: 25.4.7 [alg.min.max] Status: Open Submitter: Daniel Krügler Opened: 2008-10-04 Last modified: 2009-10-23
View other active issues in [alg.min.max].
View all other issues in [alg.min.max].
View all issues with Open status.
Discussion:
It seems that the proposed changes for N2772 were not clear enough in this point:
25.4.7 [alg.min.max], before p.23 + p.24 + before p. 27 + p. 28 say that the return type of the minmax overloads with an initializer_list is pair<const T&, const T&>, which is inconsistent with the decision for the other min/max overloads which take a initializer_list as argument and return a T, not a const T&. Doing otherwise for minmax would easily lead to unexpected life-time problems by using minmax instead of min and max separately.
[ Batavia (2009-05): ]
We agree with the proposed resolution. Move to Tentatively Ready.
[ 2009-07 Frankfurt ]
Moved from Tentatively Ready to Open only because the wording needs to be tweaked for concepts removal.
[ 2009-08-18 Daniel adds: ]
Recommend NAD since the proposed changes have already been performed as part of editorial work of N2914.
[ 2009-10 Santa Cruz: ]
Can't find initializer_list form of minmax anymore, only variadic version. Seems like we had an editing clash with concepts. Leave Open, at least until editorial issues resolved. Bring this to Editor's attention.
Proposed resolution:
In 25 [algorithms]/2, header <algorithm> synopsis change as indicated:
template<classLessThanComparable T> requires CopyConstructible<T> pair<constT&,constT&> minmax(initializer_list<T> t); template<class T,classStrictWeakOrder<auto, T> Compare> requires CopyConstructible<T> pair<constT&,constT&> minmax(initializer_list<T> t, Compare comp);
In 25.4.7 [alg.min.max] change as indicated (Begin: Just before p.20):
template<classLessThanComparable T> requires CopyConstructible<T> pair<constT&,constT&> minmax(initializer_list<T> t);
-20- Requires: T is LessThanComparable and CopyConstructible.-21- Returns: pair<
constT&,constT&>(x, y) where x is the smallest value and y the largest value in the initializer_list.[..]
template<class T,classStrictWeakOrder<auto, T> Compare> requires CopyConstructible<T> pair<constT&,constT&> minmax(initializer_list<T> t, Compare comp);
-24- Requires: type T is LessThanComparable and CopyConstructible.-25- Returns: pair<
constT&,constT&>(x, y) where x is the smallest value and y largest value in the initializer_list.
Section: 20.8.14 [func.memfn] Status: Ready Submitter: Bronek Kozicki Opened: 2008-10-06 Last modified: 2009-10-23
View all other issues in [func.memfn].
View all issues with Ready status.
Duplicate of: 1230
Discussion:
Daniel Krügler wrote:
Shouldn't above list be completed for &- and &&-qualified member functions This would cause to add:
template<Returnable R, class T, CopyConstructible... Args> unspecified mem_fn(R (T::* pm)(Args...) &); template<Returnable R, class T, CopyConstructible... Args> unspecified mem_fn(R (T::* pm)(Args...) const &); template<Returnable R, class T, CopyConstructible... Args> unspecified mem_fn(R (T::* pm)(Args...) volatile &); template<Returnable R, class T, CopyConstructible... Args> unspecified mem_fn(R (T::* pm)(Args...) const volatile &); template<Returnable R, class T, CopyConstructible... Args> unspecified mem_fn(R (T::* pm)(Args...) &&); template<Returnable R, class T, CopyConstructible... Args> unspecified mem_fn(R (T::* pm)(Args...) const &&); template<Returnable R, class T, CopyConstructible... Args> unspecified mem_fn(R (T::* pm)(Args...) volatile &&); template<Returnable R, class T, CopyConstructible... Args> unspecified mem_fn(R (T::* pm)(Args...) const volatile &&);
yes, absolutely. Thanks for spotting this. Without this change mem_fn cannot be initialized from pointer to ref-qualified member function. I believe semantics of such function pointer is well defined.
[ Post Summit Daniel provided wording. ]
[ Batavia (2009-05): ]
We need to think about whether we really want to go down the proposed path of combinatorial explosion. Perhaps a Note would suffice.
We would really like to have an implementation before proceeding.
Move to Open, and recommend this be deferred until after the next Committee Draft has been issued.
[ 2009-10-10 Daniel updated wording to post-concepts. ]
1230 has a similar proposed resolution
[ 2009-10 Santa Cruz: ]
Move to Ready.
Proposed resolution:
Change 20.8 [function.objects]/2, header <functional> synopsis as follows:
// 20.7.14, member function adaptors: template<class R, class T> unspecified mem_fn(R T::*); template<class R, class T, class ...Args> unspecified mem_fn(R (T::*)(Args...)); template<class R, class T, class ...Args> unspecified mem_fn(R (T::*)(Args...) const); template<class R, class T, class ...Args> unspecified mem_fn(R (T::*)(Args...) volatile); template<class R, class T, class ...Args> unspecified mem_fn(R (T::*)(Args...) const volatile); template<class R, class T, class ...Args> unspecified mem_fn(R (T::*)(Args...) &); template<class R, class T, class ...Args> unspecified mem_fn(R (T::*)(Args...) const &); template<class R, class T, class ...Args> unspecified mem_fn(R (T::*)(Args...) volatile &); template<class R, class T, class ...Args> unspecified mem_fn(R (T::*)(Args...) const volatile &); template<class R, class T, class ...Args> unspecified mem_fn(R (T::*)(Args...) &&); template<class R, class T, class ...Args> unspecified mem_fn(R (T::*)(Args...) const &&); template<class R, class T, class ...Args> unspecified mem_fn(R (T::*)(Args...) volatile &&); template<class R, class T, class ...Args> unspecified mem_fn(R (T::*)(Args...) const volatile &&);
Change the prototype list of 20.8.14 [func.memfn] as follows [NB: The following text, most notably p.2 and p.3 which discuss influence of the cv-qualification on the definition of the base class's first template parameter remains unchanged. ]:
template<class R, class T> unspecified mem_fn(R T::* pm); template<class R, class T, class ...Args> unspecified mem_fn(R (T::* pm)(Args...)); template<class R, class T, class ...Args> unspecified mem_fn(R (T::* pm)(Args...) const); template<class R, class T, class ...Args> unspecified mem_fn(R (T::* pm)(Args...) volatile); template<class R, class T, class ...Args> unspecified mem_fn(R (T::* pm)(Args...) const volatile); template<class R, class T, class ...Args> unspecified mem_fn(R (T::* pm)(Args...) &); template<class R, class T, class ...Args> unspecified mem_fn(R (T::* pm)(Args...) const &); template<class R, class T, class ...Args> unspecified mem_fn(R (T::* pm)(Args...) volatile &); template<class R, class T, class ...Args> unspecified mem_fn(R (T::* pm)(Args...) const volatile &); template<class R, class T, class ...Args> unspecified mem_fn(R (T::* pm)(Args...) &&); template<class R, class T, class ...Args> unspecified mem_fn(R (T::* pm)(Args...) const &&); template<class R, class T, class ...Args> unspecified mem_fn(R (T::* pm)(Args...) volatile &&); template<class R, class T, class ...Args> unspecified mem_fn(R (T::* pm)(Args...) const volatile &&);
Remove 20.8.14 [func.memfn]/5:
Remarks: Implementations may implement mem_fn as a set of overloaded function templates.
Section: 20.6.1 [ratio.ratio] Status: Ready Submitter: Pablo Halpern Opened: 2008-10-07 Last modified: 2009-10-21
View other active issues in [ratio.ratio].
View all other issues in [ratio.ratio].
View all issues with Ready status.
Discussion:
The compile-time functions that operate on ratio<N,D> require the cumbersome and error-prone "evaluation" of a type member using a meta-programming style that predates the invention of template aliases. Thus, multiplying three ratios a, b, and c requires the expression:
ratio_multiply<a, ratio_multiply<b, c>::type>::type
The simpler expression:
ratio_multiply<a, ratio_multiply<b, c>>
Could be used by if template aliases were employed in the definitions.
[ Post Summit: ]
Jens: not a complete proposed resolution: "would need to make similar change"
Consensus: We agree with the direction of the issue.
Recommend Open.
[ 2009-05-11 Daniel adds: ]
Personally I'm not in favor for the addition of:
typedef ratio type;For a reader of the standard it's usage or purpose is unclear. I haven't seen similar examples of attempts to satisfy non-feature complete compilers.
[ 2009-05-11 Pablo adds: ]
The addition of type to the ratio template allows the previous style (i.e., in the prototype implementations) to remain valid and permits the use of transitional library implementations for C++03 compilers. I do not feel strongly about its inclusion, however, and leave it up to the reviewers to decide.
[ Batavia (2009-05): ]
Bill asks for additional discussion in the issue that spells out more details of the implementation. Howard points us to issue 948 which has at least most of the requested details. Tom is strongly in favor of overflow-checking at compile time. Pete points out that there is no change of functionality implied. We agree with the proposed resolution, but recommend moving the issue to Review to allow time to improve the discussion if needed.
[ 2009-07-21 Alisdair adds: ]
See 1121 for a potentially incompatible proposal.
[ 2009-10 Santa Cruz: ]
Move to Ready.
Proposed resolution:
In 20.6 [ratio]/3 change as indicated:
// ratio arithmetic template <class R1, class R2>structusing ratio_add = see below; template <class R1, class R2>structusing ratio_subtract = see below; template <class R1, class R2>structusing ratio_multiply = see below; template <class R1, class R2>structusing ratio_divide = see below;
In 20.6.1 [ratio.ratio], change as indicated:
namespace std {
template <intmax_t N, intmax_t D = 1>
class ratio {
public:
typedef ratio type;
static const intmax_t num;
static const intmax_t den;
};
}
In 20.6.2 [ratio.arithmetic] change as indicated:
template <class R1, class R2>structusing ratio_add = see below{ typedef see below type; };1 The
nested typedeftype ratio_add<R1, R2> shall be a synonym for ratio<T1, T2> where T1 has the value R1::num * R2::den + R2::num * R1::den and T2 has the value R1::den * R2::den.
template <class R1, class R2>structusing ratio_subtract = see below{ typedef see below type; };2 The
nested typedeftype ratio_subtract<R1, R2> shall be a synonym for ratio<T1, T2> where T1 has the value R1::num * R2::den - R2::num * R1::den and T2 has the value R1::den * R2::den.
template <class R1, class R2>structusing ratio_multiply = see below{ typedef see below type; };3 The
nested typedeftype ratio_multiply<R1, R2> shall be a synonym for ratio<T1, T2> where T1 has the value R1::num * R2::num and T2 has the value R1::den * R2::den.
template <class R1, class R2>structusing ratio_divide = see below{ typedef see below type; };4 The
nested typedeftype ratio_divide<R1, R2> shall be a synonym for ratio<T1, T2> where T1 has the value R1::num * R2::den and T2 has the value R1::den * R2::num.
In 20.10.3.1 [time.duration.cons]/4 change as indicated:
Requires: treat_as_floating_point<rep>::value shall be true or ratio_divide<Period2, period>::
type::den shall be 1.[..]
In 20.10.3.7 [time.duration.cast]/2 change as indicated:
Returns: Let CF be ratio_divide<Period, typename ToDuration::period>
::type, and [..]
Section: 30.3.1.2 [thread.thread.constr] Status: Ready Submitter: Anthony Williams Opened: 2008-10-23 Last modified: 2010-03-08
View other active issues in [thread.thread.constr].
View all other issues in [thread.thread.constr].
View all issues with Ready status.
Discussion:
Addresses UK 323
The thread constructor for starting a new thread with a function and arguments is overly constrained by the signature requiring rvalue references for func and args and the CopyConstructible requirements for the elements of args. The use of an rvalue referenc