Doc. no. | N4383 |
Date: | 2015-04-10 |
Project: | Programming Language C++ |
Reply to: | Marshall Clow <lwgchair@gmail.com> |
Revised 2015-04-10 at 03:04:29 UTC
Reference ISO/IEC IS 14882:2014(E)
Also see:
The purpose of this document is to record the status of issues which have come before the Library Working Group (LWG) of the INCITS PL22.16 and ISO WG21 C++ Standards Committee. Issues represent potential defects in the ISO/IEC IS 14882:2014(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:2014(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.
Issues reported to the LWG transition through a variety of statuses, indicating their progress towards a resolution. Typically, most issues will flow through the following stages.
New - The issue has not yet been reviewed by the LWG. Any Proposed Resolution is purely a suggestion from the issue submitter, and should not be construed as the view of LWG.
Open - The LWG has discussed the issue but is not yet ready to move the issue forward. There are several possible reasons for open status:
A Proposed Resolution for an open issue is still not be construed as the view of LWG. Comments on the current state of discussions are often given at the end of open issues in an italic font. Such comments are for information only and should not be given undue importance.
Review - Exact wording of a Proposed Resolution is now available for review on an issue for which the LWG previously reached informal consensus.
Ready - The LWG has reached consensus that the issue is a defect in the Standard, the Proposed Resolution is correct, and the issue is ready to forward to the full committee for further action as a Defect Report (DR).
Typically, an issue must have a proposed resolution in the currently published issues list, whose wording does not change during LWG review, to move to the Ready status.
Voting - This status should not be seen in a published issues list, but is a marker for use during meetings to indicate an issues was Ready in the pre-meeting mailing, the Proposed Resolution is correct, and the issue will be offered to the working group at the end of the current meeting to apply to the current working paper (WP) or to close in some other appropriate manner. This easily distinguishes such issues from those moving to Ready status during the meeting itself, that should not be forwarded until the next meeting. If the issue does not move forward, it should fall back to one of the other open states before the next list is published.
Immediate - This status should not be seen in a published issues list, but is a marker for use during meetings to indicate an issues was not Ready in the pre-meeting mailing, but the Proposed Resolution is correct, and the issue will be offered to the working group at the end of the current meeting to apply to the current working paper (WP) or to close in some other appropriate manner. This status is used only rarely, typically for fixes that are both small and obvious, and usually within a meeting of the expected publication of a revised standard. If the issue does not move forward, it should fall back to one of the other open states before the next list is published.
In addition, there are a few ways to categorise and issue that remains open to a resolution within the library, but is not actively being worked on.
Deferred - The LWG has discussed the issue, is not yet ready to move the issue forward, but neither does it deem the issue significant enough to delay publishing a standard or Technical Report. A typical deferred issue would be seeking to clarify wording that might be technically correct, but easily mis-read.
A Proposed Resolution for a deferred issue is still not be construed as the view of LWG. Comments on the current state of discussions are often given at the end of open issues in an italic font. Such comments are for information only and should not be given undue importance.
Core - The LWG has discussed the issue, and feels that some key part of resolving the issue is better handled by a cleanup of the language in the Core part of the standard. The issue is passed to the Core Working Group, which should ideally open a corresponding issue that can be linked from the library issue. Such issues will be revisitted after Core have made (or declined to make) any changes.
EWG - The LWG has discussed the issue, and wonder that some key part of resolving the issue is better handled by some (hopefully small) extension to the language. The issue is passed to the Evolution Working Group, which should ideally open a corresponding issue that can be linked from the library issue. Such issues will be revisitted after Evoltion have made (or declined to make) any recommendations. Positive recommendations from EWG will often mean the issue transition to Core status while we wait for some proposed new feature to land in the working paper.
LEWG - The LWG has discussed the issue, and deemd the issue is either an extension, however small, or changes the library design in some fundamental way, and so has delegated the initial work to the Library Evolution Working Group.
Ultimately, all issues should reach closure with one of the following statuses.
DR - (Defect Report) - The full WG21/PL22.16 committee has voted to forward the issue to the Project Editor to be processed as a Potential Defect Report. The Project Editor reviews the issue, and then forwards it to the WG21 Convenor, who returns it to the full committee for final disposition. This issues list accords the status of DR to all these Defect Reports regardless of where they are in that process.
WP - (Working Paper) - The proposed resolution has not been accepted as a Technical Corrigendum, but the full WG21/PL22.16 committee has voted to apply the Defect Report's Proposed Resolution to the working paper.
C++14 - (C++ Standard, as revised for 2014) - The full WG21/PL22.16 committee has voted to accept the Defect Report's Proposed Resolution into the published 2011 revision to the C++ standard, ISO/IEC IS 14882:2014(E).
C++11 - (C++ Standard, as revised for 2011) - The full WG21/PL22.16 committee has voted to accept the Defect Report's Proposed Resolution into the published 2011 revision to the C++ standard, ISO/IEC IS 14882:2011(E).
CD1 - (Committee Draft 2008) - The full WG21/PL22.16 committee has voted to accept the Defect Report's Proposed Resolution into the Fall 2008 Committee Draft.
TC1 - (Technical Corrigenda 1) - The full WG21/PL22.16 committee has voted to accept the Defect Report's Proposed Resolution as a Technical Corrigenda. Action on this issue is thus complete and no further action is possible under ISO rules.
TRDec - (Decimal TR defect) - The LWG has voted to accept the Defect Report's Proposed Resolution into the Decimal TR. Action on this issue is thus complete and no further action is expected.
Resolved - The LWG has reached consensus that the issue is a defect in the Standard, but the resolution adopted to resolve the issue came via some other mechanism than this issue in the list - typically by applying a formal paper, occasionally as a side effect of consolidating several interacting issue resolutions into a single issue.
Dup - The LWG has reached consensus that the issue is a duplicate of another issue, and will not be further dealt with. A Rationale identifies the duplicated issue's issue number.
NAD - The LWG has reached consensus that the issue is not a defect in the Standard.
NAD Editorial - The LWG has reached consensus that the issue can either be handled editorially, or is handled by a paper (usually linked to in the rationale).
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.
The following statuses have been retired, but may show up on older issues lists.
NAD Future - In addition to the regular status, the LWG believes that this issue should be revisited at the next revision of the standard. That is now an ongoing task managed by the Library Evolution Working Group, and most issues in this status were reopended with the status LEWG.
NAD Concepts - This status reflects an evolution of the language during the development of C++11, where a new feature entered the language, called concepts, that fundamentally changed the way templates would be specified and written. While this language feature was removed towards the end of the C++11 project, there is a clear intent to revisit this part of the language design. During that development, a number of issues were opened against the updated library related to use of that feature, or requesting fixes that would require exlicit use of the concepts feature. All such issues have been closed with this status, and may be revisitted should this or a similar language feature return for a future standard.
Issues are always given the status of New when they first appear on the issues list. They may progress to Open or Review while the LWG is actively working on them. When the LWG has reached consensus on the disposition of an issue, the status will then change to Dup, NAD, or Ready as appropriate. Once the full PL22.16 committee votes to forward Ready issues to the Project Editor, they are given the status of Defect Report (DR). These in turn may become the basis for Technical Corrigenda (TC1), an updated standard (C++11, C++14), or are closed without action other than a Record of Response (Resolved) where the desired effect has already been achieved by some other process. 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: 27.6.3 [streambuf] Status: LEWG Submitter: Martin Sebor Opened: 2000-08-12 Last modified: 2015-04-08
View all other issues in [streambuf].
View all issues with LEWG status.
Discussion:
The basic_streambuf members gbump() and pbump() are specified to take an int argument. This requirement prevents the functions from effectively manipulating buffers larger than std::numeric_limits<int>::max() characters. It also makes the common use case for these functions somewhat difficult as many compilers will issue a warning when an argument of type larger than int (such as ptrdiff_t on LLP64 architectures) is passed to either of the function. Since it's often the result of the subtraction of two pointers that is passed to the functions, a cast is necessary to silence such warnings. Finally, the usage of a native type in the functions signatures is inconsistent with other member functions (such as sgetn() and sputn()) that manipulate the underlying character buffer. Those functions take a streamsize argument.
[ 2009-07 Frankfurt ]
This is part of a bigger problem. If anyone cares enough, they should write a paper solving the bigger problem of offset types in iostreams.
This is related to the paper about large file sizes. Beman has already agreed to drop the section of that paper that deals with this.
int is big enough for reasonable buffers.
Move to NAD Future.
This is related to LWG 423.
Proposed resolution:
Change the signatures of these functions in the synopsis of template class basic_streambuf (27.5.2) and in their descriptions (27.5.2.3.1, p4 and 27.5.2.3.2, p4) to take a streamsize argument.
Although this change has the potential of changing the ABI of the library, the change will affect only platforms where int is different than the definition of streamsize. However, since both functions are typically inline (they are on all known implementations), even on such platforms the change will not affect any user code unless it explicitly relies on the existing type of the functions (e.g., by taking their address). Such a possibility is IMO quite remote.
Alternate Suggestion from Howard Hinnant, c++std-lib-7780:
This is something of a nit, but I'm wondering if streamoff wouldn't be a better choice than streamsize. The argument to pbump and gbump MUST be signed. But the standard has this to say about streamsize (27.4.1/2/Footnote):
[Footnote: streamsize is used in most places where ISO C would use size_t. Most of the uses of streamsize could use size_t, except for the strstreambuf constructors, which require negative values. It should probably be the signed type corresponding to size_t (which is what Posix.2 calls ssize_t). --- end footnote]
This seems a little weak for the argument to pbump and gbump. Should we ever really get rid of strstream, this footnote might go with it, along with the reason to make streamsize signed.
Rationale:
The LWG believes this change is too big for now. We may wish to reconsider this for a future revision of the standard. One possibility is overloading pbump, rather than changing the signature.
[ [2006-05-04: Reopened at the request of Chris (Krzysztof ?elechowski)] ]
Section: 27 [input.output] Status: LEWG Submitter: Martin Sebor Opened: 2003-09-18 Last modified: 2015-04-08
View all other issues in [input.output].
View all issues with LEWG status.
Discussion:
A third party test suite tries to exercise istream::ignore(N) with a negative value of N and expects that the implementation will treat N as if it were 0. Our implementation asserts that (N >= 0) holds and aborts the test.
I can't find anything in section 27 that prohibits such values but I don't see what the effects of such calls should be, either (this applies to a number of unformatted input functions as well as some member functions of the basic_streambuf template).
[ 2009-07 Frankfurt ]
This is related to LWG 255.
Move to NAD Future.
Proposed resolution:
I propose that we add to each function in clause 27 that takes an argument, say N, of type streamsize a Requires clause saying that "N >= 0." The intent is to allow negative streamsize values in calls to precision() and width() but disallow it in calls to streambuf::sgetn(), istream::ignore(), or ostream::write().
[Kona: The LWG agreed that this is probably what we want. However, we need a review to find all places where functions in clause 27 take arguments of type streamsize that shouldn't be allowed to go negative. Martin will do that review.]
Section: 24.2.3 [input.iterators] Status: LEWG Submitter: Chris Jefferson Opened: 2004-09-16 Last modified: 2015-04-08
View all other issues in [input.iterators].
View all issues with LEWG status.
Discussion:
From comp.std.c++:
I note that given an input iterator a for type T, then *a only has to be "convertable to T", not actually of type T.
Firstly, I can't seem to find an exact definition of "convertable to T". While I assume it is the obvious definition (an implicit conversion), I can't find an exact definition. Is there one?
Slightly more worryingly, there doesn't seem to be any restriction on the this type, other than it is "convertable to T". Consider two input iterators a and b. I would personally assume that most people would expect *a==*b would perform T(*a)==T(*b), however it doesn't seem that the standard requires that, and that whatever type *a is (call it U) could have == defined on it with totally different symantics and still be a valid inputer iterator.
Is this a correct reading? When using input iterators should I write T(*a) all over the place to be sure that the object I'm using is the class I expect?
This is especially a nuisance for operations that are defined to be "convertible to bool". (This is probably allowed so that implementations could return say an int and avoid an unnessary conversion. However all implementations I have seen simply return a bool anyway. Typical implemtations of STL algorithms just write things like while(a!=b && *a!=0). But strictly speaking, there are lots of types that are convertible to T but that also overload the appropriate operators so this doesn't behave as expected.
If we want to make code like this legal (which most people seem to expect), then we'll need to tighten up what we mean by "convertible to T".
[Lillehammer: The first part is NAD, since "convertible" is well-defined in core. The second part is basically about pathological overloads. It's a minor problem but a real one. So leave open for now, hope we solve it as part of iterator redesign.]
[ 2009-07-28 Reopened by Alisdair. No longer solved by concepts. ]
[ 2009-10 Santa Cruz: ]
Mark as NAD Future. We agree there's an issue, but there is no proposed solution at this time and this will be solved by concepts in the future.
Proposed resolution:
Rationale:
[ San Francisco: ]
Solved by N2758.
Section: 28 [re] Status: LEWG Submitter: Eric Niebler Opened: 2005-07-01 Last modified: 2015-04-08
View other active issues in [re].
View all other issues in [re].
View all issues with LEWG status.
Discussion:
A problem with TR1 regex is currently being discussed on the Boost developers list. It involves the handling of case-insensitive matching of character ranges such as [Z-a]. The proper behavior (according to the ECMAScript standard) is unimplementable given the current specification of the TR1 regex_traits<> class template. John Maddock, the author of the TR1 regex proposal, agrees there is a problem. The full discussion can be found at http://lists.boost.org/boost/2005/06/28850.php (first message copied below). We don't have any recommendations as yet.
-- Begin original message --
The situation of interest is described in the ECMAScript specification (ECMA-262), section 15.10.2.15:
"Even if the pattern ignores case, the case of the two ends of a range is significant in determining which characters belong to the range. Thus, for example, the pattern /[E-F]/i matches only the letters E, F, e, and f, while the pattern /[E-f]/i matches all upper and lower-case ASCII letters as well as the symbols [, \, ], ^, _, and `."
A more interesting case is what should happen when doing a case-insentitive match on a range such as [Z-a]. It should match z, Z, a, A and the symbols [, \, ], ^, _, and `. This is not what happens with Boost.Regex (it throws an exception from the regex constructor).
The tough pill to swallow is that, given the specification in TR1, I don't think there is any effective way to handle this situation. According to the spec, case-insensitivity is handled with regex_traits<>::translate_nocase(CharT) -- two characters are equivalent if they compare equal after both are sent through the translate_nocase function. But I don't see any way of using this translation function to make character ranges case-insensitive. Consider the difficulty of detecting whether "z" is in the range [Z-a]. Applying the transformation to "z" has no effect (it is essentially std::tolower). And we're not allowed to apply the transformation to the ends of the range, because as ECMA-262 says, "the case of the two ends of a range is significant."
So AFAICT, TR1 regex is just broken, as is Boost.Regex. One possible fix is to redefine translate_nocase to return a string_type containing all the characters that should compare equal to the specified character. But this function is hard to implement for Unicode, and it doesn't play nice with the existing ctype facet. What a mess!
-- End original message --
[ John Maddock adds: ]
One small correction, I have since found that ICU's regex package does implement this correctly, using a similar mechanism to the current TR1.Regex.
Given an expression [c1-c2] that is compiled as case insensitive it:
Enumerates every character in the range c1 to c2 and converts it to it's case folded equivalent. That case folded character is then used a key to a table of equivalence classes, and each member of the class is added to the list of possible matches supported by the character-class. This second step isn't possible with our current traits class design, but isn't necessary if the input text is also converted to a case-folded equivalent on the fly.
ICU applies similar brute force mechanisms to character classes such as [[:lower:]] and [[:word:]], however these are at least cached, so the impact is less noticeable in this case.
Quick and dirty performance comparisons show that expressions such as "[X-\\x{fff0}]+" are indeed very slow to compile with ICU (about 200 times slower than a "normal" expression). For an application that uses a lot of regexes this could have a noticeable performance impact. ICU also has an advantage in that it knows the range of valid characters codes: code points outside that range are assumed not to require enumeration, as they can not be part of any equivalence class. I presume that if we want the TR1.Regex to work with arbitrarily large character sets enumeration really does become impractical.
Finally note that Unicode has:
Three cases (upper, lower and title). One to many, and many to one case transformations. Character that have context sensitive case translations - for example an uppercase sigma has two different lowercase forms - the form chosen depends on context(is it end of a word or not), a caseless match for an upper case sigma should match either of the lower case forms, which is why case folding is often approximated by tolower(toupper(c)).
Probably we need some way to enumerate character equivalence classes, including digraphs (either as a result or an input), and some way to tell whether the next character pair is a valid digraph in the current locale.
Hoping this doesn't make this even more complex that it was already,
[ Portland: Alisdair: Detect as invalid, throw an exception. Pete: Possible general problem with case insensitive ranges. ]
[ 2009-07 Frankfurt ]
We agree that this is a problem, but we do not know the answer.
We are going to declare this NAD until existing practice leads us in some direction.
No objection to NAD Future.
Move to NAD Future.
Proposed resolution:
Section: 20.4.2.7 [tuple.rel], TR1 6.1.3.5 [tr.tuple.rel] Status: LEWG Submitter: David Abrahams Opened: 2005-11-29 Last modified: 2015-04-08
View other active issues in [tuple.rel].
View all other issues in [tuple.rel].
View all issues with LEWG status.
Duplicate of: 348
Discussion:
Where possible, tuple comparison operators <,<=,=>, and > ought to be defined in terms of std::less rather than operator<, in order to support comparison of tuples of pointers.
[ 2009-07-28 Reopened by Alisdair. No longer solved by concepts. ]
[ 2009-10 Santa Cruz: ]
If we solve this for tuple we would have to solve it for pair algorithms, etc. It is too late to do that at this time. Move to NAD Future.
Proposed resolution:
change 6.1.3.5/5 from:
Returns: The result of a lexicographical comparison between t and u. The result is defined as: (bool)(get<0>(t) < get<0>(u)) || (!(bool)(get<0>(u) < get<0>(t)) && ttail < utail), where rtail for some tuple r is a tuple containing all but the first element of r. For any two zero-length tuples e and f, e < f returns false.
to:
Returns: The result of a lexicographical comparison between t and u. For any two zero-length tuples e and f, e < f returns false. Otherwise, the result is defined as: cmp( get<0>(t), get<0>(u)) || (!cmp(get<0>(u), get<0>(t)) && ttail < utail), where rtail for some tuple r is a tuple containing all but the first element of r, and cmp(x,y) is an unspecified function template defined as follows.
Where T is the type of x and U is the type of y:
if T and U are pointer types and T is convertible to U, returns less<U>()(x,y)
otherwise, if T and U are pointer types, returns less<T>()(x,y)
otherwise, returns (bool)(x < y)
[ Berlin: This issue is much bigger than just tuple (pair, containers, algorithms). Dietmar will survey and work up proposed wording. ]
Rationale:
Recommend NAD. This will be fixed with the next revision of concepts.
[ San Francisco: ]
Solved by N2770.
Section: 22 [localization] Status: LEWG Submitter: Peter Dimov Opened: 2007-07-28 Last modified: 2015-04-08
View all other issues in [localization].
View all issues with LEWG status.
Discussion:
The POSIX "Extended API Set Part 4,"
introduces extensions to the C locale mechanism that allow multiple concurrent locales to be used in the same application by introducing a type locale_t that is very similar to std::locale, and a number of _l functions that make use of it.
The global locale (set by setlocale) is now specified to be per- process. If a thread does not call uselocale, the global locale is in effect for that thread. It can install a per-thread locale by using uselocale.
There is also a nice querylocale mechanism by which one can obtain the name (such as "de_DE") for a specific facet, even for combined locales, with no std::locale equivalent.
std::locale should be harmonized with the new POSIX locale_t mechanism and provide equivalents for uselocale and querylocale.
[ Kona (2007): Bill and Nick to provide wording. ]
[ San Francisco: Bill and Nick still intend to provide wording, but this is a part of the task to be addressed by the group that will look into issue 860. ]
[ 2009-07 Frankfurt: ]
It's our intention to stay in sync with WG14. If WG14 makes a decision that requires a change in WG21 the issue will be reopened.
Move to NAD Future.
Proposed resolution:
Section: 23.2 [container.requirements] Status: Tentatively NAD Submitter: Paolo Carlini Opened: 2007-11-11 Last modified: 2015-04-08
View other active issues in [container.requirements].
View all other issues in [container.requirements].
View all issues with Tentatively NAD status.
Discussion:
In an emplace member function the function parameter pack may be bound to a priori unlimited number of objects: some or all of them can be elements of the container itself. Apparently, in order to conform to the blanket statement 23.2 [container.requirements]/11, the implementation must check all of them for that possibility. A possible solution can involve extending the exception in 23.2 [container.requirements]/12 also to the emplace member. As a side note, the push_back and push_front member functions are luckily not affected by this problem, can be efficiently implemented anyway.
[ Related to 767 and to 2164 ]
[ Bellevue: ]
The proposed addition (13) is partially redundant with the existing paragraph 12. Why was the qualifier "rvalues" added to paragraph 12? Why does it not cover subelements and pointers?
Resolution: Alan Talbot to rework language, then set state to Review.
[ 2009-07 Frankfurt ]
The problem is broader than emplace. The LWG doesn't feel that it knows how to write wording that prohibits all of the problematic use cases at this time.
NAD Future.
[2015-02 Cologne]
LWG believes that 2164 addresses this issue and therefore considers 760 as NAD.
Proposed resolution:
Add after 23.2 [container.requirements]/12:
-12- Objects passed to member functions of a container as rvalue references shall not be elements of that container. No diagnostic required.
-13- Objects bound to the function parameter pack of the emplace member function shall not be elements or sub-objects of elements of the container. No diagnostic required.
Section: 23.4 [associative], 23.5 [unord] Status: LEWG Submitter: Alan Talbot Opened: 2008-05-18 Last modified: 2015-04-08
View other active issues in [associative].
View all other issues in [associative].
View all issues with LEWG status.
Discussion:
Splice is a very useful feature of list. This functionality is also very useful for any other node based container, and I frequently wish it were available for maps and sets. It seems like an omission that these containers lack this capability. Although the complexity for a splice is the same as for an insert, the actual time can be much less since the objects need not be reallocated and copied. When the element objects are heavy and the compare operations are fast (say a map<int, huge_thingy>) this can be a big win.
Suggested resolution:
Add the following signatures to map, set, multimap, multiset, and the unordered associative containers:
void splice(list<T,Allocator>&& x); void splice(list<T,Allocator>&& x, const_iterator i); void splice(list<T,Allocator>&& x, const_iterator first, const_iterator last);
Hint versions of these are also useful to the extent hint is useful. (I'm looking for guidance about whether hints are in fact useful.)
void splice(const_iterator position, list<T,Allocator>&& x); void splice(const_iterator position, list<T,Allocator>&& x, const_iterator i); void splice(const_iterator position, list<T,Allocator>&& x, const_iterator first, const_iterator last);
[ Sophia Antipolis: ]
Don't try to splice "list" into the other containers, it should be container-type.
forward_list already has splice_after.
Would "splice" make sense for an unordered_map?
Jens, Robert: "splice" is not the right term, it implies maintaining ordering in lists.
Howard: adopt?
Jens: absorb?
Alan: subsume?
Robert: recycle?
Howard: transfer? (but no direction)
Jens: transfer_from. No.
Alisdair: Can we give a nothrow guarantee? If your compare() and hash() doesn't throw, yes.
Daniel: For unordered_map, we can't guarantee nothrow.
[ San Francisco: ]
Martin: this would possibly outlaw an implementation technique that is currently in use; caching nodes in containers.
Alan: if you cache in the allocator, rather than the individual container, this proposal doesn't interfere with that.
Martin: I'm not opposed to this, but I'd like to see an implementation that demonstrates that it works.
[ 2009-07 Frankfurt: ]
NAD Future.
[ 2009-09-19 Howard adds: ]
I'm not disagreeing with the NAD Future resolution. But when the future gets here, here is a possibility worth exploring:
Add to the "unique" associative containers:
typedef details node_ptr; node_ptr remove(const_iterator p); pair<iterator, bool> insert(node_ptr&& nd); iterator insert(const_iterator p, node_ptr&& nd);And add to the "multi" associative containers:
typedef details node_ptr; node_ptr remove(const_iterator p); iterator insert(node_ptr&& nd); iterator insert(const_iterator p, node_ptr&& nd);Container::node_ptr is a smart pointer much like unique_ptr. It owns a node obtained from the container it was removed from. It maintains a reference to the allocator in the container so that it can properly deallocate the node if asked to, even if the allocator is stateful. This being said, the node_ptr can not outlive the container for this reason.
The node_ptr offers "const-free" access to the node's value_type.
With this interface, clients have a great deal of flexibility:
- A client can remove a node from one container, and insert it into another (without any heap allocation). This is the splice functionality this issue asks for.
- A client can remove a node from a container, change its key or value, and insert it back into the same container, or another container, all without the cost of allocating a node.
- If the Compare function is nothrow (which is very common), then this functionality is nothrow unless modifying the value throws. And if this does throw, it does so outside of the containers involved.
- If the Compare function does throw, the insert function will have the argument nd retain ownership of the node.
- The node_ptr should be independent of the Compare parameter so that a node can be transferred from set<T, C1, A> to set<T, C2, A> (for example).
Here is how the customer might use this functionality:
Splice a node from one container to another:
m2.insert(m1.remove(i));Change the "key" in a std::map without the cost of node reallocation:
auto p = m.remove(i); p->first = new_key; m.insert(std::move(p));Change the "value" in a std::set without the cost of node reallocation:
auto p = s.remove(i); *p = new_value; s.insert(std::move(p));Move a move-only or heavy object out of an associative container (as opposed to the proposal in 1041):
MoveOnly x = std::move(*s.remove(i));
- remove(i) transfers ownership of the node from the set to a temporary node_ptr.
- The node_ptr is dereferenced, and that non-const reference is sent to move to cast it to an rvalue.
- The rvalue MoveOnly is move constructed into x from the node_ptr.
- ~node_ptr() destructs the moved-from MoveOnly and deallocates the node.
Contrast this with the 1041 solution:
MoveOnly x = std::move(s.extract(i).first);The former requires one move construction for x while the latter requires two (one into the pair and then one into x). Either of these constructions can throw (say if there is only a copy constructor for x). With the former, the point of throw is outside of the container s, after the element has been removed from the container. With the latter, one throwing construction takes place prior to the removal of the element, and the second takes place after the element is removed.
The "node insertion" API maintains the API associated with inserting value_types so the customer can use familiar techniques for getting an iterator to the inserted node, or finding out whether it was inserted or not for the "unique" containers.
Lightly prototyped. No implementation problems. Appears to work great for the client.
Proposed resolution:
Section: 23.3.2 [array] Status: LEWG Submitter: Benjamin Kosnik Opened: 2008-06-05 Last modified: 2015-04-08
View other active issues in [array].
View all other issues in [array].
View all issues with LEWG status.
Discussion:
This is an issue that came up on the libstdc++ list, where a discrepancy between "C" arrays and C++0x's std::array was pointed out.
In "C," this array usage is possible:
int ar[] = {1, 4, 6};
But for C++,
std::array<int> a = { 1, 4, 6 }; // error
Instead, the second parameter of the array template must be explicit, like so:
std::array<int, 3> a = { 1, 4, 6 };
Doug Gregor proposes the following solution, that assumes generalized initializer lists.
template<typename T, typename... Args> inline array<T, sizeof...(Args)> make_array(Args&&... args) { return { std::forward<Args>(args)... }; }
Then, the way to build an array from a list of unknown size is:
auto a = make_array<T>(1, 4, 6);
[ San Francisco: ]
Benjamin: Move to Ready?
Bjarne: I'm not convinced this is useful enough to add, so I'd like us to have time to reflect on it.
Alisdair: the constraints are wrong, they should be
template<ValueType T, ValueType... Args> requires Convertible<Args, T>... array<T, sizeof...(Args)> make_array(Args&&... args);Alidair: this would be useful if we had a constexpr version.
Bjarne: this is probably useful for arrays with a small number of elements, but it's not clearly useful otherwise.
Consensus is to move to Open.
[ 2009-06-07 Daniel adds: ]
I suggest a fix and a simplification of the current proposal: Recent prototyping by Howard showed, that a fix is required because narrowing conversion 8.5.4 [dcl.init.list]/6 b.3 would severely limit the possible distribution of argument types, e.g. the expression make_array<double>(1, 2.0) is ill-formed, because the narrowing happens inside the function body where no constant expressions exist anymore. Furthermore given e.g.
int f(); double g();we probably want to support
make_array<double>(f(), g());as well. To make this feasible, the currently suggested expansion
{ std::forward<Args>(args)... }needs to be replaced by
{ static_cast<T>(std::forward<Args>(args))... }which is safe, because we already ensure convertibility via the element-wise Convertible<Args, T> requirement. Some other fixes are necessary: The ValueType requirement for the function parameters is invalid, because all lvalue arguments will deduce to an lvalue-reference, thereby no longer satisfying this requirement.
The suggested simplification is to provide a default-computed effective type for the result array based on common_type and decay, in unconstrained form:
template<typename... Args> array<typename decay<typename common_type<Args...>::type>::type, sizeof...(Args)> make_array(Args&&... args);The approach used below is similar to that of make_pair and make_tuple using a symbol C to represent the decayed common type [Note: Special handling of reference_wrapper types is intentionally not provided, because our target has so satisfy ValueType, thus under the revised proposal only an all-reference_wrapper-arguments would be well-formed and an array of reference_wrapper will be constructed]. I do currently not suggest to add new concepts reflecting decay and common_type, but an implementor will need something like this to succeed. Note that we use a similar fuzziness for make_pair and make_tuple currently. This fuzziness is not related to the currently missing Constructible<Vi, Ti&&> requirement for those functions. The following proposal fixes that miss for make_array. If the corresponding C type deduction is explicitly wanted for standardization, here the implementation
auto concept DC<typename... T> { typename type = typename decay<typename common_type<T...>::type>::type; }where C is identical to DC<Args...>::type in the proposed resolution below.
I intentionally added no further type relation between type and the concept template parameters, but instead added this requirement below to make the specification as transparent as possible. As written this concept is satisfied, if the corresponding associated type exists.
Suggested Resolution:
Add to the array synopsis in 23.3 [sequences]:
template<ReferentType... Args> requires ValueType<C> && IdentityOf<Args> && Constructible<C, Args&&>... array<C, sizeof...(Args)> make_array(Args&&... args);Append after 23.3.2.9 [array.tuple] Tuple interface to class template array the following new section:
23.4.1.7 Array creation functions [array.creation]
template<ReferentType... Args> requires ValueType<C> && IdentityOf<Args> && Constructible<C, Args&&>... array<C, sizeof...(Args)> make_array(Args&&... args);Let C be decay<common_type<Args...>::type>::type.
Returns: an array<C, sizeof...(Args)> initialized with { static_cast<C>(std::forward<Args>(args))... }.
[ 2009-07 Frankfurt: ]
The proposed resolution uses concepts.
Daniel to rewrite the proposed resolution.
Leave Open.
[ 2009-07-25 Daniel provides rewritten proposed resolution. ]
[ 2009-10 Santa Cruz: ]
Argument for NAD future: everything about this could be added on. This does not require changes to the existing text.
Proposed resolution:
Add to the array synopsis in 23.3 [sequences]:
template<class... Args> array<CT, sizeof...(Args)> make_array(Args&&... args);
Append after 23.3.2.9 [array.tuple] "Tuple interface to class template array" the following new section:
XX.X.X.X Array creation functions [array.creation]
template<class... Args> array<CT, sizeof...(Args)> make_array(Args&&... args)Let CT be decay<common_type<Args...>::type>::type.
Returns: An array<CT, sizeof...(Args)> initialized with { static_cast<CT>(std::forward<Args>(args))... }.
[Example:
int i = 0; int& ri = i; make_array(42u, i, 2.78, ri);returns an array of type
array<double, 4>—end example]
Section: 17 [library] Status: LEWG Submitter: Martin Sebor Opened: 2008-08-23 Last modified: 2015-04-08
View other active issues in [library].
View all other issues in [library].
View all issues with LEWG status.
Discussion:
Recent changes to the working draft have introduced a gratuitous inconsistency with the C++ 2003 version of the specification with respect to exception guarantees provided by standard functions. While the C++ 2003 standard consistenly uses the empty exception specification, throw(), to declare functions that are guaranteed not to throw exceptions, the current working draft contains a number of "Throws: Nothing." clause to specify essentially the same requirement. The difference between the two approaches is that the former specifies the behavior of programs that violate the requirement (std::unexpected() is called) while the latter leaves the behavior undefined.
A survey of the working draft reveals that there are a total of 209 occurrences of throw() in the library portion of the spec, the majority in clause 18, a couple (literally) in 19, a handful in 20, a bunch in 22, four in 24, one in 27, and about a dozen in D.9.
There are also 203 occurrences of "Throws: Nothing." scattered throughout the spec.
While sometimes there are good reasons to use the "Throws: Nothing." approach rather than making use of throw(), these reasons do not apply in most of the cases where this new clause has been introduced and the empty exception specification would be a better approach.
First, functions declared with the empty exception specification permit compilers to generate better code for calls to such functions. In some cases, the compiler might even be able to eliminate whole chunks of user-written code when instantiating a generic template on a type whose operations invoked from the template specialization are known not to throw. The prototypical example are the std::uninitialized_copy() and std::uninitialized_fill() algorithms where the entire catch(...) block can be optimized away.
For example, given the following definition of the std::uninitialized_copy function template and a user-defined type SomeType:
template <class InputIterator, class ForwardIterator> ForwardIterator uninitialized_copy (InputIterator first, InputIterator last, ForwardIterator res) { typedef iterator_traits<ForwardIterator>::value_type ValueType; ForwardIterator start = res; try { for (; first != last; ++first, ++res) ::new (&*res) ValueType (*first); } catch (...) { for (; start != res; --start) (&*start)->~ValueType (); throw; } return res; } struct SomeType { SomeType (const SomeType&) throw (); }
compilers are able to emit the following efficient specialization of std::uninitialized_copy<const SomeType*, SomeType*> (note that the catch block has been optimized away):
template <> SomeType* uninitialized_copy (const SomeType *first, const SomeType *last, SomeType *res) { for (; first != last; ++first, ++res) ::new (res) SomeType (*first); return res; }
Another general example is default constructors which, when decorated with throw(), allow the compiler to eliminate the implicit try and catch blocks that it otherwise must emit around each the invocation of the constructor in new-expressions.
For example, given the following definitions of class MayThrow and WontThrow and the two statements below:
struct MayThrow { MayThrow (); }; struct WontThrow { WontThrow () throw (); }; MayThrow *a = new MayThrow [N]; WontThrow *b = new WontThrow [N];
the compiler generates the following code for the first statement:
MayThrow *a; { MayThrow *first = operator new[] (N * sizeof (*a)); MayThrow *last = first + N; MayThrow *next = first; try { for ( ; next != last; ++next) new (next) MayThrow; } catch (...) { for ( ; first != first; --next) next->~MayThrow (); operator delete[] (first); throw; } a = first; }
but it is can generate much more compact code for the second statement:
WontThrow *b = operator new[] (N * sizeof (*b)); WontThrow *last = b + N; for (WontThrow *next = b; next != last; ++next) new (next) WontThrow;
Second, in order for users to get the maximum benefit out of the new std::has_nothrow_xxx traits when using standard library types it will be important for implementations to decorate all non throwing copy constructors and assignment operators with throw(). Note that while an optimizer may be able to tell whether a function without an explicit exception specification can throw or not based on its definition, it can only do so when it can see the source code of the definition. When it can't it must assume that the function may throw. To prevent violating the One Definition Rule, the std::has_nothrow_xxx trait must return the most pessimistic guess across all translation units in the program, meaning that std::has_nothrow_xxx<T>::value must evaluate to false for any T whose xxx (where xxx is default or copy ctor, or assignment operator) is defined out-of-line.
Counterarguments:
During the discussion of this issue on c++std-lib@accu.org (starting with post c++std-lib-21950) the following arguments in favor of the "Throws: Nothing." style have been made.
The answer to point (1) above is that implementers can (and some have) declare functions with throw() to indicate to the compiler that calls to the function can safely be assumed not to throw in order to allow it to generate efficient code at the call site without also having to define the functions the same way and causing the compiler to generate suboptimal code for the function definition. That is, the function is declared with throw() in a header but it's defined without it in the source file. The throw() declaration is suppressed when compiling the definition to avoid compiler errors. This technique, while strictly speaking no permitted by the language, is safe and has been employed in practice. For example, the GNU C library takes this approach. Microsoft Visual C++ takes a similar approach by simply assuming that no function with C language linkage can throw an exception unless it's explicitly declared to do so using the language extension throw(...).
Our answer to point (2) above is that there is no existing practice where C++ Standard Library implementers have opted to make use of the proprietary mechanisms to declare functions that don't throw. The language provides a mechanism specifically designed for this purpose. Avoiding its use in the specification itself in favor of proprietary mechanisms defeats the purpose of the feature. In addition, making use of the empty exception specification inconsistently, in some areas of the standard, while conspicuously avoiding it and making use of the "Throws: Nothing." form in others is confusing to users.
The answer to point (3) is simply to exercise caution when declaring functions and especially function templates with the empty exception specification. Functions that required not to throw but that may call back into user code are poor candidates for the empty exception specification and should instead be specified using "Throws: Nothing." clause.
[ 2009-07 Frankfurt ]
We need someone to do an extensive review.
NAD Future.
Proposed resolution:
We propose two possible solutions. Our recommendation is to adopt Option 1 below.
Option 1:
Except for functions or function templates that make calls back to user-defined functions that may not be declared throw() replace all occurrences of the "Throws: Nothing." clause with the empty exception specification. Functions that are required not to throw but that make calls back to user code should be specified to "Throw: Nothing."
Option 2:
For consistency, replace all occurrences of the empty exception specification with a "Throws: Nothing." clause.
Section: 20.8.1.2.5 [unique.ptr.single.modifiers] Status: LEWG Submitter: Alisdair Meredith Opened: 2008-11-27 Last modified: 2015-04-08
View all other issues in [unique.ptr.single.modifiers].
View all issues with LEWG status.
Discussion:
If we are supporting stateful deleters, we need an overload for reset that takes a deleter as well.
void reset( pointer p, deleter_type d);
We probably need two overloads to support move-only deleters, and this sounds uncomfortably like the two constructors I have been ignoring for now...
[ Batavia (2009-05): ]
Howard comments that we have the functionality via move-assigment.
Move to Open.
[ 2009-10 Santa Cruz: ]
Mark as NAD Future.
Proposed resolution:
Section: 20.12.7 [time.clock] Status: LEWG Submitter: Beman Dawes Opened: 2008-11-24 Last modified: 2015-04-08
View all issues with LEWG status.
Discussion:
Each of the three clocks specified in Clocks 20.12.7 [time.clock] provides the member function:
static time_point now();
The semantics specified by Clock requirements 20.12.3 [time.clock.req] make no mention of error handling. Thus the function may throw bad_alloc or an implementation-defined exception (17.6.5.12 [res.on.exception.handling] paragraph 4).
Some implementations of these functions on POSIX, Windows, and presumably on other operating systems, may fail in ways only detectable at runtime. Some failures on Windows are due to supporting chipset errata and can even occur after successful calls to a clock's now() function.
These functions are used in cases where exceptions are not appropriate or where the specifics of the exception or cause of error need to be available to the user. See N2828, Library Support for hybrid error handling (Rev 1), for more specific discussion of use cases. Thus some change in the interface of now is required.
The proposed resolution has been implemented in the Boost version of the chrono library. No problems were encountered.
[ Batavia (2009-05): ]
We recommend this issue be deferred until the next Committee Draft has been issued and the prerequisite paper has been accepted.
Move to Open.
[ 2009-10 Santa Cruz: ]
Mark as NAD future. Too late to make this change without having already accepted the hybrid error handling proposal.
Proposed resolution:
Accept the proposed wording of N2828, Library Support for hybrid error handling (Rev 1).
Change Clock requirements 20.12.3 [time.clock.req] as indicated:
-2- In Table 55 C1 and C2 denote clock types. t1 and t2 are values returned by C1::now() where the call returning t1 happens before (1.10) the call returning t2 and both of these calls happen before C1::time_point::max(). ec denotes an object of type error_code (19.5.2.1 [syserr.errcode.overview]).
Table 55 — Clock requirements Expression Return type Operational semantics ... ... ... C1::now() C1::time_point Returns a time_point object representing the current point in time. C1::now(ec) C1::time_point Returns a time_point object representing the current point in time.
Change class system_clock 20.12.7.1 [time.clock.system] as indicated:
static time_point now(error_code& ec=throws());
Change class monotonic_clock X [time.clock.monotonic] as indicated:
static time_point now(error_code& ec=throws());
Change class high_resolution_clock 20.12.7.3 [time.clock.hires] as indicated:
static time_point now(error_code& ec=throws());
Section: 30.4.1 [thread.mutex.requirements] Status: LEWG Submitter: Pete Becker Opened: 2008-12-05 Last modified: 2015-04-08
View other active issues in [thread.mutex.requirements].
View all other issues in [thread.mutex.requirements].
View all issues with LEWG status.
Duplicate of: 961
Discussion:
30.4.1 [thread.mutex.requirements] describes the requirements for a type to be a "Mutex type". A Mutex type can be used as the template argument for the Lock type that's passed to condition_variable_any::wait (although Lock seems like the wrong name here, since Lock is given a different formal meaning in 30.4.2 [thread.lock]) and, although the WD doesn't quite say so, as the template argument for lock_guard and unique_lock.
The requirements for a Mutex type include:
Also, a Mutex type "shall not be copyable nor movable".
The latter requirement seems completely irrelevant, and the three requirements on return types are tighter than they need to be. For example, there's no reason that lock_guard can't be instantiated with a type that's copyable. The rule is, in fact, that lock_guard, etc. won't try to copy objects of that type. That's a constraint on locks, not on mutexes. Similarly, the requirements for void return types are unnecessary; the rule is, in fact, that lock_guard, etc. won't use any returned value. And with the return type of bool, the requirement should be that the return type is convertible to bool.
[ Summit: ]
Move to open. Related to conceptualization and should probably be tackled as part of that.
- The intention is not only to place a constraint on what types such as lock_guard may do with mutex types, but on what any code, including user code, may do with mutex types. Thus the constraints as they are apply to the mutex types themselves, not the current users of mutex types in the standard.
- This is a low priority issue; the wording as it is may be overly restrictive but this may not be a real issue.
[ Post Summit Anthony adds: ]
Section 30.4.1 [thread.mutex.requirements] conflates the requirements on a generic Mutex type (including user-supplied mutexes) with the requirements placed on the standard-supplied mutex types in an attempt to group everything together and save space.
When applying concepts to chapter 30, I suggest that the concepts Lockable and TimedLockable embody the requirements for *use* of a mutex type as required by unique_lock/lock_guard/condition_variable_any. These should be relaxed as Pete describes in the issue. The existing words in 30.4.1 [thread.mutex.requirements] are requirements on all of std::mutex, std::timed_mutex, std::recursive_mutex and std::recursive_timed_mutex, and should be rephrased as such.
Proposed resolution:
Section: 30.4.1 [thread.mutex.requirements] Status: LEWG Submitter: Pete Becker Opened: 2009-01-07 Last modified: 2015-04-08
View other active issues in [thread.mutex.requirements].
View all other issues in [thread.mutex.requirements].
View all issues with LEWG status.
Duplicate of: 936
Discussion:
30.4.1 [thread.mutex.requirements] describes required member functions of mutex types, and requires that they throw exceptions under certain circumstances. This is overspecified. User-defined types can abort on such errors without affecting the operation of templates supplied by standard-library.
[ Summit: ]
Move to open. Related to conceptualization and should probably be tackled as part of that.
[ 2009-10 Santa Cruz: ]
Would be OK to leave it as is for time constraints, could loosen later.
Mark as NAD Future.
Proposed resolution:
Section: 20.9.13 [unord.hash] Status: LEWG Submitter: Alisdair Meredith Opened: 2009-03-11 Last modified: 2015-04-08
View other active issues in [unord.hash].
View all other issues in [unord.hash].
View all issues with LEWG status.
Discussion:
Addresses UK 208 [CD1]
std::hash should be implemented for much more of the standard library. In particular for pair, tuple and all the standard containers.
Proposed resolution:
Section: 20.8.2.2 [util.smartptr.shared] Status: LEWG Submitter: Alisdair Meredith Opened: 2009-03-11 Last modified: 2015-04-08
View other active issues in [util.smartptr.shared].
View all other issues in [util.smartptr.shared].
View all issues with LEWG status.
Discussion:
Addresses US 78 [CD1]
There is presently no way to convert directly from a shared_ptr to a unique_ptr. Add an interface that performs the conversion.
[ Summit: ]
We look forward to a paper on this topic. We recommend no action until a paper is available. We believe that the shared pointer must use the default deleter for the conversion to succeed.
[ Peter Dimov adds: ]
This is basically a request for shared_ptr<>::release in disguise, with all the associated problems. Not a good idea.
[ 2009-07 post-Frankfurt: ]
The rationale for the omission of a release() member function from shared_ptr is given in: http://www.boost.org/doc/libs/1_39_0/libs/smart_ptr/shared_ptr.htm
The implementation of such a member is non-trivial (and maybe impossible), because it would need to account for the deleter.
[ 2009-07-26 Howard sets to Tentatively NAD Future. ]
I took an online poll and got 3 votes for NAD and 3 for NAD Future. Personally I prefer NAD Future as this does refer to an extension that could conceivably be considered beyond C++0X.
However such an extension would need to solve a couple of problems:
- What is the interface for such a conversion when the shared_ptr does not have unique ownership? Throw an exception? Create a null unique_ptr? Undefined behavior?
How does one handle custom deleters given to the shared_ptr constructor?
I do not believe it is possible to implement a general answer to this question. The shared_ptr deleter is a run time (or construction time) characteristic. The unique_ptr deleter is a compile time characteristic. In general one can not know to what type of unqiue_ptr you are converting to.
One answer is for the user of the conversion to specify the deleter type and perhaps throw an exception if the specification turns out to be incorrect.
Another answer is for the conversion to only be valid when the underlying deleter is default_delete. We would probalby need to specify that this is indeed the underlying deleter of a shared_ptr when a custom deleter is not given in the constructor.
At any rate, there are non-trivial design issues which would need to be implemented and tested in the field for usability prior to standardization.
[ 2009 Santa Cruz: ]
Moved to NAD Future.
Proposed resolution:
Section: 23.2.4 [associative.reqmts] Status: LEWG Submitter: Alisdair Meredith Opened: 2009-03-12 Last modified: 2015-04-08
View other active issues in [associative.reqmts].
View all other issues in [associative.reqmts].
View all issues with LEWG status.
Discussion:
Addresses UK 239 [CD1]
It is not possible to take a move-only key out of an unordered container, such as (multi)set or (multi)map, or the new unordered containers.
Add below a.erase(q), a.extract(q), with the following notation:
a.extract(q)>, Return type pair<key, iterator> Extracts the element pointed to by q and erases it from the set. Returns a pair containing the value pointed to by q and an iterator pointing to the element immediately following q prior to the element being erased. If no such element exists,returns a.end().
[ Summit: ]
We look forward to a paper on this topic. We recommend no action until a paper is available. The paper would need to address exception safety.
[ Post Summit Alisdair adds: ]
Would value_type be a better return type than key_type?
[ 2009-07 post-Frankfurt: ]
Leave Open. Alisdair to contact Chris Jefferson about this.
[ 2009-09-20 Howard adds: ]
See the 2009-09-19 comment of 839 for an API which accomplishes this functionality and also addresses several other use cases which this proposal does not.
[ 2009-10 Santa Cruz: ]
Mark as NAD Future. No consensus to make the change at this time.
Proposed resolution:
In 23.2.4 [associative.reqmts] Table 85, add:
Table 85 -- Associative container requirements (in addition to container) Expression Return type Assertion/note
pre-/post-conditionComplexity a.erase(q) ... ... ... a.extract(q) pair<key_type, iterator> Extracts the element pointed to by q and erases it from the set. Returns a pair containing the value pointed to by q and an iterator pointing to the element immediately following q prior to the element being erased. If no such element exists, returns a.end(). amortized constant
In 23.2.5 [unord.req] Table 87, add:
Table 87 -- Unordered associative container requirements (in addition to container) Expression Return type Assertion/note
pre-/post-conditionComplexity a.erase(q) ... ... ... a.extract(q) pair<key_type, iterator> Extracts the element pointed to by q and erases it from the set. Returns a pair containing the value pointed to by q and an iterator pointing to the element immediately following q prior to the element being erased. If no such element exists, returns a.end(). amortized constant
Section: 24.5.1.3.5 [reverse.iter.opref] Status: LEWG Submitter: Alisdair Meredith Opened: 2009-03-12 Last modified: 2015-04-08
View all other issues in [reverse.iter.opref].
View all issues with LEWG status.
Discussion:
Addresses UK 281 [CD1]
The current specification for return value for reverse_iterator::operator-> will always be a true pointer type, but reverse_iterator supports proxy iterators where the pointer type may be some kind of 'smart pointer'.
[ Summit: ]
move_iterator avoids this problem by returning a value of the wrapped Iterator type. study group formed to come up with a suggested resolution.
move_iterator solution shown in proposed wording.
[ 2009-07 post-Frankfurt: ]
Howard to deconceptize. Move to Review after that happens.
[ 2009-08-01 Howard deconceptized: ]
[ 2009-10 Santa Cruz: ]
We can't think of any reason we can't just define reverse iterator's pointer types to be the same as the underlying iterator's pointer type, and get it by calling the right arrow directly.
Here is the proposed wording that was replaced:
template <class Iterator> class reverse_iterator { ... typedeftypename iterator_traits<Iterator>::pointerpointer;Change 24.5.1.3.5 [reverse.iter.opref]:
pointer operator->() const;Returns:
&(operator*());this->tmp = current; --this->tmp; return this->tmp;
[ 2010-03-03 Daniel opens: ]
- There is a minor problem with the exposition-only declaration of the private member deref_tmp which is modified in a const member function (and the same problem occurs in the specification of operator*). The fix is to make it a mutable member.
The more severe problem is that the resolution for some reasons does not explain in the rationale why it was decided to differ from the suggested fix (using deref_tmp instead of tmp) in the [ 2009-10 Santa Cruz] comment:
this->deref_tmp = current; --this->deref_tmp; return this->deref_tmp;combined with the change of
typedef typename iterator_traits<Iterator>::pointer pointer;to
typedef Iterator pointer;The problem of the agreed on wording is that the following rather typical example, that compiled with the wording before 1052 had been applied, won't compile anymore:
#include <iterator> #include <utility> int main() { typedef std::pair<int, double> P; P op; std::reverse_iterator<P*> ri(&op + 1); ri->first; // Error }Comeau online returns (if a correspondingly changed reverse_iterator is used):
"error: expression must have class type return deref_tmp.operator->(); ^ detected during instantiation of "Iterator reverse_iterator<Iterator>::operator->() const [with Iterator=std::pair<int, double> *]""Thus the change will break valid, existing code based on std::reverse_iterator.
IMO the suggestion proposed in the comment is a necessary fix, which harmonizes with the similar specification of std::move_iterator and properly reflects the recursive nature of the evaluation of operator-> overloads.
Suggested resolution:
In the class template reverse_iterator synopsis of 24.5.1.1 [reverse.iterator] change as indicated:
namespace std { template <class Iterator> class reverse_iterator : public iterator<typename iterator_traits<Iterator>::iterator_category, typename iterator_traits<Iterator>::value_type, typename iterator_traits<Iterator>::difference_type,typename iterator_traits<Iterator>::pointer, typename iterator_traits<Iterator>::reference> { public: [..] typedeftypename iterator_traits<Iterator>::pointerpointer; [..] protected: Iterator current; private: mutable Iterator deref_tmp; // exposition only };- Change 24.5.1.3.5 [reverse.iter.opref]/1 as indicated:
pointer operator->() const;1
ReturnsEffects:&(operator*()).deref_tmp = current; --deref_tmp; return deref_tmp;
[ 2010 Pittsburgh: ]
We prefer to make to use a local variable instead of deref_tmp within operator->(). And although this means that the mutable change is no longer needed, we prefer to keep it because it is needed for operator*() anyway.
Here is the proposed wording that was replaced:
Change 24.5.1.3.5 [reverse.iter.opref]:
pointer operator->() const;Returns:
&(operator*());deref_tmp = current; --deref_tmp; return deref_tmp::operator->();
[ 2010-03-10 Howard adds: ]
Here are three tests that the current proposed wording passes, and no other solution I've seen passes all three:
Proxy pointer support:
#include <iterator> #include <cassert> struct X { int m; }; X x; struct IterX { typedef std::bidirectional_iterator_tag iterator_category; typedef X& reference; struct pointer { pointer(X& v) : value(v) {} X& value; X* operator->() const {return &value;} }; typedef std::ptrdiff_t difference_type; typedef X value_type; // additional iterator requirements not important for this issue reference operator*() const { return x; } pointer operator->() const { return pointer(x); } IterX& operator--() {return *this;} }; int main() { std::reverse_iterator<IterX> ix; assert(&ix->m == &(*ix).m); }Raw pointer support:
#include <iterator> #include <utility> int main() { typedef std::pair<int, double> P; P op; std::reverse_iterator<P*> ri(&op + 1); ri->first; // Error }Caching iterator support:
#include <iterator> #include <cassert> struct X { int m; }; struct IterX { typedef std::bidirectional_iterator_tag iterator_category; typedef X& reference; typedef X* pointer; typedef std::ptrdiff_t difference_type; typedef X value_type; // additional iterator requirements not important for this issue reference operator*() const { return value; } pointer operator->() const { return &value; } IterX& operator--() {return *this;} private: mutable X value; }; int main() { std::reverse_iterator<IterX> ix; assert(&ix->m == &(*ix).m); }
[ 2010 Pittsburgh: ]
Moved to NAD Future, rationale added.
Rationale:
The LWG did not reach a consensus for a change to the WP.
Proposed resolution:
In the class template reverse_iterator synopsis of 24.5.1.1 [reverse.iterator] change as indicated:
namespace std { template <class Iterator> class reverse_iterator : public iterator<typename iterator_traits<Iterator>::iterator_category, typename iterator_traits<Iterator>::value_type, typename iterator_traits<Iterator>::difference_type,typename iterator_traits<Iterator&>::pointer, typename iterator_traits<Iterator>::reference> { public: [..] typedeftypename iterator_traits<Iterator&>::pointerpointer; [..] protected: Iterator current; private: mutable Iterator deref_tmp; // exposition only };
pointer operator->() const;1
ReturnsEffects:&(operator*()).deref_tmp = current; --deref_tmp; return deref_tmp;
Section: 25 [algorithms] Status: LEWG Submitter: Alisdair Meredith Opened: 2009-03-12 Last modified: 2015-04-08
View other active issues in [algorithms].
View all other issues in [algorithms].
View all issues with LEWG status.
Discussion:
Addresses UK 295 [CD1]
There is a level of redundancy in the library specification for many algorithms that can be eliminated with the combination of concepts and default parameters for function templates. Eliminating redundancy simplified specification and reduces the risk of introducing accidental inconsistencies.
Proposed resolution: Adopt N2743.
[ Summit: ]
NAD, this change would break code that takes the address of an algorithm.
[ Post Summit Alisdair adds: ]
Request 'Open'. The issues in the paper go beyond just reducing the number of signatures, but cover unifying the idea of the ordering operation used by algorithms, containers and other library components. At least, it takes a first pass at the problem.
For me (personally) that was the more important part of the paper, and not clearly addressed by the Summit resolution.
[ 2009-10 Santa Cruz: ]
Too inventive, too late, would really need a paper. Moved to NAD Future.
Proposed resolution:
Section: 20.6 [template.bitset] Status: LEWG Submitter: Alisdair Meredith Opened: 2009-05-06 Last modified: 2015-04-08
View other active issues in [template.bitset].
View all other issues in [template.bitset].
View all issues with LEWG status.
Discussion:
std::bitset is a homogeneous container-like sequence of bits, yet it does not model the Range concept so cannot be used with the new for-loop syntax. It is the only such type in the library that does NOT support the new for loop.
The obvious reason is that bitset does not support iterators.
At least two reasonable solutions are available:
The latter will still need some kind of iterator-like adapter for bitset, but gives implementers greater freedom on the details. E.g. begin/end return some type that simply invokes operator[] on the object it wraps, and increments its index on operator++. A vendor can settle for InputIterator support, rather than wrapping up a full RandomAccessIterator.
I have a mild preference for option (ii) as I think it is less work to specify at this stage of the process, although (i) is probably more useful in the long run.
Hmm, my wording looks a little woolly, as it does not say what the element type of the range is. Do I get a range of bool, bitset<N>::reference, or something else entirely?
I guess most users will assume the behaviour of reference, but expect to work with bool. Bool is OK for read-only traversal, but you really need to take a reference to a bitset::reference if you want to write back.
[ Batavia (2009-05): ]
Move to Open. We further recommend this be deferred until after the next Committee Draft.
[ 2009-05-25 Alisdair adds: ]
I just stumbled over the Range concept_map for valarray and this should probably set the precedent on how to write the wording.
[ Howard: I've replaced the proposed wording with Alisdair's suggestion. ]
[ 2009-07-24 Daniel modifies the proposed wording for non-concepts. ]
[ 2009-10 post-Santa Cruz: ]
Mark as Tentatively NAD Future due to the loss of concepts.
Rationale:
All concepts-related text has been removed from the draft.
Proposed resolution:
Modify the section 20.6 [template.bitset] <bitset> synopsis by adding the following at the end of the synopsis:
// XX.X.X bitset range access [bitset.range] template<size_t N> unspecified-1 begin(bitset<N>&); template<size_t N> unspecified-2 begin(const bitset<N>&); template<size_t N> unspecified-1 end(bitset<N>&); template<size_t N> unspecified-2 end(const bitset<N>&);
Add a new section "bitset range access" [bitset.range] after the current section 20.6.4 [bitset.operators] with the following series of paragraphs:
1. In the begin and end function templates that follow, unspecified-1 is a type that meets the requirements of a mutable random access iterator (24.2.7 [random.access.iterators]) whose value_type is bool and whose reference type is bitset<N>::reference. unspecified-2 is a type that meets the requirements of a constant random access iterator (24.2.7 [random.access.iterators]) whose value_type is bool and whose reference type is bool.
template<size_t N> unspecified-1 begin(bitset<N>&); template<size_t N> unspecified-2 begin(const bitset<N>&);2. Returns: an iterator referencing the first bit in the bitset.
template<size_t N> unspecified-1 end(bitset<N>&); template<size_t N> unspecified-2 end(const bitset<N>&);3. Returns: an iterator referencing one past the last bit in the bitset.
Section: 20.10 [meta] Status: LEWG Submitter: Alisdair Meredith Opened: 2009-05-23 Last modified: 2015-04-08
View other active issues in [meta].
View all other issues in [meta].
View all issues with LEWG status.
Discussion:
Sometimes it is necessary to remove all qualifiers from a type before passing on to a further API. A good example would be calling the tuple query APIs tuple_size or tuple_element with a deduced type inside a function template. If the deduced type is cv-qualified or a reference then the call will fail. The solution is to chain calls to remove_cv<remove_reference<T>::type>::type, and note that the order matters.
Suggest it would be helpful to add a new type trait, remove_all, that removes all top-level qualifiers from a type i.e. cv-qualification and any references. Define the term in such a way that if additional qualifiers are added to the language, then remove_all is defined as stripping those as well.
[ 2009-10-14 Daniel adds: ]
remove_all seems too generic, a possible alternative matching the current naming style could be remove_cv_reference or remove_reference_cv. It should also be considered whether this trait should also remove 'extents', or pointer 'decorations'. Especially if the latter situations are considered as well, it might be easier to chose the name not in terms of what it removes (which might be a lot), but in terms of it creates. In this case I could think of e.g. extract_value_type.
[ 2009-10 Santa Cruz: ]
NAD Future.
Proposed resolution:
Section: 20.11.4 [ratio.arithmetic] Status: LEWG Submitter: Alisdair Meredith Opened: 2009-05-25 Last modified: 2015-04-08
View all other issues in [ratio.arithmetic].
View all issues with LEWG status.
Discussion:
Both add and multiply could sensibly be called with more than two arguments. The variadic template facility makes such declarations simple, and is likely to be frequently wrapped by end users if we do not supply the variant ourselves.
We deliberately ignore divide at this point as it is not transitive. Likewise, subtract places special meaning on the first argument so I do not suggest extending that immediately. Both could be supported with analogous wording to that for add/multiply below.
Note that the proposed resolution is potentially incompatible with that proposed for 921, although the addition of the typedef to ratio would be equally useful.
[ 2009-10-30 Alisdair adds: ]
The consensus of the group when we reviewed this in Santa Cruz was that 921 would proceed to Ready as planned, and the multi-paramater add/multiply templates should be renamed as ratio_sum and ratio_product to avoid the problem mixing template aliases with partial specializations.
It was also suggested to close this issue as NAD Future as it does not correspond directly to any NB comment. NBs are free to submit a specific comment (and re-open) in CD2 though.
Walter Brown also had concerns on better directing the order of evaluation to avoid overflows if we do proceed for 0x rather than TR1, so wording may not be complete yet.
[ Alisdair updates wording. ]
[ 2009-10-30 Howard: ]
Moved to Tentatively NAD Future after 5 positive votes on c++std-lib.
Rationale:
Does not have sufficient support at this time. May wish to reconsider for a future standard.
Proposed resolution:
Add the following type traits to p3 20.11 [ratio]
// ratio arithmetic template <class R1, class R2> struct ratio_add; template <class R1, class R2> struct ratio_subtract; template <class R1, class R2> struct ratio_multiply; template <class R1, class R2> struct ratio_divide; template <class R1, class ... RList> struct ratio_sum; template <class R1, class ... RList> struct ratio_product;
after 20.11.4 [ratio.arithmetic] p1: add
template <class R1, class ... RList> struct ratio_sum; // declared, never defined template <class R1> struct ratio_sum<R1> : R1 {};Requires: R1 is a specialization of class template ratio
template <class R1, class R2, class ... RList> struct ratio_sum<R1, R2, RList...> : ratio_add< R1, ratio_sum<R2, RList...>> { };Requires: R1 and each element in parmater pack RList is a specialization of class template ratio
after 20.11.4 [ratio.arithmetic] p3: add
template <class R1, class ... RList> struct ratio_product; // declared, never defined template <class R1> struct ratio_product<R1> : R1 {};Requires: R1 is a specialization of class template ratio
template <class R1, class R2, class ... RList> struct ratio_sum<R1, R2, RList...> : ratio_add< R1, ratio_product<R2, RList...>> { };Requires: R1 and each element in parmater pack RList is a specialization of class template ratio
Section: 27.9.1.14 [fstream] Status: LEWG Submitter: LWG Opened: 2009-06-28 Last modified: 2015-04-08
View all issues with LEWG status.
Discussion:
Addresses JP 73
Description
It is a problem from C++98, fstream cannot appoint a filename of wide character string(const wchar_t and const wstring&).
Suggestion
Add interface corresponding to wchar_t, char16_t and char32_t.
[ 2009-07-01 Alisdair notes that this is a duplicate of 454 which has more in-depth rationale. ]
[ 2009-09-21 Daniel adds: ]
I suggest to mark this issue as NAD Future with the intend to solve the issue with a single file path c'tor template assuming a provision of a TR2 filesystem library.
[ 2009 Santa Cruz: ]
NAD Future. This is a duplicate of 454.
Proposed resolution:
Section: 26.4 [complex.numbers] Status: LEWG Submitter: LWG Opened: 2009-06-28 Last modified: 2015-04-08
View other active issues in [complex.numbers].
View all other issues in [complex.numbers].
View all issues with LEWG status.
Discussion:
Addresses FR 35
Description
Instantiations of the class template complex<> have to be allowed for integral types, to reflect existing practice and ISO standards (LIA-III).
Suggestion
[ 2009-10-26 Proposed wording in N3002. ]
[ 2010 Pittsburgh: ]
Moved to NAD Future. Rationale added.
Rationale:
There is no consensus for making this change at this time.
Proposed resolution:
Adopt N3002.
Section: 22.4.2.1.2 [facet.num.get.virtuals] Status: Open Submitter: Cosmin Truta Opened: 2009-07-04 Last modified: 2015-04-08
View other active issues in [facet.num.get.virtuals].
View all other issues in [facet.num.get.virtuals].
View all issues with Open status.
Discussion:
As specified in the latest draft,
N2914,
num_get
is still not fully compatible with the following C
functions: strtoul
, strtoull
,
strtof
and
strtod
.
In C, when conversion of a string to an unsigned integer type falls
outside the
representable range, strtoul
and strtoull
return
ULONG_MAX
and ULLONG_MAX
, respectively,
regardless
whether the input field represents a positive or a negative value.
On the other hand, the result of num_get
conversion of
negative
values to unsigned integer types is zero. This raises a compatibility
issue.
Moreover, in C, when conversion of a string to a floating-point type falls
outside the representable range, strtof
, strtod
and
strtold
return ±HUGE_VALF
,
±HUGE_VAL
and ±HUGE_VALL
, respectively.
On the other hand, the result of num_get
conversion of such
out-of-range floating-point values results in the most positive/negative
representable value.
Although many C library implementations do implement HUGE_VAL
(etc.) as the highest representable (which is, usually, the infinity),
this isn't required by the C standard. The C library specification makes no
statement regarding the value of HUGE_VAL
and friends, which
potentially raises the same compatibility issue as in the above case of
unsigned integers.
In addition, neither C nor C++ define symbolic constants for the maximum
representable floating-point values (they only do so only for the maximum
representable finite floating-point values), which raises a
usability
issue (it would be hard for the programmer to check the result of
num_get
against overflow).
As such, we propose to adjust the specification of num_get
to
closely follow the behavior of all of its underlying C functions.
[ 2010 Rapperswil: ]
Some concern that this is changing the specification for an existing C++03 function, but it was pointed out that this was underspecified as resolved by issue 23. This is clean-up for that issue in turn. Some concern that we are trying to solve the same problem in both clause 22 and 27.
Bill: There's a change here as to whether val is stored to in an error case.
Pablo: Don't think this changes whether val is stored to or not, but changes the value that is stored.
Bill: Remembers having skirmishes with customers and testers as to whether val is stored to, and the resolution was not to store in error cases.
Howard: Believes since C++03 we made a change to always store in overflow.
Everyone took some time to review the issue.
Pablo: C++98 definitely did not store any value during an error condition.
Dietmar: Depends on the question of what is considered an error, and whether overflow is an error or not, which was the crux of LWG 23.
Pablo: Yes, but given the "zero, if the conversion function fails to convert the entire field", we are requiring every error condition to store.
Bill: When did this happen?
Alisdair: One of the last two or three meetings.
Dietmar: To store a value in case of failure is a very bad idea.
Move to Open, needs more study.
[2011-03-24 Madrid meeting]
Move to deferred
[ 2011 Bloomington ]
The proposed wording looks good, no-one sure why this was held back before. Move to Review.
[2012,Kona]
Move to Open.
THe issues is what to do with -1. Should it match 'C' or do the "sane" thing. A fix here changes behavior, but is probably what we want.
Pablo to provide wording, with help from Howard.
Proposed resolution:
Change 22.4.2.1.2 [facet.num.get.virtuals] as follows:
Stage 3: The sequence of
char
s accumulated in stage 2 (the field) is converted to a numeric value by the rules of one of the functions declared in the header<cstdlib>
:
- For a signed integer value, the function
strtoll
.- For an unsigned integer value, the function
strtoull
.- For a
float
value, the functionstrtof
.- For a
double
value, the functionstrtod
.- For a
floating-pointlong double
value, the functionstrtold
.The numeric value to be stored can be one of:
- zero, if the conversion function fails to convert the entire field.
ios_base::failbit
is assigned toerr
.- the most positive (or negative) representable value, if the field to be converted to a signed integer type represents a value too large positive (or negative) to be represented in
val
.ios_base::failbit
is assigned toerr
.the most negative representable value or zero for an unsigned integer type, if the field represents a value too large negative to be represented inval
.ios_base::failbit
is assigned toerr
.- the most positive representable value, if the field to be converted to an unsigned integer type represents a value that cannot be represented in
val
.- the converted value, otherwise.
The resultant numeric value is stored in
val
. If the conversion function fails to convert the entire field, or if the field represents a value outside the range of representable values,ios_base::failbit
is assigned toerr
.
Section: 17 [library] Status: Open Submitter: David Abrahams Opened: 2009-07-14 Last modified: 2015-04-08
View other active issues in [library].
View all other issues in [library].
View all issues with Open status.
Discussion:
Issue: The CopyConstructible requirements are wishy-washy. It requires that the copy is "equivalent" to the original, but "equivalent" is never defined.
I believe this to be an example of a more general lack of rigor around copy and assignment, although I haven't done the research to dig up all the instances.
It's a problem because if you don't know what CopyConstructible means, you also don't know what it means to copy a pair of CopyConstructible types. It doesn't prevent us from writing code, but it is a hole in our ability to understand the meaning of copy.
Furthermore, I'm pretty sure that vector's copy constructor doesn't require the elements to be EqualityComparable, so that table is actually referring to some ill-defined notion of equivalence when it uses ==.
[ 2009 Santa Cruz: ]
Move to "Open". Dave is right that this is a big issue. Paper D2987 ("Defining Move Special Member Functions", Bjarne Stroustrup and Lawrence Crowl) touches on this but does not solve it. This issue is discussed in Elements of Programming.
[ 2010 Rapperswil: ]
This issue is quite vague, so it is difficult to know if and when it has been resolved. John Lakos wrote a paper covering this area a while back, and there is a real interest in providing some sort of clean-up in the future. We need a more clearly draughted issues with an addressable set of concerns, ideally with a paper proposing a resolution, but for a future revision of the standard. Move to Tentatively NAD Future.
[ Moved to NAD Future at 2010-11 Batavia ]
Proposed resolution:
Section: 23.2.5 [unord.req] Status: Open Submitter: Pablo Halpern Opened: 2009-07-17 Last modified: 2015-04-08
View other active issues in [unord.req].
View all other issues in [unord.req].
View all issues with Open status.
Discussion:
When I look at the unordered_* constructors, I think the complexity is poorly described and does not follow the style of the rest of the standard.
The complexity for the default constructor is specified as constant. Actually, it is proportional to n, but there are no invocations of value_type constructors or other value_type operations.
For the iterator-based constructor the complexity should be:
Complexity: exactly n calls to construct value_type from InputIterator::value_type (where n = distance(f,l)). The number of calls to key_equal::operator() is proportional to n in the average case and n*n in the worst case.
[ 2010 Rapperswil: ]
Concern that the current wording may require O(1) where that cannot be delivered. We need to look at both the clause 23 requirements tables and the constructor description of each unordered container to be sure.
Howard suggests NAD Editorial as we updated the container requirement tables since this issue was written.
Daniel offers to look deeper, and hopefully produce wording addressing any outstanding concerns at the next meeting.
Move to Open.
[2011-02-26: Daniel provides wording]
I strongly suggest to clean-up the differences between requirement tables and individual specifications. In the usual way, the most specific specifications wins, which is in this case the wrong one. In regard to the concern expressed about missing DefaultConstructible requirements of the value type I disagree: The function argument n is no size-control parameter, but only some effective capacity parameter: No elements will be value-initialized by these constructors. The necessary requirement for the value type, EmplaceConstructible into *this, is already listed in Table 103 — Unordered associative container requirements. Another part of the proposed resolution is the fact that there is an inconsistency of the complexity counting when both a range and a bucket count is involved compared to constructions where only bucket counts are provided: E.g. the construction X a(n); has a complexity of n bucket allocations, but this part of the work is omitted for X a(i, j, n);, even though it is considerable larger (in the average case) for n ≫ distance(i, j).
[2011-03-24 Madrid meeting]
Move to deferred
[ 2011 Bloomington ]
The proposed wording looks good. Move to Review.
[2012, Kona]
Fix up some presentation issues with the wording, combining the big-O expressions into single expressions rather than the sum of two separate big-Os.
Strike "constant or linear", prefer "linear in the number of buckets". This allows for number of buckets being larger than requested n as well.
Default n to "unspecified" rather than "implementation-defined". It seems an un-necessary burden asking vendors to document a quantity that is easily determined through the public API of these classes.
Replace distance(f,l) with "number of elements in the range [f,l)"
Retain in Review with the updated wording
[2012, Portland: Move to Open]
The wording still does not call out Pablo's original concern, that the element constructor is called no more than N times, and that the N squared term applies to moves during rehash.
Inconsistent use of O(n)+O(N) vs. O(n+N), with a preference for the former.
AJM to update wording with a reference to "no more than N element constructor calls".
Matt concerned that calling out the O(n) requirements is noise, and dangerous noise in suggesting a precision we do not mean. The cost of constructing a bucket is very different to constructing an element of user-supplied type.
AJM notes that if there are multiple rehashes, the 'n' complexity is probably not linear.
Matt suggests back to Open, Pablo suggests potentially NAD if we keep revisitting without achieving a resolution.
Matt suggests complexity we are concerned with is the number of operations, such as constructing elements, moving nodes, and comparing/hashing keys. We are less concerned with constructing buckets, which are generally noise in this bigger picture.
[2015-01-29 Telecon]
AM: essentially correct, but do we want to complicate the spec?
HH: Pablo has given us permission to NAD it JM: when I look at the first change in the P/R I find it mildly disturbing that the existing wording says you have a constant time constructor with a single element even if your n is 10^6, so I think adding this change makes people aware there might be a large cost in initializing the hash table, even though it doesn't show up in user-visible constructions. HH: one way to avoid that problem is make the default ctor noexcept. Then the container isn't allowed to create an arbitrarily large hash table AM: but this is the constructor where the user provides n MC: happy with the changes, except I agree with the editorial recommendation to keep the two 𝒪s separate. JW: yes, the constant 'k' is different in 𝒪(n) and 𝒪(N) GR: do we want to talk about buckets at all JM: yes, good to highlight that bucket construction might be a significant cost HH: suggest we take the suggestion to split 𝒪(n+N) to 𝒪(n)+𝒪(N) and move to Tentatively Ready GR: 23.2.1p2 says all complexity requirements are stated solely in terms of the number of operations on the contained object, so we shouldn't be stating complexity in terms of the hash table initialization HH: channeling Pete, there's an implicit "unless otherwise specified" everywhere. VV: seem to be requesting modifications that render this not Tentatively Ready GR: I think it can't be T/R AM: make the editorial recommendation, consider fixing 23.2.1/3 to give us permission to state complexity in terms of bucket initialization HH: only set it to Review after we get new wording to review[2015-02 Cologne]
Update wording, revisit later.
Proposed resolution:
Modify the following rows in Table 103 — Unordered associative container requirements to add the explicit bucket allocation overhead of some constructions. As editorial recommendation it is suggested not to shorten the sum 𝒪(n) + 𝒪(N) to 𝒪(n + N), because two different work units are involved.
Table 103 — Unordered associative container requirements (in addition to container) Expression Return type Assertion/note pre-/post-condition Complexity … X(i, j, n, hf, eq)
X a(i, j, n, hf, eq)X …
Effects: Constructs an empty container with at least n
buckets, using hf as the hash function and eq as the key
equality predicate, and inserts elements from [i, j) into it.Average case 𝒪(n + N) (N is distance(i, j)),
worst case 𝒪(n) + 𝒪(N2)X(i, j, n, hf)
X a(i, j, n, hf)X …
Effects: Constructs an empty container with at least n
buckets, using hf as the hash function and key_equal() as the key
equality predicate, and inserts elements from [i, j) into it.Average case 𝒪(n + N) (N is distance(i, j)),
worst case 𝒪(n + N2)X(i, j, n)
X a(i, j, n)X …
Effects: Constructs an empty container with at least n
buckets, using hasher() as the hash function and key_equal() as the key
equality predicate, and inserts elements from [i, j) into it.Average case 𝒪(n + N) (N is distance(i, j)),
worst case 𝒪(n + N2)…
Modify 23.5.4.2 [unord.map.cnstr] p. 1-4 as indicated (The edits of p. 1 and p. 3 attempt to fix some editorial oversight.):
explicit unordered_map(size_type n = see below, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());1 Effects: Constructs an empty unordered_map using the specified hash function, key equality function, and allocator, and using at least n buckets. If n is not provided, the number of buckets is unspecified
impldefdefault number of buckets in unordered_map. max_load_factor() returns 1.0.2 Complexity:
ConstantLinear in the number of buckets.
template <class InputIterator> unordered_map(InputIterator f, InputIterator l, size_type n = see below, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());3 Effects: Constructs an empty unordered_map using the specified hash function, key equality function, and allocator, and using at least n buckets. If n is not provided, the number of buckets is unspecified
impldefdefault number of buckets in unordered_map. Then inserts elements from the range [f, l). max_load_factor() returns 1.0.4 Complexity:
Average case linear, worst case quadraticLinear in the number of buckets. In the average case linear in N and in the worst case quadratic in N to insert the elements, where N is equal to number of elements in the range [f,l).
Modify 23.5.5.2 [unord.multimap.cnstr] p. 1-4 as indicated (The edits of p. 1 and p. 3 attempt to fix some editorial oversight.):
explicit unordered_multimap(size_type n = see below, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());1 Effects: Constructs an empty unordered_multimap using the specified hash function, key equality function, and allocator, and using at least n buckets. If n is not provided, the number of buckets is unspecified
impldefdefault number of buckets in unordered_multimap. max_load_factor() returns 1.0.2 Complexity:
ConstantLinear in the number of buckets.
template <class InputIterator> unordered_multimap(InputIterator f, InputIterator l, size_type n = see below, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());3 Effects: Constructs an empty unordered_multimap using the specified hash function, key equality function, and allocator, and using at least n buckets. If n is not provided, the number of buckets is unspecified
impldefdefault number of buckets in unordered_multimap. Then inserts elements from the range [f, l). max_load_factor() returns 1.0.4 Complexity:
Average case linear, worst case quadraticLinear in the number of buckets. In the average case linear in N and in the worst case quadratic in N to insert the elements, where N is equal to number of elements in the range [f,l).
Modify 23.5.6.2 [unord.set.cnstr] p. 1-4 as indicated (The edits of p. 1 and p. 3 attempt to fix some editorial oversight.):
explicit unordered_set(size_type n = see below, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());1 Effects: Constructs an empty unordered_set using the specified hash function, key equality function, and allocator, and using at least n buckets. If n is not provided, the number of buckets is unspecified
impldefdefault number of buckets in unordered_set. max_load_factor() returns 1.0.2 Complexity:
ConstantLinear in the number of buckets.
template <class InputIterator> unordered_set(InputIterator f, InputIterator l, size_type n = see below, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());3 Effects: Constructs an empty unordered_set using the specified hash function, key equality function, and allocator, and using at least n buckets. If n is not provided, the number of buckets is unspecified
impldefdefault number of buckets in unordered_set. Then inserts elements from the range [f, l). max_load_factor() returns 1.0.4 Complexity:
Average case linear, worst case quadraticLinear in the number of buckets. In the average case linear in N and in the worst case quadratic in N to insert the elements, where N is equal to number of elements in the range [f,l).
Modify 23.5.7.2 [unord.multiset.cnstr] p. 1-4 as indicated (The edits of p. 1 and p. 3 attempt to fix some editorial oversight.):
explicit unordered_multiset(size_type n = see below, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());1 Effects: Constructs an empty unordered_multiset using the specified hash function, key equality function, and allocator, and using at least n buckets. If n is not provided, the number of buckets is unspecified
impldefdefault number of buckets in unordered_multiset. max_load_factor() returns 1.0.2 Complexity:
ConstantLinear in the number of buckets.
template <class InputIterator> unordered_multiset(InputIterator f, InputIterator l, size_type n = see below, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());3 Effects: Constructs an empty unordered_multiset using the specified hash function, key equality function, and allocator, and using at least n buckets. If n is not provided, the number of buckets is unspecified
impldefdefault number of buckets in unordered_multiset. Then inserts elements from the range [f, l). max_load_factor() returns 1.0.4 Complexity:
Average case linear, worst case quadraticLinear in the number of buckets. In the average case linear in N and in the worst case quadratic in N to insert the elements, where N is equal to number of elements in the range [f,l).
Section: 23.3.6 [vector] Status: LEWG Submitter: Alisdair Meredith Opened: 2009-07-29 Last modified: 2015-04-08
View all other issues in [vector].
View all issues with LEWG status.
Discussion:
Opened at Alisdair's request, steming from 96. Alisdair recommends NAD Future.
[ 2009-10 Santa Cruz: ]
NAD Future. We want a heap allocated bitset, but we don't have one today and don't have time to add one.
Proposed resolution:
Section: 23.2.5 [unord.req], 23.5 [unord] Status: LEWG Submitter: Matt Austern Opened: 2009-08-10 Last modified: 2015-04-08
View other active issues in [unord.req].
View all other issues in [unord.req].
View all issues with LEWG status.
Discussion:
Unordered associative containers have a notion of a maximum load factor: when the number of elements grows large enough, the containers automatically perform a rehash so that the number of elements per bucket stays below a user-specified bound. This ensures that the hash table's performance characteristics don't change dramatically as the size increases.
For similar reasons, Google has found it useful to specify a minimum load factor: when the number of elements shrinks by a large enough, the containers automatically perform a rehash so that the number of elements per bucket stays above a user-specified bound. This is useful for two reasons. First, it prevents wasting a lot of memory when an unordered associative container grows temporarily. Second, it prevents amortized iteration time from being arbitrarily large; consider the case of a hash table with a billion buckets and only one element. (This was discussed even before TR1 was published; it was TR issue 6.13, which the LWG closed as NAD on the grounds that it was a known design feature. However, the LWG did not consider the approach of a minimum load factor.)
The only interesting question is when shrinking is allowed. In principle the cleanest solution would be shrinking on erase, just as we grow on insert. However, that would be a usability problem; it would break a number of common idioms involving erase. Instead, Google's hash tables only shrink on insert and rehash.
The proposed resolution allows, but does not require, shrinking in rehash, mostly because a postcondition for rehash that involves the minimum load factor would be fairly complicated. (It would probably have to involve a number of special cases and it would probably have to mention yet another parameter, a minimum bucket count.)
The current behavior is equivalent to a minimum load factor of 0. If we specify that 0 is the default, this change will have no impact on backward compatibility.
[ 2010 Rapperswil: ]
This seems to a useful extension, but is too late for 0x. Move to Tentatively NAD Future.
[ Moved to NAD Future at 2010-11 Batavia ]
Proposed resolution:
Add two new rows, and change rehash's postcondition in the unordered associative container requirements table in 23.2.5 [unord.req]:
Table 87 — Unordered associative container requirements (in addition to container) Expression Return type Assertion/note pre-/post-condition Complexity a.min_load_factor() float Returns a non-negative number that the container attempts to keep the load factor greater than or equal to. The container automatically decreases the number of buckets as necessary to keep the load factor above this number. constant a.min_load_factor(z) void Pre: z shall be non-negative. Changes the container's minimum load factor, using z as a hint. [Footnote: the minimum load factor should be significantly smaller than the maximum. If z is too large, the implementation may reduce it to a more sensible value.] constant a.rehash(n) void Post: a.bucket_count() >= n, and a.size() <= a.bucket_count() * a.max_load_factor(). [Footnote: It is intentional that the postcondition does not mention the minimum load factor. This member function is primarily intended for cases where the user knows that the container's size will increase soon, in which case the container's load factor will temporarily fall below a.min_load_factor().] a.bucket_cout > a.size() / a.max_load_factor() and a.bucket_count() >= n.Average case linear in a.size(), worst case quadratic.
Add a footnote to 23.2.5 [unord.req] p12:
The insert members shall not affect the validity of references to container elements, but may invalidate all iterators to the container. The erase members shall invalidate only iterators and references to the erased elements.
[A consequence of these requirements is that while insert may change the number of buckets, erase may not. The number of buckets may be reduced on calls to insert or rehash.]
Change paragraph 13:
The insert members shall not affect the validity of iterators if
(N+n) < z * Bzmin * B <= (N+n) <= zmax * B, where N is the number of elements in the container prior to the insert operation, n is the number of elements inserted, B is the container's bucket count, zmin is the container's minimum load factor, and zmax is the container's maximum load factor.
Add to the unordered_map class synopsis in section 23.5.4 [unord.map], the unordered_multimap class synopsis in 23.5.5 [unord.multimap], the unordered_set class synopsis in 23.5.6 [unord.set], and the unordered_multiset class synopsis in 23.5.7 [unord.multiset]:
float min_load_factor() const; void min_load_factor(float z);
In 23.5.4.2 [unord.map.cnstr], 23.5.5.2 [unord.multimap.cnstr], 23.5.6.2 [unord.set.cnstr], and 23.5.7.2 [unord.multiset.cnstr], change:
... max_load_factor() returns 1.0 and min_load_factor() returns 0.
Section: 20.4.2.4 [tuple.creation], 20.3 [pairs] Status: LEWG Submitter: Alisdair Meredith Opened: 2009-09-05 Last modified: 2015-04-08
View all other issues in [tuple.creation].
View all issues with LEWG status.
Discussion:
Spotting a recent thread on the boost lists regarding collapsing optional representations in optional<optional<T>> instances, I wonder if we have some of the same issues with make_tuple, and now make_pair?
Essentially, if my generic code in my own library is handed a reference_wrapper by a user, and my library in turn delegates some logic to make_pair or make_tuple, then I am going to end up with a pair/tuple holding a real reference rather than the intended reference wrapper.
There are two things as a library author I can do at this point:
(There may be some metaprogramming approaches my library can use to wrap the make_tuple call, but all will be significantly more complex than simply implementing a simplified make_tuple.)
Now I don't propose we lose this library facility, I think unwrapping references will be the common behaviour. However, we might want to consider adding another overload that does nothing special with ref-wrappers. Note that we already have a second overload of make_tuple in the library, called tie.
[ 2009-09-30 Daniel adds: ]
I suggest to change the currently proposed paragraph for make_simple_pair
template<typename... Types> pair<typename decay<Types>::type...> make_simple_pair(Types&&... t);
Type requirements: sizeof...(Types) == 2.Remarks: The program shall be ill-formed, if sizeof...(Types) != 2....
or alternatively (but with a slightly different semantic):
Remarks: If sizeof...(Types) != 2, this function shall not participate in overload resolution.
to follow a currently introduced style and because the library does not have yet a specific "Type requirements" element. If such thing would be considered as useful this should be done as a separate issue. Given the increasing complexity of either of these wordings it might be preferable to use the normal two-argument-declaration style again in either of the following ways:
template<class T1, class T2> pair<typename decay<T1>::type, typename decay<T2>::type> make_simple_pair(T1&& t1, T2&& t2); template<class T1, class T2> pair<V1, V2> make_simple_pair(T1&& t1, T2&& t2);Let V1 be typename decay<T1>::type and V2 be typename decay<T2>::type.
[ 2009-10 post-Santa Cruz: ]
Mark as Tentatively NAD Future.
Rationale:
Does not have sufficient support at this time. May wish to reconsider for a future standard.
Proposed resolution:
Add the following function to 20.3 [pairs] and signature in appropriate synopses:
template<typename... Types> pair<typename decay<Types>::type...> make_simple_pair(Types&&... t);Type requirements: sizeof...(Types) == 2.
Returns: pair<typename decay<Types>::type...>(std::forward<Types>(t)...).
[ Draughting note: I chose a variadic representation similar to make_tuple rather than naming both types as it is easier to read through the clutter of metaprogramming this way. Given there are exactly two elements, the committee may prefer to draught with two explicit template type parameters instead ]
Add the following function to 20.4.2.4 [tuple.creation] and signature in appropriate synopses:
template<typename... Types> tuple<typename decay<Types>::type...> make_simple_tuple(Types&&... t);Returns: tuple<typename decay<Types>::type...>(std::forward<Types>(t)...).
Section: 27.7.3.9 [ostream.rvalue], 27.7.2.6 [istream.rvalue] Status: LEWG Submitter: Howard Hinnant Opened: 2009-09-06 Last modified: 2015-04-08
View all issues with LEWG status.
Discussion:
27.7.3.9 [ostream.rvalue] was created to preserve the ability to insert into (and extract from 27.7.2.6 [istream.rvalue]) rvalue streams:
template <class charT, class traits, class T> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>&& os, const T& x);1 Effects: os << x
2 Returns: os
This is good as it allows code that wants to (for example) open, write to, and close an ofstream all in one statement:
std::ofstream("log file") << "Some message\n";
However, I think we can easily make this "rvalue stream helper" even easier to use. Consider trying to quickly create a formatted string. With the current spec you have to write:
std::string s = static_cast<std::ostringstream&>(std::ostringstream() << "i = " << i).str();
This will store "i = 10" (for example) in the string s. Note the need to cast the stream back to ostringstream& prior to using the member .str(). This is necessary because the inserter has cast the ostringstream down to a more generic ostream during the insertion process.
I believe we can re-specify the rvalue-inserter so that this cast is unnecessary. Thus our customer now has to only type:
std::string s = (std::ostringstream() << "i = " << i).str();
This is accomplished by having the rvalue stream inserter return an rvalue of the same type, instead of casting it down to the base class. This is done by making the stream generic, and constraining it to be an rvalue of a type derived from ios_base.
The same argument and solution also applies to the inserter. This code has been implemented and tested.
[ 2009 Santa Cruz: ]
NAD Future. No concensus for change.
Proposed resolution:
Change 27.7.2.6 [istream.rvalue]:
template <classcharT, class traitsIstream, class T>basic_istream<charT, traits>&Istream&& operator>>(basic_istream<charT, traits>Istream&& is, T& x);1 Effects: is >> x
2 Returns: std::move(is)
3 Remarks: This signature shall participate in overload resolution if and only if Istream is not an lvalue reference type and is derived from ios_base.
Change 27.7.3.9 [ostream.rvalue]:
template <classcharT, class traitsOstream, class T>basic_ostream<charT, traits>&Ostream&& operator<<(basic_ostream<charT, traits>Ostream&& os, const T& x);1 Effects: os << x
2 Returns: std::move(os)
3 Remarks: This signature shall participate in overload resolution if and only if Ostream is not an lvalue reference type and is derived from ios_base.
Section: 24.2 [iterator.requirements] Status: Open Submitter: Daniel Krügler Opened: 2009-09-19 Last modified: 2015-04-08
View all other issues in [iterator.requirements].
View all issues with Open status.
Discussion:
The terms valid iterator and singular aren't properly defined. The fuzziness of those terms became even worse after the resolution of 208 (including further updates by 278). In 24.2 [iterator.requirements] as of N2723 the standard says now:
5 - These values are called past-the-end values. Values of an iterator i for which the expression *i is defined are called dereferenceable. The library never assumes that past-the-end values are dereferenceable. Iterators can also have singular values that are not associated with any container. [...] Results of most expressions are undefined for singular values; the only exceptions are destroying an iterator that holds a singular value and the assignment of a non-singular value to an iterator that holds a singular value. [...] Dereferenceable values are always non-singular.
10 - An invalid iterator is an iterator that may be singular.
First, issue 208 intentionally removed the earlier constraint that past-the-end values are always non-singular. The reason for this was to support null pointers as past-the-end iterators of e.g. empty sequences. But there seem to exist different views on what a singular (iterator) value is. E.g. according to the SGI definition a null pointer is not a singular value:
Dereferenceable iterators are always nonsingular, but the converse is not true. For example, a null pointer is nonsingular (there are well defined operations involving null pointers) even thought it is not dereferenceable.
and proceeds:
An iterator is valid if it is dereferenceable or past-the-end.
Even if the standard prefers a different meaning of singular here, the change was incomplete, because by restricting feasible expressions of singular iterators to destruction and assignment isn't sufficient for a past-the-end iterator: Of-course it must still be equality-comparable and in general be a readable value.
Second, the standard doesn't clearly say whether a past-the-end value is a valid iterator or not. E.g. 20.7.12 [specialized.algorithms]/1 says:
In all of the following algorithms, the formal template parameter ForwardIterator is required to satisfy the requirements of a forward iterator (24.1.3) [..], and is required to have the property that no exceptions are thrown from [..], or dereference of valid iterators.
The standard should make better clear what "singular pointer" and "valid iterator" means. The fact that the meaning of a valid value has a core language meaning doesn't imply that for an iterator concept the term "valid iterator" has the same meaning.
Let me add a final example: In X [allocator.concepts.members] of N2914 we find:
pointer X::allocate(size_type n);11 Returns: a pointer to the allocated memory. [Note: if n == 0, the return value is unspecified. —end note]
[..]
void X::deallocate(pointer p, size_type n);Preconditions: p shall be a non-singular pointer value obtained from a call to allocate() on this allocator or one that compares equal to it.
If singular pointer value would include null pointers this make the preconditions unclear if the pointer value is a result of allocate(0): Since the return value is unspecified, it could be a null pointer. Does that mean that programmers need to check the pointer value for a null value before calling deallocate?
[ 2010-11-09 Daniel comments: ]
A later paper is in preparation.
[ 2010 Batavia: ]
Doesn't need to be resolved for Ox
[2014-02-20 Re-open Deferred issues as Priority 4]
Proposed resolution:
Consider to await the paper.
Section: 26.4 [complex.numbers] Status: LEWG Submitter: Ted Shaneyfelt Opened: 2009-09-26 Last modified: 2015-04-08
View other active issues in [complex.numbers].
View all other issues in [complex.numbers].
View all issues with LEWG status.
Discussion:
Concerning mathematically proper operation of the type:
complex<complex<T> >
Generally accepted mathematical semantics of such a construct correspond to quaternions through Cayly-Dickson construct
(w+xi) + (y+zi) j
The proper implementation seems straightforward by adding a few declarations like those below. I have included operator definition for combining real scalars and complex types, as well, which seems appropriate, as algebra of complex numbers allows mixing complex and real numbers with operators. It also allows for constructs such as complex<double> i=(0,1), x = 12.34 + 5*i;
Quaternions are often used in areas such as computer graphics, where, for example, they avoid the problem of Gimbal lock when rotating objects in 3D space, and can be more efficient than matrix multiplications, although I am applying them to a different field.
/////////////////////////ALLOW OPERATORS TO COMBINE REAL SCALARS AND COMPLEX VALUES ///////////////////////// template<typename T,typename S> complex<T> operator+(const complex<T> x,const S a) { complex<T> result(x.real()+a, x.imag()); return result; } template<typename T,typename S> complex<T> operator+(const S a,const complex<T> x) { complex<T> result(a+x.real(), x.imag()); return result; } template<typename T,typename S> complex<T> operator-(const complex<T> x,const S a) { complex<T> result(x.real()-a, x.imag()); return result; } template<typename T,typename S> complex<T> operator-(const S a,const complex<T> x) { complex<T> result(a-x.real(), x.imag()); return result; } template<typename T,typename S> complex<T> operator*(const complex<T> x,const S a) { complex<T> result(x.real()*a, x.imag()*a); return result; } template<typename T,typename S> complex<T> operator*(const S a,const complex<T> x) { complex<T> result(a*x.real(), a*x.imag()); return result; } /////////////////////////PROPERLY IMPLEMENT QUATERNION SEMANTICS///////////////////////// template<typename T> double normSq(const complex<complex<T> >q) { return q.real().real()*q.real().real() + q.real().imag()*q.real().imag() + q.imag().real()*q.imag().real() + q.imag().imag()*q.imag().imag(); } template<typename T> double norm(const complex<complex<T> >q) { return sqrt(normSq(q)); } /////// Cayley-Dickson Construction template<typename T> complex<complex<T> > conj(const complex<complex<T> > x) { complex<complex<T> > result(conj(x.real()),-x.imag()); return result; } template<typename T> complex<complex<T> > operator*(const complex<complex<T> > ab,const complex<complex<T> > cd) { complex<T> re(ab.real()*cd.real()-conj(cd.imag())*ab.imag()); complex<T> im(cd.imag()*ab.real()+ab.imag()*conj(cd.real())); complex<complex<double> > q(re,im); return q; } //// Quaternion division template<typename S,typename T> complex<complex<T> > operator/(const complex<complex<T> > q,const S a) { return q * (1/a); } template<typename S,typename T> complex<complex<T> > operator/(const S a,const complex<complex<T> > q) { return a*conj(q)/normSq(q); } template<typename T> complex<complex<T> > operator/(const complex<complex<T> > n, const complex<complex<T> > d) { return n * (conj(d)/normSq(d)); }
[ 2009-10 Santa Cruz: ]
NAD Future. There is no consensus or time to move this into C++0X.
Proposed resolution:
Section: X [rand.concept.dist] Status: LEWG Submitter: Matthias Troyer Opened: 2009-10-12 Last modified: 2015-04-08
View all issues with LEWG status.
Discussion:
There exist optimized, vectorized vendor libraries for the creation of random number generators, such as Intel's MKL [1] and AMD's ACML [2]. In timing tests we have seen a performance gain of a factor of up to 80 (eighty) compared to a pure C++ implementation (in Boost.Random) when using these generator to generate a sequence of normally distributed random numbers. In codes dominated by the generation of random numbers (we have application codes where random number generation is more than 50% of the CPU time) this factor 80 is very significant.
To make use of these vectorized generators, we use a C++ class modeling the RandomNumberEngine concept and forwarding the generation of random numbers to those optimized generators. For example:
namespace mkl { class mt19937 {.... }; }
For the generation of random variates we also want to dispatch to optimized vectorized functions in the MKL or ACML libraries. See this example:
mkl::mt19937 eng; std::normal_distribution<double> dist; double n = dist(eng);
Since the variate generation is done through the operator() of the distribution there is no customization point to dispatch to Intel's or AMD's optimized functions to generate normally distributed numbers based on the mt19937 generator. Hence, the performance gain of 80 cannot be achieved.
Contrast this with TR1:
mkl::mt19937 eng; std::tr1::normal_distribution<double> dist; std::tr1::variate_generator<mkl::mt19937,std::tr1::normal_distribution<double> > rng(eng,dist); double n = rng();
This - admittedly much uglier from an aestethic point of view - design allowed optimization by specializing the variate_generator template for mkl::mt19937:
namespace std { namespace tr1 { template<> class variate_generator<mkl::mt19937,std::tr1::normal_distribution<double> > { .... }; } }
A similar customization point is missing in the C++0x design and prevents the optimized vectorized version to be used.
Suggested resolution:
Add a customization point to the distribution concept. Instead of the variate_generator template this can be done through a call to a free function generate_variate found by ADL instead of operator() of the distribution:
template <RandomNumberDistribution, class RandomNumberEngine> typename RandomNumberDistribution ::result_type generate_variate(RandomNumberDistribution const& dist, RandomNumberEngine& eng);
This function can be overloaded for optimized enginges like mkl::mt19937.
[ 2009-10 Santa Cruz: ]
NAD Future. No time to add this feature for C++0X.
Proposed resolution:
Section: 25 [algorithms] Status: LEWG Submitter: Alisdair Meredith Opened: 2009-10-15 Last modified: 2015-04-08
View other active issues in [algorithms].
View all other issues in [algorithms].
View all issues with LEWG status.
Discussion:
The library has many algorithms that take a source range represented by a pair of iterators, and the start of some second sequence given by a single iterator. Internally, these algorithms will produce undefined behaviour if the second 'range' is not as large as the input range, but none of the algorithms spell this out in Requires clauses, and there is no catch-all wording to cover this in clause 17 or the front matter of 25.
There was an attempt to provide such wording in paper n2944 but this seems incidental to the focus of the paper, and getting the wording of this issue right seems substantially more difficult than the simple approach taken in that paper. Such wording will be removed from an updated paper, and hopefully tracked via the LWG issues list instead.
It seems there are several classes of problems here and finding wording to solve all in one paragraph could be too much. I suspect we need several overlapping requirements that should cover the desired range of behaviours.
Motivating examples:
A good initial example is the swap_ranges algorithm. Here there is a clear requirement that first2 refers to the start of a valid range at least as long as the range [first1, last1). n2944 tries to solve this by positing a hypothetical last2 iterator that is implied by the signature, and requires distance(first2,last2) < distance(first1,last1). This mostly works, although I am uncomfortable assuming that last2 is clearly defined and well known without any description of how to obtain it (and I have no idea how to write that).
A second motivating example might be the copy algorithm. Specifically, let us image a call like:
copy(istream_iterator<int>(is),istream_iterator(),ostream_iterator<int>(os));
In this case, our input iterators are literally simple InputIterators, and the destination is a simple OutputIterator. In neither case am I happy referring to std::distance, in fact it is not possible for the ostream_iterator at all as it does not meet the requirements. However, any wording we provide must cover both cases. Perhaps we might deduce last2 == ostream_iterator<int>{}, but that might not always be valid for user-defined iterator types. I can well imagine an 'infinite range' that writes to /dev/null and has no meaningful last2.
The motivating example in n2944 is std::equal, and that seems to fall somewhere between the two.
Outlying examples might be partition_copy that takes two output iterators, and the _n algorithms where a range is specified by a specific number of iterations, rather than traditional iterator pair. We should also not accidentally apply inappropriate constraints to std::rotate which takes a third iterator that is not intended to be a separate range at all.
I suspect we want some wording similar to:
For algorithms that operate on ranges where the end iterator of the second range is not specified, the second range shall contain at least as many elements as the first.
I don't think this quite captures the intent yet though. I am not sure if 'range' is the right term here rather than sequence. More awkwardly, I am not convinced we can describe an Output sequence such as produce by an ostream_iterator as "containing elements", at least not as a precondition to the call before they have been written.
Another idea was to describe require that the trailing iterator support at least distance(input range) applications of operator++ and may be written through the same number of times if a mutable/output iterator.
We might also consider handling the case of an output range vs. an input range in separate paragraphs, if that simplifies how we describe some of these constraints.
[ 2009-11-03 Howard adds: ]
Moved to Tentatively NAD Future after 5 positive votes on c++std-lib.
Rationale:
Does not have sufficient support at this time. May wish to reconsider for a future standard.
Proposed resolution:
Section: 23 [containers] Status: LEWG Submitter: Herb Sutter Opened: 2009-10-21 Last modified: 2015-04-08
View other active issues in [containers].
View all other issues in [containers].
View all issues with LEWG status.
Discussion:
See N2980.
[ 2009-10 Santa Cruz ]
The paper was lengthy discussed but considerable concern remained to add this feature to C++0x. Strong consensus was found to consider it for C++1x, though.
Proposed resolution:
The LWG does not wish to make a change at this time.
Section: 25 [algorithms] Status: LEWG Submitter: Igor Semenov Opened: 2009-12-07 Last modified: 2015-04-08
View other active issues in [algorithms].
View all other issues in [algorithms].
View all issues with LEWG status.
Discussion:
Motivation and Scope
Splitting strings into parts by some set of delimiters is an often task, but there is no simple and generalized solution in C++ Standard. Usually C++ developers use std::basic_stringstream<> to split string into parts, but there are several inconvenient restrictions:
Impact on the Standard
This algorithm doesn't interfere with any of current standard algorithms.
Design Decisions
This algorithm is implemented in terms of input/output iterators. Also, there is one additional wrapper for const CharType * specified delimiters.
Example implementation
template< class It, class DelimIt, class OutIt > void split( It begin, It end, DelimIt d_begin, DelimIt d_end, OutIt out ) { while ( begin != end ) { It it = std::find_first_of( begin, end, d_begin, d_end ); *out++ = std::make_pair( begin, it ); begin = std::find_first_of( it, end, d_begin, d_end, std::not2( std::equal_to< typename It::value_type >() ) ); } } template< class It, class CharType, class OutIt > void split( It begin, It end, const CharType * delim, OutIt out ) { split( begin, end, delim, delim + std::strlen( delim ), out ); }
Usage
std::string ss( "word1 word2 word3" ); std::vector< std::pair< std::string::const_iterator, std::string::const_iterator > > v; split( ss.begin(), ss.end(), " ", std::back_inserter( v ) ); for ( int i = 0; i < v.size(); ++i ) { std::cout << std::string( v[ i ].first, v[ i ].second ) << std::endl; } // word1 // word2 // word3
[ 2010-01-22 Moved to Tentatively NAD Future after 5 positive votes on c++std-lib. Rationale added below. ]
Rationale:
The LWG is not considering completely new features for standardization at this time. We would like to revisit this good suggestion for a future TR and/or standard.
Proposed resolution:
Add to the synopsis in 25.1 [algorithms.general]:
template< class ForwardIterator1, class ForwardIterator2, class OutputIterator > void split( ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 delimiter_first, ForwardIterator2 delimiter_last, OutputIterator result ); template< class ForwardIterator1, class CharType, class OutputIterator > void split( ForwardIterator1 first, ForwardIterator1 last, const CharType * delimiters, OutputIterator result );
Add a new section [alg.split]:
template< class ForwardIterator1, class ForwardIterator2, class OutputIterator > void split( ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 delimiter_first, ForwardIterator2 delimiter_last, OutputIterator result );1. Effects: splits the range [first, last) into parts, using any element of [delimiter_first, delimiter_last) as a delimiter. Results are pushed to output iterator in the form of std::pair<ForwardIterator1, ForwardIterator1>. Each of these pairs specifies a maximal subrange of [first, last) which does not contain a delimiter.
2. Returns: nothing.
3. Complexity: Exactly last - first assignments.
template< class ForwardIterator1, class CharType, class OutputIterator > void split( ForwardIterator1 first, ForwardIterator1 last, const CharType * delimiters, OutputIterator result );1. Effects: split the range [first, last) into parts, using any element of delimiters (interpreted as zero-terminated string) as a delimiter. Results are pushed to output iterator in the form of std::pair<ForwardIterator1, ForwardIterator1>. Each of these pairs specifies a maximal subrange of [first, last) which does not contain a delimiter.
2. Returns: nothing.
3. Complexity: Exactly last - first assignments.
Section: 20.2 [utility] Status: LEWG Submitter: Ion Gaztañaga Opened: 2009-12-14 Last modified: 2015-04-08
View other active issues in [utility].
View all other issues in [utility].
View all issues with LEWG status.
Discussion:
In section 17.6.3.5 [allocator.requirements], Table 40 — Allocator requirements, the following expression is required for allocator pointers:
Table 40 — Allocator requirements Expression Return type Assertion/note
pre-/post-conditionDefault static_cast<X::pointer>(w) X::pointer static_cast<X::pointer>(w) == p
To achieve this expression, a smart pointer writer must introduce an explicit conversion operator from smart_ptr<void> to smart_ptr<T> so that static_cast<pointer>(void_ptr) is a valid expression. Unfortunately this explicit conversion weakens the safety of a smart pointer since the following expression (invalid for raw pointers) would become valid:
smart_ptr<void> smart_v = ...; smart_ptr<T> smart_t(smart_v);
On the other hand, shared_ptr also defines its own casting functions in 20.8.2.2.9 [util.smartptr.shared.cast], and although it's unlikely that a programmer will use shared_ptr as allocator::pointer, having two different ways to do the same cast operation does not seem reasonable. A possible solution would be to replace static_cast<X::pointer>(w) expression with a user customizable (via ADL) static_pointer_cast<value_type>(w), and establish the xxx_pointer_cast functions introduced by shared_ptr as the recommended generic casting utilities of the standard.
Unfortunately, we've experienced problems in Boost when trying to establish xxx_pointer_cast as customization points for generic libraries (http://objectmix.com/c/40424-adl-lookup-explicit-template-parameters.html) because these casting functions are called with explicit template parameters and the standard says in 14.8.1 [temp.arg.explicit] p.8 "Explicit template argument specification":
8 ...But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply.
So we can do this:
template<class BasePtr> void generic_ptr_swap(BasePtr p) { //ADL customization point swap(p, p); //... }
but not the following:
template<class BasePtr> void generic_ptr_algo(BasePtr p) { typedef std::pointer_traits<BasePtr>::template rebind<Derived> DerivedPtr; DerivedPtr dp = static_pointer_cast<Derived>(p); }
The solution to make static_pointer_cast a customization point is to add a generic declaration (no definition) of static_pointer_cast in a namespace (like std) and apply "using std::static_pointer_cast" declaration to activate ADL:
namespace std{ template<typename U, typename T> unspecified static_pointer_cast(T&&) = delete; } template<class BasePtr> void generic_ptr_algo(BasePtr p) { typedef std::pointer_traits<BasePtr>::template rebind<Derived> DerivedPtr; //ADL applies because static_pointer_cast is made // visible according to [temp.arg.explicit]/8 using std::static_pointer_cast; DerivedPtr dp = static_pointer_cast<Derived>(p); //... }
A complete solution will need also the definition of static_pointer_cast for raw pointers, and this definition has been present in Boost (http://www.boost.org/boost/ pointer_cast.hpp) for years.
[ 2010-03-26 Daniel made editorial adjustments to the proposed wording. ]
[ Moved to NAD Future at 2010-11 Batavia ]
This is a new feature rather than a defect. It can be added later: "this is such a hairy area that people will put up with changes"
Proposed resolution:
Add to section 20.2 [utility] Utility components, Header <utility> synopsis:
// 20.3.X, generic pointer cast functions template<typename U, typename T> unspecified static_pointer_cast(T&&) = delete; template<typename U, typename T> unspecified dynamic_pointer_cast(T&&) = delete; template<typename U, typename T> unspecified const_pointer_cast(T&&) = delete; //Overloads for raw pointers template<typename U, typename T> auto static_pointer_cast(T* t) -> decltype(static_cast<U*>(t)); template<typename U, typename T> auto dynamic_pointer_cast(T* t) -> decltype(dynamic_cast<U*>(t)); template<typename U, typename T> auto const_pointer_cast(T* t) -> decltype(const_cast<U*>(t));
Add to section 20.2 [utility] Utility components, a new subclause 20.3.X Pointer cast utilities [pointer.cast]:
20.3.X Pointer cast utilities [pointer.cast]
1 The library defines generic pointer casting function templates so that template code can explicitly make these names visible and activate argument-dependent lookup for pointer cast calls.
//Generic declarations template<typename U, typename T> unspecified static_pointer_cast(T&&) = delete; template<typename U, typename T> unspecified dynamic_pointer_cast(T&&) = delete; template<typename U, typename T> unspecified const_pointer_cast(T&&) = delete;2 The library also defines overloads of these functions for raw pointers.
//Overloads for raw pointers template<typename U, typename T> auto static_pointer_cast(T* t) -> decltype(static_cast<U*>(t));Returns: static_cast<U*>(t)
template<typename U, typename T> auto dynamic_pointer_cast(T* t) -> decltype(dynamic_cast<U*>(t));Returns: dynamic_cast<U*>(t)
template<typename U, typename T> auto const_pointer_cast(T* t) -> decltype(const_cast<U*>(t));Returns: const_cast<U*>(t)
[Example:
#include <utility> //static_pointer_cast #include <memory> //pointer_traits class Base{}; class Derived : public Base{}; template<class BasePtr> void generic_pointer_code(BasePtr b) { typedef std::pointer_traits<BasePtr>::template rebind<Derived> DerivedPtr; using std::static_pointer_cast; //ADL applies now that static_pointer_cast is visible DerivedPtr d = static_pointer_cast<Derived>(b); }— end example]
Replace in section 17.6.3.5 [allocator.requirements] Table 40 — Allocator requirements, the following table entries for allocator pointers:
Table 40 — Allocator requirements Expression Return type Assertion/note
pre-/post-conditionDefault static_pointer_cast< X::pointerT>(w)X::pointer static_pointer_cast< X::pointerT>(w) == pstatic_pointer_cast< X::const_pointerconst T>(w)X::const_pointer static_pointer_cast< X::const_pointerconst T>(z) == q
Section: 20.9.13 [unord.hash] Status: LEWG Submitter: Nicolai M. Josuttis Opened: 2010-02-10 Last modified: 2015-04-08
View other active issues in [unord.hash].
View all other issues in [unord.hash].
View all issues with LEWG status.
Discussion:
Currently, the library lacks a convenient way to provide a hash function that can be used with the provided unordered containers to allow the usage of non trivial element types.
While we can easily declare an
std::unordered_set<int>
or
std::unordered_set<std::string>
we have no easy way to declare an unordered_set for a user defined type. IMO, this is a big obstacle to use unordered containers in practice. Note that in Java, the wide usage of HashMap is based on the fact that there is always a default hash function provided.
Of course, a default hash function implies the risk to provide poor hash functions. But often even poor hash functions are good enough.
While I really would like to see a default hash function, I don't propose it here because this would probably introduce a discussion that's too big for this state of C++0x.
However, I strongly suggest at least to provide a convenience variadic template function make_hash<>() to allow an easy definition of a (possibly poor) hash function.
As a consequence for a user-defined type such as
class Customer { friend class CustomerHash; private: string firstname; string lastname; long no; ... };
would allow to specify:
class CustomerHash : public std::unary_function<Customer, std::size_t> { public: std::size_t operator() (const Customer& c) const { return make_hash(c.firstname,c.lastname,c.no); } };
instead of:
class CustomerHash : public std::unary_function<Customer, std::size_t> { public: std::size_t operator() (const Customer& c) const { return std::hash<std::string>()(c.firstname) + std::hash<std::string>()(c.lastname) + std::hash<long>()(c.no); } };
Note that, in principle, we can either specify that
make_hash returns the sum of a call of std::hash<T>()(x) for each argument x of type T
or we can specify that
make_hash provides a hash value for each argument, for which a std::hash() function is provided
with the possible note that the hash value may be poor or only a good hash value if the ranges of all passed arguments is equally distributed.
For my convenience, I propose wording that describes the concrete implementation.
[ 2010 Pittsburgh: Moved to NAD Editorial, rationale added below. ]
Rationale:
There is no consensus to make this change at this time.
Proposed resolution:
In Function objects 20.9 [function.objects] in paragraph 2 at the end of the Header <functional> synopsis insert:
// convenience functions template <class T> size_t make_hash (const T&); template <class T, class... Types> size_t make_hash (const T&, const Types&...);
In Class template hash 20.9.13 [unord.hash] add:
20.7.16.1 Hash creation functions [hash.creation]
template <class T> size_t make_hash (const T& val);Returns: hash<T>()(val);
template <class T, class... Types> size_t make_hash (const T& val, const Types&... args);Returns: hash<T>()(val) + std::make_hash(args...)
Section: 24.3 [iterator.synopsis] Status: LEWG Submitter: Alisdair Meredith Opened: 2010-02-16 Last modified: 2015-04-08
View all other issues in [iterator.synopsis].
View all issues with LEWG status.
Discussion:
The iter_swap function template appears in the <algorithm> header, yet its main use is in building further algorithms, not calling existing ones. The main clients are implementers of data structures and their iterators, so it seems most appropriate to place the template in the <iterator> header instead.
Note that this is not an issue for implementers of the standard library, as they rarely use the standard headers directly, designing a more fine-grained set of headers for their own internal use. This option is not available to customers of the standard library.
Note that we cannot remove iter_swap from <algorithm> without breaking code, but there is no reason we cannot offer the same declaration via two standard headers. Alternatively, require <algorithm> to #include <iterator>, but introducing the dependency on the iterator adaptors seems un-necessary.
[ ]
Discussed possibly moving to <utility> but don't like that. Some not seeing this as a defect, and want to keep it in <algorithm>. No one seems to feel strongly about moving to <iterator>.
Proposed resolution:
Add the declaration of iter_swap to the <iterator> header synopsis (24.3 [iterator.synopsis]), with a note that it is documented in clause 25 [algorithms].
... template <class T, size_t N> T* end(T (&array)[N]); // documented in 25 [algorithms] template<class ForwardIterator1, class ForwardIterator2> void iter_swap(ForwardIterator1 a, ForwardIterator2 b);
Section: 28.8 [re.regex] Status: LEWG Submitter: INCITS Opened: 2010-08-25 Last modified: 2015-04-08
View all other issues in [re.regex].
View all issues with LEWG status.
Duplicate of: 1451
Discussion:
Addresses US-104, US-141
std::basic_regex should have an allocator for all the reasons that a std::string does. For example, I can use boost::interprocess to put a string or vector in shared memory, but not a regex.
[ Resolution proposed by ballot comment ]
Add allocators to regexes
[ 2010-10-24 Daniel adds: ]
Accepting n3171 would solve this issue.
[2011-03-22 Madrid]
Close 1396 as NAD Future.
Rationale:
No consensus for a change at this time
Proposed resolution:
Section: 20.8.2.2 [util.smartptr.shared] Status: LEWG Submitter: Japan Opened: 2010-08-25 Last modified: 2015-04-08
View other active issues in [util.smartptr.shared].
View all other issues in [util.smartptr.shared].
View all issues with LEWG status.
Discussion:
Addresses JP-5
Hash support based on ownership sharing should be supplied for shared_ptr and weak_ptr. For two shared_ptr objects p and q, two distinct equivalence relations can be defined. One is based on equivalence of pointer values, which is derived from the expression p.get() == q.get() (hereafter called address based equivalence relation), the other is based on equivalence of ownership sharing, which is derived from the expression !p.owner_before(q) && !q.owner_before(p) (hereafter called ownership-based equivalence relation). These two equivalence relations are independent in general. For example, a shared_ptr object created by the constructor of the signature shared_ptr(shared_ptr<U> const &, T *) could reveal a difference between these two relations. Therefore, hash support based on each equivalence relation should be supplied for shared_ptr. However, while the standard library provides the hash support for address-based one (20.9.11.6 paragraph 2), it lacks the hash support for ownership-based one. In addition, associative containers work well in combination with the shared_ptr's ownership-based comparison but unordered associative containers don't. This is inconsistent.
For the case of weak_ptr, hash support for the ownership based equivalence relation can be safely defined on weak_ptrs, and even on expired ones. The absence of hash support for the ownership-based equivalence relation is fatal, especially for expired weak_ptrs. And the absence of such hash support precludes some quite effective use-cases, e.g. erasing the unordered_map entry of an expired weak_ptr key from a customized deleter supplied to shared_ptrs.
Hash support for the ownership-based equivalence relation cannot be provided by any user-defined manner because information about ownership sharing is not available to users at all. Therefore, the only way to provide ownership-based hash support is to offer it intrusively by the standard library.
As far as we know, such hash support is implementable. Typical implementation of such hash function could return the hash value of the pointer of the counter object that is internally managed by shared_ptr and weak_ptr.
[2010 Rapperswil:]
No consensus to make this change at this time.
Proposed resolution:
Add the following non-static member functions to shared_ptr and weak_ptr class template;
Update [util.smartptr.shared], 20.9.11.2 paragraph 1
namespace std{ template<class T> class shared_ptr { public: ... size_t owner_hash() const; ... }; }
Update [util.smartptr.weak], 20.9.11.3 paragraph 1
namespace std{ template<class T> class weak_ptr { public: ... size_t owner_hash() const; ... }; }
These functions satisfy the following requirements. Let p and q be objects of either shared_ptr or weak_ptr, H be a hypothetical function object type that satisfies the hash requirements ([hash.requirements], 20.2.4) and h be an object of the type H. The expression p.owner_hash() behaves as if it were equivalent to the expression h(p). In addition, h(p) == h(q) must become true if p and q share ownership.
Section: 23.3.7 [vector.bool] Status: LEWG Submitter: BSI Opened: 2010-08-25 Last modified: 2015-04-08
View all other issues in [vector.bool].
View all issues with LEWG status.
Discussion:
Addresses GB-118
vector<bool> iterators are not random access iterators because their reference type is a special class, and not bool &. All standard libary operations taking iterators should treat this iterator as if it was a random access iterator, rather than a simple input iterator.
[ Resolution proposed in ballot comment ]
Either revise the iterator requirements to support proxy iterators (restoring functionality that was lost when the Concept facility was removed) or add an extra paragraph to the vector<bool> specification requiring the library to treat vector<bool> iterators as-if they were random access iterators, despite having the wrong reference type.
[ Rapperswil Review ]
The consensus at Rapperswil is that it is too late for full support for proxy iterators, but requiring the library to respect vector<bool> iterators as-if they were random access would be preferable to flagging this container as deliberately incompatible with standard library algorithms.
Alisdair to write the note, which may become normative Remark depending on the preferences of the project editor.
[ Post-Rapperswil Alisdair provides wording ]
Initial wording is supplied, deliberately using Note in preference to Remark although the author notes his preference for Remark. The issue of whether iterator_traits<vector<bool>>::iterator_category is permitted to report random_access_iterator_tag or must report input_iterator_tag is not addressed.
[ Old Proposed Resolution: ]
Insert a new paragraph into 23.3.7 [vector.bool] between p4 and p5:
[Note All functions in the library that take a pair of iterators to denote a range shall treat vector<bool> iterators as-if they were random access iterators, even though the reference type is not a true reference.-- end note]
[ 2010-11 Batavia: ]
Closed as NAD Future, because the current iterator categories cannot correctly describe vector<bool>::iterator. But saying that they are Random Access Iterators is also incorrect, because it is not too hard to create a corresponding test that fails. We should deal with the more general proxy iterator problem in the future, and see no benefit to take a partial workaround specific to vector<bool> now.
Proposed resolution:
Rationale:
No consensus to make this change at this time.
Section: 29.3 [atomics.order] Status: LEWG Submitter: Canada Opened: 2010-08-25 Last modified: 2015-04-08
View other active issues in [atomics.order].
View all other issues in [atomics.order].
View all issues with LEWG status.
Duplicate of: 1458
Discussion:
Addresses CA-21, GB-131
29.4 [atomics.lockfree] p.8 states:
An atomic store shall only store a value that has been computed from constants and program input values by a finite sequence of program evaluations, such that each evaluation observes the values of variables as computed by the last prior assignment in the sequence.
... but 1.9 [intro.execution] p.13 states:
If A is not sequenced before B and B is not sequenced before A, then A and B are unsequenced. [ Note: The execution of unsequenced evaluations can overlap. — end note ]
Overlapping executions can make it impossible to construct the sequence described in 29.4 [atomics.lockfree] p.8. We are not sure of the intention here and do not offer a suggestion for change, but note that 29.4 [atomics.lockfree] p.8 is the condition that prevents out-of-thin-air reads.
For an example, suppose we have a function invocation f(e1,e2). The evaluations of e1 and e2 can overlap. Suppose that the evaluation of e1 writes y and reads x whereas the evaluation of e2 reads y and writes x, with reads-from edges as below (all this is within a single thread).
e1 e2 Wrlx y-- --Wrlx x rf\ /rf X / \ Rrlx x<- ->Rrlx y
This seems like it should be allowed, but there seems to be no way to produce a sequence of evaluations with the property above.
In more detail, here the two evaluations, e1 and e2, are being executed as the arguments of a function and are consequently not sequenced-before each other. In practice we'd expect that they could overlap (as allowed by 1.9 [intro.execution] p.13), with the two writes taking effect before the two reads. However, if we have to construct a linear order of evaluations, as in 29.4 [atomics.lockfree] p.8, then the execution above is not permited. Is that really intended?
[ Resolution proposed by ballot comment ]
Please clarify.
[2011-03-09 Hans comments:]
I'm not proud of 29.3 [atomics.order] p9 (formerly p8), and I agree with the comments that this isn't entirely satisfactory. 29.3 [atomics.order] p9 was designed to preclude out-of-thin-air results for races among memory_order_relaxed atomics, in spite of the fact that Java experience has shown we don't really know how to do that adequately. In the long run, we probably want to revisit this.
However, in the short term, I'm still inclined to declare this NAD, for two separate reasons:1.9 [intro.execution] p15 states: "If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined." I think the examples presented here have undefined behavior as a result. It's not completely clear to me whether examples can be constructed that exhibit this problem, and don't have undefined behavior.
This comment seems to be using a different meaning of "evaluation" from what is used elsewhere in the standard. The sequence of evaluations here doesn't have to consist of full expression evaluations. They can be evaluations of operations like lvalue to rvalue conversion, or individual assignments. In particular, the reads and writes executed by e1 and e2 in the example could be treated as separate evaluations for purposes of producing the sequence. The definition of "sequenced before" in 1.9 [intro.execution] makes little sense if the term "evaluation" is restricted to any notion of complete expression. Perhaps we should add yet another note to clarify this? 29.3 [atomics.order] p10 probably leads to the wrong impression here.
An alternative resolution would be to simply delete our flakey attempt at preventing out-of-thin-air reads, by removing 29.3 [atomics.order] p9-11, possibly adding a note that explains that we technically allow, but strongly discourage them. If we were starting this from scratch now, that would probably be my preference. But it seems like too drastic a resolution at this stage.[2011-03-24 Madrid]
Moved to NAD Future
Proposed resolution:
Section: 30.3.1 [thread.thread.class] Status: LEWG Submitter: INCITS Opened: 2010-08-25 Last modified: 2015-04-08
View all issues with LEWG status.
Discussion:
Addresses US-183
There is no way to join a thread with a timeout.
[ Resolution proposed by ballot comment: ]
Add join_for and join_until. Or decide one should never join a thread with a timeout since pthread_join doesn't have a timeout version.
[ 2010 Batavia ]
The concurrency working group deemed this an extension beyond the scope of C++0x.
Rationale:
The LWG does not wish to make a change at this time.
Proposed resolution:
Section: 30.4 [thread.mutex] Status: LEWG Submitter: INCITS Opened: 2010-08-25 Last modified: 2015-04-08
View all other issues in [thread.mutex].
View all issues with LEWG status.
Discussion:
Addresses US-185
Cooperate with WG14 to improve interoperability between the C++0x and C1x threads APIs. In particular, C1x mutexes should be conveniently usable with a C++0x lock_guard. Performance overheads for this combination should be considered.
[ Resolution proposed by ballot comment: ]
Remove C++0x timed_mutex and timed_recursive_mutex if that facilitates development of more compatible APIs.
[ 2010 Batavia ]
The concurrency sub-group reviewed the options, and decided that closer harmony should wait until both standards are published.
Rationale:
The LWG does not wish to make any change at this time.
Proposed resolution:
Section: 30.4.1 [thread.mutex.requirements] Status: LEWG Submitter: INCITS Opened: 2010-08-25 Last modified: 2015-04-08
View other active issues in [thread.mutex.requirements].
View all other issues in [thread.mutex.requirements].
View all issues with LEWG status.
Discussion:
Addresses US-189
mutex and recursive_mutex should have an is_locked() member function. is_locked allows a user to test a lock without acquiring it and can be used to implement a lightweight try_try_lock.
[ Resolution proposed by ballot comment: ]
Add a member function:
bool is_locked() const;to std::mutex and std::recursive_mutex. These functions return true if the current thread would not be able to obtain a mutex. These functions do not synchronize with anything (and, thus, can avoid a memory fence).
[ 2010 Batavia ]
The Concurrency subgroup reviewed this issue and deemed it to be an extension to be handled after publishing C++0x.
Rationale:
The LWG does not wish to make a change at this time.
Proposed resolution:
Section: 30.5 [thread.condition] Status: LEWG Submitter: INCITS Opened: 2010-08-25 Last modified: 2015-04-08
View all other issues in [thread.condition].
View all issues with LEWG status.
Discussion:
Addresses US-193
Condition variables preclude a wakeup optimization.
[ Resolution proposed by ballot comment: ]
Change condition_variable to allow such optimization. See Appendix 1 - Additional Details
[ 2010 Batavia ]
The Concurrency subgroup reviewed the issue, and deemed it an extension to be handled after C++0x.
Rationale:
The LWG does not wish to make the change at this time.
Proposed resolution:
Section: 23.2.1 [container.requirements.general] Status: LEWG Submitter: Mike Spertus Opened: 2010-10-16 Last modified: 2015-04-08
View other active issues in [container.requirements.general].
View all other issues in [container.requirements.general].
View all issues with LEWG status.
Discussion:
Addresses US-104, US-141
The standard doesn't say that containers should use abstract pointer types internally. Both Howard and Pablo agree that this is the intent. Further, it is necessary for containers to be stored, for example, in shared memory with an interprocess allocator (the type of scenario that allocators are intended to support).
In spite of the (possible) agreement on intent, it is necessary to make this explicit:
An implementations may like to store the result of dereferencing the pointer (which is a raw reference) as an optimization, but that prevents the data structure from being put in shared memory, etc. In fact, a container could store raw references to the allocator, which would be a little weird but conforming as long as it has one by-value copy. Furthermore, pointers to locales, ctypes, etc. may be there, which also prevents the data structure from being put in shared memory, so we should make explicit that a container does not store raw pointers or references at all.
[ Pre-batavia ]
This issue is being opened as part of the response to NB comments US-104/141. See paper N3171 in the pre-Batavia mailing.
[2011-03-23 Madrid meeting]
Deferred
[ 2011 Batavia ]
This may be an issue, but it is not clear. We want to gain a few years experience with the C++11 allocator model to see if this is already implied by the existing specification.
Proposed resolution:
Add to the end of 23.2.1 [container.requirements.general] p. 8:
[..] In all container types defined in this Clause, the member get_allocator() returns a copy of the allocator used to construct the container or, if that allocator has been replaced, a copy of the most recent replacement. The container may not store internal objects whose types are of the form T * or T & except insofar as they are part of the item type or members.
Section: 17.6.5.9 [res.on.data.races] Status: Open Submitter: BSI Opened: 2011-03-24 Last modified: 2015-04-08
View all issues with Open status.
Discussion:
Addresses GB-111
Section 17.6.5.9 [res.on.data.races], Data Race Avoidance, requires the C++ Standard Library to avoid data races that might otherwise result from two threads making calls to C++ Standard Library functions on distinct objects. The C standard library is part of the C++ Standard Library and some C++ Standary library functions (parts of the Localization library, as well as Numeric Conversions in 21.5), are specified to make use of the C standard library. Therefore, the C++ standard indirectly imposes a requirement on the thread safety of the C standard library. However, since the C standard does not address the concept of thread safety conforming C implementations exist that do no provide such guarantees. This conflict needs to be reconciled.
Suggested resolution by national body comment:
remove the requirement to make use of strtol() and sprintf() since these functions depend on the global C locale and thus cannot be made thread safe.
[2011-03-24 Madrid meeting]
Deferred
[ 2011 Bloomington ]
Alisdair: PJ, does this cause a problem in C?
PJ: Every implementation know of is thread safe.
Pete: There a couple of effects that are specified on strtol() and sprintf() which is a problem.
PJ: When C++ talks about C calls it should be "as if" calling the function.
Pete: Culprit is to string stuff. My fault.
PJ: Not your fault. You did what you were told. Distinct resolution to change wording.
Dietmar: What would we break if we change it back?
Pete: Nothing. If implemented on top of thread safe C library you are just fine.
Alisdair: Anyone want to clean up wording and put it back to what Pete gave us?
Alisdair: No volunteers. Do we want to mark as NAD? We could leave it as deferred.
Stefanus: Did original submitter care about this?
Lawrence: There is some work to make local calls thread safe. The resolution would be to call those thread safe version.
Pete: "As if called under single threaded C program"
Action Item (Alisdair): Write wording for this issue.
[2012, Kona]
Re-opened at the request of the concurrency subgroup, who feel there is an issue that needs clarifying for the (planned) 2017 standard.
Rationale:
No consensus to make a change at this time
[2012, Portland]
The concurrency subgroup decided to encourage the LWG to consider a change to 17.2 [library.c] or thereabouts to clarify that we are requiring C++-like thread-safety for setlocale, so that races are not introduced by C locale accesses, even when the C library allows it. This would require e.g. adding "and data race avoidance" at the end of 17.2 [library.c] p1:
"The C++ standard library also makes available the facilities of the C standard library, suitably adjusted to ensure static type safety and data race avoidance.",
with some further clarifications in the sections mentioned in 1526.
This seems to be consistent with existing implementations. This would technically not be constraining C implementation, but it would be further constraining C libraries used for both C and C++.
Proposed resolution:
This wording is relative to N3376.
Change 17.2 [library.c] p1 as indicated:
-1- The C++ standard library also makes available the facilities of the C standard library, suitably adjusted to ensure static type safety and data race avoidance.
Section: 24.2.4 [output.iterators] Status: Open Submitter: Daniel Krügler Opened: 2011-02-27 Last modified: 2015-04-08
View other active issues in [output.iterators].
View all other issues in [output.iterators].
View all issues with Open status.
Discussion:
During the Pittsburgh meeting the proposal N3066 became accepted because it fixed several severe issues related to the iterator specification. But the current working draft (N3225) does not reflect all these changes. Since I'm unaware whether every correction can be done editorial, this issue is submitted to take care of that. To give one example: All expressions of Table 108 — "Output iterator requirements" have a post-condition that the iterator is incrementable. This is impossible, because it would exclude any finite sequence that is accessed by an output iterator, such as a pointer to a C array. The N3066 wording changes did not have these effects.
[2011-03-01: Daniel comments:]
This issue has some overlap with the issue 2038 and I would prefer if we could solve both at one location. I suggest the following approach:
The terms dereferencable and incrementable could be defined in a more general way not restricted to iterators (similar to the concepts HasDereference and HasPreincrement from working draft N2914). But on the other hand, all current usages of dereferencable and incrementable are involved with types that satisfy iterator requirements. Thus, I believe that it is sufficient for C++0x to add corresponding definitions to 24.2.1 [iterator.requirements.general] and to let all previous usages of these terms refer to this sub-clause. Since the same problem occurs with the past-the-end iterator, this proposal suggest providing similar references to usages that precede its definition as well.
We also need to ensure that all iterator expressions get either an operational semantics in terms of others or we need to add missing pre- and post-conditions. E.g. we have the following ones without semantics:
*r++ = o // output iterator *r-- // bidirectional iterator
According to the SGI specification these correspond to
{ *r = o; ++r; } // output iterator { reference tmp = *r; --r; return tmp; } // bidirectional iterator
respectively. Please note especially the latter expression for bidirectional iterator. It fixes a problem that we have for forward iterator as well: Both these iterator categories provide stronger guarantees than input iterator, because the result of the dereference operation is reference, and not only convertible to the value type (The exact form from the SGI documentation does not correctly refer to reference).
[2011-03-14: Daniel comments and updates the suggested wording]
In addition to the before mentioned necessary changes there is another one need, which became obvious due to issue 2042: forward_list<>::before_begin() returns an iterator value which is not dereferencable, but obviously the intention is that it should be incrementable. This leads to the conclusion that imposing dereferencable as a requirement for the expressions ++r is wrong: We only need the iterator to be incrementable. A similar conclusion applies to the expression --r of bidirectional iterators.
[ 2011 Bloomington ]
Consensus this is the correct direction, but there are (potentially) missing incrementable preconditions on some table rows, and the Remarks on when an output iterator becomes dereferencable are probably better handled outside the table, in a manner similar to the way we word for input iterators.
There was some concern about redundant pre-conditions when the operational semantic is defined in terms of operations that have preconditions, and a similar level of concern over dropping such redundancies vs. applying a consistent level of redundant specification in all the iterator tables. Wording clean-up in either direction would be welcome.
[2011-08-18: Daniel adapts the proposed resolution to honor the Bloomington request]
There is only a small number of further changes suggested to get rid of superfluous requirements and essentially non-normative assertions. Operations should not have extra pre-conditions, if defined by "in-terms-of" semantics, see e.g. a != b or a->m for Table 107. Further, some remarks, that do not impose anything or say nothing new have been removed, because I could not find anything helpful they provide. E.g. consider the remarks for Table 108 for the operations dereference-assignment and preincrement: They don't provide additional information say nothing surprising. With the new pre-conditions and post-conditions it is implied what the remarks intend to say.
[ 2011-11-03: Some observations from Alexander Stepanov via c++std-lib-31405 ]
The following sentence is dropped from the standard section on OutputIterators:
"In particular, the following two conditions should hold: first, any iterator value should be assigned through before it is incremented (this is, for an output iterator i, i++; i++; is not a valid code sequence); second, any value of an output iterator may have at most one active copy at any given time (for example, i = j; *++i = a; *j = b; is not a valid code sequence)."[ 2011-11-04: Daniel comments and improves the wording ]
In regard to the first part of the comment, the intention of the newly proposed wording was to make clear that for the expression
*r = o
we have the precondition dereferenceable and the post-condition incrementable. And for the expression
++r
we have the precondition incrementable and the post-condition dereferenceable or past-the-end. This should not allow for a sequence like i++; i++; but I agree that it doesn't exactly say that.
In regard to the second point: To make this point clearer, I suggest to add a similar additional wording as we already have for input iterator to the "Assertion/note" column of the expression ++r: "Post: any copies of the previous value of r are no longer required to be dereferenceable or incrementable." The proposed has been updated to honor the observations of Alexander Stepanov.[2015-02 Cologne]
The matter is complicated, Daniel volunteers to write a paper.
Proposed resolution:
Add a reference to 24.2.1 [iterator.requirements.general] to the following parts of the library preceding Clause 24 Iterators library: (I stopped from 23.2.5 [unord.req] on, because the remaining references are the concrete containers)
17.6.3.2 [swappable.requirements] p5:
-5- A type X satisfying any of the iterator requirements (24.2) is ValueSwappable if, for any dereferenceable (24.2.1 [iterator.requirements.general]) object x of type X, *x is swappable.
17.6.3.5 [allocator.requirements], Table 27 — "Descriptive variable definitions", row with the expression c:
a dereferenceable (24.2.1 [iterator.requirements.general]) pointer of type C*
20.7.3.2 [pointer.traits.functions]:
Returns: The first template function returns a dereferenceable (24.2.1 [iterator.requirements.general]) pointer to r obtained by calling Ptr::pointer_to(r); […]
21.4.3 [string.iterators] p. 2:
Returns: An iterator which is the past-the-end value (24.2.1 [iterator.requirements.general]).
22.4.5.1.2 [locale.time.get.virtuals] p. 11:
iter_type do_get(iter_type s, iter_type end, ios_base& f, ios_base::iostate& err, tm *t, char format, char modifier) const;Requires: t shall be dereferenceable (24.2.1 [iterator.requirements.general]).
23.2.1 [container.requirements.general] p. 6:
[…] end() returns an iterator which is the past-the-end (24.2.1 [iterator.requirements.general]) value for the container. […]
23.2.3 [sequence.reqmts] p. 3:
[…] q denotes a valid dereferenceable (24.2.1 [iterator.requirements.general]) const iterator to a, […]
23.2.4 [associative.reqmts] p. 8 (I omit intentionally one further reference in the same sub-clause):
[…] q denotes a valid dereferenceable (24.2.1 [iterator.requirements.general]) const iterator to a, […]
23.2.5 [unord.req] p. 10 (I omit intentionally one further reference in the same sub-clause):
[…] q and q1 are valid dereferenceable (24.2.1 [iterator.requirements.general]) const iterators to a, […]
Edit 24.2.1 [iterator.requirements.general] p. 5 as indicated (The intent is to properly define incrementable and to ensure some further library guarantee related to past-the-end iterator values):
-5- Just as a regular pointer to an array guarantees that there is a pointer value pointing past the last element of the array, so for any iterator type there is an iterator value that points past the last element of a corresponding sequence. These values are called past-the-end values. Values of an iterator i for which the expression *i is defined are called dereferenceable. Values of an iterator i for which the expression ++i is defined are called incrementable. The library never assumes that past-the-end values are dereferenceable or incrementable. Iterators can also have singular values that are not associated with any sequence. […]
Modify the column contents of Table 106 — "Iterator requirements", 24.2.2 [iterator.iterators], as indicated:
Table 106 — Iterator requirements Expression Return type Operational semantics Assertion/note
pre-/post-condition*r reference pre: r is dereferenceable. ++r X& pre: r is incrementable.
Modify the column contents of Table 107 — "Input iterator requirements", 24.2.3 [input.iterators], as indicated [Rationale: The wording changes attempt to define a minimal "independent" set of operations, namely *a and ++r, and to specify the semantics of the remaining ones. This approach seems to be in agreement with the original SGI specification — end rationale]:
Table 107 — Input iterator requirements (in addition to Iterator) Expression Return type Operational semantics Assertion/note
pre-/post-conditiona != b contextually
convertible to bool!(a == b) pre: (a, b) is in the domain
of ==.*a convertible to T pre: a is dereferenceable.
The expression
(void)*a, *a is equivalent
to *a.
If a == b and (a,b) is in
the domain of == then *a is
equivalent to *b.a->m (*a).m pre: a is dereferenceable.++r X& pre: r is dereferenceableincrementable.
post: r is dereferenceable or
r is past-the-end.
post: any copies of the
previous value of r are no
longer required either to be
dereferenceable, incrementable,
or to be in the domain of ==.(void)r++ (void)++r equivalent to (void)++r*r++ convertible to T { T tmp = *r;
++r;
return tmp; }
Modify the column contents of Table 108 — "Output iterator requirements", 24.2.4 [output.iterators], as indicated [Rationale: The wording changes attempt to define a minimal "independent" set of operations, namely *r = o and ++r, and to specify the semantics of the remaining ones. This approach seems to be in agreement with the original SGI specification — end rationale]:
Table 108 — Output iterator requirements (in addition to Iterator) Expression Return type Operational semantics Assertion/note
pre-/post-condition*r = o result is not used pre: r is dereferenceable.
Remark: After this operation
r is not required to be
dereferenceable and any copies of
the previous value of r are no
longer required to be dereferenceable
or incrementable.
post: r is incrementable.++r X& pre: r is incrementable.
&r == &++r.
Remark: After this operationRemark: After this operation
r is not required to be
dereferenceable.
r is not required to be
incrementable and any copies of
the previous value of r are no
longer required to be dereferenceable
or incrementable.
post: r is dereferenceable
or r is past-the-endincrementable.
r++ convertible to const X& { X tmp = r;
++r;
return tmp; }Remark: After this operation
r is not required to be
dereferenceable.
post: r is incrementable.*r++ = o result is not used { *r = o; ++r; } Remark: After this operation
r is not required to be
dereferenceable.
post: r is incrementable.
Modify the column contents of Table 109 — "Forward iterator requirements", 24.2.5 [forward.iterators], as indicated [Rationale: Since the return type of the expression *r++ is now guaranteed to be type reference, the implied operational semantics from input iterator based on value copies is wrong — end rationale]
Table 109 — Forward iterator requirements (in addition to input iterator) Expression Return type Operational semantics Assertion/note
pre-/post-conditionr++ convertible to const X& { X tmp = r;
++r;
return tmp; }*r++ reference { reference tmp = *r;
++r;
return tmp; }
Modify the column contents of Table 110 — "Bidirectional iterator requirements", 24.2.6 [bidirectional.iterators], as indicated:
Table 110 — Bidirectional iterator requirements (in addition to forward iterator) Expression Return type Operational semantics Assertion/note
pre-/post-condition--r X& pre: there exists s such that
r == ++s.
post: r isdereferenceableincrementable.
--(++r) == r.
--r == --s implies r == s.
&r == &--r.r-- convertible to const X& { X tmp = r;
--r;
return tmp; }*r-- reference { reference tmp = *r;
--r;
return tmp; }
Section: 24.2.4 [output.iterators] Status: Open Submitter: Pete Becker Opened: 2011-02-27 Last modified: 2015-04-08
View other active issues in [output.iterators].
View all other issues in [output.iterators].
View all issues with Open status.
Discussion:
In comp.lang.c++, Vicente Botet raises the following questions:
"In "24.2.4 Output iterators" there are 3 uses of incrementable. I've not found the definition. Could some one point me where it is defined?
Something similar occurs with dereferenceable. While the definition is given in "24.2.1 In general" it is used several times before. Shouldn't these definitions be moved to some previous section?"
He's right: both terms are used without being properly defined.
There is no definition of "incrementable". While there is a definition of "dereferenceable", it is, in fact, a definition of "dereferenceable iterator". "dereferenceable" is used throughout Clause 23 (Containers) before its definition in Clause 24. In almost all cases it's referring to iterators, but in 17.6.3.2 [swappable.requirements] there is a mention of "dereferenceable object"; in 17.6.3.5 [allocator.requirements] the table of Descriptive variable definitions refers to a "dereferenceable pointer"; 20.7.3.2 [pointer.traits.functions] refers to a "dereferenceable pointer"; in 22.4.5.1.2 [locale.time.get.virtuals]/11 (do_get) there is a requirement that a pointer "shall be dereferenceable". In those specific cases it is not defined.[2011-03-02: Daniel comments:]
I believe that the currently proposed resolution of issue 2035 solves this issue as well.
[ 2011 Bloomington ]
Agree with Daniel, this will be handled by the resolution of 2035.
Proposed resolution:
Section: 20.10 [meta] Status: LEWG Submitter: Daniel Krügler Opened: 2011-03-03 Last modified: 2015-04-08
View other active issues in [meta].
View all other issues in [meta].
View all issues with LEWG status.
Discussion:
When n3142 was suggested, it concentrated on constructions, assignments, and destructions, but overlooked to complement the single remaining compiler-support trait
template <class From, class To> struct is_convertible;
with the no-throw and triviality related aspects as it had been done with the other expression-based traits. Specifically, the current specification misses to add the following traits:
template <class From, class To> struct is_nothrow_convertible; template <class From, class To> struct is_trivially_convertible;
In particular the lack of is_nothrow_convertible is severly restricting. This was recently recognized when the proposal for decay_copy was prepared by n3255. There does not exist a portable means to define the correct conditional noexcept specification for the decay_copy function template, which is declared as:
template <class T> typename decay<T>::type decay_copy(T&& v) noexcept(???);
The semantics of decay_copy bases on an implicit conversion which again influences the overload set of functions that are viable here. In most circumstances this will have the same effect as comparing against the trait std::is_nothrow_move_constructible, but there is no guarantee for that being the right answer. It is possible to construct examples, where this would lead to the false result, e.g.
struct S { S(const S&) noexcept(false); template<class T> explicit S(T&&) noexcept(true); };
std::is_nothrow_move_constructible will properly honor the explicit template constructor because of the direct-initialization context which is part of the std::is_constructible definition and will in this case select it, such that std::is_nothrow_move_constructible<S>::value == true, but if we had the traits is_nothrow_convertible, is_nothrow_convertible<S, S>::value would evaluate to false, because it would use the copy-initialization context that is part of the is_convertible definition, excluding any explicit constructors and giving the opposite result.
The decay_copy example is surely not one of the most convincing examples, but is_nothrow_convertible has several use-cases, and can e.g. be used to express whether calling the following implicit conversion function could throw an exception or not:
template<class T, class U> T implicit_cast(U&& u) noexcept(is_nothrow_convertible<U, T>::value) { return std::forward<U>(u); }
Therefore I suggest to add the missing trait is_nothrow_convertible and for completeness also the missing trait is_trivially_convertible to 20.10 [meta].
[2011-03-24 Madrid meeting]
Daniel K: This is a new feature so out of scope.
Pablo: Any objections to moving 2040 to Open? No objections.[Bloomington, 2011]
Move to NAD Future, this would be an extension to existing functionality.
Proposed resolution:
Ammend the following declarations to the header <type_traits> synopsis in 20.10.2 [meta.type.synop]:
namespace std { … // 20.9.6, type relations: template <class T, class U> struct is_same; template <class Base, class Derived> struct is_base_of; template <class From, class To> struct is_convertible; template <class From, class To> struct is_trivially_convertible; template <class From, class To> struct is_nothrow_convertible; … }
Modify Table 51 — "Type relationship predicates" as indicated. The removal of the remaining traces of the trait is_explicitly_convertible is an editorial step, it was removed by n3047:
Table 51 — Type relationship predicates Template Condition Comments … template <class From, class To>
struct is_convertible;see below From and To shall be complete
types, arrays of unknown bound, or
(possibly cv-qualified) void
types.template <class From, class To>
struct is_explicitly_convertible;is_constructible<To, From>::valuea synonym for a two-argument
version of is_constructible.
An implementation may define it
as an alias template.template <class From, class To>
struct is_trivially_convertible;is_convertible<From,
To>::value is true and the
conversion, as defined by
is_convertible, is known
to call no operation that is
not trivial ([basic.types], [special]).From and To shall be complete
types, arrays of unknown bound,
or (possibly cv-qualified) void
types.template <class From, class To>
struct is_nothrow_convertible;is_convertible<From,
To>::value is true and the
conversion, as defined by
is_convertible, is known
not to throw any
exceptions ([expr.unary.noexcept]).From and To shall be complete
types, arrays of unknown bound,
or (possibly cv-qualified) void
types.…
Section: 20.4.2 [tuple.tuple], 20.4.2.1 [tuple.cnstr] Status: Open Submitter: Ville Voutilainen Opened: 2011-05-01 Last modified: 2015-04-08
View all other issues in [tuple.tuple].
View all issues with Open status.
Discussion:
One of my constituents wrote the following:
-------snip------------ So far the only use I've found for std::tuple is as an ad-hoc type to emulate multiple return values. If the tuple ctor was made non-explicit one could almost think C++ supported multiple return values especially when combined with std::tie().// assume types line_segment and point // assume function double distance(point const&, point const&) std::tuple<point, point> closest_points(line_segment const& a, line_segment const& b) { point ax; point bx; /* some math */ return {ax, bx}; } double distance(line_segment const& a, line_segment const& b) { point ax; point bx; std::tie(ax, bx) = closest_points(a, b); return distance(ax, bx); }
-------snap----------
See also the messages starting from lib-29330. Some notes:I would recommend making non-unary tuple constructors non-explicit.
[Bloomington, 2011]
Move to NAD Future, this would be an extension to existing functionality.
[Portland, 2012]
Move to Open at the request of the Evolution Working Group.
Proposed resolution:
Section: 26.7 [numeric.ops] Status: LEWG Submitter: Chris Jefferson Opened: 2011-01-01 Last modified: 2015-04-08
View all other issues in [numeric.ops].
View all issues with LEWG status.
Discussion:
The C++0x draft says std::accumulate uses: acc = binary_op(acc, *i).
Eelis van der Weegen has pointed out, on the libstdc++ mailing list, that using acc = binary_op(std::move(acc), *i) can lead to massive improvements (particularly, it means accumulating strings is linear rather than quadratic). Consider the simple case, accumulating a bunch of strings of length 1 (the same argument holds for other length buffers). For strings s and t, s+t takes time length(s)+length(t), as you have to copy both s and t into a new buffer. So in accumulating n strings, step i adds a string of length i-1 to a string of length 1, so takes time i. Therefore the total time taken is: 1+2+3+...+n = O(n2) std::move(s)+t, for a "good" implementation, is amortized time length(t), like vector, just copy t onto the end of the buffer. So the total time taken is: 1+1+1+...+1 (n times) = O(n). This is the same as push_back on a vector. I'm trying to decide if this implementation might already be allowed. I suspect it might not be (although I can't imagine any sensible code it would break). There are other algorithms which could benefit similarly (inner_product, partial_sum and adjacent_difference are the most obvious). Is there any general wording for "you can use rvalues of temporaries"? The reflector discussion starting with message c++std-lib-29763 came to the conclusion that above example is not covered by the "as-if" rules and that enabling this behaviour would seem quite useful.[ 2011 Bloomington ]
Moved to NAD Future. This would be a larger change than we would consider for a simple TC.
Proposed resolution:
Section: 23.4.4 [map] Status: Tentatively Ready Submitter: Christopher Jefferson Opened: 2011-05-18 Last modified: 2015-04-08
View all other issues in [map].
View all issues with Tentatively Ready status.
Discussion:
map::erase (and several related methods) took an iterator in C++03, but take a const_iterator in C++0x. This breaks code where the map's key_type has a constructor which accepts an iterator (for example a template constructor), as the compiler cannot choose between erase(const key_type&) and erase(const_iterator).
#include <map> struct X { template<typename T> X(T&) {} }; bool operator<(const X&, const X&) { return false; } void erasor(std::map<X,int>& s, X x) { std::map<X,int>::iterator it = s.find(x); if (it != s.end()) s.erase(it); }
[ 2011 Bloomington ]
This issue affects only associative container erase calls, and is not more general, as these are the only functions that are also overloaded on another single arguement that might cause confusion - the erase by key method. The complete resolution should simply restore the iterator overload in addition to the const_iterator overload for all eight associative containers.
Proposed wording supplied by Alan Talbot, and moved to Review.
[2012, Kona]
Moved back to Open by post-meeting issues processing group.
Pablo very unhappy about case of breaking code with ambiguous conversion between both iterator types.
Alisdair strongly in favor of proposed resolution, this change from C++11 bit Chris in real code, and it took a while to track down the cause.
Move to open, bring in front of a larger group
Proposed wording from Jeremiah: erase(key) shall not participate in overload resolution if iterator is convertible to key. Note that this means making erase(key) a template-method
Poll Chris to find out if he already fixed his code, or fixed his library
Jeremiah - allow both overloads, but enable_if the const_iterator form as a template, requiring is_same to match only const_iterator.
Poll PJ to see if he has already applied this fix?
[2015-02 Cologne]
AM: To summarize, we changed a signature and code broke. At what point do we stop and accept breakage in increasingly obscure code? VV: libc++ is still broken, but libstdc++ works, so they've fixed this — perhaps using this PR? [Checks] Yes, libstdc++ uses this solution, and has a comment pointing to LWG 2059. AM: This issue hasn't been looked at since Kona. In any case, we already have implementation experience now.
AM: I'd say let's ship it. We already have implementation experience (libstdc++ and MSVS). MC: And "tentatively ready" lets me try to implement this and see how it works.Proposed resolution:
Editorial note: The following things are different between 23.2.4 [associative.reqmts] p.8 and 23.2.5 [unord.req] p.10. These should probably be reconciled.
- First uses the convention "denotes"; second uses the convention "is".
- First redundantly says: "If no such element exists, returns a.end()." in erase table entry, second does not.
23.2.4 [associative.reqmts] Associative containers
8 In Table 102, X denotes an associative container class, a denotes a value of X, a_uniq denotes a value of X when X supports unique keys, a_eq denotes a value of X when X supports multiple keys, u denotes an identifier, i and j satisfy input iterator requirements and refer to elements implicitly convertible to value_type, [i,j) denotes a valid range, p denotes a valid const iterator to a, q denotes a valid dereferenceable const iterator to a, r denotes a valid dereferenceable iterator to a, [q1, q2) denotes a valid range of const iterators in a, il designates an object of type initializer_list<value_type>, t denotes a value of X::value_type, k denotes a value of X::key_type and c denotes a value of type X::key_compare. A denotes the storage allocator used by X, if any, or std::allocator<X::value_type> otherwise, and m denotes an allocator of a type convertible to A.
23.2.4 [associative.reqmts] Associative containers Table 102
Add row:
a.erase(r) | iterator | erases the element pointed to by r. Returns an iterator pointing to the element immediately following r prior to the element being erased. If no such element exists, returns a.end(). | amortized constant |
23.2.5 [unord.req] Unordered associative containers
10 In table 103: X is an unordered associative container class, a is an object of type X, b is a possibly const object of type X, a_uniq is an object of type X when X supports unique keys, a_eq is an object of type X when X supports equivalent keys, i and j are input iterators that refer to value_type, [i, j) is a valid range, p and q2 are valid const iterators to a, q and q1 are valid dereferenceable const iterators to a, r is a valid dereferenceable iterator to a, [q1,q2) is a valid range in a, il designates an object of type initializer_list<value_type>, t is a value of type X::value_type, k is a value of type key_type, hf is a possibly const value of type hasher, eq is a possibly const value of type key_equal, n is a value of type size_type, and z is a value of type float.
23.2.5 [unord.req] Unordered associative containers Table 103
Add row:
a.erase(r) | iterator | Erases the element pointed to by r. Returns the iterator immediately following r prior to the erasure. | Average case O(1), worst case O(a.size()). |
23.4.4.1 [map.overview] Class template map overview p. 2
iterator erase(iterator position); iterator erase(const_iterator position); size_type erase(const key_type& x); iterator erase(const_iterator first, const_iterator last);
23.4.5.1 [multimap.overview] Class template multimap overview p. 2
iterator erase(iterator position); iterator erase(const_iterator position); size_type erase(const key_type& x); iterator erase(const_iterator first, const_iterator last);
23.4.6.1 [set.overview] Class template set overview p. 2
iterator erase(iterator position); iterator erase(const_iterator position); size_type erase(const key_type& x); iterator erase(const_iterator first, const_iterator last);
23.4.7.1 [multiset.overview] Class template multiset overview
iterator erase(iterator position); iterator erase(const_iterator position); size_type erase(const key_type& x); iterator erase(const_iterator first, const_iterator last);
23.5.4.1 [unord.map.overview] Class template unordered_map overview p. 3
iterator erase(iterator position); iterator erase(const_iterator position); size_type erase(const key_type& x); iterator erase(const_iterator first, const_iterator last);
23.5.5.1 [unord.multimap.overview] Class template unordered_multimap overview p. 3
iterator erase(iterator position); iterator erase(const_iterator position); size_type erase(const key_type& x); iterator erase(const_iterator first, const_iterator last);
23.5.6.1 [unord.set.overview] Class template unordered_set overview p. 3
iterator erase(iterator position); iterator erase(const_iterator position); size_type erase(const key_type& x); iterator erase(const_iterator first, const_iterator last);
23.5.7.1 [unord.multiset.overview] Class template unordered_multiset overview p. 3
iterator erase(iterator position); iterator erase(const_iterator position); size_type erase(const key_type& x); iterator erase(const_iterator first, const_iterator last);
C.2.13 [diff.cpp03.containers] C.2.12 Clause 23: containers library
23.2.3, 23.2.4
Change: Signature changes: from iterator to const_iterator parameters
Rationale: Overspecification. Effects: The signatures of the following member functions changed from taking an iterator to taking a const_iterator:
Valid C++ 2003 code that uses these functions may fail to compile with this International Standard.
Section: 20.9.12.2 [func.wrap.func], 20.9.12.2.2 [func.wrap.func.mod] Status: Open Submitter: Daniel Krügler Opened: 2011-05-28 Last modified: 2015-04-08
View other active issues in [func.wrap.func].
View all other issues in [func.wrap.func].
View all issues with Open status.
Discussion:
Howard Hinnant observed in reflector message c++std-lib-30841 that 20.9.12.2 [func.wrap.func] makes the member swap noexcept, even though the non-member swap is not noexcept.
The latter was an outcome of the discussions during the Batavia meeting and the Madrid meeting involving LWG 1349, which seems to indicate that the remaining noexcept specifier at the member swap is incorrect and should be removed. But if we allow for a potentially throwing member swap of std::function, this causes another conflict with the exception specification for the following member function:template<class F> function& operator=(reference_wrapper<F> f) noexcept;
Effects: function(f).swap(*this);
Note that in this example the sub-expression function(f) does not cause any problems, because of the nothrow-guarantee given in 20.9.12.2.1 [func.wrap.func.con] p. 10. The problem is located in the usage of the swap which could potentially throw given the general latitude.
So, either the Madrid meeting decision need to be revised (and both member and free swap of std::function should be noexcept), or this function needs to be adapted as well, e.g. by taking the exception-specification away or by changing the semantics. One argument for "swap-may-throw" would be to allow for small-object optimization techniques where the copy of the target may throw. But given the fact that the swap function has been guaranteed to be "Throws: Nothing" from TR1 on, it seems to me that that there would still be opportunities to perform small-object optimizations just restricted to the set of target copies that cannot throw. In my opinion member swap of std::function has always been intended to be no-throw, because otherwise there would be no good technical reason to specify the effects of several member functions in terms of the "construct-swap" idiom (There are three functions that are defined this way), which provides the strong exception safety in this case. I suggest to enforce that both member swap and non-member swap of std::function are nothrow functions as it had been guaranteed since TR1 on.[ 2011 Bloomington ]
Dietmar: May not be swappable in the first place.
Alisdair: This is wide contact. Then we should be taking noexcept off instead of putting it on. This is preferred resolution.
Pablo: This is bigger issue. Specification of assignment in terms of swap is suspect to begin with. It is over specification. How this was applied to string is a better example to work from.
Pablo: Two problems: inconsistency that should be fixed (neither should have noexcept), the other issues is that assignment should not be specified in terms of swap. There are cases where assignment should succeed where swap would fail. This is easier with string as it should follow container rules.
Action Item (Alisdair): There are a few more issues found to file.
Dave: This is because of allocators? The allocator makes this not work.
Howard: There is a type erased allocator in shared_ptr. There is a noexcept allocator in shared_ptr.
Pablo: shared_ptr is a different case. There are shared semantics and the allocator does move around. A function does not have shared semantics.
Alisdair: Function objects think they have unique ownership.
Howard: In function we specify semantics with copy construction and swap.
Action Item (Pablo): Write this up better (why assignment should not be defined in terms of swap)
Howard: Not having trouble making function constructor no throw.
Dietmar: Function must allocate memory.
Howard: Does not put stuff that will throw on copy or swap in small object optimization. Put those on heap. Storing allocator, but has to be no throw copy constructable.
Pablo: Are you allowed to or required to swap or move allocators in case or swap or move.
Dave: An allocator that is type erased should be different...
Pablo: it is
Dave: Do you need to know something about allocator types? But only at construction time.
Pablo: You could have allocators that are different types.
Dave: Swap is two ended operation.
Pablo: Opinion is that both have to say propagate on swap for them to swap.
John: It is not arbitrary. If one person says no. No is no.
Howard: Find noexcept swap to be very useful. Would like to move in that direction and bring container design along.
Dave: If you have something were allocator must not propagate you can detect that at construction time.
...
Pablo: Need to leave this open and discuss in smaller group.
Alisdair: Tried to add boost::any as TR2 proposal and ran into this issue. Only the first place where we run into issues with type erased allocators. Suggest we move it to open.
Action Item: Move to open.
Action Item (Pablo works with Howard and Daniel): Address the more fundamental issue (which may be multiple issues) and write up findings.
[ Original resolution: ]
This wording is relative to the FDIS.
Modify the header <functional> synopsis in 20.9 [function.objects] as indicated:
namespace std { […] template<class R, class... ArgTypes> void swap(function<R(ArgTypes...)>&, function<R(ArgTypes...)>&) noexcept; […] }
Modify the class template function synopsis in 20.9.12.2 [func.wrap.func] as indicated:
namespace std { […] // [func.wrap.func.alg], specialized algorithms: template<class R, class... ArgTypes> void swap(function<R(ArgTypes...)>&, function<R(ArgTypes...)>&) noexcept; […] }
Modify 20.9.12.2.7 [func.wrap.func.alg] as indicated:
template<class R, class... ArgTypes> void swap(function<R(ArgTypes...)>& f1, function<R(ArgTypes...)>& f2) noexcept;-1- Effects: f1.swap(f2);
[2014-02-28 (Post Issaquah), Pablo provides more information]
For cross-referencing purposes: The resolution of this issue should be harmonized with any resolution to LWG 2370, which addresses inappropriate noexcepts in some function constructors.
We have the following choices:
swap() does not throw
Discussion: This definition is desirable, and allows assignment to be implemented with the strong exception guarantee, but it does have consequences: The implementation cannot use the small-object optimization for a function-object F unless F is NothrowMovable (nothrow-swappable is unimportant because F is not swapped with another F). Note that many functors written before C++11 will not have move constructors decorated with noexcept, so this limitation could affect a lot of code.
It is not clear what other implementation restrictions might be needed. Allocators are required not to throw on move or copy. Is that sufficient?
swap() can throw
Discussion: This definition gives maximum latitude to implementation to use small-object optimization. However, the strong guarantee on assignment is difficult to achieve. Should we consider giving up on the strong guarantee? How much are we willing to pessimize code for exceptions?
swap() will not throw if both functions have NoThrowMoveable functors
Discussion: This definition is similar to option 2, but gives slightly stronger guarantees. Here, swap() can throw, but the programmer can theoretically prevent that from happening. This should be straight-forward to implement and gives the implementation a lot of latitude for optimization. However, because this is a dynamic decision, the program is not as easy to reason about. Also, the strong guarantee for assignment is compromized as in option 2.
Proposed resolution:
Section: 21.4 [basic.string] Status: Open Submitter: Howard Hinnant Opened: 2011-05-29 Last modified: 2015-04-08
View other active issues in [basic.string].
View all other issues in [basic.string].
View all issues with Open status.
Discussion:
21.4.1 [string.require]/p4 says that basic_string is an "allocator-aware" container and behaves as described in 23.2.1 [container.requirements.general].
23.2.1 [container.requirements.general] describes move assignment in p7 and Table 99. If allocator_traits<allocator_type>::propagate_on_container_move_assignment::value is false, and if the allocators stored in the lhs and rhs sides are not equal, then move assigning a string has the same semantics as copy assigning a string as far as resources are concerned (resources can not be transferred). And in this event, the lhs may have to acquire resources to gain sufficient capacity to store a copy of the rhs. However 21.4.2 [string.cons]/p22 says:basic_string<charT,traits,Allocator>& operator=(basic_string<charT,traits,Allocator>&& str) noexcept;Effects: If *this and str are not the same object, modifies *this as shown in Table 71. [Note: A valid implementation is swap(str). — end note ]
These two specifications for basic_string::operator=(basic_string&&) are in conflict with each other. It is not possible to implement a basic_string which satisfies both requirements.
Additionally assign from an rvalue basic_string is defined as:basic_string& assign(basic_string&& str) noexcept;Effects: The function replaces the string controlled by *this with a string of length str.size() whose elements are a copy of the string controlled by str. [ Note: A valid implementation is swap(str). — end note ]
It seems contradictory that this member can be sensitive to propagate_on_container_swap instead of propagate_on_container_move_assignment. Indeed, there is a very subtle chance for undefined behavior here: If the implementation implements this in terms of swap, and if propagate_on_container_swap is false, and if the two allocators are unequal, the behavior is undefined, and will likely lead to memory corruption. That's a lot to go wrong under a member named "assign".
[ 2011 Bloomington ]
Alisdair: Can this be conditional noexcept?
Pablo: We said we were not going to put in many conditional noexcepts. Problem is not allocator, but non-normative definition. It says swap is a valid operation which it is not.
Dave: Move assignment is not a critical method.
Alisdair: Was confusing assignment and construction.
Dave: Move construction is critical for efficiency.
Kyle: Is it possible to test for noexcept.
Alisdair: Yes, query the noexcept operator.
Alisdair: Agreed there is a problem that we cannot unconditionally mark these operations as noexcept.
Pablo: How come swap is not defined in alloc
Alisdair: It is in utility.
Pablo: Swap has a conditional noexcept. Is no throw move constructable, is no throw move assignable.
Pablo: Not critical for strings or containers.
Kyle: Why?
Pablo: They do not use the default swap.
Dave: Important for deduction in other types.
Alisdair: Would change the policy we adopted during FDIS mode.
Pablo: Keep it simple and get some vendor experience.
Alisdair: Is this wording correct? Concerned with bullet 2.
Pablo: Where does it reference containers section.
Alisdair: String is a container.
Alisdair: We should not remove redundancy piecemeal.
Pablo: I agree. This is a deviation from rest of string. Missing forward reference to containers section.
Pablo: To fix section 2. Only the note needs to be removed. The rest needs to be a forward reference to containers.
Alisdair: That is a new issue.
Pablo: Not really. Talking about adding one sentence, saying that basic string is a container.
Dave: That is not just a forward reference, it is a semantic change.
PJ: We intended to make it look like a container, but it did not satisfy all the requirements.
Pablo: Clause 1 is correct. Clause 2 is removing note and noexcept (do not remove the rest). Clause 3 is correct.
Alisdair: Not sure data() is correct (in clause 2).
Conclusion: Move to open, Alisdair and Pablo volunteered to provide wording
[ originally proposed wording: ]
This wording is relative to the FDIS.
Modify the class template basic_string synopsis in 21.4 [basic.string]:
namespace std { template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> > class basic_string { public: […] basic_string& operator=(basic_string&& str)noexcept; […] basic_string& assign(basic_string&& str)noexcept; […] }; }
Remove the definition of the basic_string move assignment operator from 21.4.2 [string.cons] entirely, including Table 71 — operator=(const basic_string<charT, traits, Allocator>&&). This is consistent with how we define move assignment for the containers in Clause 23:
basic_string<charT,traits,Allocator>& operator=(basic_string<charT,traits,Allocator>&& str) noexcept;
-22- Effects: If *this and str are not the same object, modifies *this as shown in Table 71. [ Note: A valid implementation is swap(str). — end note ]-23- If *this and str are the same object, the member has no effect.-24- Returns: *this
Table 71 — operator=(const basic_string<charT, traits, Allocator>&&)ElementValuedata()points at the array whose first element was pointed at by str.data()size()previous value of str.size()capacity()a value at least as large as size()
Modify the paragraphs prior to 21.4.6.3 [string::assign] p.3 as indicated (The first insertion recommends a separate paragraph number for the indicated paragraph):
basic_string& assign(basic_string&& str)noexcept;-?- Effects: Equivalent to *this = std::move(str).
-3- Returns: *thisThe function replaces the string controlled by *this with a string of length str.size() whose elements are a copy of the string controlled by str. [ Note: A valid implementation is swap(str). — end note ]
[ 2012-08-11 Joe Gottman observes: ]
One of the effects of basic_string's move-assignment operator (21.4.2 [string.cons], Table 71) is
Element Value data() points at the array whose first element was pointed at by str.data() If a string implementation uses the small-string optimization and the input string str is small enough to make use of it, this effect is impossible to achieve. To use the small string optimization, a string has to be implemented using something like
union { char buffer[SMALL_STRING_SIZE]; char *pdata; };When the string is small enough to fit inside buffer, the data() member function returns static_cast<const char *>(buffer), and since buffer is an array variable, there is no way to implement move so that the moved-to string's buffer member variable is equal to this->buffer.
Resolution proposal: Change Table 71 to read:
Element Value data() points at the array whose first element was pointed at by str.data()that contains the same characters in the same order as str.data() contained before operator=() was called
Proposed resolution:
Section: 20.8.2.2.6 [util.smartptr.shared.create] Status: Open Submitter: Jonathan Wakely Opened: 2011-07-11 Last modified: 2015-04-08
View all issues with Open status.
Discussion:
20.8.2.2.6 [util.smartptr.shared.create] says:
-2- Effects: Allocates memory suitable for an object of type T and constructs an object in that memory via the placement new expression ::new (pv) T(std::forward<Args>(args)...). The template allocate_shared uses a copy of a to allocate memory. If an exception is thrown, the functions have no effect.
This explicitly requires placement new rather than using allocator_traits<A>::construct(a, (T*)pv, std::forward<Args>(args)...) In most cases that would result in the same placement new expression, but would allow more control over how the object is constructed e.g. using scoped_allocator_adaptor to do uses-allocator construction, or using an allocator declared as a friend to construct objects with no public constructors.
[ 2011-08-16 Bloomington: ]
Agreed to fix in principle, but believe that make_shared and allocate_shared have now diverged enough that their descriptions should be separated. Pablo and Stefanus to provide revised wording.
Daniel's (old) proposed resolution:
This wording is relative to the FDIS.
Change the following paragraphs of 20.8.2.2.6 [util.smartptr.shared.create] as indicated (The suggested removal of the last sentence of p1 is not strictly required to resolve this issue, but is still recommended, because it does not say anything new but may give the impression that it says something new):
template<class T, class... Args> shared_ptr<T> make_shared(Args&&... args); template<class T, class A, class... Args> shared_ptr<T> allocate_shared(const A& a, Args&&... args);-1- Requires: For the template make_shared, t
-2- Effects: Allocates memory suitable for an object of type T and constructs an object in that memory. The template make_shared constructs the object via the placement new expression ::new (pv) T(std::forward<Args>(args)...). The template allocate_shared uses a copy of a to allocate memory and constructs the object by calling allocator_traits<A>::construct(a, pt, std::forward<Args>(args)...). If an exception is thrown, the functions have no effect. -3- Returns: A shared_ptr instance that stores and owns the address of the newly constructed object of type T. -4- Postconditions: get() != 0 && use_count() == 1 -5- Throws: bad_alloc, or, for the template make_shared, an exception thrown from the constructor of T, or, for the template allocate_shared, an exception thrown from A::allocate or from allocator_traits<A>::constructThe expression ::new (pv) T(std::forward<Args>(args)...), where pv has type void* and points to storage suitable to hold an object of type T, shall be well formed. For the template allocate_shared, the expression allocator_traits<A>::construct(a, pt, std::forward<Args>(args)...), where pt has type T* and points to storage suitable to hold an object of type T, shall be well formed. A shall be an allocator ([allocator.requirements]).The copy constructor and destructor of A shall not throw exceptions.from the constructor of T. -6- Remarks: Implementations are encouraged, but not required, to perform no more than one memory allocation. [ Note: This provides efficiency equivalent to an intrusive smart pointer. — end note ] -7- [ Note: These functions will typically allocate more memory than sizeof(T) to allow for internal bookkeeping structures such as the reference counts. — end note ]
[2011-12-04: Jonathan and Daniel improve wording]
See also c++std-lib-31796
[2013-10-13, Ville]
This issue is related to 2089.
[2014-02-15 post-Issaquah session : move to Tentatively NAD]
STL: This takes an allocator, but then ignores its construct. That's squirrely.
Alisdair: The convention is when you take an allocator, you use its construct.
STL: 23.2.1 [container.requirements.general]/3, argh! This fills me with despair, but I understand it now.
STL: Ok, this is some cleanup.
STL: You're requiring b to be of type A and not being rebound, is that an overspecification?
Pablo: Good point. Hmm, that's only a requirement on what must be well-formed.
STL: If it's just a well-formed requirement, then why not just use a directly?
Pablo: Yeah, the well-formed requirement is overly complex. It's not a real call, we could just use a directly. It makes it harder to read.
Alisdair: b should be an allocator in the same family as a.
Pablo: This is a well-formed requirement, I wonder if it's the capital A that's the problem here. It doesn't matter here, this is way too much wording.
Alisdair: It's trying to tie the constructor arguments into the allocator requirements.
Pablo: b could be struck, that's a runtime quality. The construct will work with anything that's in the family of A.
Alisdair: The important part is the forward of Args.
Pablo: A must be an allocator, and forward Args must work with that.
Alisdair: First let's nail down A.
Pablo: Then replace b with a, and strike the rest.
STL: You need pt's type, at least.
Pablo: There's nothing to be said about runtime constraints here, this function doesn't even take a pt.
STL: Looking at the Effects, I believe b is similarly messed up, we can use a2 to construct an object.
Alisdair: Or any allocator in the family of a.
STL: We say this stuff for the deallocate too, it should be lifted up.
STL: "owns the address" is weird.
Alisdair: shared_ptr owns pointers, although it does sound funky.
Walter: "to destruct" is ungrammatical.
STL: "When ownership is given up" is not what we usually say.
Alisdair: I think the Returns clause is the right place to say this.
STL: The right place to say this is shared_ptr's dtor, we don't want to use Core's "come from" convention.
Alisdair: I'm on the hook to draft cleaner wording.
Proposed resolution:
This wording is relative to the FDIS.
Change the following paragraphs of 20.8.2.2.6 [util.smartptr.shared.create] as indicated:
template<class T, class... Args> shared_ptr<T> make_shared(Args&&... args);template<class T, class A, class... Args> shared_ptr<T> allocate_shared(const A& a, Args&&... args);
-1- Requires: The expression ::new (pv) T(std::forward<Args>(args)...), where pv
has type void* and points to storage suitable to hold an object of type T, shall be well
formed. A shall be an allocator (17.6.3.5 [allocator.requirements]). The copy constructor
and destructor of A shall not throw exceptions.
return allocate_shared<T>(allocator<T>(), std::forward<Args>(args)...);
Allocates memory suitable for an object of type T
and constructs an object in that memory via the placement new expression
::new (pv) T(std::forward<Args>(args)...). The template allocate_shared uses a copy
of a to allocate memory. If an exception is thrown, the functions have no effect.
Add the following set of new paragraphs immediately following the previous paragraph 7 of 20.8.2.2.6 [util.smartptr.shared.create]:
template<class T, class A, class... Args> shared_ptr<T> allocate_shared(const A& a, Args&&... args);
-?- Requires: The expressions allocator_traits<A>::construct(b, pt, std::forward<Args>(args)...) and allocator_traits<A>::destroy(b, pt) shall be well-formed and well-defined, where b has type A and is a copy of a and where pt has type T* and points to storage suitable to hold an object of type T. A shall meet the allocator requirements (17.6.3.5 [allocator.requirements]).
-?- Effects: Uses an object a2 of type allocator_traits<A>::rebind_alloc<unspecified> that compares equal to a to allocate memory suitable for an object of type T. Uses a copy b of type A from a to construct an object of type T in that memory by calling allocator_traits<A>::construct(b, pt, std::forward<Args>(args)...). If an exception is thrown, the function has no effect. -?- Returns: A shared_ptr instance that stores and owns the address of the newly constructed object of type T. When ownership is given up, the effects are as follows: Uses a copy b2 of type A from a to destruct an object of type T by calling allocator_traits<A>::destroy(b2, pt2) where pt2 has type T* and refers to the newly constructed object. Then uses an object of type allocator_traits<A>::rebind_alloc<unspecified> that compares equal to a to deallocate the allocated memory. -?- Postconditions: get() != 0 && use_count() == 1 -?- Throws: Nothing unless memory allocation or allocator_traits<A>::construct throws an exception. -?- Remarks: Implementations are encouraged, but not required, to perform no more than one memory allocation. [Note: Such an implementation provides efficiency equivalent to an intrusive smart pointer. — end note] -?- [Note: This function will typically allocate more memory than sizeof(T) to allow for internal bookkeeping structures such as the reference counts. — end note]Section: 20.7.11 [temporary.buffer] Status: Open Submitter: Kazutoshi Satoda Opened: 2011-08-10 Last modified: 2015-04-08
View all other issues in [temporary.buffer].
View all issues with Open status.
Discussion:
According to 20.7.11 [temporary.buffer] p1+2:
template <class T> pair<T*, ptrdiff_t> get_temporary_buffer(ptrdiff_t n) noexcept;-1- Effects: Obtains a pointer to storage sufficient to store up to n adjacent T objects. It is implementation-defined whether over-aligned types are supported (3.11).
-2- Returns: A pair containing the buffer's address and capacity (in the units of sizeof(T)), or a pair of 0 values if no storage can be obtained or if n <= 0.
I read this as prohibiting to return a buffer of which capacity is less than n, because such a buffer is not sufficient to store n objects.
The corresponding description in SGI STL is clear on this point, but I think it is a bit too verbose:(for the return value, a pair P) [...] the buffer pointed to by P.first is large enough to hold P.second objects of type T. P.second is greater than or equal to 0, and less than or equal to len.
There seems to be two different targets of the "up to n" modification: The capacity of obtained buffer, and the actual number that the caller will store into the buffer.
First I read as the latter, and got surprised seeing that libstdc++ implementation can return a smaller buffer. I started searching about get_temporary_buffer(). After reading a quote from TC++PL at stackoverflow, I realized that the former is intended. Such misinterpretation seems common:JIS standard (Japanese translation of ISO/IEC standard) says nothing like "up to". I think the editor misinterpreted the original wording, and omitted words for "up to" as it is redundant. (If a buffer is sufficient to store n objects, it is also sufficient to store up to n objects.)
Rogue Wave implementation doesn't return smaller buffer, instead, it can return larger buffer on some circumstances. Apache STDCXX is a derived version of that implementation, and publicly accessible:
Specializations of the get_temporary_buffer() function template attempt to allocate a region of storage sufficiently large to store at least n adjacent objects of type T.
I know one commercial compiler package based on Rogue Wave implementation, and its implementation is essentially same as the above.
[2014-05-18, Daniel comments and suggests concrete wording]
The provided wording attempts to clarify the discussed capacity freedom, but it also makes it clearer that the returned memory is just "raw memory", which is currently not really clear. In addition the wording clarifies that the deallocating return_temporary_buffer function does not throw exceptions, which I believe is the intention when the preconditions of the functions are satisfied. Then, my understanding is that we can provide to return_temporary_buffer a null pointer value if that was the value, get_temporary_buffer() had returned. Furthermore, as STL noticed, the current wording seemingly allows multiple invocations of return_temporary_buffer with the same value returned by get_temporary_buffer; this should be constrained similar to the wording we have for operator delete (unfortunately we miss such wording for allocators).
Proposed resolution:
This wording is relative to N3936.
Change 20.7.11 [temporary.buffer] as indicated:
template <class T> pair<T*, ptrdiff_t> get_temporary_buffer(ptrdiff_t n) noexcept;-1- Effects: Obtains a pointer to uninitialized, contiguous storage for N adjacent objects of type T, for some non-negative number N.
-?- Remarks: Calling get_temporary_buffer with a positive number n is a non-binding request to return storage for n objects of type T. In this case, an implementation is permitted to return instead storage for a non-negative number N of such objects, where N != n (including N == 0). [Note: The request is non-binding to allow latitude for implementation-specific optimizations of its memory management. — end note]. -2- Returns: If n <= 0 or if no storage could be obtained, returns a pair P such that P.first is a null pointer value and P.second == 0; otherwise returns a pair P such that P.first refers to the address of the uninitialized storage and P.second refers to its capacity N (in the units of sizeof(T)).Obtains a pointer to storage sufficient to store up to n adjacent T objects.It is implementation-defined whether over-aligned types are supported (3.11).A pair containing the buffer's address and capacity (in the units of sizeof(T)), or a pair of 0 values if no storage can be obtained or if n <= 0.template <class T> void return_temporary_buffer(T* p);-3- Effects: Deallocates the
-4- Requires:buffer to which p pointsstorage referenced by p.The buffer shall have been previously allocated byp shall be a pointer value returned by an earlier call to get_temporary_buffer which has not been invalidated by an intervening call to return_temporary_buffer(T*). -?- Throws: Nothing.
Section: 23.4.6.2 [set.cons] Status: Tentatively Ready Submitter: Jens Maurer Opened: 2011-08-20 Last modified: 2015-04-08
View all issues with Tentatively Ready status.
Discussion:
23.4.6.2 [set.cons] paragraph 4 says:
Requires: If the iterator's dereference operator returns an lvalue or a non-const rvalue, then Key shall be CopyConstructible.
I'm confused why a "non-const rvalue" for the return value of the iterator would require CopyConstructible; isn't that exactly the situation when you'd want to apply the move constructor?
The corresponding requirement for multimap seems better in that regard ([multimap.cons] paragraph 3):Requires: If the iterator's dereference operator returns an lvalue or a const rvalue pair<key_type, mapped_type>, then both key_type and mapped_type shall be CopyConstructible.
Obviously, if I have a const rvalue, I can't apply the move constructor (which will likely attempt modify its argument).
Dave Abrahams: I think you are right. Proposed resolution: drop "non-" from 23.4.6.2 [set.cons] paragraph 3.[2012, Kona]
The wording is in this area will be affected by Pablo's paper being adopted at this meeting. Wait for that paper to be applied before visiting this issue - deliberately leave in New status until the next meeting.
Proposed resolution from Kona 2012:
This wording is relative to the FDIS.
Change 23.4.6.2 [set.cons] p3 as follows:
template <class InputIterator> set(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator());-3- Effects: Constructs an empty set using the specified comparison object and allocator, and inserts elements from the range [first,last).
-4- Requires: If the iterator's dereference operator returns an lvalue or anon-const rvalue, then Key shall be CopyConstructible. -5- Complexity: Linear in N if the range [first,last) is already sorted using comp and otherwise N logN, where N is last - first.
[2014-05-18, Daniel comments]
According to Pablo, the current P/R correctly incorporates the changes from his paper (which was adopted in Kona)
[2014-06-10, STL comments and suggests better wording]
N1858 was voted into WP N2284 but was "(reworded)", introducing the "non-const" damage.
N1858 wanted to add this for map:Requires: Does not require CopyConstructible of either key_type or mapped_type if the dereferenced InputIterator returns a non-const rvalue pair<key_type, mapped_type>. Otherwise CopyConstructible is required for both key_type and mapped_type.
And this for set:
Requires: Key must be CopyConstructible only if the dereferenced InputIterator returns an lvalue or const rvalue.
(And similarly for multi.)
This was reworded to N2284 23.3.1.1 [map.cons]/3 and N2284 23.3.3.1 [set.cons]/4, and it slightly changed over the years into N3936 23.4.4.2 [map.cons]/3 and N3936 23.4.6.2 [set.cons]/4. In 2005/2007, this was the best known way to say "hey, we should try to move this stuff", as the fine-grained element requirements were taking shape. Then in 2010, N3173 was voted into WP N3225, adding the definition of EmplaceConstructible and modifying the container requirements tables to make the range constructors require EmplaceConstructible. After looking at this history and double-checking our implementation (where map/set range construction goes through emplacement, with absolutely no special-casing for map's pairs), I am convinced that N3173 superseded N1858 here. (Range-insert() and the unordered containers are unaffected.)Previous resolution [SUPERSEDED]:
This wording is relative to the N3936.
Change 23.4.6.2 [set.cons] p4 as follows:
template <class InputIterator> set(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator());-3- Effects: Constructs an empty set using the specified comparison object and allocator, and inserts elements from the range [first,last).
-4- Requires: If the iterator's indirection operator returns an lvalue or anon-const rvalue, then Key shall be CopyInsertible into *this. -5- Complexity: Linear in N if the range [first,last) is already sorted using comp and otherwise N logN, where N is last - first.
[2015-02 Cologne]
GR: Do requirements supersede rather than compose [container requirements and per-function requirements]? AM: Yes, they supersede.
AM: This looks good. Ready? Agreement.Proposed resolution:
This wording is relative to the N4296.
Remove 23.4.4.2 [map.cons] p3:
template <class InputIterator> map(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator());[…]
-3- Requires: If the iterator's indirection operator returns an lvalue or a const rvalue pair<key_type, mapped_type>, then both key_type and mapped_type shall be CopyInsertible into *this.
Remove 23.4.5.2 [multimap.cons] p3:
template <class InputIterator> multimap(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator());[…]
-3- Requires: If the iterator's indirection operator returns an lvalue or a const rvalue pair<key_type, mapped_type>, then both key_type and mapped_type shall be CopyInsertible into *this.
Remove 23.4.6.2 [set.cons] p4:
template <class InputIterator> set(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator());[…]
-4- Requires: If the iterator's indirection operator returns an lvalue or a non-const rvalue, then Key shall be CopyInsertible into *this.
Remove 23.4.7.2 [multiset.cons] p3:
template <class InputIterator> multiset(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator());[…]
-3- Requires: If the iterator's indirection operator returns an lvalue or a const rvalue, then Key shall be CopyInsertible into *this.
Section: 20.10.4.3 [meta.unary.prop] Status: Open Submitter: Daniel Krügler Opened: 2011-08-20 Last modified: 2015-04-08
View other active issues in [meta.unary.prop].
View all other issues in [meta.unary.prop].
View all issues with Open status.
Discussion:
The currently agreed on proposed wording for 2015 using remove_all_extents<T>::type instead of the "an array of unknown bound" terminology in the precondition should be extended to some further entries especially in Table 49, notably the is_*constructible, is_*assignable, and is_*destructible entries. To prevent ODR violations, incomplete element types of arrays must be excluded for value-initialization and destruction for example. Construction and assignment has to be honored, when we have array-to-pointer conversions or pointer conversions of incomplete pointees in effect.
[2012, Kona]
The issue is that in three type traits, we are accidentally saying that in certain circumstances the type must give a specified answer when given an incomplete type. (Specifically: an array of unknown bound of incomplete type.) The issue asserts that there's an ODR violation, since the trait returns false in that case but might return a different version when the trait is completed.
Howard argues: no, there is no risk of an ODR violation. is_constructible<A[]> must return false regardless of whether A is complete, so there's no reason to forbid an array of unknown bound of incomplete types. Same argument applies to is_assignable. General agreement with Howard's reasoning.
There may be a real issue for is_destructible. None of us are sure what is_destructible is supposed to mean for an array of unknown bound (regardless of whether its type is complete), and the standard doesn't make it clear. The middle column doesn't say what it's supposed to do for incomplete types.
In at least one implementation, is_destructible<A[]> does return true if A is complete, which would result in ODR violation unless we forbid it for incomplete types.
Move to open. We believe there is no issue for is_constructible or is_assignable, but that there is a real issue for is_destructible.
Proposed resolution:
Section: 26.8 [c.math] Status: New Submitter: Steve Clamage Opened: 2011-08-29 Last modified: 2015-04-08
View other active issues in [c.math].
View all other issues in [c.math].
View all issues with New status.
Discussion:
LWG issue 550 removed the functions:
float pow(float, int); double pow(double, int); long double pow(long double, int);
from header <cmath>. This change does not seem to be mentioned in Annex C, C.2.14.
Howard:N3290 26.8 [c.math]/p11 says:
Moreover, there shall be additional overloads sufficient to ensure:
- If any argument corresponding to a double parameter has type long double, then all arguments corresponding to double parameters are effectively cast to long double.
- Otherwise, if any argument corresponding to a double parameter has type double or an integer type, then all arguments corresponding to double parameters are effectively cast to double.
- Otherwise, all arguments corresponding to double parameters are effectively cast to float.
From C99 7.12.7.4 we have:
double pow(double, double);26.8 [c.math]/p11/b2 says that if the client calls pow(2.0f, 2), then the int for second argument causes the following effective call to be made:
pow(static_cast<double>(2.0f), static_cast<double>(2)) -> doubleThe first sentence of p11 implies that this is done by supplying the following additional overload:
double pow(float, int);If the client calls pow(2.0, 2), then the same reasoning (b2 again) implies the following additional overload:
double pow(double, int);If the client calls pow(2.0l, 2), then b1 implies the following additional overload:
long double pow(long double, int);In all, p11 implies hundreds (perhaps thousands?) of extra overloads. All but one of which is a superset of the overloads required by C++98/03 (that one being pow(float, int) which had its return type changed from float to double).
In practice, at least some vendors implement p11 by using templated overloads as opposed to ordinary overloads.
Steve Clamage:
Thanks. I didn't see that those extra overloads were actually implied by p11, despite the first sentence. Without examples, the point is a bit subtle (at least for me).
Proposed resolution:
Section: 18.8.3 [exception.terminate] Status: Open Submitter: Daniel Krügler Opened: 2011-09-25 Last modified: 2015-04-08
View all issues with Open status.
Discussion:
Andrzej Krzemienski reported the following on comp.std.c++:
In N3290, which is to become the official standard, in 18.8.3.4 [terminate], paragraph 1 reads
Remarks: Called by the implementation when exception handling must be abandoned for any of several reasons (15.5.1), in effect immediately after evaluating the throw-expression (18.8.3.1). May also be called directly by the program.
It is not clear what is "in effect". It was clear in previous drafts where paragraphs 1 and 2 read:
Called by the implementation when exception handling must be abandoned for any of several reasons (15.5.1). May also be called directly by the program.
Effects: Calls the terminate_handler function in effect immediately after evaluating the throw-expression (18.8.3.1), if called by the implementation, or calls the current terminate_handler function, if called by the program.It was changed by N3189. The same applies to function unexpected (D. 11.4, paragraph 1).
Assuming the previous wording is still intended, the wording can be read "unless std::terminate is called by the program, we will use the handler that was in effect immediately after evaluating the throw-expression". This assumes that there is some throw-expression connected to every situation that triggers the call to std::terminate. But this is not the case:
- In case std::thread is assigned to or destroyed while being joinable there is no throw-expression involved.
- In case std::unexpected is called by the program, std::terminate is triggered by the implementation - no throw-expression involved.
- In case a destructor throws during stack unwinding we have two throw-expressions involved.
Which one is referred to?
In case std::nested_exception::rethrow_nested is called for an object that has captured no exception, there is no throw-expression involved directly (and may no throw be involved even indirectly). Next, 18.8.3.1 [terminate.handler], paragraph 2 saysRequired behavior: A terminate_handler shall terminate execution of the program without returning to the caller.
This seems to allow that the function may exit by throwing an exception (because word "return" implies a normal return).
One could argue that words "terminate execution of the program" are sufficient, but then why "without returning to the caller" would be mentioned. In case such handler throws, noexcept specification in function std::terminate is violated, and std::terminate would be called recursively - should std::abort not be called in case of recursive std::terminate call? On the other hand some controlled recursion could be useful, like in the following technique.
The here mentioned wording changes by N3189 in regard to 18.8.3.4 [terminate] p1 were done for a better separation of effects (Effects element) and additional normative wording explanations (Remarks element), there was no meaning change intended. Further, there was already a defect existing in the previous wording, which was not updated when further situations where defined, when std::terminate where supposed to be called by the implementation.
The part "in effect immediately after evaluating the throw-expression" should be removed and the quoted reference to 18.8.3.1 [terminate.handler] need to be part of the effects element where it refers to the current terminate_handler function, so should be moved just after "Effects: Calls the current terminate_handler function." It seems ok to allow a termination handler to exit via an exception, but the suggested idiom should better be replaced by a more simpler one based on evaluating the current exception pointer in the terminate handler, e.g.void our_terminate (void) { std::exception_ptr p = std::current_exception(); if (p) { ... // OK to rethrow and to determine it's nature } else { ... // Do something else } }
[2011-12-09: Daniel comments]
A related issue is 2111.
[2012, Kona]
Move to Open.
There is an interaction with Core issues in this area that Jens is already supplying wording for. Review this issue again once Jens wording is available.
Alisdair to review clause 15.5 (per Jens suggestion) and recommend any changes, then integrate Jens wording into this issue.
Proposed resolution:
Section: 20.7.9.1 [allocator.members] Status: EWG Submitter: David Krauss Opened: 2011-10-07 Last modified: 2015-04-08
View all other issues in [allocator.members].
Discussion:
When the EmplaceConstructible (23.2.1 [container.requirements.general]/13) requirement is used to initialize an object, direct-initialization occurs. Initializing an aggregate or using a std::initializer_list constructor with emplace requires naming the initialized type and moving a temporary. This is a result of std::allocator::construct using direct-initialization, not list-initialization (sometimes called "uniform initialization") syntax.
Altering std::allocator<T>::construct to use list-initialization would, among other things, give preference to std::initializer_list constructor overloads, breaking valid code in an unintuitive and unfixable way — there would be no way for emplace_back to access a constructor preempted by std::initializer_list without essentially reimplementing push_back.std::vector<std::vector<int>> v; v.emplace_back(3, 4); // v[0] == {4, 4, 4}, not {3, 4} as in list-initialization
The proposed compromise is to use SFINAE with std::is_constructible, which tests whether direct-initialization is well formed. If is_constructible is false, then an alternative std::allocator::construct overload is chosen which uses list-initialization. Since list-initialization always falls back on direct-initialization, the user will see diagnostic messages as if list-initialization (uniform-initialization) were always being used, because the direct-initialization overload cannot fail.
I can see two corner cases that expose gaps in this scheme. One occurs when arguments intended for std::initializer_list satisfy a constructor, such as trying to emplace-insert a value of {3, 4} in the above example. The workaround is to explicitly specify the std::initializer_list type, as in v.emplace_back(std::initializer_list<int>(3, 4)). Since this matches the semantics as if std::initializer_list were deduced, there seems to be no real problem here. The other case is when arguments intended for aggregate initialization satisfy a constructor. Since aggregates cannot have user-defined constructors, this requires that the first nonstatic data member of the aggregate be implicitly convertible from the aggregate type, and that the initializer list have one element. The workaround is to supply an initializer for the second member. It remains impossible to in-place construct an aggregate with only one nonstatic data member by conversion from a type convertible to the aggregate's own type. This seems like an acceptably small hole. The change is quite small because EmplaceConstructible is defined in terms of whatever allocator is specified, and there is no need to explicitly mention SFINAE in the normative text.[2012, Kona]
Move to Open.
There appears to be a real concern with initializing aggregates, that can be performed only using brace-initialization. There is little interest in the rest of the issue, given the existence of 'emplace' methods in C++11.
Move to Open, to find an acceptable solution for intializing aggregates. There is the potential that EWG may have an interest in this area of language consistency as well.
[2013-10-13, Ville]
This issue is related to 2070.
[2015-02 Cologne]
Move to EWG, Ville to write a paper.
Proposed resolution:
This wording is relative to the FDIS.
Change 20.7.9.1 [allocator.members] p12 as indicated:
template <class U, class... Args> void construct(U* p, Args&&... args);12 Effects: ::new((void *)p) U(std::forward<Args>(args)...) if is_constructible<U, Args...>::value is true, else ::new((void *)p) U{std::forward<Args>(args)...}
Section: 30.6.5 [futures.promise], 30.6.9 [futures.task] Status: Open Submitter: Jonathan Wakely Opened: 2011-11-01 Last modified: 2015-04-08
View other active issues in [futures.promise].
View all other issues in [futures.promise].
View all issues with Open status.
Discussion:
This example is ill-formed according to C++11 because uses_allocator<promise<R>, A>::value is true, but is_constructible<promise<R>, A, promise<R>&&>::value is false. Similarly for packaged_task.
#include <future> #include <memory> #include <tuple> using namespace std; typedef packaged_task<void()> task; typedef promise<void> prom; allocator<task> a; tuple<task, prom> t1{ allocator_arg, a }; tuple<task, prom> t2{ allocator_arg, a, task{}, prom{} };
[2012, Portland]
This is an allocator issue, and should be dealt with directly by LWG.
[2013-03-06]
Jonathan suggests to make the new constructors non-explicit and makes some representational improvements.
[2013-09 Chicago]
Move to deferred.
This issue has much in common with similar problems with std::function that are being addressed by the polymorphic allocators proposal currently under evaluation in LEWG. Defer further discussion on this topic until the final outcome of that paper and its proposed resolution is known.
[2014-02-20 Re-open Deferred issues as Priority 4]
Proposed resolution:
[This wording is relative to the FDIS.]
Add to 30.6.5 [futures.promise], class template promise synopsis, as indicated:
namespace std { template <class R> class promise { public: promise(); template <class Allocator> promise(allocator_arg_t, const Allocator& a); template <class Allocator> promise(allocator_arg_t, const Allocator& a, promise&& rhs) noexcept; promise(promise&& rhs) noexcept; promise(const promise& rhs) = delete; ~promise(); […] }; […] }
Change 30.6.5 [futures.promise] as indicated:
promise(promise&& rhs) noexcept; template <class Allocator> promise(allocator_arg_t, const Allocator& a, promise&& rhs) noexcept;-5- Effects: constructs a new promise object and transfers ownership of the shared state of rhs (if any) to the newly-constructed object.
-6- Postcondition: rhs has no shared state. -?- [Note: a is not used — end note]
Add to 30.6.9 [futures.task], class template packaged_task synopsis, as indicated:
namespace std { template<class> class packaged_task; // undefined template<class R, class... ArgTypes> class packaged_task<R(ArgTypes...)> { public: // construction and destruction packaged_task() noexcept; template <class Allocator> packaged_task(allocator_arg_t, const Allocator& a) noexcept; template <class F> explicit packaged_task(F&& f); template <class F, class Allocator> explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f); ~packaged_task(); // no copy packaged_task(const packaged_task&) = delete; template<class Allocator> packaged_task(allocator_arg_t, const Allocator& a, const packaged_task&) = delete; packaged_task& operator=(const packaged_task&) = delete; // move support packaged_task(packaged_task&& rhs) noexcept; template <class Allocator> packaged_task(allocator_arg_t, const Allocator& a, packaged_task&& rhs) noexcept; packaged_task& operator=(packaged_task&& rhs) noexcept; void swap(packaged_task& other) noexcept; […] }; […] }
Change 30.6.9.1 [futures.task.members] as indicated:
packaged_task() noexcept; template <class Allocator> packaged_task(allocator_arg_t, const Allocator& a) noexcept;-1- Effects: constructs a packaged_task object with no shared state and no stored task.
-?- [Note: a is not used — end note]
[…]
packaged_task(packaged_task&& rhs) noexcept; template <class Allocator> packaged_task(allocator_arg_t, const Allocator& a, packaged_task&& rhs) noexcept;-5- Effects: constructs a new packaged_task object and transfers ownership of rhs's shared state to *this, leaving rhs with no shared state. Moves the stored task from rhs to *this.
-6- Postcondition: rhs has no shared state. -?- [Note: a is not used — end note]
Section: 20.10.7 [meta.trans] Status: Open Submitter: Daniel Krügler Opened: 2011-11-18 Last modified: 2015-04-08
View all issues with Open status.
Discussion:
Table 53 — "Reference modifications" says in regard to the type trait add_lvalue_reference (emphasize mine)
If T names an object or function type then the member typedef type shall name T&;
The problem with this specification is that function types with cv-qualifier or ref-qualifier, like
void() const void() &
are also affected by the first part of the rule, but this would essentially mean, that instantiating add_lvalue_reference with such a type would attempt to form a type that is not defined in the C++ type system, namely
void(&)() const void(&)() &
The general policy for TransformationTraits is to define always some meaningful mapping type, but this does not hold for add_lvalue_reference, add_rvalue_reference, and in addition to these two for add_pointer as well. The latter one would attempt to form the invalid types
void(*)() const void(*)() &
A possible reason why those traits were specified in this way is that in C++03 (and that means for TR1), cv-qualifier were underspecified in the core language and several compilers just ignored them during template instantiations. This situation became fixed by adopting CWG issues 295 and 547.
While there is possibly some core language clarification needed (see reflector messages starting from c++std-core-20740), it seems also clear that the library should fix the specification. The suggested resolution follows the style of the specification of the support concepts PointeeType and ReferentType defined in N2914.[2012-02-10, Kona]
Move to NAD.
These cv- and ref-qualified function types are aberrations in the type system, and do not represent any actual entity defined by the language. The notion of cv- and ref- qualification applies only to the implicit *this reference in a member function.
However, these types can be produced by quirks of template metaprogramming, the question remains what the library should do about it. For example, add_reference returns the original type if passed a reference type, or a void type. Conversely, add_pointer will return a pointer to the referenced type when passed a reference.
It is most likely that the 'right' answer in any case will depend on the context that the question is being asked, in terms of forming these obscure types. The best the LWG can do is allow an error to propagate back to the user, so they can provide their own meaningful answer in their context - with additional metaprogramming on their part. The consensus is that if anyone is dangerous enough with templates to get themselves into this problem, they will also have the skills to resolve the problem themselves. This is not going to trip up the non-expert developer.
Lastly, it was noted that this problem arises only because the language is inconsistent in providing us these nonsense types that do no really represent anything in the language. There may be some way Core or Evolution could give us a more consistent type system so that the LWG does not need to invent an answer at all, should this question need resolving. This is another reason to not specify anything at the LWG trait level at this time, leaving the other working groups free to produce the 'right' answer that we can then follow without changing the meaning of existing, well-defined programs.
[2012-02-10, post-Kona]
Move back to Open. Daniel is concerned that this is not an issue we can simply ignore, further details to follow.
[2012-10-06, Daniel comments]
This issue really should be resolved as a defect: First, the argument that "forming these obscure types" should "allow an error to propagate" is inconsistent with the exact same "obscure type" that would be formed when std::add_lvalue_reference<void> wouldn't have an extra rules for void types, which also cannot form references. The originally proposed resolution attempts to apply the same solution for the same common property of void types and function types with cv-qualifiers or ref-qualifier. These functions had the property of ReferentType during concept time (see CWG 749 bullet three for the final wording).
Core issue CWG 1417 has clarified that any attempt to form a reference of a pointer to a function type with cv-qualifiers or ref-qualifier is ill-formed. Unfortunately, many compilers don't implement this yet. I also would like to warn about so-called "obscure" types: The problem is that these can occur as the side effect of finding a best match overload of function templates, where this type is exactly correct for one of these overloads, but causes a deep (not-sfinae-friendly) error for others where one of these traits are part of the signature. Existing experience with void types shows, that this extra rule is not so unexpected. Further, any usage of the result types of these traits as argument types or return types of functions would make these ill-formed (and in a template context would be sfinaed away), so the expected effects are rarely unnoticed. Checking all existing explicit usages of the traits add_rvalue_reference, add_lvalue_reference, and add_pointer didn't show any example where the error would be silent: add_rvalue_reference is used to specify the return value of declval() and the instantiation of declval<void() const>() would be invalid, because of the attempt to return a function type. Similarly, add_lvalue_reference is used to specify the return type of unique_ptr<T>::operator*(). Again, any instantiation with void() const wouldn't remain unnoticed. The trait add_pointer is used to specify the trait std::decay and this is an interesting example, because it is well-formed when instantiated with void types, too, and is heavily used throughout the library specification. All use-cases would not be negatively affected by the suggested acceptance of function types with cv-qualifiers or ref-qualifier, because they involve types that are either function arguments, function parameters or types were references are formed from. The alternative would be to add an additional extra rule that doesn't define a type member 'type' when we have a function type with cv-qualifiers or ref-qualifier. This is better than the current state but it is not superior than the proposal to specify the result as the original type, because both variants are sfinae-friendly. A further disadvantage of the "non-type" approach here would be that any usage of std::decay would require special protection against these function types, because instantiating std::decay<void() const> again would lead to a deep, sfinae-unfriendly error. The following example demonstrates the problem: Even though the second f template is the best final match here, the first one will be instantiated. During that process std::decay<T>::type becomes instantiated as well and will raise a deep error, because as part of the implementation the trait std::add_pointer<void() const> becomes instantiated:#include <type_traits> template<class T> typename std::decay<T>::type f(T&& t); template<class T, class U> U f(U u); int main() { f<void() const>(0); }
When the here proposed resolution would be applied this program would be well-formed and selects the expected function.
Previous resolution from Daniel [SUPERSEDED]:
Change Table 53 — "Reference modifications" in 20.10.7.2 [meta.trans.ref] as indicated:
Table 53 — Reference modifications Template Comments … template <class T>
struct
add_lvalue_reference;If T names an object type or if T names a function type that does not have
cv-qualifiers or a ref-qualifier then the member typedef type
shall name T&; otherwise, if T names a type "rvalue reference to T1" then
the member typedef type shall name T1&; otherwise, type shall name T.template <class T>
struct
add_rvalue_reference;If T names an object type or if T names a function type that does not have
cv-qualifiers or a ref-qualifier then the member typedef type
shall name T&&; otherwise, type shall name T. [Note: This rule reflects
the semantics of reference collapsing (8.3.2 [dcl.ref]). For example, when a type T
names a type T1&, the type add_rvalue_reference<T>::type is not an
rvalue reference. — end note]Change Table 56 — "Pointer modifications" in 20.10.7.5 [meta.trans.ptr] as indicated:
Table 56 — Pointer modifications Template Comments … template <class T>
struct add_pointer;The member typedef type shall name the same type as
If T names a function type that has cv-qualifiers or a ref-qualifier
then the member typedef type shall name T; otherwise, it
shall name the same type as remove_reference<T>::type*.
The following revised proposed resolution defines - in the absence of a proper core language definition - a new term referenceable type as also suggested by the resolution for LWG 2196 as an umbrella of the negation of void types and function types with cv-qualifiers or ref-qualifier. This simplifies and minimizes the requires wording changes.
[ 2013-09-26, Daniel synchronizes wording with recent draft ]
[ 2014-05-18, Daniel synchronizes wording with recent draft and comments ]
My impression is that this urgency of action this issue attempts to point out is partly caused by the fact that even for the most recent C++14 compilers the implementations have just recently changed to adopt the core wording. Examples for these are bug reports to gcc or clang.
Occasionally the argument has been presented to me that the suggested changes to the traits affected by this issue would lead to irregularities compared to other traits, especially the lack of guarantee that add_pointer might not return a pointer or that add_(l/r)value_reference might not return a reference type. I would like to point out that this kind of divergence is actually already present in most add/remove traits: For example, we have no guarantee that add_const returns a const type (Reference types or function types get special treatments), or that add_rvalue_reference returns an rvalue-reference (e.g. when applied to an lvalue-reference type). Zhihao Yuan brought to my attention, that the originally proposing paper N1345 carefully discussed these design choices.Proposed resolution:
This wording is relative to N3936.
Change Table 53 — "Reference modifications" in 20.10.7.2 [meta.trans.ref] as indicated:
Template | Comments |
---|---|
… | |
template <class T> struct add_lvalue_reference; |
If T names then the member typedef type shall name T&; otherwise, the member typedef type shall name T1&; otherwise, [Note: This rule reflects the semantics of reference collapsing (8.3.2 [dcl.ref]). — end note] |
template <class T> struct add_rvalue_reference; |
If T names then the member typedef type shall name T&&; otherwise, type shall name T. [Note: This rule reflects the semantics of reference collapsing (8.3.2 [dcl.ref]). For example, when a type T names a type T1&, the type add_rvalue_reference_t<T> is not an rvalue reference. — end note] |
Change Table 56 — "Pointer modifications" in 20.10.7.5 [meta.trans.ptr] as indicated:
Template | Comments |
---|---|
… | |
template <class T> struct add_pointer; |
If T names a referenceable type or a (possibly cv-qualified) void type then remove_reference_t<T>*; otherwise, type shall name T. |
Section: 18.8.3.4 [terminate], D.8.4 [unexpected] Status: Review Submitter: Howard Hinnant Opened: 2011-12-06 Last modified: 2015-04-08
View all other issues in [terminate].
View all issues with Review status.
Discussion:
Prior to N3242, modified by N3189, we said this about unexpected():
Effects: Calls the unexpected_handler function in effect immediately after evaluating the throw-expression (D.13.1), if called by the implementation, or calls the current unexpected_handler, if called by the program.
and this about terminate():
Effects: Calls the terminate_handler function in effect immediately after evaluating the throw-expression (18.8.3.1), if called by the implementation, or calls the current terminate_handler function, if called by the program.
But now in both places we say:
Calls the current unexpected_handler function.
and:
Calls the current terminate function.
The difference is that in C++98/03 if a destructor reset a handler during stack unwinding, that new handler was not called if the unwinding later led to unexpected() or terminate() being called. But these new words say that this new handler is called. This is an ABI-breaking change in the way exceptions are handled. Was this change intentional?
N3189 was mainly about introducing exception safety and getters for the handlers. I don't recall the issue of which handler gets called being part of the discussion. I propose that we revert to the C++98/03 behavior in this regard, lest ABI's such as the Itanium ABI are invalidated. A mechanical way to do this is to revert bullets 9 and 12 of N3189.[2011-12-09: Daniel comments]
There was no such semantic change intended. It was an unfortunate side effect when trying to better separate different responsibilities in the previous wording.
A related issue is 2088.[2012-01-30: Howard comments]
The C++98/03 wording is somewhat ambiguous:
Calls the terminate_handler function in effect immediately after evaluating the throw-expression...
There are potentially two throw-expressions being referred to here, and it is not clear if this sentence is referring to just the first or both:
There is ample evidence in current implementations that it is understood that only 1. was meant. But clearly both 1 and 2 could have been meant. We need a clarification. Does an execution of a rethrow (throw;) update which handlers can potentially be called?
My opinion: Go with existing practice, and clarify what that practice is, if surveys find that everyone does the same thing. Gcc 4.2 and Apple do 1. only, and do not reset the handlers to the current handlers on throw;.
If current practice is not unanimously one way or the other, I have no strong opinion. I have not found a motivating use case for the use of any particular handler. Most applications set the handlers once at the beginning of the program and then do not change them, and so will not be impacted by whatever decision is made here.[2014-02-15 Issaquah: Move to Review]
STL: Original change in N3242 came from trying to make set/get exception handler thread safe. The issue requests we revert to 98/03, which Howard notes was already ambiguous.
Alisdair: Issue author thinks we made this change in C++11 without taking into account Itanium ABI, which cannot implement the new semantic (without breaking compatibility).
Alisdair: original change in N3242 was trying to solve the problem of which handler is called when the handler is changing in another thread, but this turns out to be an issue in even the single-threaded case.
Pablo: despite wanting to make it thread safe, you are still changing a global
STL and Marshall confirm that there is real implementation divergance on the question, so we cannot pick just one behavior if we want to avoid breaking exisitng practice.
Alisdair: not sure who to talk to across all library vendors to fix, need more information for progress (IBM and Sun)
STL: Howard did identify a problem with the wording as well: throw; is a throw expression, but we typically want to re-activate the in-flight exception, not throw a new copy.
Pablo: wondering why all of this wording is here (N3189)? It looks like we were trying to handle another thread changing handler between a throw and terminate in current thread.
Alisdair: Anything working with exception handling should have used only thread-local resources, but that ship has sailed. We must account for the same exception object being re-thrown in multiple threads simultaneously, with no happens-before relationships.
Room: Why on earth would we care about exactly which way the program dies when the terminate calls are racing?!
Pablo: Reasonable to set the handler once (in main) and never change it.
Pablo: If willing to put lots of work into this, you could say at point of a throw these handlers become thread local but that is overkill. We want destructors to be able to change these handlers (if only for backwards compatibility).
Alisdair: the "do it right" is to do something per thread, but that is more work than vendors will want to do. Want to say setting handler while running multiple threads is unspecified.
Pablo: possible all we need to do is say it is always the current handler
STL: That prevents an implementation or single threaded program from calling a new handler after a throw, probably should say if terminate is called by the implementation (during EH), any handler that was current can be called. Leaves it up in the air as to when the handler is captured, supporting the diverging existing practices.
Jeffrey: use happens before terminology to avoid introducing races
STL: Give this to concurrency?
Jeffrey: It is in clause 18, generally LWG and not SG1 territory.
Alisdair: Concerned about introducing happens before into fundamental exception handling since it would affect single threaded performance as well. Want to give to concurrency or LEWG/EWG, we are into language design here.
Jeffrey: suspect LEWG won't have a strong opinion. I don't want it to be ours!!!
Pablo: Might be a case for core>
Alisdair: Would be happier if at least one core person were in the discussion.
STL: No sympathy for code that tries to guard the terminate handler.
Alisdair: We are back to set it once, globally. Want to be clear that if set_terminate is called just once, when EH is not active, and never changed again, then the user should get the handler from that specific call.
AlisdairM: "unspecified which handler is called if an exception is active when set_terminate is called." This supports existing behaviors, and guarantees which handler is called in non-conentious situations. Implicit assumption that a funtion becomes a handler only after a successful call to set_handler, so we are not leaving a door open to the implementation inventing entirely new handlers of its own.
Consensus.
Poll to confirm status as P1: new consensus is P3
Action: Alisdair provides new wording. Drop from P1 to P3, and move to Review.
Proposed resolution:
Amend 18.8.3.4 [terminate] as indicated:
[[noreturn]] void terminate() noexcept;Remarks: Called by the implementation when exception handling must be abandoned for any of several reasons (15.5.1)
, in effect immediately after throwing the exception. May also be called directly by the program.
Effects: Calls a terminate_handler function. It is unspecified which terminate_handler function will be called if an exception is active during a call to set_terminate. Otherwise c
Calls the current terminate_handler function. [Note: A default terminate_handler is always considered a callable handler in this context. — end note]
Amend D.8.4 [unexpected] as indicated:
[[noreturn]] void unexpected();Remarks: Called by the implementation when a function exits via an exception not allowed by its exception-specification (15.5.2)
, in effect after evaluating the throw-expression (D.11.1). May also be called directly by the program.
Effects: Calls an unexpected_handler function. It is unspecified which unexpected_handler function will be called if an exception is active during a call to set_unexpected. Otherwise c
Calls the current unexpected_handler function. [Note: A default unexpected_handler is always considered a callable handler in this context. — end note]
Section: 17.6.3.3 [nullablepointer.requirements], 24.2.3 [input.iterators], 24.2.7 [random.access.iterators], 25.1 [algorithms.general], 25.4 [alg.sorting], 30.2.1 [thread.req.paramname] Status: Open Submitter: Daniel Krügler Opened: 2011-12-09 Last modified: 2015-04-08
View all issues with Open status.
Discussion:
As of 17.6.3.1 [utility.arg.requirements] Table 17/18, the return types of the expressions
a == b
or
a < b
for types satisfying the EqualityComparable or LessThanComparable types, respectively, are required to be "convertible to bool" which corresponds to a copy-initialization context. But several newer parts of the library that refer to such contexts have lowered the requirements taking advantage of the new terminology of "contextually convertible to bool" instead, which corresponds to a direct-initialization context (In addition to "normal" direct-initialization constructions, operands of logical operations as well as if or switch conditions also belong to this special context).
One example for these new requirements are input iterators which satisfy EqualityComparable but also specify that the expressiona != b
shall be just "contextually convertible to bool". The same discrepancy exists for requirement set NullablePointer in regard to several equality-related expressions.
For random access iterators we havea < b contextually convertible to bool
as well as for all derived comparison functions, so strictly speaking we could have a random access iterator that does not satisfy the LessThanComparable requirements, which looks like an artifact to me.
Even if we keep with the existing requirements based on LessThanComparable or EqualityComparable we still would have the problem that some current specifications are actually based on the assumption of implicit convertibility instead of "explicit convertibility", e.g. 20.8.1.5 [unique.ptr.special] p3:template <class T1, class D1, class T2, class D2> bool operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);-3- Returns: x.get() != y.get().
Similar examples exist in 20.8.1.2.2 [unique.ptr.single.dtor] p2, 20.8.1.2.3 [unique.ptr.single.asgn] p9, 20.8.1.2.4 [unique.ptr.single.observers] p1+3+8, etc.
In all these places the expressions involving comparison functions (but not those of the conversion of a NullablePointer to bool!) assume to be "convertible to bool". I think this is a very natural assumption and all delegations of the comparison functions of some type X to some other API type Y in third-party code does so assuming that copy-initialization semantics will just work. The actual reason for using the newer terminology can be rooted back to LWG 556. My hypotheses is that the resolution of that issue also needs a slight correction. Why so? The reason for opening that issue were worries based on the previous "convertible to bool" wording. An expressions like "!pred(a, b)" might not be well-formed in those situations, because operator! might not be accessible or might have an unusual semantics (and similarly for other logical operations). This can indeed happen with unusual proxy return types, so the idea was that the evaluation of Predicate, BinaryPredicate (25.1 [algorithms.general] p8+9), and Compare (25.4 [alg.sorting] p2) should be defined based on contextual conversion to bool. Unfortunately this alone is not sufficient: In addition, I think, we also want the predicates to be (implicitly) convertible to bool! Without this wording, several conditions are plain wrong, e.g. 25.2.5 [alg.find] p2, which talks about "pred(*i) != false" (find_if) and "pred(*i) == false" (find_if_not). These expressions are not within a boolean context! While we could simply fix all these places by proper wording to be considered in a "contextual conversion to bool", I think that this is not the correct solution: Many third-party libraries already refer to the previous C++03 Predicate definition — it actually predates C++98 and is as old as the SGI specification. It seems to be a high price to pay to switch to direct initialization here instead of fixing a completely different specification problem. A final observation is that we have another definition for a Predicate in 30.2.1 [thread.req.paramname] p2:If a parameter is Predicate, operator() applied to the actual template argument shall return a value that is convertible to bool.
The problem here is not that we have two different definitions of Predicate in the standard — this is confusing, but this fact alone is not a defect. The first (minor) problem is that this definition does not properly apply to function objects that are function pointers, because operator() is not defined in a strict sense. But the actually worse second problem is that this wording has the very same problem that has originally lead to LWG 556! We only need to look at 30.5.1 [thread.condition.condvar] p15 to recognice this:
while (!pred()) wait(lock);
The negation expression here looks very familiar to the example provided in LWG 556 and is sensitive to the same "unusual proxy" problem. Changing the 30.2.1 [thread.req.paramname] wording to a corresponding "contextual conversion to bool" wouldn't work either, because existing specifications rely on "convertible to bool", e.g. 30.5.1 [thread.condition.condvar] p32+33+42 or 30.5.2 [thread.condition.condvarany] p25+26+32+33.
To summarize: I believe that LWG 556 was not completely resolved. A pessimistic interpretation is, that even with the current wording based on "contextually convertible to bool" the actual problem of that issue has not been fixed. What actually needs to be required here is some normative wording that basically expresses something along the lines of:The semantics of any contextual conversion to bool shall be equivalent to the semantics of any implicit conversion to bool.
This is still not complete without having concepts, but it seems to be a better approximation. Another way of solving this issue would be to define a minimum requirements table with equivalent semantics. The proposed wording is a bit simpler but attempts to express the same thing.
[2012, Kona]
Agree with Daniel that we potentially broke some C++03 user code, accept the changes striking "contextually" from tables. Stefan to provide revised wording for section 25, and figure out changes to section 30.
Move to open, and then to Review when updated wording from Stefan is available.
[2012-10-12, STL comments]
The current proposed resolution still isn't completely satisfying. It would certainly be possible for the Standard to require these various expressions to be implicitly and contextually convertible to bool, but that would have a subtle consequence (which, I will argue, is undesirable - regardless of the fact that it dates all the way back to C++98/03). It would allow users to provide really wacky types to the Standard Library, with one of two effects:
Standard Library implementations would have to go to great lengths to respect such wacky types, essentially using static_cast<bool> when invoking any predicates or comparators.
Otherwise, such wacky types would be de facto nonportable, because they would make Standard Library implementations explode.
Effect B is the status quo we're living with today. What Standard Library implementations want to do with pred(args) goes beyond "if (pred(args))" (C++03), contextually converting pred(args) to bool (C++11), or implicitly and contextually converting pred(args) to bool (the current proposed resolution). Implementations want to say things like:
if (pred(args)) if (!pred(args)) if (cond && pred(args)) if (cond && !pred(args))
These are real examples taken from Dinkumware's implementation. There are others that would be realistic ("pred(args) && cond", "cond || pred(args)", etc.)
Although negation was mentioned in this issue's Discussion section, and in LWG 556's, the current proposed resolution doesn't fix this problem. Requiring pred(args) to be implicitly and contextually convertible to bool doesn't prevent operator!() from being overloaded and returning std::string (as a wacky example). More ominously, it doesn't prevent operator&&() and operator||() from being overloaded and destroying short-circuiting.I would like LWG input before working on Standardese for a new proposed resolution. Here's an outline of what I'd like to do:
Introduce a new "concept" in 17.6.3 [utility.requirements], which I would call BooleanTestable in the absence of better ideas.
Centralize things and reduce verbosity by having everything simply refer to BooleanTestable when necessary. I believe that the tables could say "Return type: BooleanTestable", while Predicate/BinaryPredicate/Compare would need the incantation "shall satisfy the requirements of BooleanTestable".
Resolve the tug-of-war between users (who occasionally want to do weird things) and implementers (who don't want to have to contort their code) by requiring that:
Given a BooleanTestable x, x is both implicitly and contextually convertible to bool.
Given a BooleanTestable x, !x is BooleanTestable. (This is intentionally "recursive".)
Given a BooleanTestable x, bool t = x, t2(x), f = !x; has the postcondition t == t2 && t != f.
Given a BooleanTestable x and a BooleanTestable y of possibly different types, "x && y" and "x || y" invoke the built-in operator&&() and operator||(), triggering short-circuiting.
bool is BooleanTestable.
I believe that this simultaneously gives users great latitude to use types other than bool, while allowing implementers to write reasonable code in order to get their jobs done. (If I'm forgetting anything that implementers would want to say, please let me know.)
About requirement (I): As Daniel patiently explained to me, we need to talk about both implicit conversions and contextual conversions, because it's possible for a devious type to have both "explicit operator bool()" and "operator int()", which might behave differently (or be deleted, etc.).
About requirement (IV): This is kind of tricky. What we'd like to say is, "BooleanTestable can't ever trigger an overloaded logical operator". However, given a perfectly reasonable type Nice - perhaps even bool itself! - other code (perhaps a third-party library) could overload operator&&(Nice, Evil). Therefore, I believe that the requirement should be "no first use" - the Standard Library will ask for various BooleanTestable types from users (for example, the result of "first != last" and the result of "pred(args)"), and as long as they don't trigger overloaded logical operators with each other, everything is awesome.
About requirement (V): This is possibly redundant, but it's trivial to specify, makes it easier for users to understand what they need to do ("oh, I can always achieve this with bool"), and provides a "base case" for requirement (IV) that may or may not be necessary. Since bool is BooleanTestable, overloading operator&&(bool, Other) (etc.) clearly makes the Other type non-BooleanTestable.
This wording is relative to the FDIS.
Change Table 25 — "NullablePointer requirements" in 17.6.3.3 [nullablepointer.requirements] as indicated:
Table 25 — NullablePointer requirements Expression Return type Operational semantics […] a != b contextuallyconvertible to bool!(a == b) a == np
np == acontextuallyconvertible to boola == P() a != np
np != acontextuallyconvertible to bool!(a == np) Change Table 107 — "Input iterator requirements" in 24.2.3 [input.iterators] as indicated:
Table 107 — Input iterator requirements (in addition to Iterator) Expression Return type Operational semantics Assertion/note
pre-/post-conditiona != b contextuallyconvertible to bool!(a == b) pre: (a, b) is in the domain of ==. […] Change Table 111 — "Random access iterator requirements" in 24.2.7 [random.access.iterators] as indicated:
Table 111 — Random access iterator requirements (in addition to bidirectional iterator) Expression Return type Operational semantics Assertion/note
pre-/post-condition[…] a < b contextuallyconvertible to boolb - a > 0 < is a total ordering relation a > b contextuallyconvertible to boolb < a > is a total ordering relation opposite to <. a >= b contextuallyconvertible to bool!(a < b) a <= b contextuallyconvertible to bool!(a > b) Change 25.1 [algorithms.general] p8+9 as indicated:
-8- The Predicate parameter is used whenever an algorithm expects a function object (20.9 [function.objects]) that, when applied to the result of dereferencing the corresponding iterator, returns a value testable as true. In other words, if an algorithm takes Predicate pred as its argument and first as its iterator argument, it should work correctly in the construct pred(*first) implicitly or contextually converted to bool (Clause 4 [conv]). The function object pred shall not apply any non-constant function through the dereferenced iterator.
-9- The BinaryPredicate parameter is used whenever an algorithm expects a function object that when applied to the result of dereferencing two corresponding iterators or to dereferencing an iterator and type T when T is part of the signature returns a value testable as true. In other words, if an algorithm takes BinaryPredicate binary_pred as its argument and first1 and first2 as its iterator arguments, it should work correctly in the construct binary_pred(*first1, *first2) implicitly or contextually converted to bool (Clause 4 [conv]). BinaryPredicate always takes the first iterator's value_type as its first argument, that is, in those cases when T value is part of the signature, it should work correctly in the construct binary_pred(*first1, value) implicitly or contextually converted to bool (Clause 4 [conv]). binary_pred shall not apply any non-constant function through the dereferenced iterators.Change 25.4 [alg.sorting] p2 as indicated:
-2- Compare is a function object type (20.9 [function.objects]). The return value of the function call operation applied to an object of type Compare, when implicitly or contextually converted to bool (4 [conv]), yields true if the first argument of the call is less than the second, and false otherwise. Compare comp is used throughout for algorithms assuming an ordering relation. It is assumed that comp will not apply any non-constant function through the dereferenced iterator.
Change 30.2.1 [thread.req.paramname] p2 as indicated:
-2-
If a parameter is Predicate, operator() applied to the actual template argument shall return a value that is convertible to boolPredicate is a function object type (20.9 [function.objects]). The return value of the function call operation applied to an object of type Predicate, when implicitly or contextually converted to bool (4 [conv]), yields true if the corresponding test condition is satisfied, and false otherwise.
[2014-05-20, Daniel suggests concrete wording based on STL's proposal]
The presented wording follows relatively closely STL's outline with the following notable exceptions:
A reference to BooleanTestable in table "Return Type" specifications seemed very unusual to me and I found no "prior art" for this in the Standard. Instead I decided to follow the usual style to add a symbol with a specific meaning to a specific paragraph that specifies symbols and their meanings.
STL's requirement IV suggested to directly refer to built-in operators && and ||. In my opinion this concrete requirement isn't needed if we simply require that two BooleanTestable operands behave equivalently to two those operands after conversion to bool (each of them).
I couldn't find a good reason to require normatively that type bool meets the requirements of BooleanTestable: My assertion is that after having defined them, the result simply falls out of this. But to make this a bit clearer, I added also a non-normative note to these effects.
[2014-06-10, STL comments]
In the current wording I would like to see changed the suggested changes described by bullet #6:
In 23.2.1 [container.requirements.general] p4 undo the suggested change
Then change the 7 occurrences of "convertible to bool" in the denoted tables to "bool".
Proposed resolution:
This wording is relative to N3936.
Change 17.6.3.1 [utility.arg.requirements] p1, Table 17 — "EqualityComparable requirements", and Table 18 — "LessThanComparable requirements" as indicated:
-1- […] In these tables, T is an object or reference type to be supplied by a C++ program instantiating a template; a, b, and c are values of type (possibly const) T; s and t are modifiable lvalues of type T; u denotes an identifier; rv is an rvalue of type T;
[…]andv is an lvalue of type (possibly const) T or an rvalue of type const T; and BT denotes a type that meets the BooleanTestable requirements ([booleantestable.requirements]).
Table 17 — EqualityComparable requirements [equalitycomparable] Expression Return type Requirement a == b convertible toBT
bool== is an equivalence relation, that is, it has the following properties: […] […]
Table 18 — LessThanComparable requirements [lessthancomparable] Expression Return type Requirement a < b convertible toBT
bool< is a strict weak ordering relation (25.4 [alg.sorting])
Between 17.6.3.2 [swappable.requirements] and 17.6.3.3 [nullablepointer.requirements] insert a new sub-clause as indicated:
?.?.?.? BooleanTestable requirements [booleantestable.requirements]-?- A BooleanTestable type is a boolean-like type that also supports conversions to bool. A type B meets the BooleanTestable requirements if the expressions described in Table ?? are valid and have the indicated semantics, and if B also satisfies all the other requirements of this sub-clause [booleantestable.requirements].
An object b of type B can be implicitly converted to bool and can be contextually converted to bool (Clause 4). The result values of both kinds of conversions shall be equivalent. [Example: The types bool, std::true_type, and std::bitset<>::reference are BooleanTestable types. — end example] In Table ??, B2 and Bn denote types (possibly equal to B or to each other) that meet the BooleanTestable requirements, b1 denotes a (possibly const) value of B, b2 denotes a (possibly const) value of B2, and t1 denotes a value of type bool.
Somewhere within the new sub-clause [booleantestable.requirements] insert the following new Table (?? denotes the assigned table number):
Table ?? — BooleanTestable requirements [booleantestable] Expression Return type Operational semantics bool(b1) bool Remarks: bool(b1) == t1 for every value
b1 implicitly converted to t1.!b1 Bn Remarks: bool(b1) == !bool(!b1) for
every value b1.b1 && b2 bool bool(b1) && bool(b2) b1 || b2 bool bool(b1) || bool(b2)
Change 17.6.3.3 [nullablepointer.requirements] p5 and Table 25 — "NullablePointer requirements" as indicated:
[…]
-5- In Table 25, u denotes an identifier, t denotes a non-const lvalue of type P, a and b denote values of type (possibly const) P,andnp denotes a value of type (possibly const) std::nullptr_t, and BT denotes a type that meets the BooleanTestable requirements ([booleantestable.requirements]). […]
Table 25 — NullablePointer requirements [nullablepointer] Expression Return type Operational semantics … a != b contextually convertible to boolBT[…] a == np
np == acontextually convertible to boolBT[…] a != np
np != acontextually convertible to boolBT[…]
Change 20.4.2.7 [tuple.rel] as indicated;
template<class... TTypes, class... UTypes> constexpr bool operator==(const tuple<TTypes...>& t, const tuple<UTypes...>& u);-1- Requires: For all i, where 0 <= i and i < sizeof...(TTypes), get<i>(t) == get<i>(u) is a valid expression returning a type that
[…]is convertible to boolmeets the BooleanTestable requirements ([booleantestable.requirements]). sizeof...(TTypes) == sizeof...(UTypes).template<class... TTypes, class... UTypes> constexpr bool operator<(const tuple<TTypes...>& t, const tuple<UTypes...>& u);-4- Requires: For all i, where 0 <= i and i < sizeof...(TTypes), get<i>(t) < get<i>(u) and get<i>(u) < get<i>(t) are valid expressions returning types that
[…]are convertible to boolmeet the BooleanTestable requirements ([booleantestable.requirements]). sizeof...(TTypes) == sizeof...(UTypes).
Change 23.2.1 [container.requirements.general], Table 96 — "Container requirements", and Table 98 — "Optional container operations" as indicated:
-4- In Tables 96, 97, and 98 X denotes a container class containing objects of type T, a and b denote values of type X, u denotes an identifier, r denotes a non-const value of type X,
andrv denotes a non-const rvalue of type X, and BT denotes a type that meets the BooleanTestable requirements ([booleantestable.requirements]).
Table 96 — Container requirements Expression Return type […] … a == b convertible toBT
bool[…] a != b convertible toBT
bool[…] … a.empty() convertible toBT
bool[…] […]
Table 98 — Optional container requirements Expression Return type […] … a < b convertible toBT
bool[…] a > b convertible toBT
bool[…] a <= b convertible toBT
bool[…] a >= b convertible toBT
bool[…]
Change 24.2.1 [iterator.requirements.general], Table 107 — "Input iterator requirements", and Table 111 — "Random access iterator requirements" as indicated:
-11- In the following sections, a and b denote values of type X or const X, difference_type and reference refer to the types iterator_traits<X>::difference_type and iterator_traits<X>::reference, respectively, n denotes a value of difference_type, u, tmp, and m denote identifiers, r denotes a value of X&, t denotes a value of value type T, o denotes a value of some type that is writable to the output iterator, and BT denotes a type that meets the BooleanTestable requirements ([booleantestable.requirements]).
Table 107 — Input iterator requirements Expression Return type […] a != b contextually convertible toBT
bool[…] […]
Table 111 — Random access iterator requirements Expression Return type […] … a < b contextually convertible toBT
bool[…] a > b contextually convertible toBT
bool[…] a >= b contextually convertible toBT
bool[…] a <= b contextually convertible toBT
bool[…]
Change 25.1 [algorithms.general] p8+p9 as indicated: [Drafting note: The wording change also fixes (a) unusual wording forms used ("should work") which are unclear in which sense they are imposing normative requirements and (b) the problem, that the current wording seems to allow that the predicate may mutate a call argument, if that is not a dereferenced iterator. Upon applying the new wording it became obvious that the wording has the effect that currently algorithms such as adjacent_find, search_n, unique, and unique_copy are not correctly described (because they have no iterator argument named first1), which could give raise to a new library issue. — end drafting note]
-8- The Predicate parameter is used whenever an algorithm expects a function object (20.9) that, when applied to the result of dereferencing the corresponding iterator, returns a value testable as true.
-9- The BinaryPredicate parameter is used whenever an algorithm expects a function object that when applied to the result of dereferencing two corresponding iterators or to dereferencing an iterator and type T when T is part of the signature returns a value testable as true.In other words, iIf an algorithm takes Predicate pred as its argument and first as its iterator argument,it should work correctly in the construct pred(*first) contextually converted to bool (Clause 4)the expression pred(*first) shall have a type that meets the BooleanTestable requirements ( [booleantestable.requirements]). The function object pred shall not apply any non-constant function throughthe dereferenced iteratorits argument.In other words, iIf an algorithm takes BinaryPredicate binary_pred as its argument and first1 and first2 as its iterator arguments,it should work correctly in the construct binary_pred(*first1, *first2) contextually converted to bool (Clause 4)the expression binary_pred(*first1, *first2) shall have a type that meets the BooleanTestable requirements ( [booleantestable.requirements]). BinaryPredicate always takes the first iterator's value_type as its first argument, that is, in those cases when T value is part of the signature,it should work correctly in the construct binary_pred(*first1, value) contextually converted to bool (Clause 4)the expression binary_pred(*first1, value) shall have a type that meets the BooleanTestable requirements ( [booleantestable.requirements]). binary_pred shall not apply any non-constant function throughthe dereferenced iteratorsany of its arguments.
Change 25.4 [alg.sorting] p2 as indicated:
[…]
-2- Compare is a function object type (20.9).The return value of the function call operation applied to an object of type Compare, when contextually converted to bool(Clause 4), yields true if the first argument of the call is less than the second, and false otherwise.Compare comp is used throughout for algorithms assuming an ordering relation. Let a and b denote two argument values whose types depend on the corresponding algorithm. Then the expression comp(a, b) shall have a type that meets the BooleanTestable requirements ( [booleantestable.requirements]). The return value of comp(a, b), converted to bool, yields true if the first argument a is less than the second argument b, and false otherwise. It is assumed that comp will not apply any non-constant function throughthe dereferenced iteratorany of its arguments. […]
Change 27.5.4.2 [fpos.operations] and Table 127 — "Position type requirements" as indicated:
-1- Operations specified in Table 127 are permitted. In that table,
P refers to an instance of fpos,
[…]
o refers to a value of type streamoff,
BT refers to a type that meets the BooleanTestable requirements ([booleantestable.requirements]),
[…]
Table 127 — Position type requirements Expression Return type […] … p == q convertible to boolBT[…] p != q convertible to boolBT[…]
Change 30.2.1 [thread.req.paramname] p2 as indicated:
-2-
If a parameter is Predicate, operator() applied to the actual template argument shall return a value that is convertible to boolPredicate is a function object type (20.9 [function.objects]). Let pred denote an lvalue of type Predicate. Then the expression pred() shall have a type that meets the BooleanTestable requirements ( [booleantestable.requirements]). The return value of pred(), converted to bool, yields true if the corresponding test condition is satisfied, and false otherwise.
Section: 26.6.8 [template.mask.array] Status: Open Submitter: Thomas Plum Opened: 2011-12-10 Last modified: 2015-04-08
View all issues with Open status.
Discussion:
Recently I received a Service Request (SR) alleging that one of our testcases causes an undefined behavior. The complaint is that 26.6.8 [template.mask.array] in C++11 (and the corresponding subclause in C++03) are interpreted by some people to require that in an assignment "a[mask] = b", the subscript mask and the rhs b must have the same number of elements.
IMHO, if that is the intended requirement, it should be stated explicitly. In any event, there is a tiny editorial cleanup that could be made: In C++11, 26.6.8.1 [template.mask.array.overview] para 2 mentions"the expression a[mask] = b;"
but the semicolon cannot be part of an expression. The correction could omit the semicolon, or change the word "expression" to "assignment" or "statement".
Here is the text of the SR, slightly modified for publication:Subject: SR01174 LVS _26322Y31 has undefined behavior [open]
[Client:]
The test case t263.dir/_26322Y31.cpp seems to be illegal as it has an undefined behaviour. I searched into the SRs but found SRs were not related to the topic explained in this mail (SR00324, SR00595, SR00838).const char vl[] = {"abcdefghijklmnopqrstuvwxyz"}; const char vu[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ"}; const std::valarray<char> v0(vl, 27), vm5(vu, 5), vm6(vu, 6); std::valarray<char> x = v0; […] const bool vb[] = {false, false, true, true, false, true}; const std::valarray<bool> vmask(vb, 6); x = v0; x[vmask] = vm5; // ***** HERE.... steq(&x[0], "abABeCghijklmnopqrstuvwxyz"); x2 = x[vmask]; // ***** ....AND HERE […]This problem has already been discussed between [experts]: See thread http://gcc.gnu.org/ml/libstdc++/2009-11/threads.html#00051 Conclusion http://gcc.gnu.org/ml/libstdc++/2009-11/msg00099.html
[Plum Hall:]
Before I log this as an SR, I need to check one detail with you. I did read the email thread you mentioned, and I did find a citation (see INCITS ISO/IEC 14882-2003 Section 26.3.2.6 on valarray computed assignments): Quote: "If the array and the argument array do not have the same length, the behavior is undefined", But this applies to computed assignment (*=, +=, etc), not to simple assignment. Here is the C++03 citation re simple assignment: 26.3.2.2 valarray assignment [lib.valarray.assign]valarray<T>& operator=(const valarray<T>&);1 Each element of the *this array is assigned the value of the corresponding element of the argument array. The resulting behavior is undefined if the length of the argument array is not equal to the length of the *this array.
In the new C++11 (N3291), we find ...
26.6.2.3 valarray assignment [valarray.assign]valarray<T>& operator=(const valarray<T>& v);1 Each element of the *this array is assigned the value of the corresponding element of the argument array. If the length of v is not equal to the length of *this, resizes *this to make the two arrays the same length, as if by calling resize(v.size()), before performing the assignment.
So it looks like the testcase might be valid for C++11 but not for C++03; what do you think?
[Client:]
I quite agree with you but the two problems I mentioned:x[vmask] = vm5; // ***** HERE.... […] x2 = x[vmask]; // ***** ....AND HERErefer to mask_array assignment hence target the C++03 26.3.8 paragraph. Correct?
[Plum Hall:]
I mentioned the contrast between C++03 26.3.2.2 para 1 versus C++11 26.6.2.3 para 1. But in C++03 26.3.8, I don't find any corresponding restriction. Could you quote the specific requirement you're writing about? [Client:]
I do notice the difference between c++03 26.3.2.2 and c++11 26.6.2.3 about assignments between different sized valarray and I perfectly agree with you. But, as already stated, this is not a simple valarray assignment but a mask_array assignment (c++03 26.3.8 / c++11 26.6.8). See c++11 quote below: 26.6.8 Class template mask_array
26.6.8.1 Class template mask_array overview
[....]
This template is a helper template used by the mask subscript operator: mask_array<T> valarray<T>::operator[](const valarray<bool>&).
It has reference semantics to a subset of an array specified by a boolean mask. Thus, the expression a[mask] = b; has the effect of assigning the elements of b to the masked elements in a (those for which the corresponding element in mask is true.)
26.6.8.2 mask_array assignment
void operator=(const valarray<T>&) const; const mask_array& operator=(const mask_array&) const;1 These assignment operators have reference semantics, assigning the values of the argument array elements to selected elements of the valarray<T> object to which it refers.
In particular, [one of the WG21 experts] insisted on the piece "the elements of b".
That is why I reported the test t263.dir/_26322Y31.cpp having an undefined behaviour. [Plum Hall:]
OK, I can see that I will have to ask WG21; I will file an appropriate issue with the Library subgroup. In the meantime, I will mark this testcase as "DISPUTED" so that it is not required for conformance testing, until we get a definitive opinion.
[2012, Kona]
Moved to Open.
There appears to be a real need for clarification in the standard, and implementations differ in their current interpretation. This will need some research by implementers and a proposed resolution before further discussion is likely to be fruitful.
Proposed resolution:
Section: 20.10.4.3 [meta.unary.prop] Status: Open Submitter: Dave Abrahams Opened: 2011-12-09 Last modified: 2015-04-08
View other active issues in [meta.unary.prop].
View all other issues in [meta.unary.prop].
View all issues with Open status.
Discussion:
IMO if we specified is_[nothrow_]constructible in terms of a variable declaration whose validity requires destructibility, it is clearly a bug in our specification and a failure to realize the actual original intent. The specification should have been in terms of placement-new.
Daniel:A defaulted copy/move constructor for a class X is defined as deleted (8.4.3 [dcl.fct.def.delete]) if X has:
[…]
— any direct or virtual base class or non-static data member of a type with a destructor that is deleted or inaccessible from the defaulted constructor,
[…]
Dave:
This is about is_nothrow_constructible in particular. The fact that it is
foiled by not having a noexcept dtor is a defect.
[2012, Kona]
Move to Open.
is_nothrow_constructible is defined in terms of is_constructible, which is defined by looking at a hypothetical variable and asking whether the variable definition is known not to throw exceptions. The issue claims that this also examines the type's destructor, given the context, and thus will return false if the destructor can potentially throw. At least one implementation (Howard's) does return false if the constructor is noexcept(true) and the destructor is noexcept(false). So that's not a strained interpretation. The issue is asking for this to be defined in terms of placement new, instead of in terms of a temporary object, to make it clearer that is_nothrow_constructible looks at the noexcept status of only the constructor, and not the destructor.
Sketch of what the wording would look like:
require is_constructible, and then also require that a placement new operation does not throw. (Remembering the title of this issue... What does this imply for swap?
If we accept this resolution, do we need any changes to swap?
STL argues: no, because you are already forbidden from passing anything with a throwing desturctor to swap.
Dietmar argues: no, not true. Maybe statically the destructor can conceivably throw for some values, but maybe there are some values known not to throw. In that case, it's correct to pass those values to swap.
Proposed resolution:
Section: 22.4.2.2.2 [facet.num.put.virtuals], 27.5.3.1.2 [ios::fmtflags], 27.5.6.1 [fmtflags.manip] Status: New Submitter: Benjamin Kosnik Opened: 2011-12-15 Last modified: 2015-04-08
View all other issues in [facet.num.put.virtuals].
View all issues with New status.
Discussion:
Iostreams should include a manipulator to toggle grouping on/off for locales that support grouped digits. This has come up repeatedly and been deferred. See LWG 826 for the previous attempt.
If one is using a locale that supports grouped digits, then output will always include the generated grouping characters. However, very plausible scenarios exist where one might want to output the number, un-grouped. This is similar to existing manipulators that toggle on/off the decimal point, numeric base, or positive sign. See some user commentary here.[21012, Kona]
Move to Open.
This is a feature request.
Walter is slightly uncomfortable with processing feature requests through the issues lists.
Alisdair says this is far from the first feature request that has come in from the issues list.
STL: The fact that you can turn off grouping on hex output is compelling.
Marshall: if we add this flag, we'll need to update tables 87-91 as well.
STL: If it has been implemented somewhere, and it works, we'd be glad to add it.
Howard: We need to say what the default is.
Alisdair sumarizes:
(1) We want clear wording that says what the effect is of turning the flag off;
(2) what the default values are, and
(3) how this fits into tables 87-90. (and 128)
[Issaquah 2014-02-10-12: Move to LEWG]
Since this issue was filed, we have grown a new working group that is better placed to handle feature requests.
We will track such issues with an LEWG status until we get feedback from the Library Evolution Working Group.
[Issaquah 2014-02-12: LEWG discussion]
SF | F | N | A | SA |
2 | 4 | 1 | 0 | 0 |
Think about the ABI break for adding a flag. But this could be mitigated by putting the data into an iword instead of a flag.
This needs to change Stage 2 in [facet.num.put.virtuals].
Previous resolution, which needs the above corrections:
This wording is relative to the FDIS.
Insert in 22.4.2.2.2 [facet.num.put.virtuals] paragraph 5:
Stage 1: The first action of stage 1 is to determine a conversion specifier. The tables that describe this determination use the following local variables
fmtflags flags = str.flags() ; fmtflags basefield = (flags & (ios_base::basefield)); fmtflags uppercase = (flags & (ios_base::uppercase)); fmtflags floatfield = (flags & (ios_base::floatfield)); fmtflags showpos = (flags & (ios_base::showpos)); fmtflags showbase = (flags & (ios_base::showbase)); fmtflags showgrouping = (flags & (ios_base::showgrouping));Change header <ios> synopsis, 27.5.1 [iostreams.base.overview] as indicated:
#include <iosfwd> namespace std { […] // 27.5.6, manipulators: […] ios_base& showpoint (ios_base& str); ios_base& noshowpoint (ios_base& str); ios_base& showgrouping (ios_base& str); ios_base& noshowgrouping(ios_base& str); ios_base& showpos (ios_base& str); ios_base& noshowpos (ios_base& str); […] }Change class ios_base synopsis, 27.5.3 [ios.base] as indicated:
namespace std { class ios_base { public: class failure; // 27.5.3.1.2 fmtflags typedef T1 fmtflags; […] static constexpr fmtflags showpoint = unspecified ; static constexpr fmtflags showgrouping = unspecified ; static constexpr fmtflags showpos = unspecified ; […] }; }Add a new entry to Table 122 — "fmtflags effects" as indicated:
Table 122 — fmtflags effects Element Effect(s) if set […] showpoint generates a decimal-point character unconditionally in generated floatingpoint output showgrouping generates grouping characters unconditionally in generated output […] After 27.5.3.1.2 [ios::fmtflags] p12 insert the following:
ios_base& showgrouping(ios_base& str);-?- Effects: Calls str.setf(ios_base::showgrouping).
-?- Returns: str.ios_base& noshowgrouping(ios_base& str);-?- Effects: Calls str.unsetf(ios_base::showgrouping).
-?- Returns: str.
Proposed resolution:
Section: 20.9.13 [unord.hash] Status: Open Submitter: Daniel Krügler Opened: 2011-12-16 Last modified: 2015-04-08
View other active issues in [unord.hash].
View all other issues in [unord.hash].
View all issues with Open status.
Discussion:
According to the header <functional> synopsis 20.9 [function.objects] and to the explicit description in 20.9.13 [unord.hash] class template hash specializations shall be provided for all arithmetic types that are not extended integer types. This is not explicitly mentioned, but neither the list nor any normative wording does include them, so it follows by implication.
What are the reasons that extended integer types are excluded? E.g. for numeric_limits corresponding specializations are required. I would expect that an unordered_map with key type std::uintmax_t would just work, but that depends now on whether this type is an extended integer type or not. This issue is not asking for also providing specializations for the cv-qualified arithmetic types. While this is surely a nice-to-have feature, I consider that restriction as a more secondary problem in practice. The proposed resolution also fixes a problem mentioned in 2109 in regard to confusing requirements on user-defined types and those on implementations.[2012, Kona]
Move to Open.
Agreed that it's a real issue and that the proposed wording fixes it. However, the wording change is not minimal and isn't consistent with the way we fixed hash wording elsewhere.
Alisdair will provide updated wording.
[2014-05-06 Geoffrey Romer suggests alternative wording]
Previous resolution from Daniel [SUPERSEDED]:
This wording is relative to the FDIS.
Change 20.9.13 [unord.hash] p2 as indicated:
template <> struct hash<bool>; template <> struct hash<char>; […] template <> struct hash<long double>; template <class T> struct hash<T*>;-2-
Requires: the template specializations shall meet the requirements of class template hash (20.9.13 [unord.hash])The header <functional> provides definitions for specializations of the hash class template for each cv-unqualified arithmetic type. This header also provides a definition for a partial specialization of the hash class template for any pointer type. The requirements for the members of these specializations are given in sub-clause 20.9.13 [unord.hash].
Proposed resolution:
This wording is relative to N3936.
Change 20.9.13 [unord.hash] p1 as indicated:
The unordered associative containers defined in 23.5 use specializations of the class template hash as the default hash function. For all object types Key for which there exists a specialization hash<Key>, and for all integral and enumeration types (7.2) Key, the instantiation hash<Key> shall: […]
Section: 27.8.5.1 [stringstream.cons] Status: New Submitter: Nicolai Josuttis Opened: 2012-01-15 Last modified: 2015-04-08
View all issues with New status.
Discussion:
This issue was raised while discussing issue 1448.
Note the following program:string s("s1: 123456789"); ostringstream s1(s, ios_base::out|ios_base::app); s1 << "hello"; cout << s1.str() << endl;
With g++4.x it prints:
s1: 123456789hello
With VisualC++10 it prints:
hello23456789
From my intuitive understanding the flag "app" should result in the output of g++4.x. I also would read that from 27.5.3.1.4 [ios::openmode] claiming:
app seek to end before each write
However in issue 1448 P.J.Plauger comments:
I think we should say nothing special about app at construction time (thus leaving the write pointer at the beginning of the buffer). Leave implementers wiggle room to ensure subsequent append writes as they see fit, but don't change existing rules for initial seek position.
Note that the flag ate on both platforms appends "hello" to s.
Proposed resolution:
Section: 20.7.10 [storage.iterator] Status: Open Submitter: Jonathan Wakely Opened: 2012-01-23 Last modified: 2015-04-08
View other active issues in [storage.iterator].
View all other issues in [storage.iterator].
View all issues with Open status.
Discussion:
Aliaksandr Valialkin pointed out that raw_storage_iterator only supports constructing a new object from lvalues so cannot be used to construct move-only types:
template <typename InputIterator, typename T> void move_to_raw_buffer(InputIterator first, InputIterator last, T *raw_buffer) { std::move(first, last, std::raw_storage_iterator<T *, T>(raw_buffer)); }
This could easily be solved by overloading operator= for rvalues.
Dave Abrahams: raw_storage_iterator causes exception-safety problems when used with any generic algorithm. I suggest leaving it alone and not encouraging its use.[2014-11-11, Jonathan provides improved wording]
In Urbana LWG decided to explicitly say the value is constructed from an rvalue.
Previous resolution from Jonathan [SUPERSEDED]:This wording is relative to N3337.
Add a new signature to the synopsis in 20.7.10 [storage.iterator] p1:
namespace std { template <class OutputIterator, class T> class raw_storage_iterator : public iterator<output_iterator_tag,void,void,void,void> { public: explicit raw_storage_iterator(OutputIterator x); raw_storage_iterator<OutputIterator,T>& operator*(); raw_storage_iterator<OutputIterator,T>& operator=(const T& element); raw_storage_iterator<OutputIterator,T>& operator=(T&& element); raw_storage_iterator<OutputIterator,T>& operator++(); raw_storage_iterator<OutputIterator,T> operator++(int); }; }Insert the new signature and a new paragraph before p4:
raw_storage_iterator<OutputIterator,T>& operator=(const T& element); raw_storage_iterator<OutputIterator,T>& operator=(T&& element);-?- Requires: For the first signature T shall be CopyConstructible. For the second signature T shall be MoveConstructible.
-4- Effects: Constructs a value from element at the location to which the iterator points. -5- Returns: A reference to the iterator.
Proposed resolution:
This wording is relative to N4140.
Add a new signature to the synopsis in 20.7.10 [storage.iterator] p1:
namespace std { template <class OutputIterator, class T> class raw_storage_iterator : public iterator<output_iterator_tag,void,void,void,void> { public: explicit raw_storage_iterator(OutputIterator x); raw_storage_iterator<OutputIterator,T>& operator*(); raw_storage_iterator<OutputIterator,T>& operator=(const T& element); raw_storage_iterator<OutputIterator,T>& operator=(T&& element); raw_storage_iterator<OutputIterator,T>& operator++(); raw_storage_iterator<OutputIterator,T> operator++(int); }; }
Insert a new paragraph before p4:
raw_storage_iterator<OutputIterator,T>& operator=(const T& element);-?- Requires: T shall be CopyConstructible.
-4- Effects: Constructs a value from element at the location to which the iterator points. -5- Returns: A reference to the iterator.
Insert the new signature and a new paragraph after p5:
raw_storage_iterator<OutputIterator,T>& operator=(T&& element);-?- Requires: T shall be MoveConstructible.
-?- Effects: Constructs a value from std::move(element) at the location to which the iterator points. -?- Returns: A reference to the iterator.
Section: 17.6.5.4 [global.functions] Status: Open Submitter: Yakov Galka Opened: 2012-01-25 Last modified: 2015-04-08
View all other issues in [global.functions].
View all issues with Open status.
Discussion:
17.6.5.4 [global.functions] says
Unless otherwise specified, global and non-member functions in the standard library shall not use functions from another namespace which are found through argument-dependent name lookup (3.4.2).
This sounds clear enough. There are just two problems:
Both implementations I tested (VS2005 and GCC 3.4.3) do unqualified calls to the comma operator in some parts of the library with operands of user-defined types.
The standard itself does this in the description of some algorithms. E.g. uninitialized_copy is defined as:
Effects:
for (; first != last; ++result, ++first) ::new (static_cast<void*>(&*result)) typename iterator_traits<ForwardIterator>::value_type(*first);
If understood literally, it is required to call operator,(ForwardIterator, InputIterator).
For detailed discussion with code samples see here. Proposal:[2013-03-15 Issues Teleconference]
Moved to Open.
There are real questions here, that may require a paper to explore and answer properly.
[2014-05-18, Daniel comments and suggests concrete wording]
Other issues, such as 2114 already follow a similar spirit as the one suggested by bullet 2 of the issue submitter. I assert that consideration of possible user-provided overloads of the comma-operator were not intended by the original wording and doing so afterwards would unnecessarily complicate a future conceptualization of the library and would needlessly restrict implementations.
I don't think that a paper is needed to solve this issue, there is a simply way to ensure that the code-semantics excludes consideration of user-provided comma operators. The provided wording below clarifies this by explicitly casting the first argument of the operator to void.Proposed resolution:
This wording is relative to N3936.
Change 20.7.12.2 [uninitialized.copy] as indicated:
template <class InputIterator, class ForwardIterator> ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result);-1- Effects:
for (; first != last; ++result, (void) ++first) ::new (static_cast<void*>(&*result)) typename iterator_traits<ForwardIterator>::value_type(*first);[…]
template <class InputIterator, class Size,class ForwardIterator> ForwardIterator uninitialized_copy_n(InputIterator first, Size n, ForwardIterator result);-3- Effects:
for (; n > 0; ++result, (void) ++first, --n) ::new (static_cast<void*>(&*result)) typename iterator_traits<ForwardIterator>::value_type(*first);
Change 25.4.8 [alg.lex.comparison] p3 as indicated:
template<class InputIterator1, class InputIterator2> bool lexicographical_compare(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2); template<class InputIterator1, class InputIterator2, class Compare> bool lexicographical_compare(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, Compare comp);-3- Remarks: […]
for ( ; first1 != last1 && first2 != last2 ; ++first1, (void) ++first2) { if (*first1 < *first2) return true; if (*first2 < *first1) return false; } return first1 == last1 && first2 != last2;
Section: 17.5.1 [structure] Status: Open Submitter: Jens Maurer Opened: 2012-03-08 Last modified: 2015-04-08
View all issues with Open status.
Discussion:
The front matter in clause 17 should clarify that postconditions will not hold if a standard library function exits via an exception. Postconditions or guarantees that apply when an exception is thrown (beyond the basic guarantee) are described in an "Exception safety" section.
[ 2012-10 Portland: Move to Open ]
Consensus that we do not clearly say this, and that we probably should. A likely location to describe the guarantees of postconditions could well be a new sub-clause following 17.6.4.11 [res.on.required] which serves the same purpose for requires clauses. However, we need such wording before we can make progress.
Also, see 2137 for a suggestion that we want to see a paper resolving both issues together.
Proposed resolution:
Section: 28.8.3 [re.regex.assign] Status: Open Submitter: Jonathan Wakely Opened: 2012-03-08 Last modified: 2015-04-08
View all other issues in [re.regex.assign].
View all issues with Open status.
Discussion:
The post-conditions of basic_regex<>::assign 28.8.3 [re.regex.assign] p16 say:
If no exception is thrown, flags() returns f and mark_count() returns the number of marked sub-expressions within the expression.
The default expectation in the library is that post-conditions only hold, if there is no failure (see also 2136), therefore the initial condition should be removed to prevent any misunderstanding.
[ 2012-10 Portland: Move to Open ]
A favorable resolution clearly depends on a favorable resolution to 2136. There is also a concern that this is just one example of where we would want to apply such a wording clean-up, and which is really needed to resolve both this issue and 2136 is a paper providing the clause 17 wording that gives the guarantee for postcondition paragaraphs, and then reviews clauses 18-30 to apply that guarantee consistently. We do not want to pick up these issues piecemeal, as we risk openning many issues in an ongoing process.
Proposed resolution:
This wording is relative to N3376.
template <class string_traits, class A> basic_regex& assign(const basic_string<charT, string_traits, A>& s, flag_type f = regex_constants::ECMAScript);[…]
-15- Effects: Assigns the regular expression contained in the string s, interpreted according the flags specified in f. If an exception is thrown, *this is unchanged. -16- Postconditions:If no exception is thrown,flags() returns f and mark_count() returns the number of marked sub-expressions within the expression.
Section: 17.6.4.2.1 [namespace.std], 19.5 [syserr], 20.7.7.1 [allocator.uses.trait], 20.9.10.1 [func.bind.isbind], 20.9.10.2 [func.bind.isplace], 20.9.13 [unord.hash], 20.10.7.6 [meta.trans.other], 22.3.1 [locale], 22.4.1.4 [locale.codecvt], 28.12.1.4 [re.regiter.incr] Status: Open Submitter: Loïc Joly Opened: 2012-03-08 Last modified: 2015-04-08
View all other issues in [namespace.std].
View all issues with Open status.
Discussion:
The expression "user-defined type" is used in several places in the standard, but I'm not sure what it means. More specifically, is a type defined in the standard library a user-defined type?
From my understanding of English, it is not. From most of the uses of this term in the standard, it seem to be considered as user defined. In some places, I'm hesitant, e.g. 17.6.4.2.1 [namespace.std] p1:A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.
Does it mean we are allowed to add in the namespace std a specialization for std::vector<std::pair<T, U>>, for instance?
Additional remarks from the reflector discussion: The traditional meaning of user-defined types refers to class types and enum types, but the library actually means here user-defined types that are not (purely) library-provided. Presumably a new term - like user-provided type - should be introduced and properly defined.[ 2012-10 Portland: Move to Deferred ]
The issue is real, in that we never define this term and rely on a "know it when I see it" intuition. However, there is a fear that any attempt to pin down a definition is more likely to introduce bugs than solve them - getting the wording for this precisely correct is likely far more work than we are able to give it.
There is unease at simple closing as NAD, but not real enthusiasm to provide wording either. Move to Deferred as we are not opposed to some motivated individual coming back with full wording to review, but do not want to go out of our way to encourage someone to work on this in preference to other issues.
[2014-02-20 Re-open Deferred issues as Priority 4]
[2015-03-05 Jonathan suggests wording]
I dislike the suggestion to change to "user-provided" type because I already find the difference between user-declared / user-provided confusing for special member functions, so I think it would be better to use a completely different term. The core language uses "user-defined conversion sequence" and "user-defined literal" and similar terms for things which the library provides, so I think we should not refer to "user" at all to distinguish entities defined outside the implementation from things provided by the implementation.
I propose "program-defined type" (and "program-defined specialization"), defined below. The P/R below demonstrates the scope of the changes required, even if this name isn't adopted. I haven't proposed a change for "User-defined facets" in [locale].Proposed resolution:
This wording is relative to N4296.
Add a new sub-clause to 17.3 [definitions]:
17.3.? [defns.program.defined]
program-defined
<type> a class type or enumeration type which is not part of the C++ standard library and not defined by the implementation. [Note: Types defined by the implementation include extensions (1.4 [intro.compliance]) and internal types used by the library. — end note]program-defined
<specialization> an explicit template specialization or partial specialization which is not part of the C++ standard library and not defined by the implementation.Change 17.6.4.2.1 [namespace.std] paragraph 1+2:
-1- The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a
namespace within namespace std unless otherwise specified. A program may add a template specialization
for any standard library template to namespace std only if the declaration depends on a
userprogram-defined type and the specialization meets the standard library requirements for the
original template and is not explicitly prohibited.
Change 19.5 [syserr] paragraph 4:
-4- The is_error_code_enum and is_error_condition_enum may be specialized for
userprogram-defined types to indicate that such types are eligible for class error_code
and class error_condition automatic conversions, respectively.
Change 20.7.7.1 [allocator.uses.trait] paragraph 1:
-1- Remarks: automatically detects […]. A program may specialize this template to derive from
true_type for a userprogram-defined type T that does not have a nested
allocator_type but nonetheless can be constructed with an allocator where either: […]
Change 20.9.10.1 [func.bind.isbind] paragraph 2:
-2- Instantiations of the is_bind_expression template […]. A program may specialize
this template for a userprogram-defined type T to have a BaseCharacteristic
of true_type to indicate that T should be treated as a subexpression in a bind call.
Change 20.9.10.2 [func.bind.isplace] paragraph 2:
-2- Instantiations of the is_placeholder template […]. A program may specialize this template for a
userprogram-defined type T to have a BaseCharacteristic of
integral_constant<int, N> with N > 0 to indicate that T should be
treated as a placeholder type.
Change 20.9.13 [unord.hash] paragraph 1:
The unordered associative containers defined in 23.5 use specializations of the class template hash […], the instantiation hash<Key> shall:
[…]
[…]
[…]
[…]
satisfy the requirement that the expression h(k), where h is an object of type
hash<Key> and k is an object of type Key, shall not throw an exception unless
hash<Key> is a userprogram-defined specialization that depends on at least one
userprogram-defined type.
Change 20.10.7.5 [meta.trans.ptr] Table 57 (common_type row):
Table 57 — Other transformations Template Condition Comments … template <class... T>
struct common_type;The member typedef type shall be
defined or omitted as specified below.
[…]. A program may
specialize this trait if at least one
template parameter in the
specialization is auserprogram-defined type.
[…]…
Change 22.4.1.4 [locale.codecvt] paragraph 3:
-3- The specializations required in Table 81 (22.3.1.1.1) […]. Other encodings can be converted
by specializing on a userprogram-defined stateT type.[…]
Change 28.12.1.4 [re.regiter.incr] paragraph 8:
-8- [Note: This means that a compiler may call an implementation-specific search function, in which case
a userprogram-defined specialization of regex_search will not be called. —
end note]
Section: 17.6.3.1 [utility.arg.requirements] Status: Open Submitter: Nikolay Ivchenkov Opened: 2012-03-23 Last modified: 2015-04-08
View all other issues in [utility.arg.requirements].
View all issues with Open status.
Discussion:
According to 17.6.3.1 [utility.arg.requirements] p1
The template definitions in the C++ standard library refer to various named requirements whose details are set out in tables 17-24. In these tables, T is an object or reference type to be supplied by a C++ program instantiating a template; a, b, and c are values of type (possibly const) T; s and t are modifiable lvalues of type T; u denotes an identifier; rv is an rvalue of type T; and v is an lvalue of type (possibly const) T or an rvalue of type const T.
Is it really intended that T may be a reference type? If so, what should a, b, c, s, t, u, rv, and v mean? For example, are "int &" and "int &&" MoveConstructible?
As far as I understand, we can explicitly specify template arguments for std::swap and std::for_each. Can we use reference types there?
#include <iostream>
#include <utility>
int main()
{
int x = 1;
int y = 2;
std::swap<int &&>(x, y); // undefined?
std::cout << x << " " << y << std::endl;
}
#include <algorithm>
#include <iostream>
#include <iterator>
#include <utility>
struct F
{
void operator()(int n)
{
std::cout << n << std::endl;
++count;
}
int count;
} f;
int main()
{
int arr[] = { 1, 2, 3 };
auto&& result = std::for_each<int *, F &&>( // undefined?
std::begin(arr),
std::end(arr),
std::move(f));
std::cout << "count: " << result.count << std::endl;
}
Are these forms of usage well-defined?
Let's also consider the following constructor of std::thread:template <class F, class ...Args> explicit thread(F&& f, Args&&... args);Requires: F and each Ti in Args shall satisfy the MoveConstructible requirements.
When the first argument of this constructor is an lvalue (e.g. a name of a global function), template argument for F is deduced to be lvalue reference type. What should "MoveConstructible" mean with regard to an lvalue reference type? Maybe the wording should say that std::decay<F>::type and each std::decay<Ti>::type (where Ti is an arbitrary item in Args) shall satisfy the MoveConstructible requirements?
[2013-03-15 Issues Teleconference]
Moved to Open.
The questions raised by the issue are real, and should have a clear answer.
Proposed resolution:
Section: 21.4.1 [string.require] Status: Open Submitter: Robert Shearer Opened: 2012-04-13 Last modified: 2015-04-08
View all other issues in [string.require].
View all issues with Open status.
Discussion:
In C++11, basic_string is not described as a "container", and is not governed by the allocator-aware container semantics described in sub-clause 23.2 [container.requirements]; as a result, and requirements or contracts for the basic_string interface must be documented in Clause 21 [strings].
Sub-clause 21.4.6.8 [string::swap] defines the swap member function with no requirements, and with guarantees to execute in constant time without throwing. Fulfilling such a contract is not reasonable in the presence of unequal non-propagating allocators. In contrast, 23.2.1 [container.requirements.general] p7 declares the behavior of member swap for containers with unequal non-propagating allocators to be undefined. Resolution proposal: Additional language from Clause 23 [containers] should probably be copied to Clause 21 [strings]. I will refrain from an exactly recommendation, however, as I am raising further issues related to the language in Clause 23 [containers].[2013-03-15 Issues Teleconference]
Moved to Open.
Alisdair has offered to provide wording.
Telecon notes that 23.2.1 [container.requirements.general]p13 says that string is an allocator-aware container.
Proposed resolution:
Section: 17.6.3.2 [swappable.requirements], 23.2.1 [container.requirements.general] Status: Open Submitter: Robert Shearer Opened: 2012-04-13 Last modified: 2015-04-08
View all other issues in [swappable.requirements].
View all issues with Open status.
Discussion:
Sub-clause 17.6.3.2 [swappable.requirements] defines two notions of swappability: a binary version defining when two objects are swappable with one another, and a unary notion defining whether an object is swappable (without qualification), with the latter definition requiring that the object satisfy the former with respect to all values of the same type.
Let T be a container type based on a non-propagating allocator whose instances do not necessarily compare equal. Then sub-clause 23.2.1 [container.requirements.general] p7 implies that no object t of type T is swappable (by the unary definition). Throughout the standard it is the unary definition of "swappable" that is listed as a requirement (with the exceptions of 20.2.2 [utility.swap] p4, 20.3.2 [pairs.pair] p31, 20.4.2.3 [tuple.swap] p2, 25.3.3 [alg.swap] p2, and 25.3.3 [alg.swap] p6, which use the binary definition). This renders many of the mutating sequence algorithms of sub-clause 25.3 [alg.modifying.operations], for example, inapplicable to sequences of standard container types, even where every element of the sequence is swappable with every other. Note that this concern extends beyond standard containers to all future allocator-based types. Resolution proposal: I see two distinct straightforward solutions:I favor the latter solution, for reasons detailed in the following issue.
[ 2012-10 Portland: Move to Open ]
The issue is broader than containers with stateful allocotors, although they are the most obvious example contained within the standard itself. The basic problem is that once you have a stateful allocator, that does not propagate_on_swap, then whether two objects of this type can be swapped with well defined behavior is a run-time property (the allocators compare equal) rather than a simple compile-time property that can be deduced from the type. Strictly speaking, any type where the nature of swap is a runtime property does not meet the swappable requirements of C++11, although typical sequences of such types are going to have elements that are all swappable with any other element in the sequence (using our other term of art for specifying requirements) as the common case is a container of elements who all share the same allocator.
The heart of the problem is that the swappable requirments demand that any two objects of the same type be swappable with each other, so if any two such objects would not be swappable with each other, then the whole type is never swappable. Many algorithms in clause 25 are specified in terms of swappable which is essentially an overspecification as all they actually need is that any element in the sequence is swappable with any other element in the sequence.
At this point Howard joins the discussion and points out that the intent of introducing the two swap-related terms was to support vector<bool>::reference types, and we are reading something into the wording that was never intended. Consuses is that regardless of the intent, that is what the words today say.
There is some support to see a paper reviewing the whole of clause 25 for this issue, and other select clauses as may be necessary.
There was some consideration to introducing a note into the front of clause 25 to indicate swappable requirements in the clause should be interpreted to allow such awkward types, but ultimately no real enthusiasm for introducing a swappable for clause 25 requirement term, especially if it confusingly had the same name as a term used with a subtly different meaning through the rest of the standard.
There was no enthusiasm for the alternate resolution of requiring containers with unequal allocators that do not propagate provide a well-defined swap behavior, as it is not believed to be possible without giving swap linear complexity for such values, and even then would require adding the constraint that the container element types are CopyConstructible.
Final conclusion: move to open pending a paper from a party with a strong interest in stateful allocators.
Proposed resolution:
Section: 20.2.2 [utility.swap], 17.6.3.2 [swappable.requirements], 23.2.1 [container.requirements.general] Status: Open Submitter: Robert Shearer Opened: 2012-04-13 Last modified: 2015-04-08
View all issues with Open status.
Discussion:
Sub-clause 20.2.2 [utility.swap] defines a non-member 'swap' function with defined behavior for all MoveConstructible and MoveAssignable types. It does not guarantee constant-time complexity or noexcept in general, however this definition does render all objects of MoveConstructible and MoveAssignable type swappable (by the unary definition of sub-clause 17.6.3.2 [swappable.requirements]) in the absence of specializations or overloads.
The overload of the non-member swap function defined in Table 96, however, defines semantics incompatible with the generic non-member swap function, since it is defined to call a member swap function whose semantics are undefined for some values of MoveConstructible and MoveAssignable types. The obvious (perhaps naive) interpretation of sub-clause 17.6.3.2 [swappable.requirements] is as a guide to the "right" semantics to provide for a non-member swap function (called in the context defined by 17.6.3.2 [swappable.requirements] p3) in order to provide interoperable user-defined types for generic programming. The standard container types don't follow these guidelines. More generally, the design in the standard represents a classic example of "contract narrowing". It is entirely reasonable for the contract of a particular swap overload to provide more guarantees, such as constant-time execution and noexcept, than are provided by the swap that is provided for any MoveConstructible and MoveAssignable types, but it is not reasonable for such an overload to fail to live up to the guarantees it provides for general types when it is applied to more specific types. Such an overload or specialization in generic programming is akin to an override of an inherited virtual function in OO programming: violating a superclass contract in a subclass may be legal from the point of view of the language, but it is poor design and can easily lead to errors. While we cannot prevent user code from providing overloads that violate the more general swap contract, we can avoid doing so within the library itself. My proposed resolution is to draw a sharp distinction between member swap functions, which provide optimal performance but idiosyncratic contracts, and non-member swap functions, which should always fulfill at least the contract of 20.2.2 [utility.swap] and thus render objects swappable. The member swap for containers with non-propagating allocators, for example, would offer constant-time guarantees and noexcept but would only offer defined behavior for values with allocators that compare equal; non-member swap would test allocator equality and then dispatch to either member swap or std::swap depending on the result, providing defined behavior for all values (and rendering the type "swappable"), but offering neither the constant-time nor the noexcept guarantees.[2013-03-15 Issues Teleconference]
Moved to Open.
This topic deserves more attention than can be given in the telocon, and there is no proposed resolution.
Proposed resolution:
Section: 26.5.1.3 [rand.req.urng] Status: New Submitter: John Salmon Opened: 2012-04-26 Last modified: 2015-04-08
View all other issues in [rand.req.urng].
View all issues with New status.
Discussion:
The expressions G::min() and G::max() in Table 116 in 26.5.1.3 [rand.req.urng] are specified as having "compile-time" complexity.
It is not clear what, exactly, this requirement implies. If a URNG has a method:static int min();
then is the method required to have a constexpr qualifier? I believe the standard would benefit from clarification of this point.
Proposed resolution:
Section: 18.10 [support.runtime] Status: Open Submitter: Thomas Plum Opened: 2012-04-30 Last modified: 2015-04-08
View other active issues in [support.runtime].
View all other issues in [support.runtime].
View all issues with Open status.
Discussion:
Since C99, the C standard describes a macro named __bool_true_false_are_defined.
In the process of harmonizing C++11 with C99, this name became part of the C++ standard. I propose that all mention of this name should be removed from the C and C++ standards. Here's the problem: The name was originally proposed as a transition tool, so that the headers for a project could contain lines like the following.#if !defined(__bool_true_false_are_defined) #define bool int /* or whatever */ #define true 1 #define false 0 #endif
Then when the project was compiled by a "new" compiler that implemented bool as defined by the evolving C++98 or C99 standards, those lines would be skipped; but when compiled by an "old" compiler that didn't yet provide bool, true, and false, then the #define's would provide a simulation that worked for most purposes.
It turns out that there is an unfortunate ambiguity in the name. One interpretation is as shown above, but a different reading says "bool, true, and false are #define'd", i.e. that the meaning of the macro is to assert that these names are macros (not built-in) ... which is true in C, but not in C++. In C++11, the name appears in parentheses followed by a stray period, so some editorial change is needed in any event: 18.10 [support.runtime] para 1:Headers <csetjmp> (nonlocal jumps), <csignal> (signal handling), <cstdalign> (alignment), <cstdarg> (variable arguments), <cstdbool> (__bool_true_false_are_defined). <cstdlib> (runtime environment getenv(), system()), and <ctime> (system clock clock(), time()) provide further compatibility with C code.
However, para 2 says
"The contents of these headers are the same as the Standard C library headers <setjmp.h>, <signal.h>, <stdalign.h>, <stdarg.h>, <stdbool.h>, <stdlib.h>, and <time.h>, respectively, with the following changes:",
and para 8 says
"The header <cstdbool> and the header <stdbool.h> shall not define macros named bool, true, or false."
Thus para 8 doesn't exempt the C++ implementation from the arguably clear requirement of the C standard, to provide a macro named __bool_true_false_are_defined defined to be 1.
Real implementations of the C++ library differ, so the user cannot count upon any consistency; furthermore, the usefulness of the transition tool has faded long ago. That's why my suggestion is that both C and C++ standards should eliminate any mention of __bool_true_false_are_defined. In that case, the name belongs to implementers to provide, or not, as they choose.[2013-03-15 Issues Teleconference]
Moved to Open.
While not strictly necessary, the clean-up look good.
We would like to hear from our C liaison before moving on this issue though.
Proposed resolution:
Section: 23.2.5 [unord.req] Status: Open Submitter: Daniel James Opened: 2012-05-07 Last modified: 2015-04-08
View other active issues in [unord.req].
View all other issues in [unord.req].
View all issues with Open status.
Discussion:
I think that unordered containers' reserve doesn't quite do what it should. I'd expect after calling x.reserve(n) to be able to insert n elements without invalidating iterators. But as the standard is written (I'm looking at n3376), I think the guarantee only holds for n-1 elements.
For a container with max_load_factor of 1, reserve(n) is equivalent to rehash(ceil(n/1)), ie. rehash(n). rehash(n) requires that the bucket count is >= n, so it can be n (Table 103). The rule is that insert shall not affect the validity of iterators if (N + n) < z * B (23.2.5 [unord.req] p15). But for this case the two sides of the equation are equal, so insert can affect the validity of iterators.[2013-03-16 Howard comments and provides wording]
Given the following:
LF := load_factor() MLF := max_load_factor() S := size() B := bucket_count() LF == S/B
The container has an invariant:
LF <= MLF
Therefore:
MLF >= S/B S <= MLF * B B >= S/MLF
[2013-03-15 Issues Teleconference]
Moved to Open.
Howard to provide rationale and potentally revised wording.
[2012-02-12 Issaquah : recategorize as P3]
Jonathon Wakely: submitter is Boost.Hash maintainer. Think it's right.
Marshall Clow: even if wrong it's more right than what we have now
Geoffrey Romer: issue is saying rehash should not leave container in such a state that a notional insertion of zero elements should not trigger a rehash
AJM: e.g. if you do a range insert from an empty range
AJM: we don't have enough brainpower to do this now, so not priority zero
Recategorised as P3
Proposed resolution:
This wording is relative to N3485.
In 23.2.5 [unord.req] Table 103 — Unordered associative container requirements, change the post-condition
in the row for a.rehash(n)
to:
Post:a.bucket_count() >= a.size() / a.max_load_factor()
anda.bucket_count() >= n
.
In 23.2.5 [unord.req]/p15 change
Theinsert
andemplace
members shall not affect the validity of iterators if(N+n) <= z * B
, whereN
is the number of elements in the container prior to the insert operation,n
is the number of elements inserted,B
is the container's bucket count, andz
is the container's maximum load factor.
Section: 23.3.2.8 [array.zero] Status: Open Submitter: Daryle Walker Opened: 2012-05-08 Last modified: 2015-04-08
View all other issues in [array.zero].
View all issues with Open status.
Discussion:
Objects of std::array<T,N> are supposed to be initialized with aggregate initialization (when not the destination of a copy or move). This clearly works when N is positive. What happens when N is zero? To continue using an (inner) set of braces for initialization, a std::array<T,0> implementation must have an array member of at least one element, and let default initialization take care of those secret elements. This cannot work when T has a set of constructors and the default constructor is deleted from that set. Solution: Add a new paragraph in 23.3.2.8 [array.zero]:
The unspecified internal structure of array for this case shall allow initializations like:
array<T, 0> a = { };and said initializations must be valid even when T is not default-constructible.
[2012, Portland: Move to Open]
Some discussion to understand the issue, which is that implementations currently have freedom to implement an empty array by holding a dummy element, and so might not support value initialization, which is surprising when trying to construct an empty container. However, this is not mandated, it is an unspecified implementation detail.
Jeffrey points out that the implication of 23.3.2.1 [array.overview] is that this initialization syntax must be supported by empty array objects already. This is a surprising inference that was not obvious to the room, but consensus is that the reading is accurate, so the proposed resolution is not necessary, although the increased clarity may be useful.
Further observation is that the same clause effectively implies that T must always be DefaultConstructible, regardless of N for the same reasons - as an initializer-list may not supply enough values, and the remaining elements must all be value initialized.
Concern that we are dancing angels on the head of pin, and that relying on such subtle implications in wording is not helpful. We need a clarification of the text in this area, and await wording.
[2015-02 Cologne]
DK: What was the outcome of Portland? AM: Initially we thought we already had the intended behaviour. We concluded that T must always be DefaultConstructible, but I'm not sure why. GR: It's p2 in std::array, "up to N". AM: That wording already implies that "{}" has to work when N is zero. But the wording of p2 needs to be fixed to make clear that it does not imply that T must be DefaultConstructible.
Conclusion: Update wording, revisit later.Proposed resolution:
This wording is relative to N3376.
Add the following new paragraph between the current 23.3.2.8 [array.zero] p1 and p2:
-1- array shall provide support for the special case N == 0.
-?- The unspecified internal structure of array for this case shall allow initializations like:array<T, 0> a = { };and said initializations must be valid even when T is not default-constructible.
-2- In the case that N == 0, begin() == end() == unique value. The return value of data() is unspecified. -3- The effect of calling front() or back() for a zero-sized array is undefined. -4- Member function swap() shall have a noexcept-specification which is equivalent to noexcept(true).
Section: 23.3.6.3 [vector.capacity] Status: New Submitter: Nikolay Ivchenkov Opened: 2012-05-08 Last modified: 2015-04-08
View other active issues in [vector.capacity].
View all other issues in [vector.capacity].
View all issues with New status.
Discussion:
There are various operations on std::vector that can cause elements of the vector to be moved from one location to another. A move operation can use either rvalue or const lvalue as argument; the choice depends on the value of !is_nothrow_move_constructible<T>::value && is_copy_constructible<T>::value, where T is the element type. Thus, some operations on std::vector (e.g. 'resize' with single parameter, 'reserve', 'emplace_back') should have conditional requirements. For example, let's consider the requirement for 'reserve' in N3376 – 23.3.6.3 [vector.capacity]/2:
Requires: T shall be MoveInsertable into *this.
This requirement is not sufficient if an implementation is free to select copy constructor when !is_nothrow_move_constructible<T>::value && is_copy_constructible<T>::value evaluates to true. Unfortunately, is_copy_constructible cannot reliably determine whether T is really copy-constructible. A class may contain public non-deleted copy constructor whose definition does not exist or cannot be instantiated successfully (e.g., std::vector<std::unique_ptr<int>> has copy constructor, but this type is not copy-constructible). Thus, the actual requirements should be:
if !is_nothrow_move_constructible<T>::value && is_copy_constructible<T>::value then T shall be CopyInsertable into *this;
otherwise T shall be MoveInsertable into *this.
Maybe it would be useful to introduce a new name for such conditional requirement (in addition to "CopyInsertable" and "MoveInsertable").
Proposed resolution:
Section: 23.3.6.3 [vector.capacity] Status: Ready Submitter: Daniel Krügler Opened: 2012-06-07 Last modified: 2015-04-08
View other active issues in [vector.capacity].
View all other issues in [vector.capacity].
View all issues with Ready status.
Discussion:
As part of resolving LWG issue 2033 a wording change was done for resize() to respect the problem mentioned in the question:
Does a call to 'void resize(size_type sz)' of std::vector require the element type to be MoveAssignable because the call erase(begin() + sz, end()) mentioned in the Effects paragraph would require the element type to be MoveAssignable?
The wording change was to replace in 23.3.3.3 [deque.capacity] and 23.3.6.3 [vector.capacity]:
-1- Effects: If sz <= size(), equivalent to erase(begin() + sz, end()); […]
by:
-1- Effects: If sz <= size(), equivalent to calling pop_back() size() - sz times. […]
The overlooked side-effect of this wording change is that this implies a destruction order of the removed elements to be in reverse order of construction, but the previous version did not impose any specific destruction order due to the way how the semantics of erase is specified in Table 100.
Given the program:
#include <vector>
#include <iostream>
struct Probe {
int value;
Probe() : value(0) {}
Probe(int value) : value(value) {}
~Probe() { std::cout << "~Probe() of " << value << std::endl; }
};
int main() {
std::vector<Probe> v;
v.push_back(Probe(1));
v.push_back(Probe(2));
v.push_back(Probe(3));
std::cout << "---" << std::endl;
v.resize(0);
}
the last three lines of the output for every compiler I tested was:
~Probe() of 1 ~Probe() of 2 ~Probe() of 3
but a conforming implementation would now need to change this order to
~Probe() of 3 ~Probe() of 2 ~Probe() of 1
This possible stringent interpretation makes sense, because one can argue that sequence containers (or at least std::vector) should have the same required destruction order of it's elements, as elements of a C array or controlled by memory deallocated with an array delete have. I also learned that libc++ does indeed implement std::vector::resize in a way that the second output form is observed.
While I agree that required reverse-destruction would better mimic the natural behaviour of std::vector this was not required in C++03 and this request may be too strong. My current suggestion would be to restore the effects of the previous wording in regard to the destruction order, because otherwise several currently existing implementations would be broken just because of this additional requirement.[2013-03-15 Issues Teleconference]
Moved to Open.
Jonathan says that he believes this is a valid issue.
Walter wonders if this was intended when we made the previous change - if so, this would be NAD.
Jonathan said that Issue 2033 doesn't mention ordering.
Walter then asked if anyone is really unhappy that we're destroying items in reverse order of construction.
Jonathan points out that this conflicts with existing practice (libstc++, but not libc++).
Jonathan asked for clarification as to whether this change was intended by 2033.
[2014-06 Rapperswil]
Daniel points out that the ordering change was not intended.
General agreement that implementations should not be required to change.[2014-06-28 Daniel provides alternative wording]
[Urbana 2014-11-07: Move to Ready]
Proposed resolution:
This wording is relative to N3936.
Change 23.3.3.3 [deque.capacity] as indicated: [Drafting note: The chosen wording form is similar to that for forward_list. Note that the existing Requires element already specifies the necessary operational requirements on the value type. — end drafting note]
void resize(size_type sz);-1- Effects: If sz <
[…]=size(), erases the last size() - sz elements from the sequenceequivalent to calling pop_back() size() - sz times. OtherwiseIf size() <= sz, appends sz - size() default-inserted elements to the sequence.void resize(size_type sz, const T& c);-3- Effects: If sz <
[…]=size(), erases the last size() - sz elements from the sequenceequivalent to calling pop_back() size() - sz times. OtherwiseIf size() < sz, appends sz - size() copies of c to the sequence.
Change 23.3.6.3 [vector.capacity] as indicated: [Drafting note: See deque for the rationale of the used wording. — end drafting note]
void resize(size_type sz);-12- Effects: If sz <
[…]=size(), erases the last size() - sz elements from the sequenceequivalent to calling pop_back() size() - sz times. OtherwiseIf size() < sz, appends sz - size() default-inserted elements to the sequence.void resize(size_type sz, const T& c);-15- Effects: If sz <
[…]=size(), erases the last size() - sz elements from the sequenceequivalent to calling pop_back() size() - sz times. OtherwiseIf size() < sz, appends sz - size() copies of c to the sequence.
Section: 23.4 [associative], 23.5 [unord] Status: New Submitter: Bjarne Stroustrup Opened: 2012-06-18 Last modified: 2015-04-08
View other active issues in [associative].
View all other issues in [associative].
View all issues with New status.
Discussion:
As described in the reflector discussion c++std-core-21860 consider the following example:
map<const int, int> mci{}; map<int, int> mi = mci; // ?? mci[1] = 2; mi[1] = 2;
Should it be required that the marked initialization is well-formed? As a possible solution this could be realized by an alias template:
template <class K, class T> struct OriginalMap { […] }; template <class K, class T> using ImprovedMap = OriginalMap<const K, T>;
Proposed resolution:
Section: 23.3.6.5 [vector.modifiers], 23.2 [container.requirements] Status: New Submitter: Howard Hinnant Opened: 2012-07-07 Last modified: 2015-04-08
View other active issues in [vector.modifiers].
View all other issues in [vector.modifiers].
View all issues with New status.
Discussion:
Nikolay Ivchenkov recently brought the following example on the std-discussion newsgroup, asking whether the following program well-defined:
#include <iostream> #include <vector> int main() { std::vector<int> v; v.reserve(4); v = { 1, 2, 3 }; v.emplace(v.begin(), v.back()); for (int x : v) std::cout << x << std::endl; }
Nikolay Ivchenkov:
I think that an implementation of vector's 'emplace' should initialize an intermediate object with v.back() before any shifts take place, then perform all necessary shifts and finally replace the value pointed to by v.begin() with the value of the intermediate object. So, I would expect the following output:3 1 2 3
GNU C++ 4.7.1 and GNU C++ 4.8.0 produce other results:
2 1 2 3
Howard Hinnant:
I believe Nikolay is correct that vector should initialize an intermediate object with v.back() before any shifts take place. As Nikolay pointed out in another email, this appears to be the only way to satisfy the strong exception guarantee when an exception is not thrown by T's copy constructor, move constructor, copy assignment operator, or move assignment operator as specified by 23.3.6.5 [vector.modifiers]/p1. I.e. if the emplace construction throws, the vector must remain unaltered. That leads to an implementation that tolerates objects bound to the function parameter pack of the emplace member function may be elements or sub-objects of elements of the container. My position is that the standard is correct as written, but needs a clarification in this area. Self-referencing emplace should be legal and give the result Nikolay expects. The proposed resolution of LWG 760 is not correct.[2015-02 Cologne]
LWG agrees with the analysis including the assessment of LWG 760 and would appreciate a concrete wording proposal.
[2015-04-07 dyp comments]
The Standard currently does not require that creation of such intermediate objects is legal. 23.2.3 [sequence.reqmts] Table 100 — "Sequence container requirements" currently specifies:
Table 100 — Sequence container requirements Expression Return type Assertion/note
pre-/post-condition… a.emplace(p, args); iterator Requires: T is EmplaceConstructible into X from args. For vector and deque, T is also MoveInsertable into X and MoveAssignable. […] …
The EmplaceConstructible concept is defined via allocator_traits<A>::construct in 23.2.1 [container.requirements.general] p15.5 That's surprising to me since the related concepts use the suffix Insertable if they refer to the allocator. An additional requirement such as std::is_constructible<T, Args...> is necessary to allow creation of intermediate objects.
The creation of intermediate objects also affects other functions, such as vector.insert. Since aliasing the vector is only allowed for the single-element forms of insert and emplace (see 526), the range-forms are not affected. Similarly, aliasing is not allowed for the rvalue-reference overload. See also LWG 2266.
There might be a problem with a requirement of std::is_constructible<T, Args...> related to the issues described in LWG 2461. For example, a scoped allocator adapter passes additional arguments to the constructor of the value type. This is currently not done in recent implementations of libstdc++ and libc++ when creating the intermediate objects, they simply create the intermediate object by perfectly forwarding the arguments. If such an intermediate object is then moved to its final destination in the vector, a change of the allocator instance might be required — potentially leading to an expensive copy. One can also imagine worse problems, such as run-time errors (allocators not comparing equal at run-time) or compile-time errors (if the value type cannot be created without the additional arguments). I have not looked in detail into this issue, but I'd be reluctant adding a requirement such as std::is_constructible<T, Args...> without further investigation.
It should be noted that the creation of intermediate objects currently is inconsistent in libstdc++ vs libc++. For example, libstdc++ creates an intermediate object for vector.insert, but not vector.emplace, whereas libc++ does the exact opposite in this respect.
A live demo of the inconsistent creation of intermediate objects can be found here.
Proposed resolution:
Section: 29.5 [atomics.types.generic], 29.6 [atomics.types.operations] Status: Core Submitter: Jonathan Wakely Opened: 2012-07-19 Last modified: 2015-04-09
View other active issues in [atomics.types.generic].
View all other issues in [atomics.types.generic].
View all issues with Core status.
Discussion:
As raised in c++std-lib-32781, this fails to compile even though the default constructor is not used:
#include <atomic> struct X { X() noexcept(false) {} X(int) { } }; std::atomic<X> x(3);
This is because atomic<T>'s default constructor is declared to be non-throwing and is explicitly-defaulted on its first declaration:
atomic() noexcept = default;
This is ill-formed if the implicitly-declared default constructor would not be non-throwing.
Possible solutions:[2012, Portland: move to Core]
Recommend referring to core to see if the constructor noexcept mismatch can be resolved there. The issue is not specific to concurrency.
[2015-04-09 Daniel comments]
CWG issue 1778, which had been created in behalf of this LWG issue, has been resolved as a defect.
Proposed resolution:
Section: 25.4.6 [alg.heap.operations] Status: New Submitter: Peter Sommerlad Opened: 2012-07-09 Last modified: 2015-04-08
View all other issues in [alg.heap.operations].
View all issues with New status.
Discussion:
Another similar issue to the operator< vs greater in nth_element but not as direct occurs in 25.4.6 [alg.heap.operations]:
-1- A heap is a particular organization of elements in a range between two random access iterators [a,b). Its two key properties are:
- There is no element greater than *a in the range and
- *a may be removed by pop_heap(), or a new element added by push_heap(), in O(log(N)) time.
As noted by Richard Smith, it seems that the first bullet should read:
*a is not less than any element in the range
Even better the heap condition could be stated here directly, instead of leaving it unspecified, i.e.,
Each element at (a+2*i+1) and (a+2*i+2) is less than the element at (a+i), if those elements exist, for i>=0.
But may be that was may be intentional to allow other heap organizations?
See also follow-up discussion of c++std-lib-32780.Proposed resolution:
Section: 26.5.8.2.2 [rand.dist.uni.real] Status: Ready Submitter: Marshall Clow Opened: 2012-07-14 Last modified: 2015-04-08
View all issues with Ready status.
Discussion:
uniform_real says in 26.5.8.2.2 [rand.dist.uni.real] p1:
A uniform_real_distribution random number distribution produces random numbers x, a ≤ x < b,
but also that (26.5.8.2.2 [rand.dist.uni.real] p2):
explicit uniform_real_distribution(RealType a = 0.0, RealType b = 1.0);-2- Requires: a ≤ b and b - a ≤ numeric_limits<RealType>::max().
If you construct a uniform_real_distribution<RealType>(a, b) where there are no representable numbers between 'a' and 'b' (using RealType's representation) then you cannot satisfy 26.5.8.2.2 [rand.dist.uni.real].
An obvious example is when a == b.[2014-11-04 Urbana]
Jonathan provides wording.
[2014-11-08 Urbana]
Moved to Ready with the node.
There remains concern that the constructors are permitting values that may (or may not) be strictly outside the domain of the function, but that is a concern that affects the design of the random number facility as a whole, and should be addressed by a paper reviewing and addressing the whole clause, not picked up in the issues list one distribution at a time. It is still not clear that such a paper would be uncontroversial.
Proposed resolution:
This wording is relative to N4140.
Add a note after paragraph 1 before the synopsis in 26.5.8.2.2 [rand.dist.uni.real]:
-1- A uniform_real_distribution random number distribution produces random numbers , , distributed according to the constant probability density function
.
[Note: This implies that is undefined when a == b. — end note]
Drafting note: should be in math font, and a == b should be in code font.
Section: 25 [algorithms] Status: New Submitter: Nikolay Ivchenkov Opened: 2012-08-01 Last modified: 2015-04-08
View other active issues in [algorithms].
View all other issues in [algorithms].
View all issues with New status.
Discussion:
According to 25.1 [algorithms.general]/12,
In the description of the algorithms operators + and - are used for some of the iterator categories for which they do not have to be defined. In these cases the semantics of a+n is the same as that of
X tmp = a; advance(tmp, n); return tmp;
There are several places where such operator + is applied to an output iterator — for example, see the description of std::copy:
template<class InputIterator, class OutputIterator> OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result);-1- Effects: Copies elements in the range [first,last) into the range [result,result + (last - first)) starting from first and proceeding to last. For each non-negative integer n < (last - first), performs *(result + n) = *(first + n).
std::advance is not supposed to be applicable to output iterators, so we need a different method of description.
See also message c++std-lib-32908.[2014-06-07 Daniel comments and provides wording]
The specification for output iterators is somewhat tricky, because here a sequence of increments is required to be combined with intervening assignments to the dereferenced iterator. I tried to respect this fact by using a conceptual assignment operation as part of the specification.
Another problem in the provided as-if-code is the question which requirements are imposed on n. Unfortunately, the corresponding function advance is completely underspecified in this regard, so I couldn't borrow wording from it. We cannot even assume here that n is the difference type of the iterator, because for output iterators there is no requirements for this associated type to be defined. The presented wording attempts to minimize assumptions, but still can be considered as controversial.Proposed resolution:
This wording is relative to N3936.
Change 25.1 [algorithms.general] around p12 as indicated:
-12- In the description of the algorithms operators + and - are used for some of the iterator categories for which they do not have to be defined. In these cases the semantics of a+n is the same as that of
X tmp = a; advance(tmp, n); return tmp;when X meets the input iterator requirements (24.2.3 [input.iterators]), otherwise it is the same as that of
X tmp = a; for (auto i = n; i; ++tmp, (void) --i) *tmp = Expr(i); return tmp;where Expr(i) denotes the n-i-th expression that is assigned to for the corresponding algorithm; and that of b-a is the same as of
return distance(a, b);
Section: 17.6.3.5 [allocator.requirements], C.5 [diff.library] Status: Open Submitter: Nevin Liber Opened: 2012-08-14 Last modified: 2015-04-08
View other active issues in [allocator.requirements].
View all other issues in [allocator.requirements].
View all issues with Open status.
Discussion:
Given that a number of things were removed from the allocator requirements (reference, const_reference, address() in 17.6.3.5 [allocator.requirements]), it seems that these incompatible changes should be mentioned in Annex C.5 [diff.library], more specifically in [diff.cpp03].
[ 2012-10 Portland: Move to Open ]
It was clearly pointed out by Bill during the C++11 process that our change to allocator requirements potentially broke 3rd party user containers written to expect C++03 allocators, or rather, an allocator written to the minimal requirements of C++11 might not be guaranteed to work with a container written to the previous rules. This was a trade-off in making allocaters easier to write by use of the allocator_traits framework.
This probably does merit a write-up in Annex C, and we look forward to seeing wording. Until then, the best we can do is move the issue to Open.
Proposed resolution:
Section: 20.8.2.5 [util.smartptr.enab], 20.8.2.2.1 [util.smartptr.shared.const] Status: Open Submitter: Daniel Krügler Opened: 2012-08-16 Last modified: 2015-04-08
View all issues with Open status.
Discussion:
On reflector message c++std-lib-32927, Matt Austern asked whether the following example should be well-defined or not
struct X : public enable_shared_from_this<X> { }; auto xraw = new X; shared_ptr<X> xp1(xraw); shared_ptr<X> xp2(xraw);
pointing out that 20.8.2.2.1 [util.smartptr.shared.const] does not seem to allow it, since xp1 and xp2 aren't allowed to share ownership, because each of them is required to have use_count() == 1. Despite this wording it might be reasonable (and technical possible) to implement that request.
On the other hand, there is the non-normative note in 20.8.2.5 [util.smartptr.enab] p11 (already part of TR1):The shared_ptr constructors that create unique pointers can detect the presence of an enable_shared_from_this base and assign the newly created shared_ptr to its __weak_this member.
Now according to the specification in 20.8.2.2.1 [util.smartptr.shared.const] p3-7:
template<class Y> explicit shared_ptr(Y* p);
the notion of creating unique pointers can be read to be included by this note, because the post-condition of this constructor is unique() == true. Evidence for this interpretation seems to be weak, though.
Howard Hinnant presented the counter argument, that actually the following is an "anti-idiom" and it seems questionable to teach it to be well-defined in any case:auto xraw = new X; shared_ptr<X> xp1(xraw); shared_ptr<X> xp2(xraw);
He also pointed out that the current post-conditions of the affected shared_ptr constructor would need to be reworded.
It needs to be decided, which direction to follow. If this idiom seems too much broken to be supported, the note could be improved. If it should be supported, the constructors in 20.8.2.2.1 [util.smartptr.shared.const] need a careful analysis to ensure that post-conditions are correct. Several library implementations currently do not support this example, instead they typically cause a crash. Matt points out that there are currently no explicit requirements imposed on shared_ptr objects to prevent them from owning the same underlying object without sharing the ownership. It might be useful to add such a requirement.[2013-03-15 Issues Teleconference]
Moved to Open.
More discussion is needed to pick a direction to guide a proposed resolution.
[2013-05-09 Jonathan comments]
The note says the newly created shared_ptr is assigned to the weak_ptr member. It doesn't say before doing that the shared_ptr should check if the weak_ptr is non-empty and possibly share ownership with some other pre-existing shared_ptr.
Proposed resolution:
Section: 26.5.1.2 [rand.req.seedseq], 26.5.3 [rand.eng], 26.5.4 [rand.adapt] Status: Open Submitter: Daniel Krügler Opened: 2012-08-18 Last modified: 2015-04-08
View all other issues in [rand.req.seedseq].
View all issues with Open status.
Discussion:
LWG issue 2180 points out some deficiences in regard to the specification of the library-provided type std::seed_seq regarding exceptions, but there is another specification problem in regard to general types satisfying the seed sequence constraints (named SSeq) as described in 26.5.1.2 [rand.req.seedseq].
26.5.3 [rand.eng] p3 and 26.5.4.1 [rand.adapt.general] p3 say upfront:Except where specified otherwise, no function described in this section 26.5.3 [rand.eng]/26.5.4 [rand.adapt] throws an exception.
This constraint causes problems, because the described templates in these sub-clauses depend on operations of SSeq::generate() which is a function template, that depends both on operations provided by the implementor of SSeq (e.g. of std::seed_seq), and those of the random access iterator type provided by the caller. With class template linear_congruential_engine we have just one example for a user of SSeq::generate() via:
template<class Sseq> linear_congruential_engine<>::linear_congruential_engine(Sseq& q); template<class Sseq> void linear_congruential_engine<>::seed(Sseq& q);
None of these operations has an exclusion rule for exceptions.
As described in 2180 the wording for std::seed_seq should and can be fixed to ensure that operations of seed_seq::generate() won't throw except from operations of the provided iterator range, but there is no corresponding "safety belt" for user-provided SSeq types, since 26.5.1.2 [rand.req.seedseq] does not impose no-throw requirements onto operations of seed sequences.A quite radical step to fix this problem would be to impose general no-throw requirements on the expression q.generate(rb,re) from Table 115, but this is not as simple as it looks initially, because this function again depends on general types that are mutable random access iterators. Typically, we do not impose no-throw requirements on iterator operations and this would restrict general seed sequences where exceptions are not a problem. Furthermore, we do not impose comparable constraints for other expressions, like that of the expression g() in Table 116 for good reasons, e.g. random_device::operator() explicitly states when it throws exceptions.
A less radical variant of the previous suggestion would be to add a normative requirement on the expression q.generate(rb,re) from Table 115 that says: "Throws nothing if operations of rb and re do not throw exceptions". Nevertheless we typically do not describe conditional Throws elements in proper requirement sets elsewhere (Container requirements excluded, they just describe the containers from Clause 23) and this may exclude resonable implementations of seed sequences that could throw exceptions under rare situations.
The iterator arguments provided to SSeq::generate() for operations in templates of 26.5.3 [rand.eng] and 26.5.4 [rand.adapt] are under control of implementations, so we could impose stricter exceptions requirements on SSeq::generate() for SSeq types that are used to instantiate member templates in 26.5.3 [rand.eng] and 26.5.4 [rand.adapt] solely.
We simply add extra wording to the introductive parts of 26.5.3 [rand.eng] and 26.5.4 [rand.adapt] that specify that operations of the engine (adaptor) templates that depend on a template parameter SSeq throw no exception unless SSeq::generate() throws an exception.
Given these options I would suggest to apply the variant described in the fourth bullet.
The proposed resolution attempts to reduce a lot of the redundancies of requirements in the introductory paragraphs of 26.5.3 [rand.eng] and 26.5.4 [rand.adapt] by introducing a new intermediate sub-clause "Engine and engine adaptor class templates" following sub-clause 26.5.2 [rand.synopsis]. This approach also solves the problem that currently 26.5.3 [rand.eng] also describes requirements that apply for 26.5.4 [rand.adapt] (Constrained templates involving the Sseq parameters).[2013-04-20, Bristol]
Remove the first bullet point:
?- Throughout this sub-clause general requirements and conventions are described that apply to every class template specified in sub-clause 26.5.3 [rand.eng] and 26.5.4 [rand.adapt]. Phrases of the form "in those sub-clauses" shall be interpreted as equivalent to "in sub-clauses 26.5.3 [rand.eng] and 26.5.4 [rand.adapt]".
Replace "in those sub-clauses" with "in sub-clauses 26.5.3 [rand.eng] and 26.5.4 [rand.adapt]".
Find another place for the wording. Daniel: These are requirements on the implementation not on the types. I'm not comfortable in moving it to another place without double checking. Improve the text (there are 4 "for"s): for copy constructors, for copy assignment operators, for streaming operators, and for equality and inequality operators are not shown in the synopses. Move the information of this paragraph to the paragraphs it refers to:"-?- Descriptions are provided in those sub-clauses only for engine operations that are not described in 26.5.1.4 [rand.req.eng], for adaptor operations that are not described in 26.5.1.5 [rand.req.adapt], or for operations where there is additional semantic information. In particular, declarations for copy constructors, for copy assignment operators, for streaming operators, and for equality and inequality operators are not shown in the synopses."
Alisdair: I prefer duplication here than consolidation/reference to these paragraphs.
The room showed weakly favjust or for duplication.Previous resolution from Daniel [SUPERSEDED]:
Add a new sub-clause titled "Engine and engine adaptor class templates" following sub-clause 26.5.2 [rand.synopsis] (but at the same level) and add one further sub-clause "General" as child of the new sub-clause as follows:
Engine and engine adaptor class templates [rand.engadapt] General [rand.engadapt.general]-?- Throughout this sub-clause general requirements and conventions are described that apply to every class template specified in sub-clause 26.5.3 [rand.eng] and 26.5.4 [rand.adapt]. Phrases of the form "in those sub-clauses" shall be interpreted as equivalent to "in sub-clauses 26.5.3 [rand.eng] and 26.5.4 [rand.adapt]".
-?- Except where specified otherwise, the complexity of each function specified in those sub-clauses is constant. -?- Except where specified otherwise, no function described in those sub-clauses throws an exception. -?- Every function described in those sub-clauses that has a function parameter q of type SSeq& for a template type parameter named SSeq that is different from type std::seed_seq throws what and when the invocation of q.generate throws. -?- Descriptions are provided in those sub-clauses only for engine operations that are not described in 26.5.1.4 [rand.req.eng], for adaptor operations that are not described in 26.5.1.5 [rand.req.adapt], or for operations where there is additional semantic information. In particular, declarations for copy constructors, for copy assignment operators, for streaming operators, and for equality and inequality operators are not shown in the synopses. -?- Each template specified in those sub-clauses requires one or more relationships, involving the value(s) of its non-type template parameter(s), to hold. A program instantiating any of these templates is ill-formed if any such required relationship fails to hold. -?- For every random number engine and for every random number engine adaptor X defined in those sub-clauses:
if the constructor
template <class Sseq> explicit X(Sseq& q);is called with a type Sseq that does not qualify as a seed sequence, then this constructor shall not participate in overload resolution;
if the member function
template <class Sseq> void seed(Sseq& q);is called with a type Sseq that does not qualify as a seed sequence, then this function shall not participate in overload resolution;
The extent to which an implementation determines that a type cannot be a seed sequence is unspecified, except that as a minimum a type shall not qualify as a seed sequence if it is implicitly convertible to X::result_type.
Edit the contents of sub-clause 26.5.3 [rand.eng] as indicated:
-1- Each type instantiated from a class template specified in this section 26.5.3 [rand.eng] satisfies the requirements of a random number engine (26.5.1.4 [rand.req.eng]) type and the general implementation requirements specified in sub-clause [rand.engadapt.general].
-2- Except where specified otherwise, the complexity of each function specified in this section 26.5.3 [rand.eng] is constant.-3- Except where specified otherwise, no function described in this section 26.5.3 [rand.eng] throws an exception.-4- Descriptions are provided in this section 26.5.3 [rand.eng] only for engine operations that are not described in 26.5.1.4 [rand.req.eng] […]-5- Each template specified in this section 26.5.3 [rand.eng] requires one or more relationships, involving the value(s) of its non-type template parameter(s), to hold. […]-6- For every random number engine and for every random number engine adaptor X defined in this subclause (26.5.3 [rand.eng]) and in sub-clause 26.5.3 [rand.eng]: […]Edit the contents of sub-clause 26.5.4.1 [rand.adapt.general] as indicated:
-1- Each type instantiated from a class template specified in this section
26.5.3 [rand.eng]26.5.4 [rand.adapt] satisfies the requirements of a random number engine adaptor (26.5.1.5 [rand.req.adapt]) type and the general implementation requirements specified in sub-clause [rand.engadapt.general].-2- Except where specified otherwise, the complexity of each function specified in this section 26.5.4 [rand.adapt] is constant.-3- Except where specified otherwise, no function described in this section 26.5.4 [rand.adapt] throws an exception.-4- Descriptions are provided in this section 26.5.4 [rand.adapt] only for engine operations that are not described in 26.5.1.5 [rand.req.adapt] […]-5- Each template specified in this section 26.5.4 [rand.adapt] requires one or more relationships, involving the value(s) of its non-type template parameter(s), to hold. […]
[2014-02-09, Daniel provides alternative resolution]
[2014-05-22, Daniel syncs with recent WP]
Proposed resolution:
This wording is relative to N3936.
Edit the contents of sub-clause 26.5.3 [rand.eng] as indicated:
-1- Each type instantiated from a class template specified in this section 26.5.3 [rand.eng] satisfies the requirements of a random number engine (26.5.1.4 [rand.req.eng]) type.
-2- Except where specified otherwise, the complexity of each function specified in this section 26.5.3 [rand.eng] is constant. -3- Except where specified otherwise, no function described in this section 26.5.3 [rand.eng] throws an exception. -?- Every function described in this section 26.5.3 [rand.eng] that has a function parameter q of type Sseq& for a template type parameter named Sseq that is different from type std::seed_seq throws what and when the invocation of q.generate throws. -4- Descriptions are provided in this section 26.5.3 [rand.eng] only for engine operations that are not described in 26.5.1.4 [rand.req.eng] or for operations where there is additional semantic information. In particular, declarations for copy constructors,forcopy assignment operators,forstreaming operators,and forequality operators, and inequality operators are not shown in the synopses. -5- Each template specified in this section 26.5.3 [rand.eng] requires one or more relationships, involving the value(s) of its non-type template parameter(s), to hold. A program instantiating any of these templates is ill-formed if any such required relationship fails to hold. -6- For every random number engine and for every random number engine adaptor X defined in this subclause (26.5.3 [rand.eng]) and in sub-clause 26.5.4 [rand.adapt]:
if the constructor
template <class Sseq> explicit X(Sseq& q);is called with a type Sseq that does not qualify as a seed sequence, then this constructor shall not participate in overload resolution;
if the member function
template <class Sseq> void seed(Sseq& q);is called with a type Sseq that does not qualify as a seed sequence, then this function shall not participate in overload resolution;
The extent to which an implementation determines that a type cannot be a seed sequence is unspecified, except that as a minimum a type shall not qualify as a seed sequence if it is implicitly convertible to X::result_type.
Edit the contents of sub-clause 26.5.4.1 [rand.adapt.general] as indicated:
-1- Each type instantiated from a class template specified in this section
-2- Except where specified otherwise, the complexity of each function specified in this section 26.5.4 [rand.adapt] is constant. -3- Except where specified otherwise, no function described in this section 26.5.4 [rand.adapt] throws an exception. -?- Every function described in this section 26.5.4 [rand.adapt] that has a function parameter q of type Sseq& for a template type parameter named Sseq that is different from type std::seed_seq throws what and when the invocation of q.generate throws. -4- Descriptions are provided in this section 26.5.4 [rand.adapt] only for adaptor operations that are not described in section 26.5.1.5 [rand.req.adapt] or for operations where there is additional semantic information. In particular, declarations for copy constructors,26.5.3 [rand.eng]26.5.4 [rand.adapt] satisfies the requirements of a random number engine adaptor (26.5.1.5 [rand.req.adapt]) type.forcopy assignment operators,forstreaming operators,and forequality operators, and inequality operators are not shown in the synopses. -5- Each template specified in this section 26.5.4 [rand.adapt] requires one or more relationships, involving the value(s) of its non-type template parameter(s), to hold. A program instantiating any of these templates is ill-formed if any such required relationship fails to hold.
Edit the contents of sub-clause 26.5.8.1 [rand.dist.general] p2 as indicated: [Drafting note: These editorial changes are just for consistency with those applied to 26.5.3 [rand.eng] and 26.5.4.1 [rand.adapt.general] — end drafting note]
-2- Descriptions are provided in this section 26.5.8 [rand.dist] only for distribution operations that are not described in 26.5.1.6 [rand.req.dist] or for operations where there is additional semantic information. In particular, declarations for copy constructors,
forcopy assignment operators,forstreaming operators,and forequality operators, and inequality operators are not shown in the synopses.
Section: 28.10.1 [re.results.const], 28.10.6 [re.results.all] Status: New Submitter: Pete Becker Opened: 2012-08-29 Last modified: 2015-04-08
View other active issues in [re.results.const].
View all other issues in [re.results.const].
View all issues with New status.
Discussion:
28.10.1 [re.results.const] p1 says:
In all match_results constructors, a copy of the Allocator argument shall be used for any memory allocation performed by the constructor or member functions during the lifetime of the object.
There are three constructors:
match_results(const Allocator& = Allocator()); match_results(const match_results& m); match_results(match_results&& m) noexcept;
The second and third constructors do no have an Allocator argument, so despite the "all match_results constructors", it is not possible to use "the Allocator argument" for the second and third constructors.
The requirements for those two constructors also does not give any guidance. The second constructor has no language about allocators, and the third states that the stored Allocator value is move constructed from m.get_allocator(), but doesn't require using that allocator to allocate memory. The same basic problem recurs in 28.10.6 [re.results.all], which gives the required return value for get_allocator():Returns: A copy of the Allocator that was passed to the object's constructor or, if that allocator has been replaced, a copy of the most recent replacement.
Again, the second and third constructors do not take an Allocator, so there is nothing that meets this requirement when those constructors are used.
Proposed resolution:
Section: 28.10.1 [re.results.const], 28.10.6 [re.results.all] Status: New Submitter: Pete Becker Opened: 2012-08-29 Last modified: 2015-04-08
View other active issues in [re.results.const].
View all other issues in [re.results.const].
View all issues with New status.
Discussion:
The effects of the two assignment operators are specified in Table 141. Table 141 makes no mention of allocators, so, presumably, they don't touch the target object's allocator. That's okay, but it leaves the question: match_results::get_allocator() is supposed to return "A copy of the Allocator that was passed to the object's constructor or, if that allocator has been replaced, a copy of the most recent replacement"; if assignment doesn't replace the allocator, how can the allocator be replaced?
Proposed resolution:
Section: 23.2.5.1 [unord.req.except] Status: Open Submitter: Alisdair Meredith Opened: 2012-09-23 Last modified: 2015-04-08
View all issues with Open status.
Discussion:
The hash functor and key-comparison functor of unordered containers are allowed to throw on swap.
23.2.5.1 [unord.req.except]p3 "For unordered associative containers, no swap function throws an exception unless that exception is thrown by the swap of the container's Hash or Pred object (if any)."
In such a case we must offer the basic exception safety guarantee, where both objects are left in valid but unspecified states, and no resources are leaked. This yields a corrupt, un-usable container if the first swap succeeds, but the second fails by throwing, as the functors form a matched pair.
So our basic scenario is first, swap the allocators if the allocators propagate on swap, according to allocator_traits. Next we swap the pointers to our internal hash table data structures, so that they match the allocators that allocated them. (Typically, this operation cannot throw). Now our containers are back in a safely destructible state if an exception follows.
Next, let's say we swap the hash functor, and that throws. We have a corrupt data structure, in that the buckets are not correctly indexed by the correct functors, lookups will give unpredicatable results etc. We can safely restore a usable state by forcibly clearing each container - which does not leak resources and leaves us with two (empty but) usable containers.
Now let us assume that the hasher swap succeeds. Next we swap the equality comparator functor, and this too could throw. The important point to bear in mind is that these two functors form an important pairing - two objects that compare equal by the equality functor must also hash to the same value. If we swap one without the other, we most likely leave the container in an unusable state, even if we clear out all elements.
1. A colleague pointed out that the solution for this is to dynamically allocate the two functors, and then we need only swap pointers, which is not a throwing operation. And if we don't want to allocate on default construction (a common QoI request), we might consider moving to a dynamically allocated functors whenever swap is called, or on first insertion. Of course, allocating memory in swap is a whole new can of worms, but this does not really sound like the design we had intended.
2. The simplest option is to say that we do not support hasher or equality functors that throw on ADL swap. Note that the requirement is simply to not throw, rather than to be explicitly marked as noexcept. Throwing functors are allowed, so long as we never use values that would actually manifest a throw when used in an unordered container.
Pablo went on to give me several more options, to be sure we have a full set to consider:
3. Disallow one or the other functor from throwing. In that case, the possibly-throwing functor must be swapped first, then the other functor, the allocator, and the data pointer(s) afterwards (in any order -- there was a TC that allocator assignment and swap may not throw if the corresponding propagation trait is true.). Of course, the question becomes: which functor is allowed to throw and which one is not?
4. Require that any successful functor swap be reliably reversible. This is very inventive. I know of no other place in the standard where such a requirement is stated, though I have occasionally wanted such a guarantee.
5. Allow a failed swap to leave the containers in a state where future insertions may fail for reasons other than is currently allowed. Specifically, if the hash and equality functors are out of sync, all insertions will fail. Presumably some "incompletely swapped" exception would be thrown. This is "slightly" inventive, although people have been discussing "radioactive" states for a while.
[2013-03-15 Issues Teleconference]
Moved to Open.
Proposed resolution:
Section: 28.10.1 [re.results.const] Status: New Submitter: Pete Becker Opened: 2012-10-02 Last modified: 2015-04-08
View other active issues in [re.results.const].
View all other issues in [re.results.const].
View all issues with New status.
Discussion:
28.10.1 [re.results.const]/3: "Move-constructs an object of class match_results satisfying the same postconditions as Table 141."
Table 141 lists various member functions and says that their results should be the results of the corresponding member function calls on m. But m has been moved from, so the actual requirement ought to be based on the value that m had before the move construction, not on m itself.
In addition to that, the requirements for the copy constructor should refer to Table 141.
Ganesh: Also, the requirements for move-assignment should refer to Table 141. Further it seems as if in Table 141 all phrases of "for all integers n < m.size()" should be replaced by "for all unsigned integers n < m.size()".Proposed resolution:
Section: 26.8 [c.math] Status: Open Submitter: Daniel Krügler Opened: 2012-10-02 Last modified: 2015-04-08
View other active issues in [c.math].
View all other issues in [c.math].
View all issues with Open status.
Discussion:
In C++03 the following two programs are invalid:
#include <cmath> int main() { std::abs(0u); }
#include <cstdlib> int main() { std::abs(0u); }
because none of the std::abs() overloads is a best match.
In C++11 the additional "sufficient overload" rule from 26.8 [c.math] p11 (see also LWG 2086) can be read to be applicable to the std::abs() overloads as well, which can lead to the following possible conclusions:
The program
#include <type_traits> #include <cmath> static_assert(std::is_same<decltype(std::abs(0u)), double>(), "Oops"); int main() { std::abs(0u); // Calls std::abs(double) }
is required to be well-formed, because of sub-bullet 2 ("[..] or an integer type [..]") of 26.8 [c.math] p11 (Note that the current resolution of LWG 2086 doesn't fix this problem).
Any translation unit including both <cmath> and <cstdlib> might be ill-formed because of two conflicting requirements for the return type of the overload std::abs(int).
It seems to me that at least the second outcome is not intended, personally I think that both are unfortunate: In contrast to all other floating-point functions explicitly listed in sub-clause 26.8 [c.math], the abs overloads have a special and well-defined meaning for signed integers and thus have explicit overloads returning a signed integral type. I also believe that there is no problem accepting that std::fabs(0u) is well-defined with return type double, because the leading 'f' clearly signals that we have a floating point function here. But the expected return type of std::abs(0u) seems less than clear to me. A very reasonable answer could be that this has the same type as its argument type, alternatively it could be a reasonably chosen signed integer type, or a floating point type. It should also be noted, that the corresponding "generic type function" rule set from C99/C1x in 7.25 p2+3 is restricted to the floating-point functions from <math.h> and <complex.h>, so cannot be applied to the abs functions (but to the fabs functions!).
Selecting a signed integer return type for unsigned input values can also problematic: The directly corresponding signed integer type would give half of the possible argument values an implementation-defined result value. Choosing the first signed integer value that can represent all positive values would solve this problem for unsigned int, but there would be no clear answer for the input type std::uintmax_t.Based on this it seems to me that the C++03 state in regard to unsigned integer values was the better situation, alerting the user that this code is ambigious at the moment (This might be change with different core-language rules as described in N3387).
[2013-04-20, Bristol]
Resolution: leave as new and bring it back in Chicago.
[2013-09 Chicago]
This issue also relates to LWG 2294
STL: these two issues should be bundled Stefanus: do what Pete says, and add overloads for unsigned to return directly STL: agree Consensus that this is an issue Walter: motion to move to Open STL: no wording for 2294 Stefanus: move to open and note the 2 issues are related and should be moved together Stefanus: add and define unsigned versions of abs()[2014-02-03 Howard comments]
Defining abs() for unsigned integers is a bad idea. Doing so would turn compile time errors into run time errors, especially in C++ where we have templates, and the types involved are not always apparent to the programmer at design time. For example, consider:
template <class Int>
Int
analyze(Int x, Int y)
{
// ...
if (std::abs(x - y) < threshold)
{
// ...
}
// ...
}
std::abs(expr) is often used to ask: Are these two numbers sufficiently close? When the assumption is that the two numbers are signed (either signed integral, or floating point), the logic is sound. But when the same logic is accidentally used with an arithmetic type not capable of representing negative numbers, and especially if unsigned overflow will silently happen, then the logic is no longer correct:
auto i = analyze(20u, 21u); // Today a compile time error // But with abs(unsigned) becomes a run time error
This is not idle speculation. Search the net for "abs unsigned" here or here.
In C++11, chrono durations and time_points are allowed to be based on unsigned integers. Taking the absolute value of the difference of two such time_points would be easy to accidentally do (say in code templated on time_points), and would certainly be a logic bug, caught at compile time unless we provide the error prone abs(unsigned).[2015-02, Cologne]
GR: Do we want to make the changes to both <cmath> and <cstdlib>?
AM: I think so; we should provide consistent overloads.
GR: Then we're imposing restrictions on what users put in the global namespace.
AM: I'm not so worried about that. Users already know not to use C library names.
VV: So what are we going to do about unsigned integers? AM: We will say that they are ill-formed.
AM: Does anyone volunteer to send updated wording to Daniel? GR, can you do it? GR: Sure.
GR: To clarify: we want to make unsigned types ill-formed?
AM: With promotion rank at least unsigned int.
GR: And NL suggests to just list those types.
This wording is relative to N3376.
Change 26.8 [c.math] p11 as indicated:
-11- Moreover, except for the abs functions, there shall be additional overloads sufficient to ensure:
[…]
[2015-03-03, Geoffrey Romer provides improved wording]
In the following I've drafted combined wording to resolve LWG 2192 and 2294. Note that the first two paragraphs are taken verbatim from the P/R of LWG 2294, but the third is newly drafted:
Proposed resolution:
This wording is relative to N4296.
Insert the following new paragraphs after 26.8 [c.math] p7:
-6- In addition to the int versions of certain math functions in <cstdlib>, C++ adds long and long long overloaded versions of these functions, with the same semantics.
-7- The added signatures are:long abs(long); // labs() long long abs(long long); // llabs() ldiv_t div(long, long); // ldiv() lldiv_t div(long long, long long); // lldiv()-?- To avoid ambiguities, C++ also adds the following overloads of abs() to <cstdlib>, with the semantics defined in <cmath>:
float abs(float); double abs(double); long double abs(long double);-?- To avoid ambiguities, C++ also adds the following overloads of abs() to <cmath>, with the semantics defined in <cstdlib>:
int abs(int); long abs(long); long long abs(long long);-?- If abs() is called with an argument of unsigned integral type that cannot be converted to int by integral promotion (4.5 [conv.prom]), the program is ill-formed. [Note: arguments that can be promoted to int are permitted for compatibility with C. — end note]
Section: 28.10 [re.results] Status: Open Submitter: Daniel Krügler Opened: 2012-10-06 Last modified: 2015-04-08
View all other issues in [re.results].
View all issues with Open status.
Discussion:
The requirement expressed in 28.10 [re.results] p2
The class template match_results shall satisfy the requirements of an allocator-aware container and of a sequence container, as specified in 23.2.3 [sequence.reqmts], except that only operations defined for const-qualified sequence containers are supported.
can be read to require the existence of the described constructors from as well, but they do not exist in the synopsis.
The missing sequence constructors are:match_results(initializer_list<value_type>); match_results(size_type, const value_type&); template<class InputIterator> match_results(InputIterator, InputIterator);
The missing allocator-aware container constructors are:
match_results(const match_results&, const Allocator&); match_results(match_results&&, const Allocator&);
It should be clarified, whether (a) constructors are an exception of above mentioned operations or (b) whether at least some of them (like those accepting a match_results value and an allocator) should be added.
As visible in several places of the standard (including the core language), constructors seem usually to be considered as "operations" and they certainly can be invoked for const-qualified objects. The below given proposed resolution applies only the minimum necessary fix, i.e. it excludes constructors from above requirement.[2013-04-20, Bristol]
Check current implementations to see what they do and, possibly, write a paper.
[2013-09 Chicago]
Ask Daniel to update the proposed wording to include the allocator copy and move constructors.
[2014-01-18 Daniel changes proposed resolution]
Previous resolution from Daniel [SUPERSEDED]:
Change 28.10 [re.results] p2 as indicated:
The class template match_results shall satisfy the requirements of an allocator-aware container and of a sequence container, as specified in 23.2.3 [sequence.reqmts], except that only operations defined for const-qualified sequence containers that are not constructors are supported.
Proposed resolution:
This wording is relative to N3936.
Change 28.10 [re.results] p4, class template match_results synopsis, as indicated:
[…] // 28.10.1, construct/copy/destroy: explicit match_results(const Allocator& a = Allocator()); match_results(const match_results& m); match_results(const match_results& m, const Allocator& a); match_results(match_results&& m) noexcept; match_results(match_results&& m, const Allocator& a) noexcept; […]
Change 28.10.1 [re.results.const] as indicated: [Drafting note: Paragraph 6 as currently written, makes not much sense, because the noexcept does not allow any exception to propagate. Further-on, the allocator requirements do not allow for throwing move constructors. Deleting it seems to be near to editorial — end drafting note]
match_results(const match_results& m); match_results(const match_results& m, const Allocator& a);-4- Effects: Constructs an object of class match_results, as a copy of m.
match_results(match_results&& m) noexcept; match_results(match_results&& m, const Allocator& a) noexcept;-5- Effects: Move-constructs an object of class match_results from m satisfying the same postconditions as Table 142.
AdditionallyFor the first form, the stored Allocator value is move constructed from m.get_allocator().-6- Throws: Nothing if the allocator's move constructor throws nothing.
Section: 23.2.5 [unord.req] Status: Open Submitter: Alisdair Meredith Opened: 2012-10-09 Last modified: 2015-04-08
View other active issues in [unord.req].
View all other issues in [unord.req].
View all issues with Open status.
Discussion:
The user cannot specify a max_load_factor for their unordered container at construction, it must be supplied after the event, when the container is potentially not empty. The contract for this method is deliberately vague, not guaranteeing to use the value supplied by the user, and any value actually used will be used as a ceiling that the container will attempt to respect.
The only guarantee we have is that, if user requests a max_load_factor that is less than the current load_factor, then the operation will take constant time, thus outlawing an implementation that chooses to rehash and so preserve as a class invariant that load_factor < max_load_factor.
Reasonable options conforming to the standard include ignoring the user's request if the requested value is too low, or deferring the rehash to the next insert operation and allowing the container to have a strange state (wrt max_load_factor) until then - and there is still the question of rehashing if the next insert is for a duplicate key in a unique container.
Given the deliberate vagueness of the current wording, to support a range of reasonable (but not perfect) behaviors, it is not clear why the equally reasonable rehash to restore the constraint should be outlawed. It is not thought that this is a performance critical operation, where users will be repeatedly setting low load factors on populated containers, in a tight or (less unlikely) an instant response scenario.
[2013-03-15 Issues Teleconference]
Moved to Open.
Alisdair to provide wording.
Proposed resolution:
Section: 23.2.5 [unord.req] Status: Open Submitter: Alisdair Meredith Opened: 2012-10-09 Last modified: 2015-04-08
View other active issues in [unord.req].
View all other issues in [unord.req].
View all issues with Open status.
Discussion:
The default constructor, allocator-aware constructor, and range-based constructors for the unordered containers do not offer a means to control the initial max_load_factor, so the standard mandates the value 1.0. This seems overly restrictive, as there is plenty of research suggesting a value between 0.5 and 1.0 is more often optimal for unique-key containers, and perhaps a slightly higher value might be appropriate for multi-containers.
Rather than guess at the appropriate max_load_factor, it seems reasonable that the standard should allow vendors to pick a value at their discretion, with perhaps a note of advice. It is less clear whether the default value should be implementation-defined or unspecified, given the ease of a user determining this by querying this attribute immediately after construction.
[2013-03-15 Issues Teleconference]
Moved to Open.
Alisdair to provide wording.
Marshall: It seems to me that what you really want is to be able to pass a max load factor in the constructor, but that's a different issue.
Alisdair agrees in principle, but concerned with adding yet more constructors to these classes.
Proposed resolution:
Section: C.5 [diff.library] Status: New Submitter: Kevin McCarty Opened: 2012-02-03 Last modified: 2015-04-08
View all other issues in [diff.library].
View all issues with New status.
Discussion:
It seems that in C.5 [diff.library], Table 150 the following macros from 18.3.3 [c.limits], Table 31 are missing:
LLONG_MIN LLONG_MAX ULLONG_MAX
In addition in C.5 [diff.library], Table 150 the following macros from 18.3.3 [c.limits], Table 32 are missing:
DECIMAL_DIG FLT_EVAL_METHOD
Furtheron it seems that in C.5 [diff.library], Table 149/150 further macros are missing as well, e.g. HUGE_VALF, INFINITY, etc.
[2014-02 Issaquah:]
This is an issue, all of C has not been updated for C99, C99 functions are missing, whole section needs to be overhauled.
The issue needs to be updated for functions and other missing items and when that happens the issue title is wrong and needs to be adapted.Proposed resolution:
Section: 30.6.8 [futures.async] Status: Open Submitter: Detlef Vollmann Opened: 2012-10-19 Last modified: 2015-04-08
View all other issues in [futures.async].
View all issues with Open status.
Discussion:
promise, packaged_task, and async are the only places where a shared state is actually supposed to be allocated. Accordingly, promise and packaged_task are "allocator-aware". But function template async provides no way to provide an allocator.
[2013-09 Chicago]
Matt: deprecate async
Nico: read my paper Alisdair: defer issues to wait for polymorphic allocators Alisdair: defer, active topic of research Deferred[2014-02-20 Re-open Deferred issues as Priority 4]
Proposed resolution:
Section: 23.2.3 [sequence.reqmts], 23.2.4 [associative.reqmts], 23.2.5 [unord.req], 26.5.1.2 [rand.req.seedseq] Status: Open Submitter: Jeffrey Yasskin Opened: 2012-10-21 Last modified: 2015-04-08
View all other issues in [sequence.reqmts].
View all issues with Open status.
Discussion:
In 23.2.3 [sequence.reqmts] p3, we have "il designates an object of type initializer_list<value_type>", and then several functions that take 'il' as an argument. However, an expression like {1, 2, 'a'} is not an object of type initializer_list<int> unless it's used to initialize an explicitly-typed variable of that type. I believe we want:
std::vector<int> v; v = {1, 2, 'a'};
to compile portably, so we should say something different when defining 'il'. The same phrasing happens in 23.2.4 [associative.reqmts], 23.2.5 [unord.req], and 26.5.1.2 [rand.req.seedseq].
This may just be an editorial issue because the actual class synopses declare the functions to take initializer_list<exact_type>.[2013-03-15 Issues Teleconference]
Moved to Open.
This is definitely not NAD
Should copy the suggested wording as the proposed resolution.
Proposed resolution:
Section: 24.5.1 [reverse.iterators] Status: New Submitter: Jeffrey Yasskin Opened: 2012-10-30 Last modified: 2015-04-08
View all other issues in [reverse.iterators].
View all issues with New status.
Discussion:
std::reverse_iterator::reverse_iterator(Iterator) should be constexpr so that other constexpr functions can return reverse_iterators. Of the other methods, the other constructors, base(), operator+, operator-, operator[], and the non-member operators can probably also be constexpr.
operator* cannot be constexpr because it involves an assignment to a member variable. Discussion starting with c++std-lib-33282 indicated that it would be useful to make reverse_iterator a literal type despite this restriction on its use at compile time.Proposed resolution:
Section: 27.5.5.2 [basic.ios.cons] Status: Open Submitter: Andrey Semashev Opened: 2012-11-09 Last modified: 2015-04-08
View all other issues in [basic.ios.cons].
View all issues with Open status.
Discussion:
There is an ambiguity in how std::basic_ios::init method (27.5.5.2 [basic.ios.cons]) can be used in the derived class. The Standard only specify the state of the basic_ios object after the call completes. However, in basic_ios default constructor description (27.5.5.2 [basic.ios.cons]) there is this sentence:
Effects: Constructs an object of class basic_ios (27.5.3.7 [ios.base.cons]) leaving its member objects uninitialized. The object shall be initialized by calling basic_ios::init before its first use or before it is destroyed, whichever comes first; otherwise the behavior is undefined.
This restriction hints that basic_ios::init should be called exactly once before the object can be used or destroyed, because basic_ios::init may not know whether it was called before or not (i.e. whether its members are actually uninitialized or are initialized by the previous call to basic_ios::init). There is no such restriction in the basic_ios::init preconditions so it is not clear whether it is allowed to call basic_ios::init multiple times or not.
This problem has already affected publicly available implementations. For example, Microsoft Visual C++ STL introduces a memory leak if basic_ios::init is called multiple times, while GCC 4.7 and STLPort reinitialize the basic_ios object correctly without memory leak or any other undesired effects. There was a discussion of this issue on Boost developers mailing list, and there is a test case that reproduces the problem. The test case is actually a bug report for my Boost.Log library, which attempts to cache basic_ostream-derived objects internally to avoid expensive construction and destruction. My stream objects allowed resetting the stream buffer pointers the stream is attached to, without requiring to destroy and construct the stream. My personal view of the problem and proposed resolution follows. While apparently the intent of basic_ios::init is to provide a way to initialize basic_ios after default construction, I see no reason to forbid it from being called multiple times to reinitialize the stream. Furthermore, it is possible to implement a conforming basic_ios that does not have this restriction. The quoted above section of the Standard that describes the effects of the default constructor is misleading. The Standard does not mandate any data members of basic_ios or ios_base (27.5.3 [ios.base]), which it derives from. This means that the implementation is allowed to use non-POD data members with default constructors that initialize the members with particular default values. For example, in the case of Microsoft Visual C++ STL the leaked memory is an std::locale instance that is dynamically allocated during basic_ios::init, a raw pointer to which is stored within ios_base. It is possible to store e.g. an unique_ptr instead of a raw pointer as a member of ios_base, the smart pointer will default initialize the underlying raw pointer on default construction and automatically destroy the allocated object upon being reset or destroyed, which would eliminate the leak and allow basic_ios::init to be called multiple times. This leads to conclusion that the default constructor of basic_ios cannot leave "its member objects uninitialized" but instead performs default initialization of the member objects, which would mean the same thing in case of POD types. However, I feel that restricting ios_base and basic_ios members to non-POD types is not acceptable. Since multiple calls to basic_ios::init are not forbidden by the Standard, I propose to correct the basic_ios default constructor description so that it is allowed to destroy basic_ios object without calling basic_ios::init. This would imply that any raw members of basic_ios and ios_base should be initialized to values suitable for destruction (essentially, this means only initializing raw pointers to NULL). The new wording could look like this:Effects: Constructs an object of class basic_ios (27.5.3.7 [ios.base.cons]) initializing its member objects to unspecified state, only suitable for basic_ios destruction. The object shall be initialized by calling basic_ios::init before its first use; otherwise the behavior is undefined.
This would remove the hint that basic_ios::init must be called exactly once. Also, this would remove the requirement for basic_ios::init to be called at all before the destruction. This is also an important issue because the derived stream constructor may throw an exception before it manages to call basic_ios::init (for example, if the streambuf constructor throws), and in this case the basic_ios destructor has undefined behavior.
To my mind, the described modification is sufficient to resolve the issue. But to emphasize the possibility to call basic_ios::init multiple times, a remark or a footnote for basic_ios::init postconditions could be added to explicitly state the semantics of calling it multiple times. The note could read as follows:The function can be called multiple times during the object lifetime. Each subsequent call reinitializes the object to the described in postconditions initial state.
[2013-04-20, Bristol]
Alisdair: The current wording is unclear but the proposed resolution is wrong
Solution: Clarify that init must be called once and only once. Move then to review.Proposed resolution:
This wording is relative to N3485.
Edit 27.5.5.2 [basic.ios.cons] as indicated:
basic_ios();-2- Effects: Constructs an object of class basic_ios (27.5.3.7 [ios.base.cons])
leaving its member objects uninitializedinitializing its member objects to unspecified state, only suitable for basic_ios destruction. The object shall be initialized by calling basic_ios::init before its first useor before it is destroyed, whichever comes first; otherwise the behavior is undefined.void init(basic_streambuf<charT,traits>* sb);Postconditions: The postconditions of this function are indicated in Table 128.
-?- Remarks: The function can be called multiple times during the object lifetime. Each subsequent call reinitializes the object to the described in postconditions initial state.
Section: 23.2.4 [associative.reqmts], 23.2.5 [unord.req] Status: Open Submitter: Alisdair Meredith Opened: 2012-11-14 Last modified: 2015-04-08
View other active issues in [associative.reqmts].
View all other issues in [associative.reqmts].
View all issues with Open status.
Discussion:
The requirements on the functors used to arrange elements in the various associative and unordered containers are given by a set of expressions in tables 102 — Associative container requirements, and 103 — Unordered associative container requirements. In keeping with Library convention these expressions make the minimal requirements necessary on their types. For example, we have the following 3 row extracts for the unordered containers:
Expression | Assertion/note pre-/post-condition |
X(n, hf, eq) X a(n, hf, eq) |
Requires: hasher and key_equal are CopyConstructible. |
X(n, hf) X a(n, hf) |
Requires: hasher is CopyConstructible and key_equal is DefaultConstructible. |
X(n) X a(n) |
Requires: hasher and key_equal are DefaultConstructible. |
However, the signature for each class template requires that the functors must effectively be CopyConstructible for each of these expressions:
template <class Key, class T, class Hash = hash<Key>, class Pred = std::equal_to<Key>, class Allocator = std::allocator<std::pair<const Key, T> > > class unordered_map { ... // construct/destroy/copy explicit unordered_map(size_type n = see below, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type()); ... }
The letter of the standard can be honored as long as implementors recognize their freedom to split this one signature into multiple overloads, so that the documented default arguments (requiring a CopyConstructible functor) are not actually passed as default arguments.
As we look into the requirements for the copy constructor and copy-assignment operator, the requirements are even more vague, as the explicit requirements on the functors are not called out, other than saying that the functors are copied.
Must the functors be CopyAssignable? Or is CopyConstructible sufficient in this case? Do we require that the functors be Swappable so that the copy-swap idiom can be deployed here? Note that a type that is both CopyConstructible and CopyAssignable is still not guaranteed to be Swappable as the user may delete the swap function for their type in their own namespace, which would be found via ADL.
Some clean-up of the requirements table looks necessary, to at least document the assignment behavior. In addition, we should have clear guidance on whether these functors should always be CopyConstructible, as suggested by the class template definitions, or if the requirement tables are correct and we should explicitly split up the constructors in the (unordered) associative containers to no longer use default (function) arguments to obtain their defaulted functors.
I recommend the simplest solution would be to always require that the functors for (unordered) associative containers be CopyConstructible, above the requirements tables themselves, so that the issue need not be addressed within the tables. I suggest that the assignment operators for these containers add the requirement that the functors be Swappable, rather than forwarding the corresponding Assignable requirement.
[2013-03-15 Issues Teleconference]
Moved to Open.
Alisdair to propose wording.
[2014-06-08, Daniel comments]
The area of this issue partially overlaps what LWG 2227 addresses.
Proposed resolution:
Section: 28.11.4 [re.alg.replace] Status: New Submitter: Jeffrey Yasskin Opened: 2012-11-26 Last modified: 2015-04-08
View all other issues in [re.alg.replace].
View all issues with New status.
Discussion:
template <class traits, class charT, class ST, class SA> basic_string<charT, ST, SA> regex_replace(const basic_string<charT, ST, SA>& s, const basic_regex<charT, traits>& e, const charT* fmt, regex_constants::match_flag_type flags = regex_constants::match_default);
and friends are documented as
Constructs an empty string result of type basic_string<charT, ST, SA> and calls regex_replace(back_inserter(result), s.begin(), s.end(), e, fmt, flags).
This appears to require the result to have a default-constructed allocator, which isn't even possible for all allocator types. I suspect the allocator should be copied from 's' instead. Possibly there should be an additional defaulted argument to override the allocator of the result.
Proposed resolution:
Section: 23.2.1 [container.requirements.general] Status: Open Submitter: Jonathan Wakely Opened: 2012-11-27 Last modified: 2015-04-08
View other active issues in [container.requirements.general].
View all other issues in [container.requirements.general].
View all issues with Open status.
Discussion:
Firstly, 23.2.1 [container.requirements.general]/7 says a container's allocator is used to obtain memory, but it isn't stated explicitly that the same allocator is used to construct and destroy elements, as opposed to a value-initialized allocator of the same type.
Secondly, 23.2.1 [container.requirements.general]/3 says elements "shall be constructed using the allocator_traits<allocator_type>::construct function and destroyed using the allocator_traits<allocator_type>::destroy function" and 23.2.1 [container.requirements.general]/13 defines CopyInsertable etc. in terms of an allocator A which is identical to the container's allocator_type.
The intent of making construct() and destroy() function templates was that containers would be permitted to use allocator_traits<A>::construct() instead of allocator_traits<allocator_type>::construct(), where A is allocator_traits<allocator_type>::rebind_alloc<U> for some other type U. This allows node-based containers to store an allocator of the right type for allocating nodes and to use the same object to construct elements in aligned storage within those nodes, avoiding rebinding and copying the stored allocator every time an element needs to be constructed.
It should be made clear that a possibly-rebound copy of the container's allocator is used for object construction.[2013-03-15 Issues Teleconference]
Moved to Open.
Jonathan: point 2 in the proposed resolution is definitely needed.
[2014-11-28, Jonathan improves wording]
In the first set of edits to paragraph 3 both pieces inserting "rebind_alloc<U>::" should be replaced by "rebind_traits<U>::"
Otherwise it implies using the allocator's functions directly, but they might not exist and it should be through the rebound traits type.Proposed resolution:
This wording is relative to N3485.
Edit 23.2.1 [container.requirements.general] paragraph 3:
For the components affected by this subclause that declare an allocator_type, objects stored in these components shall be constructed using the allocator_traits<allocator_type>::rebind_traits<U>::construct function and destroyed using the allocator_traits<allocator_type>::rebind_traits<U>::destroy function (20.7.8.2 [allocator.traits.members]), where U is either allocator_type::value_type or an internal type used by the container. These functions are called only for the container's element type, not for internal types used by the container. [ Note: This means, for example, that a node-based container might need to construct nodes containing aligned buffers and call construct to place the element into the buffer. — end note ]
Edit 23.2.1 [container.requirements.general] paragraph 7:
[…] A copy of this allocator is used for any memory allocation and element construction performed, by these constructors and by all member functions, during the lifetime of each container object or until the allocator is replaced. […]
Edit 23.2.1 [container.requirements.general] paragraph 13:
[…] Given an allocator type A and given a container type X having
[…] [ Note: A container calls allocator_traits<A>::construct(m, p, args) to construct an element at p using args, with m == get_allocator(). The default construct in std::allocator will call ::new((void*)p) T(args), but specialized allocators may choose a different definition. — end note ]an allocator_type identical to A anda value_type identical to T and an allocator_type identical to allocator_traits<A>::rebind_alloc<T> and given an lvalue m of type A, a pointer p of type T*, an expression v of type (possibly const) T, and an rvalue rv of type T, the following terms are defined.
Section: 20.9.2 [func.require] Status: Open Submitter: Jonathan Wakely Opened: 2012-11-28 Last modified: 2015-04-08
View other active issues in [func.require].
View all other issues in [func.require].
View all issues with Open status.
Discussion:
The standard currently requires this to be invalid:
#include <functional> struct X { int i; } x; auto f = &X::i; auto t1 = std::ref(x); int i = std::mem_fn(f)(t1);
The call expression on the last line is equivalent to INVOKE(f, std::ref(x)) which according to 20.9.2 [func.require]p1 results in the invalid expression (*t1).*f because reference_wrapper<X> is neither an object of type X nor a reference to an object of type X nor a reference to an object of a type derived from X.
The same argument applies to pointers to member functions, and if they don't work with INVOKE it becomes harder to do all sorts of things such as:
call_once(o, &std::thread::join, std::ref(thr))
or
async(&std::list<int>::sort, std::ref(list));
The definition of INVOKE should be extended to handle reference wrappers.
[2013-03-15 Issues Teleconference]
Moved to Review.
The wording seems accurate, but verbose. If possible, we would like to define the kind of thing being specified so carefully as one of a number of potential language constructs in a single place. It is also possible that this clause is that single place.
[2013-04-18, Bristol]
Jonathan comments:
In the proposed resolution in the first bullet (t1.*f) is not valid if t1 is a reference_wrapper, so we probably need a separate bullet to handle the reference_wrapper case.
[2014-02-14, Issaquah, Mike Spertus supplies wording]
Previous resolution from Jonathan [SUPERSEDED]:
This wording is relative to N3485.
Edit 20.9.2 [func.require]:
Define INVOKE(f, t1, t2, ..., tN) as follows:
(t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of type T or a reference to an object of type
T or a reference to an object of a type derived from TU or an object of type reference_wrapper<U> or a reference to an object of type reference_wrapper<U> where U is either the type T or a type derived from T;((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of the types described in the previous item;
t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is an object of type T or a reference to an object of type
T or a reference to an object of a type derived from TU or an object of type reference_wrapper<U> or a reference to an object of type reference_wrapper<U> where U is either the type T or a type derived from T;(*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 is not one of the types described in the previous item;
f(t1, t2, ..., tN) in all other cases.
[2014-10-01, STL adds discussion and provides an improved resolution]
Because neither t1.*f nor (*t1).*f will compile when t1 is reference_wrapper<U> for any U, we don't need to inspect U carefully. We can bluntly detect all reference_wrappers and use get() for them.
We would have to be more careful if we had to deal with pointers to members of reference_wrapper itself. Fortunately, we don't. First, it doesn't have user-visible data members. Second, users technically can't take the addresses of its member functions (this is a consequence of 17.6.5.5 [member.functions], the Implementer's Best Friend). While we're in the neighborhood, I recommend simplifying and clarifying the wording used to detect base/derived objects.Previous resolution from Mike Spertus [SUPERSEDED]:
This wording is relative to N3936.
Edit 20.9.2 [func.require]:
Define INVOKE(f, t1, t2, ..., tN) as follows:
(t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T;
(t1.get().*f)(t2, ..., tN) when f is a pointer to a member function of class T and t1 is an object of type reference_wrapper<U> where U is either the type T or a type derived from T.
((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of the types described in the previous item;
t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T;
t1.get().*f when N == 1 and f is a pointer to member data of a class T and t1 is an object of type reference_wrapper<U> where U is either the type T or a type derived from T.
(*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 is not one of the types described in the previous item;
f(t1, t2, ..., tN) in all other cases.
[2015-02 Cologne]
Waiting for implementation experience.
Proposed resolution:
This wording is relative to N3936.
Change 20.9.2 [func.require] p1 as depicted:
Define INVOKE(f, t1, t2, ..., tN) as follows:
(t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and
t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from Tis_base_of<T, decay_t<decltype(t1)>>::value is true;(t1.get().*f)(t2, ..., tN) when f is a pointer to a member function of a class T and decay_t<decltype(t1)> is a specialization of reference_wrapper;
((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1
is not one of the types described in the previous itemdoes not satisfy the previous two items;t1.*f when N == 1 and f is a pointer to member data of a class T and
t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from Tis_base_of<T, decay_t<decltype(t1)>>::value is true;t1.get().*f when N == 1 and f is a pointer to member data of a class T and decay_t<decltype(t1)> is a specialization of reference_wrapper;
(*t1).*f when N == 1 and f is a pointer to member data of a class T and t1
is not one of the types described in the previous itemdoes not satisfy the previous two items;f(t1, t2, ..., tN) in all other cases.
Section: 28.12.2.2 [re.tokiter.comp] Status: New Submitter: Pete Becker Opened: 2012-11-21 Last modified: 2015-04-08
View all issues with New status.
Discussion:
Consider the following example:
std::string str0("x"); std::regex rg0("a"); std::regex_token_iterator it0(str0.begin(), str0.end(), rg0, -1); // points at "x" in str0 std::string str1("x"); std::regex rg1("b"); std::regex_token_iterator it1(str1.begin(), str1.end(), rg1, -1); // points at "x" in str1
28.12.2.2 [re.tokiter.comp] p1 says that it0.operator==(it1) returns true "if *this and right are both suffix iterators and suffix == right.suffix"; both conditions are satisfied in this example. It does not say that they must both be iterators into the same sequence, nor does it say (as general iterator requirements do) that they must both be in the domain of == in order for the comparison to be meaningful. It's a simple statement: they're equal if the strings they point at compare equal. Given this being a valid comparison, the obtained result of "true" looks odd.
The problem is that for iterator values prior to the suffix iterator, equality means the same regular expression and the same matched sequence (both uses of "same" refer to identity, not equality); for the suffix iterator, equality means that the matched sequences compare equal.Proposed resolution:
Section: 27.7.3 [output.streams] Status: New Submitter: Matt Austern Opened: 2012-12-07 Last modified: 2015-04-08
View all issues with New status.
Discussion:
When I write
std::cout << nullptr << std::endl;
I get a compilation error, "ambiguous overload for 'operator<<' in 'std::cout << nullptr'". As far as I can tell, the compiler is right to issue that error. There are inserters for const void*, const char*, const signed char*, and const unsigned char*, and none for nullptr_t, so the expression really is ambiguous.
Proposed wording: The obvious library solution is to add a nullptr_t overload, which would be defined something liketemplate<class C, class T> basic_ostream<C, T>& operator<<(basic_ostream<C, T>& os, nullptr_t) { return os << (void*) nullptr; }
We might also consider addressing this at a core level: add a special-case language rule that addresses all cases where you write f(nullptr) and f is overloaded on multiple pointer types. (Perhaps a tiebreaker saying that void* is preferred in such cases.)
Proposed resolution:
Section: 23.3.6.3 [vector.capacity] Status: Open Submitter: Juan Soulie Opened: 2012-12-17 Last modified: 2015-04-08
View other active issues in [vector.capacity].
View all other issues in [vector.capacity].
View all issues with Open status.
Discussion:
After the additions by 2033, it appears clear that the intended effect includes a reallocation and thus the potential effect on iterators should be explicitly added to the text in order to not contradict 23.2.1 [container.requirements.general]/11, or at the very least, explicitly state that a reallocation may happen.
Taking consistency with "reserve" into consideration, I propose:that the current "Remarks" are made its "Effect" instead, inserting "Reallocation happens at this point if and only if the function effectively reduces the capacity." after the note on non-bindingness.
adding a "Remarks" paragraph, similar to that of reserve: "Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence."
BTW, while we are at it, I believe the effect on iterators should also be explicitly stated in the other instance a reallocation may happen: 23.3.6.5 [vector.modifiers]/1 — even if obvious, it only contradicts 23.2.1 [container.requirements.general]/11 implicitly.
I propose to also insert "Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence." at the appropriate location in its "Remarks".[2012-12-19: Jonathan Wakely comments]
The described problem also affects std::basic_string and std::deque.
[2013-03-15 Issues Teleconference]
Moved to Review.
[2013-04-18, Bristol]
Daniel extends the P/R.
Rationale:
The wording in 21.4.4 [string.capacity] combined with 21.4.1 [string.require] seems to say the necessary things. We cannot impose all requirements as we do for vector, because we want to allow the short-string-optimization.
[2014-02-15 post-Issaquah session]
STL: I think that shrink_to_fit should be a no-op when called twice.
STL: Do we ever define reallocation for deque? Nope, all mentions of "reallocation" are in vector. We define what it means in vector::reserve(), but not for deque.
STL: Oh duh, they define reallocate in the PR. But I think we can do better here.
STL: Optimally, deque shrinking just allocates a new map of pointers, and drops empty blocks, but preserves pointers/references to elements.
Alisdair: That's like unordered containers, invalidating only iterators.
Pablo: It doesn't make sense to reduce capacity() to size(), because deque doesn't have capacity!
STL: For vector, "effectively reduces the capacity" is unnecessary, the capacity there is observable.
STL: There is a strong reason to provide an optimal shrink to fit for deque, since only the library implementer can do this.
STL: The other thing I don't like the repeated definition of reallocation for vector, we define it once and use it in a bunch of places. At most we can lift it up to the vector synopsis.
STL: I'll write new wording.
[2014-10-01, STL adds discussion and provides new wording]
Compared to the previous proposed resolution:
I'm changing basic_string's wording because (1) we should guarantee that capacity won't increase, (2) we should mention that it's linear complexity, and (3) we can provide a better invalidation guarantee than 21.4.1 [string.require]/5. (As previously noted, we already have the strong exception guarantee.) This introduces the term "reallocation" into basic_string, but immediately explains what it means for iterator validity. As far as I can tell, the Small String Optimization doesn't complicate the wording here; it's a reason why an implementation might not honor the request, but if the capacity is reduced, we are definitely reallocating buffers and will invalidate everything (including when the destination is the small buffer).
Between N3485 and N3936, deque's wording was updated to avoid talking about capacity() which it doesn't have. Since the container's capacity is unobservable, I'm saying that invalidation is unconditional.
In vector's wording, I'm also guaranteeing that capacity won't increase, and that iterators/etc. remain valid if the capacity is unchanged.
My wording doesn't directly say that shrink_to_fit() should be a no-op when called twice in a row. (Indirectly, if the first call reduces capacity() to size(), the second call must preserve iterators/etc.) I considered rewording the complexity to say "linear if reallocation happens", but that's potentially problematic (what if we copy almost all N elements, then one throws and we have to unwind? There are no effects, so reallocation didn't happen, yet we took longer than constant time). Implementers can always do better than the stated complexity bounds.
I chose not to modify deque's requirements, so implementations remain free to reallocate the elements themselves. I didn't attempt to centralize vector's reallocation wording. That can be done editorially, if someone is sufficiently motivated.Previous resolution from Juan Soulie/Daniel [SUPERSEDED]:
This wording is relative to N3485.
Keep 21.4.4 [string.capacity] around p14 unchanged, because we don't speak about reallocations and we give the strong exception guarantee in 21.4.1 [string.require] (Invalidation specification also at that place):
void shrink_to_fit();-14- Remarks: shrink_to_fit is a non-binding request to reduce capacity() to size(). [Note: The request is non-binding to allow latitude for implementation-specific optimizations. — end note ].
Edit 23.3.3.3 [deque.capacity] around p7 as indicated:
void shrink_to_fit();-5- Requires: T shall be MoveInsertable into *this.
-?- Effects: shrink_to_fit is a non-binding request to reduce capacity() to size(). [Note: The request is non-binding to allow latitude for implementation-specific optimizations. — end note ] Reallocation happens at this point if and only if the function effectively reduces the capacity. If an exception is thrown other than by the move constructor of a non-CopyInsertable T there are no effects. -6- Complexity: Linear in the size of the sequence. -7- Remarks:shrink_to_fit is a non-binding request to reduce capacity() to size(). [Note: The request is non-binding to allow latitude for implementation-specific optimizations. — end note ] If an exception is thrown other than by the move constructor of a non-CopyInsertable T there are no effects.Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence.Edit 23.3.6.3 [vector.capacity] around p7 as indicated:
void shrink_to_fit();-7- Requires: T shall be MoveInsertable into *this.
-?- Effects: shrink_to_fit is a non-binding request to reduce capacity() to size(). [Note: The request is non-binding to allow latitude for implementation-specific optimizations. — end note ] Reallocation happens at this point if and only if the function effectively reduces the capacity. If an exception is thrown other than by the move constructor of a non-CopyInsertable T there are no effects. -8- Complexity: Linear in the size of the sequence. -9- Remarks:shrink_to_fit is a non-binding request to reduce capacity() to size(). [Note: The request is non-binding to allow latitude for implementation-specific optimizations. — end note ] If an exception is thrown other than by the move constructor of a non-CopyInsertable T there are no effects.Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence.Edit 23.3.6.5 [vector.modifiers] p1 as indicated:
iterator insert(const_iterator position, const T& x); iterator insert(const_iterator position, T&& x); iterator insert(const_iterator position, size_type n, const T& x); template <class InputIterator> iterator insert(const_iterator position, InputIterator first, InputIterator last); iterator insert(const_iterator position, initializer_list<T>); template <class... Args> void emplace_back(Args&&... args); template <class... Args> iterator emplace(const_iterator position, Args&&... args); void push_back(const T& x); void push_back(T&& x);-1- Remarks: Causes reallocation if the new size is greater than the old capacity. Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence. If no reallocation happens, all the iterators and references before the insertion point remain valid. If an exception is thrown other than by the copy constructor, move constructor, assignment operator, or move assignment operator of T or by any InputIterator operation there are no effects. If an exception is thrown by the move constructor of a non-CopyInsertable T, the effects are unspecified.
[2015-02, Cologne]
GR: I'm concerned that shrink_to_fit may cause reallocation without changing the capacity. […] It's about correctness. The statement about invalidation is useless if I cannot detect whether reallocation has happened?
AM: It seems like the logic goes the other way round: It's the capacity change that causes reallocation, so if there's no capacity change, there's no reallocation. But that's not quite how I'd like to say it... maybe this, : "If capacity does not change, no reallocation occurs." GR: Where does it actually say that reserve() invalidates? AM: It should say that in the container requirements. VV: vector specifies in reserve that there's reallocation if and only if the capacity changes. GR: I can't find anything in the container requirements about reserve. DK: No, it's specified for every container separately. GR: It isn't specified for string. GR: I'm noticing that the issue touches on shrink_to_fit for a bunch of containers. Anyway, I think the reserve issue [re string] is in scope for this issue. This change is touching on a lot of members. AM: Landing this change will provide clarity for what we should do with basic_string. GR: We're already asking for changes; we should fix string as well. AM: If one of the changes is ready before the other, I'd like to land the finished part first, but if both are ready for Lenexa, I'm equally happy to fix them in one go. DK will reword this. Conclusion: Update wording, revisit in Lenexa.Proposed resolution:
This wording is relative to N3936.
Change 21.4.4 [string.capacity] p14 as depicted:
void shrink_to_fit();-14-
-?- Complexity: Linear in the size of the sequence. -?- Remarks: Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence. If no reallocation happens, they remain valid.RemarksEffects: shrink_to_fit is a non-binding request to reduce capacity() to size(). [Note: The request is non-binding to allow latitude for implementation-specific optimizations. — end note] It does not increase capacity(), but may reduce capacity() by causing reallocation.
Change 23.3.3.3 [deque.capacity] p5-p7 as depicted:
void shrink_to_fit();-5- Requires: T shall be MoveInsertable into *this.
-?- Effects: shrink_to_fit is a non-binding request to reduce memory use but does not change the size of the sequence. [Note: The request is non-binding to allow latitude for implementation-specific optimizations. — end note] If an exception is thrown other than by the move constructor of a non-CopyInsertable T there are no effects. -6- Complexity: Linear in the size of the sequence. -7- Remarks:shrink_to_fit is a non-binding request to reduce memory use but does not change the size of the sequence. [Note: The request is non-binding to allow latitude for implementation-specific optimizations. — end note]shrink_to_fit invalidates all the references, pointers, and iterators referring to the elements in the sequence.
Change 23.3.6.3 [vector.capacity] p7-p9 as depicted:
void shrink_to_fit();-7- Requires: T shall be MoveInsertable into *this.
-?- Effects: shrink_to_fit is a non-binding request to reduce capacity() to size(). [Note: The request is non-binding to allow latitude for implementation-specific optimizations. — end note] It does not increase capacity(), but may reduce capacity() by causing reallocation. If an exception is thrown other than by the move constructor of a non-CopyInsertable T there are no effects. -8- Complexity: Linear in the size of the sequence. -9- Remarks:shrink_to_fit is a non-binding request to reduce capacity() to size(). [Note: The request is non-binding to allow latitude for implementation-specific optimizations. — end note] If an exception is thrown other than by the move constructor of a non-CopyInsertable T there are no effects.Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence. If no reallocation happens, they remain valid.
Change 23.3.6.5 [vector.modifiers] p1 as depicted:
-1- Remarks: Causes reallocation if the new size is greater than the old capacity. Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence. If no reallocation happens, all the iterators and references before the insertion point remain valid. […]
Section: 17.6.4.10 [res.on.objects] Status: Open Submitter: Geoffrey Romer Opened: 2012-12-17 Last modified: 2015-04-08
View all other issues in [res.on.objects].
View all issues with Open status.
Discussion:
The standard currently does not discuss when library objects may be accessed, except in a non-normative note pertaining to synchronization in [res.on.objects], leaving it ambiguous whether single-threaded code can access a library object during its construction or destruction. For example, there is a reasonable question as to what happens if the deleter supplied to a unique_ptr transitively accesses the unique_ptr itself during unique_ptr's destruction; a straightforward reading suggests that this is permitted, and that the deleter will see the unique_ptr still holding the originally stored pointer, but consensus on the LWG reflector indicates this was not the intent (see discussion beginning with c++std-lib-33362).
[2013-03-15 Issues Teleconference]
Moved to Open.
Geoffrey will provide an example that clearly highlights the issue.
[2013-03-19 Geoffrey provides revised resolution and an example]
I contend that the most straightforward reading of the current standard requires the following example code to print "good" (because ~unique_ptr is not specified to modify the state of the internal pointer), but the consensus on the reflector was that its behavior should be undefined.
This example also shows that, contrary to a comment in the telecon, the PR is not tautological. 12.7 [class.cdtor]/p4 explicitly permits member function calls during destruction, so the behavior of this code is well-defined as far as the core language is concerned, despite the fact that it accesses a library object after the end of the object's lifetime. If we want this code to have undefined behavior, we need to specify that at the library level.#include <memory> #include <iostream> class A; struct B { std::unique_ptr<A> a; }; struct A { B* b; ~A() { if (b->a.get() == this) { std::cout << "good" << std::endl; } } }; int main() { B b; b.a.reset(new A); b.a->b = &b; }
Previous resolution:
Change the title of sub-clause 17.6.4.10 [res.on.objects] as indicated:
Shared objects and the libraryLibrary object access [res.on.objects]Edit 17.6.4.10 [res.on.objects] p2 as indicated:
-2-
[Note: In particular, the program is required to ensure that completion of the constructor of any object of a class type defined in the standard library happens before any other member function invocation on that object and, unless otherwise specified, to ensure that completion of any member function invocation other than destruction on such an object happens before destruction of that object. This applies even to objects such as mutexes intended for thread synchronization. — end note]If an object of a standard library type is accessed outside of the object's lifetime (3.8 [basic.life]), the behavior is undefined unless otherwise specified.
Proposed resolution:
This wording is relative to N3485.
Change the title of sub-clause 17.6.4.10 [res.on.objects] as indicated:
Shared objects and the libraryLibrary object access [res.on.objects]
Edit 17.6.4.10 [res.on.objects] p2 as indicated: [Editorial remark: The motivation, is to be more precise about the meaning of "outside the object's lifetime" in the presence of threads — end editorial remark]
-2- [Note: In particular, the program is required to ensure that completion of the constructor
of any object of a class type defined in the standard library happens before any other member function
invocation on that object and, unless otherwise specified, to ensure that completion of any member function
invocation other than destruction on such an object happens before destruction of that object. This applies
even to objects such as mutexes intended for thread synchronization. — end note]
If an object of a standard library type is accessed, and the beginning of the object's lifetime
(3.8 [basic.life]) does not happen before the access, or the access does not happen before the end
of the object's lifetime, the behavior is undefined unless otherwise specified.
Section: 22.3.3.2.2 [conversions.string] Status: LEWG Submitter: Glen Fernandes Opened: 2012-12-14 Last modified: 2015-04-08
View other active issues in [conversions.string].
View all other issues in [conversions.string].
View all issues with LEWG status.
Discussion:
The wstring_convert class template, described in 22.3.3.2.2 [conversions.string], does not support custom stateful allocators. It only supports custom stateless allocators.
The to_bytes member function returns basic_string<char, char_traits<char>, Byte_alloc> but it does not take an instance of Byte_alloc to pass to the constructor of the basic_string. Similarly the from_bytes member function returns basic_string<Elem, char_traits<Elem>, Wide_alloc> but it does not take an instance of Wide_alloc to pass to the constructor of the basic_string. This makes these two member functions and the wstring_convert class template not usable when Wide_alloc or Byte_alloc are stateful allocators.[2013-01-22, Glen provides wording]
[2013-03-15 Issues Teleconference]
Moved to NAD Future.
This is clearly an extension that the LEWG may want to take a look at, once we have more experience with appropriate use of allocators with the C++11 model.
Proposed resolution:
This wording is relative to N3485.
In 22.3.3.2.2 [conversions.string]/2 and /6 "Class template wstring_convert synopsis" change the overloads of the member function from_bytes() so that all four overloads take an additional parameter which is an instance of Wide_alloc:
wide_string from_bytes(char byte, const Wide_alloc& alloc = Wide_alloc()); wide_string from_bytes(const char *ptr, const Wide_alloc& alloc = Wide_alloc()); wide_string from_bytes(const byte_string& str, const Wide_alloc& alloc = Wide_alloc()); wide_string from_bytes(const char *first, const char *last, const Wide_alloc& alloc = Wide_alloc());
In 22.3.3.2.2 [conversions.string] /8 specify that this Wide_alloc allocator parameter is used to construct the wide_string object returned from the function:
-7- Effects: The first member function shall convert the single-element sequence byte to a wide string. The second member function shall convert the null-terminated sequence beginning at ptr to a wide string. The third member function shall convert the sequence stored in str to a wide string. The fourth member function shall convert the sequence defined by the range [first, last) to a wide string.
-8- In all cases:If the cvtstate object was not constructed with an explicit value, it shall be set to its default value (the initial conversion state) before the conversion begins. Otherwise it shall be left unchanged.
The number of input elements successfully converted shall be stored in cvtcount.
The Wide_alloc allocator parameter is used to construct the wide_string object returned from the function.
In 22.3.3.2.2 [conversions.string]/2 and /12 "Class template wstring_convert synopsis" change the overloads of the member function to_bytes() so that all four overloads take an additional parameter which is an instance of Byte_alloc:
byte_string to_bytes(Elem wchar, const Byte_alloc& alloc = Byte_alloc()); byte_string to_bytes(const Elem *wptr, const Byte_alloc& alloc = Byte_alloc()); byte_string to_bytes(const wide_string& wstr, const Byte_alloc& alloc = Byte_alloc()); byte_string to_bytes(const Elem *first, const Elem *last, const Byte_alloc& alloc = Byte_alloc());
In 22.3.3.2.2 [conversions.string] /13 specify that this Byte_alloc allocator parameter is used to construct the byte_string object returned from the function:
-12- Effects: The first member function shall convert the single-element sequence wchar to a byte string. The second member function shall convert the null-terminated sequence beginning at wptr to a byte string. The third member function shall convert the sequence stored in wstr to a byte string. The fourth member function shall convert the sequence defined by the range [first, last) to a byte string.
-13- In all cases:If the cvtstate object was not constructed with an explicit value, it shall be set to its default value (the initial conversion state) before the conversion begins. Otherwise it shall be left unchanged.
The number of input elements successfully converted shall be stored in cvtcount.
The Byte_alloc allocator parameter is used to construct the byte_string object returned from the function.
Section: 23.2.4 [associative.reqmts] Status: Open Submitter: Juan Soulie Opened: 2012-12-19 Last modified: 2015-04-08
View other active issues in [associative.reqmts].
View all other issues in [associative.reqmts].
View all issues with Open status.
Discussion:
Table 102 in 23.2.4 [associative.reqmts]/8 states on expression a.key_comp() that it "returns the comparison object out of which a was constructed". At the same time, 23.2.1 [container.requirements.general]/8 states (starting in the third line) that "...Any Compare, Pred, or Hash objects belonging to a and b shall be swappable and shall be exchanged by unqualified calls to non-member swap...". This is problematic for any compliant implementation, since once swapped the container cannot return the comparison object out of which it was constructed unless incurring in storing an otherwise needless object.
The simple solution is to correct that statement in Table 102, but I believe this is part of a larger problem of underspecified behavior: The new standard has made an effort in regards to allocators and now fully specifies what happens to stateful allocator objects. It has even specified what happens to stateful hasher and key_equal members of unordered containers (they propagate), but it says nothing about stateful comparison objects of (ordered) associative containers, except for the statement in 23.2.1 [container.requirements.general]/8 referred above and only related to swap. For example, it is unclear to me what is specified to happen on an assignment: should the comparison object be copied/moved along with the elements, or should the left-hand side object keep its own? Maybe this has been intentionally left unspecified with the purpose of compatibility with C++98, which I understand it specified that comparison objects were kept for the entire life of the container (like allocators) — an unfortunate choice. But anyway, the segment of 23.2.1 [container.requirements.general] quoted above seems to break any possible backwards compatibility with C++98 in this regard. Therefore, taking into consideration consistency with how this is dealed with for unordered associative containers, I propose that Table 102 is modified as follows:The row for expression a.key_comp() is changed so that its "assertion/note pre-/post-condition" reads "Returns a's comparison object."
A new row is added at the appropriate location (which I believe would be after "X(il)" row), with:
Table 102 — Associative container requirements (in addition to container) Expression Return type Assertion/note pre-/post-condition Complexity X(b)
X a(b)X Copy constructor. In addition to
the requirements of Table 96, copies
the comparison object.Linear in b.size() a = b X& Copy assignment operator. In addition to
the requirements of Table 96, copies the
comparison object.Linear in a.size() and b.size()
[2013-03-15 Issues Teleconference]
Moved to Review.
[2013-04-18, Bristol]
STL: can't believe we don't specify this already. this is totally necessary
Alisdair: how does it do this? copy construction? assignment? Also need it for move. STL: we already specify this for constructing from a comparator, not during copy construction though. Jonathan: don't like wording, should say "key_compare is CopyConstructible. Uses b.key_comp() as a comparison object." STL: we get it right for unordered! Jonathan: can't wordsmith this now, but I think implementations do the right thing. Alisdair: not sure what right thing is for moves. Also we say nothing about propagating allocators to functors.Moved to Open.
[2015-02 Cologne]
TK: There's no need for fine-grained propagate/not-propagate control. If you don't want to propagate the predicate, you can simply construct or insert from an iterator range.
VV: libstdc++ already implements the resolution of this issue. GR: There are a couple of other problems. We don't specify move constructor and move assignment for maps. Those are just general. TK: General container requirements already describe the semantics for {copy,move}-{construction,assignment}, so it doesn't seem that there's room for choice in std::map assignments. unordered_map is different, though. [Note: Check what general container requirements say about container equality.] DK will draft wording. The decision is to unambiguously make all {copy,move}-{construction,assignment} operations endow the LHS with the exact state of the RHS, including all predicates and hash function states. Conclusion: Update wording, revisit later.Proposed resolution:
This wording is relative to N3485.
Change Table 102 as indicated:
Table 102 — Associative container requirements (in addition to container) Expression Return type Assertion/note pre-/post-condition Complexity … X(il) Same as X(il.begin(), il.end()). same as X(il.begin(), il.end()). X(b)
X a(b)Copy constructor. In addition to
the requirements of Table 96, copies
the comparison object.Linear in b.size() a = b X& Copy assignment operator. In addition to
the requirements of Table 96, copies the
comparison object.Linear in a.size() and b.size() … a.key_comp() X::key_compare rReturnsthea's comparison object
out of which a was constructed.constant
Section: 20.8.1.2.3 [unique.ptr.single.asgn] Status: Review Submitter: Geoffrey Romer Opened: 2012-12-20 Last modified: 2015-04-08
View all other issues in [unique.ptr.single.asgn].
View all issues with Review status.
Discussion:
20.8.1.2.3 [unique.ptr.single.asgn]/5 permits unique_ptr's templated assignment operator to participate in overload resolution even when incompatibilities between D and E will render the result ill-formed, but the corresponding templated copy constructor is removed from the overload set in those situations (see the third bullet point of 20.8.1.2.1 [unique.ptr.single.ctor]/19). This asymmetry is confusing, and presumably unintended; it may lead to situations where constructing one unique_ptr from another is well-formed, but assigning from the same unique_ptr would be ill-formed.
There is a slight coupling between this and LWG 2118, in that my PR for LWG 2118 incorporates equivalent wording in the specification of the templated assignment operator for the array specialization; the two PRs are logically independent, but if my PR for 2118 is accepted but the above PR is not, the discrepancy between the base template and the specialization could be confusing.[2013-03-15 Issues Teleconference]
Moved to Review.
The wording looks good, but we want a little more time than the telecon permits to be truly comfortable. We expect this issue to resolve fairly easily in Bristol.
[2015.05.18, Howard comments]
Updated proposed wording has been provided in N4366.
Proposed resolution:
This wording is relative to N3485.
Revise 20.8.1.2.3 [unique.ptr.single.asgn] p5 as follows:
template <class U, class E> unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept;-4- Requires: If E is not a reference type, assignment of the deleter from an rvalue of type E shall be well-formed and shall not throw an exception. Otherwise, E is a reference type and assignment of the deleter from an lvalue of type E shall be well-formed and shall not throw an exception.
-5- Remarks: This operator shall not participate in overload resolution unless:
unique_ptr<U, E>::pointer is implicitly convertible to pointer and
U is not an array type
., andeither D is a reference type and E is the same type as D, or D is not a reference type and E is implicitly convertible to D.
-6- Effects: Transfers ownership from u to *this as if by calling reset(u.release()) followed by an assignment from std::forward<E>(u.get_deleter()).
-7- Returns: *this.
Section: 21.2.3 [char.traits.specializations] Status: LEWG Submitter: Jeffrey Yasskin Opened: 2012-12-24 Last modified: 2015-04-08
View all other issues in [char.traits.specializations].
View all issues with LEWG status.
Discussion:
Addresses ES 14, US 19
These functions have easy recursive constexpr implementations that, unfortunately, aren't efficient at runtime. EWG is still figuring out how to solve this problem in general (e.g., N3444 isn't sufficient to avoid stack overflows in debug builds or to get the optimal assembly-based implementations at runtime), so users can't portably solve this problem for themselves, but implementations can use compiler-specific techniques to choose the right implementation inside their standard libraries.
The LWG is still undecided about whether individual implementations can add constexpr to these functions, so we need to add constexpr to the standard here for implementations to be able to improve this.
[2013-03-15 Issues Teleconference]
Moved to Open.
There are a number of people who have a strong interest in this issue not available for the telecon.
It also plays at the heart of a discussion about library freedoms for constexpr and specifying a library that may depend on unspecified compiler intrinsics to be implementable.
[2013-09 Chicago]
Moved to NAD Future.
While it is clear that this feature can be implemented using only C++14 constexpr features, there is real concern that we cannot call the efficient, highly optimized, C implementations of these functions under a C++14 constexpr implementation, nor implement similar ourselves as this typically involves use of inline asm instructions.
Clang and libc++ have some experience of using intrinsics to try to address the performance issue, but the current intrinsics are not general enough to support char_traits. The intrinsics support only operations on character string literals, and the string literal is no longer visible as a literal after passing as a const char * to the char_traits functions.
Additional concern was raised that these operations are unlikely to be useful anyway, as the only client is basic_string which relies on dynamic memory allocation, and so cannot effectively be made a literal type. Jeffrey then pointed out the pending string_view library that will also use char_traits and would most certainly benefit from being a literal type.
Given the choice of giving up performance on a critical library component, or requiring a compiler intrinsic with only unsuccessful implementation experience, the consensus is to not reject this, unless compelling implementation experience is demonstrated. NAD Future seems the appropriate resolution.
Proposed resolution:
This wording is relative to N3691.
In 21.2.3.1 [char.traits.specializations.char], 21.2.3.2 [char.traits.specializations.char16_t], 21.2.3.3 [char.traits.specializations.char32_t], and 21.2.3.4 [char.traits.specializations.wchar.t]:
static constexpr int compare(const char_type* s1, const char_type* s2, size_t n); static constexpr size_t length(const char_type* s); static constexpr const char_type* find(const char_type* s, size_t n, const char_type& a);
Section: 19.3 [assertions] Status: Open Submitter: Daniel Krügler Opened: 2013-01-12 Last modified: 2015-04-08
View other active issues in [assertions].
View all other issues in [assertions].
View all issues with Open status.
Discussion:
It is unclear from the current specification whether assert() expressions can be used in (potential) constant expressions. As an example consider the implementation of a constexpr function:
#include <cassert> template<class T, unsigned N> struct array { T data[N]; constexpr const T& operator[](unsigned i) const { return assert(i < N), data[i]; } }; int main() { constexpr array<int, 3> ai = {1, 2, 3}; constexpr int i = ai[0]; int j = ai[0]; // constexpr int k = ai[5]; }
The first question is whether this program is guaranteed well-formed? A second question is whether is would guaranteed to be ill-formed, if we uncomment the last code line in main()?
The wording in 19.3 [assertions] doesn't add anything significant to the C99 wording. From the C99 specification (7.2 p1 and 7.2.1.1 p2) we get already some valuable guarantees:
The expression assert(e) is a void expression for all expressions e independent of the definition of NDEBUG.
If NDEBUG is defined, assert(e) is equivalent to the expression void() (or anything that cannot be distinguished from that).
The current wording does not yet guarantee that assert expressions can be used in constant expressions, but all tested implementations (gcc, MSVC) would already support this use-case. It seems to me that this should be possible without giving assert a special meaning for the core language.
As a related comment it should be added, that there is a core language proposal that intents to relax some current constraints for constexpr functions and literal types. The most interesting one (making void a literal types and allowing for expression-statements) would simplify the motivating example implementation of operator[] to:constexpr const T& operator[](unsigned i) const { assert(i < N); return data[i]; };
[2013-03-15 Issues Teleconference]
Moved to Open.
We are still gaining experience with constexpr as a language feature, and there may be work in Evolution that would help address some of these concerns. Defer discussion until we have a group familiar with any evolutionary direction.
[2014-06-08, Daniel comments and suggests wording]
After approval of N3652, void is now a literal type and constexpr functions can contain multiple statements, so this makes the guarantee that assert expressions are per-se constexpr-friendly even more relevant. A possible wording form could be along the lines of:
For every core constant expression e of scalar type that evaluates to true after being contextually converted to bool, the expression assert(e) shall be a prvalue core constant expression of type void.
Richard Smith pointed out some weaknesses of this wording form, for example it would not guarantee to require the following example to work:
constexpr void check(bool b) { assert(b); }
because b is not a core constant expression in this context.
He suggested improvements that lead to the wording form presented below (any defects mine).Proposed resolution:
This wording is relative to N3936.
Introduce the following new definition to the existing list in 17.3 [definitions]: [Drafting note: If LWG 2296 is accepted before this issue, the accepted wording for the new definition should be used instead — end drafting note]
constant subexpression [defns.const.subexpr]
an expression whose evaluation as subexpression of a conditional-expression CE (5.16 [expr.cond]) would not prevent CE from being a core constant expression (5.20 [expr.const]).
Insert a new paragraph following 19.3 [assertions] p1 as indicated:
-?- An expression assert(E) is a constant subexpression ( [defns.const.subexpr]), if either
NDEBUG is defined at the point where assert(E) appears, or
E contextually converted to bool (4 [conv]), is a constant subexpression that evaluates to the value true.
Section: 29.2 [atomics.syn], 29.3 [atomics.order] Status: SG1 Submitter: Daniel Krügler Opened: 2013-01-19 Last modified: 2015-04-08
View all other issues in [atomics.syn].
View all issues with SG1 status.
Discussion:
The "magic" kill_dependency function is a function without any constraints on the template parameter T and is specified as
template <class T> T kill_dependency(T y) noexcept;-14- Effects: The argument does not carry a dependency to the return value (1.10).
-15- Returns: y.
I wonder whether the unconditional noexcept is really intended here: Assume we have some type U that has a potentially throwing move constructor (or it has a potentially throwing copy constructor and no move constructor), for any "normal" function template with the same signature and the same effects (modulo the dependency magic) this would mean that it cannot safely be declared noexcept because of the return statement being part of the complete function call affected by noexcept (The by-value function argument is irrelevant in this context). In other words it seems that a function call such as
struct S { ... S(const S& r) { if(some condition) throw Something(); } ... }; int main() { S s1 = ...; S s2 = std::kill_dependency(s1); }
would be required to call std::terminate if the copy constructor of S throws during the return of std::kill_dependency.
To require copy elision for this already magic function would look like a low-hanging fruit to solve this problem, but this case is not covered by current copy elision rules see 12.8 p31 b1: "— in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function's return value". Some options come into my mind:Make the exception-specification a constrained one in regard via std::is_nothrow_move_constructible:
template <class T> T kill_dependency(T y) noexcept(see below);
This is similar to the approach taken for function templates such as std::swap.
Use perfect forwarding (This needs further wording to correct the effects):
template <class T> T&& kill_dependency(T&& y) noexcept;
Impose constraints on the template arguments in regard to throwing exceptions while copying/moving.
Keep the state as it is but possibly add a note about a call of std::terminate in above scenario.
A second problem is that the current wording is not clear whether it is well-defined to call the function with types that are reference types, such as in the following example:
#include <atomic> int main() { int a = 12; int& b = std::kill_dependency<int&>(a); }
It is unclear what kind of dependency is killed here. This is presumably a core language problem, but could affect the possible resolutions of the problem.
[2014-11 Urbana]
Recommend using a revised example:
int lookup(class D* p) { class E* q = p->a.load(memory_order_consume); int y = std::kill_dependency(q->y); }
[2015-02 Cologne]
Handed over to SG1.
Proposed resolution:
Section: 21.8 [c.strings] Status: New Submitter: Jason Merrill Opened: 2013-01-29 Last modified: 2015-04-08
View other active issues in [c.strings].
View all other issues in [c.strings].
View all issues with New status.
Discussion:
Apparently C1X changes __STDC_UTF_16__ and __STDC_UTF_32__ from macros defined in uchar.h (and reflected in C++ by Table 79) to be predefined by the compiler. Do we want to do the same?
Proposed resolution:
Section: 21.8 [c.strings] Status: Open Submitter: Johannes Schaub Opened: 2013-02-02 Last modified: 2015-04-08
View other active issues in [c.strings].
View all other issues in [c.strings].
View all issues with Open status.
Discussion:
The non-explicit nature of the iterator-pair constructor of containers, such a
template <class InputIterator> vector(InputIterator first, InputIterator last, const Allocator& = Allocator());
can be selected in unexpected situations, leading to a hard runtime error, as demonstrated by the following example:
#include <vector> void f(std::vector<char> v){ /* ... */} int main() { f({"A", "B"}); }
The actually intended initializer-list constructor isn't feasible here, so the best match is the constructor template
template <class InputIterator> vector(InputIterator first, InputIterator last, const Allocator& = Allocator());
This compiles, but will result in code running amok. The potential trap (that cannot be easily detected by the library implementation) could be reduced by making this constructor explicit. It would still have the effect to be selected here, but the code would be ill-formed, so the programmer gets a clear meassage here.
[2014-06 Rapperswil]
JW: can't fix this, don't want to touch this, Do The Right Thing clause has been a source of tricky issues. only really happens with string literals, that's the only way to create an array that isn't obviously an array
GR: want to see paper AM: is it only string literals, or also UDLs? STL: maybe, but we don't need to deal with that. This is only a problem in a very specific case Leave as Open.Proposed resolution:
Section: 25.4.7 [alg.min.max] Status: Tentatively Ready Submitter: Juan Soulie Opened: 2013-01-26 Last modified: 2015-04-08
View other active issues in [alg.min.max].
View all other issues in [alg.min.max].
View all issues with Tentatively Ready status.
Discussion:
25.4.7 [alg.min.max] requires type T in min, max, and minmax to be LessThanComparable, but I don't believe this should be required for the versions that take a Compare argument.
Paragraphs 1 to 4 of 25.4 [alg.sorting] should apply anyway, although I'm not sure about Compare being required to induce a strict weak ordering here. Further, min and max also lack formal complexity guarantees.[2014-06-07 Daniel comments and provides wording]
Certainly, the functions with Compare should not impose LessThanComparable requirements.
In regard to the question whether a strict weak ordering should be required as implied by the Compare requirements, I would like to point out that this is requirement is in fact needed, because the specification of the normative Remarks elements (e.g. "Returns the first argument when the arguments are equivalent.") do depend on the existence of a equivalence relation that can be relied on and this is also consistent with the same strict weak ordering requirement that is indirectly imposed by the LessThanComparable requirement set for functions referring to operator< (Let me note that the very same StrictWeakOrder language concept had intentionally been required for similar reasons during "concept-time" in N2914).[2015-02 Cologne]
JY: We have library-wide requirements that Comp induce a strict weak ordering.
JY/MC: The un-marked-up "Complexity" (p16) is wrong. DK: I'll fix that. DK will update the wording for Lenexa.[2015-03-30 Daniel comments]
The Complexity element of p16 is correct, but some others involving initializer_list arguments are wrong.
[2015-04-02 Library reflector vote]
The issue has been identified as Tentatively Ready based on six votes in favour.
Proposed resolution:
This wording is relative to N4296.
Change 25.4.7 [alg.min.max] as indicated:
template<class T> constexpr const T& min(const T& a, const T& b); template<class T, class Compare> constexpr const T& min(const T& a, const T& b, Compare comp);-1- Requires: For the first form, type T shall be
-2- Returns: The smaller value. -3- Remarks: Returns the first argument when the arguments are equivalent. -?- Complexity: Exactly one comparison.Type T isLessThanComparable (Table 18).template<class T> constexpr T min(initializer_list<T> t); template<class T, class Compare> constexpr T min(initializer_list<T> t, Compare comp);-4- Requires: T
-5- Returns: […] -6- Remarks: […] -?- Complexity: Exactly t.size() - 1 comparisons.is LessThanComparable andshall be CopyConstructible and t.size() > 0. For the first form, type T shall be LessThanComparable.template<class T> constexpr const T& max(const T& a, const T& b); template<class T, class Compare> constexpr const T& max(const T& a, const T& b, Compare comp);-7- Requires: For the first form, type T shall be
-8- Returns: […] -9- Remarks: […] -?- Complexity: Exactly one comparison.Type T isLessThanComparable (Table 18).template<class T> constexpr T max(initializer_list<T> t); template<class T, class Compare> constexpr T max(initializer_list<T> t, Compare comp);-10- Requires: T
-11- Returns: […] -12- Remarks: […] -?- Complexity: Exactly t.size() - 1 comparisons.is LessThanComparable andshall be CopyConstructible and t.size() > 0. For the first form, type T shall be LessThanComparable.template<class T> constexpr pair<const T&, const T&> minmax(const T& a, const T& b); template<class T, class Compare> constexpr pair<const T&, const T&> minmax(const T& a, const T& b, Compare comp);-13- Requires: For the first form, t
-14- Returns: […] -15- Remarks: […] -16- Complexity: Exactly one comparison.Type T shall be LessThanComparable (Table 18).template<class T> constexpr pair<T, T> minmax(initializer_list<T> t); template<class T, class Compare> constexpr pair<T, T> minmax(initializer_list<T> t, Compare comp);-17- Requires: T
-18- Returns: […] -19- Remarks: […] -20- Complexity: At most (3/2) * t.size() applications of the corresponding predicate.is LessThanComparable andshall be CopyConstructible and t.size() > 0. For the first form, type T shall be LessThanComparable.
Section: 18.10 [support.runtime] Status: Open Submitter: Richard Smith Opened: 2013-02-14 Last modified: 2015-04-08
View other active issues in [support.runtime].
View all other issues in [support.runtime].
View all issues with Open status.
Discussion:
According to 18.10 [support.runtime] p2:
The contents of these headers are the same as the Standard C library headers [..], <stdalign.h>, [..]
Since our base C standard is C99, which doesn't have a <stdalign.h>, the reference to a non-existing C header is irritating (In this context <stdalign.h> doesn't refer to the deprecated C++ header <stdalign.h> described in D.5 [depr.c.headers]).
Furthermore, it would be also important that it doesn not define a macro named alignof, which C11 also defines in this header. Currently we only have the following guarantee as part of 18.10 [support.runtime] p7:The header <cstdalign> and the header <stdalign.h> shall not define a macro named alignas.
It is unclear what the better strategy is: Striking the reference to <stdalign.h> in 18.10 [support.runtime] p2 or upgrading to C11 as new base C standard.
[2014-02-15 Issaquah]
STL: related to earlier issue on C4, 2201, and now we get a C11 header
JY: find _Alignof as keyword C11 FDIS has four defines in stdalign.h
AM: need paper for C11 as base library we should really do that
STL: really need vendor input
STL: don't think we need to do anything right now not P1
AM: any objections to downscale to P2 (no objections)
Proposed resolution:
Section: 25.3.1 [alg.copy], 20.7.12.2 [uninitialized.copy] Status: New Submitter: Sean Parent Opened: 2013-02-14 Last modified: 2015-04-08
View other active issues in [alg.copy].
View all other issues in [alg.copy].
View all issues with New status.
Discussion:
copy_n() and uninitialized_copy_n() only return the output iterator, and not the input iterator. Likely the interface was simply copied from the original STL. Unfortunately the interface in the original STL contains a bug.
copy_n() and uninitialized_copy_n() must return the resulting input iterator as well as the output iterator (I would suggest returning a pair). Without this, there is no way to continue reading from an actual input iterator — and if it is really a forward iterator, it will cost n increments to get back to where you were.Proposed resolution:
Section: 27.7.2.3 [istream.unformatted] Status: New Submitter: Juan Soulie Opened: 2013-03-01 Last modified: 2015-04-08
View other active issues in [istream.unformatted].
View all other issues in [istream.unformatted].
View all issues with New status.
Discussion:
In 27.7.2.3 [istream.unformatted] / 34, when describing putback, it says that "rdbuf->sputbackc()" is called. The problem are not the obvious typos in the expression, but the fact that it may lead to different interpretations, since nowhere is specified what the required argument to sputbackc is.
It can be guessed to be "rdbuf()->sputbackc(c)", but "rdbuf()->sputbackc(char_type())" or just anything would be as conforming (or non-confoming) as the first guess.Proposed resolution:
Section: 27.7.2.3 [istream.unformatted] Status: New Submitter: Juan Soulie Opened: 2013-03-04 Last modified: 2015-04-08
View other active issues in [istream.unformatted].
View all other issues in [istream.unformatted].
View all issues with New status.
Discussion:
When issue 1445 was resolved by adopting N3168, it exposed the need to modify both overloads of basic_istream::seekg (by inserting "the function clears eofbit," after "except that"), but the fix applied to the text apparently forgets the second overload at 27.7.2.3 [istream.unformatted] p43.
[2013-10-17: Daniel provides concrete wording]
It seems that the tiny sentence "SIMILARLY for 27.7.1.3/43 (seekg)." had been overlooked. I agree that the wording needs to be applied here as well.
Proposed resolution:
This wording is relative to N3691.
Change 27.7.2.3 [istream.unformatted] p43 as indicated:
basic_istream<charT,traits>& seekg(off_type off, ios_base::seekdir dir);-43- Effects: Behaves as an unformatted input function (as described in 27.7.2.3, paragraph 1), except that the function first clears eofbit, it does not count the number of characters extracted, and does not affect the value returned by subsequent calls to gcount(). […]
Section: 30.6.9.1 [futures.task.members] Status: SG1 Submitter: Jonathan Wakely Opened: 2013-03-05 Last modified: 2015-04-08
View other active issues in [futures.task.members].
View all other issues in [futures.task.members].
View all issues with SG1 status.
Discussion:
The effects of packaged_task::reset() result in memory allocation, but don't allow a user to provide an allocator.
packaged_task::reset() needs to be overloaded like so:template<class Alloc> void reset(const Alloc&);
Alternatively, the effects of reset() need to require the same allocator is used as at construction, which would require the constructor to store the allocator for later use.
I like to remark that GCC at the moment uses the second option, i.e. the allocator passed to the constructor (if any) is used to create the new shared state, because this didn't require any change to the interface.[2015-02 Cologne]
Handed over to SG1.
Proposed resolution:
Section: 18.3.2 [limits] Status: New Submitter: Pete Becker Opened: 2013-03-08 Last modified: 2015-04-08
View all other issues in [limits].
View all issues with New status.
Discussion:
This member should probably be named "is_ieee754". Or at least the standard should explain that IEC-559 no longer exists, and that it's been superseded by IEEE-754.
Proposed resolution:
Section: 20.6.1 [bitset.cons], 20.6.2 [bitset.members], 21.4.2 [string.cons], 21.4.6 [string.modifiers], 21.4.7 [string.ops] Status: New Submitter: Frank Birbacher Opened: 2013-04-18 Last modified: 2015-04-08
View all other issues in [bitset.cons].
View all issues with New status.
Discussion:
Similar to LWG 2207 there are several other places where the "Requires" clause precludes the "Throws" condition. Searching for the out_of_range exception to be thrown, the following have been found (based on the working draft N3485):
20.6.1 [bitset.cons] p3+4
20.6.2 [bitset.members] p13+14 (set)
20.6.2 [bitset.members] p19+20 (reset)
20.6.2 [bitset.members] p27+28 (flip)
20.6.2 [bitset.members] p41+42 (test)
21.4.2 [string.cons] p3+4
21.4.6.2 [string::append] p3+4
21.4.6.3 [string::assign] p4+5
21.4.6.4 [string::insert] p1+2, p5+6, p9+10 (partially)
21.4.6.5 [string::erase] p1+2
21.4.6.6 [string::replace] p1+2, p5+6, p9+10 (partially)
21.4.6.7 [string::copy] p1+2
21.4.7.8 [string::substr] p1+2
[2013-10-15: Daniel provides wording]
In addition to the examples mentioned in the discussion, a similar defect exists for thread's join() and detach functions (see 30.3.1.5 [thread.thread.member]). The suggested wording applies a similar fix for these as well.
Proposed resolution:
This wording is relative to N3936.
Modify 20.6.1 [bitset.cons] as indicated: [Editorial comment: The wording form used to ammend the Throws element is borrowed from a similar style used in 21.4.6.6 [string::replace] p10]
template <class charT, class traits, class Allocator> explicit bitset(const basic_string<charT, traits, Allocator>& str, typename basic_string<charT, traits, Allocator>::size_type pos = 0, typename basic_string<charT, traits, Allocator>::size_type n = basic_string<charT, traits, Allocator>::npos, charT zero = charT('0'), charT one = charT('1'));-4- Throws: out_of_range if pos > str.size() or invalid_argument if an invalid character is found (see below). -5- Effects: Determines the effective length rlen of the initializing string as the smaller of n and str.size() - pos. The function then throws invalid_argument if any of the rlen characters in str beginning at position pos is other than zero or one. The function uses traits::eq() to compare the character values. […]
-3- Requires: pos <= str.size().
Modify 20.6.2 [bitset.members] as indicated:
bitset<N>& set(size_t pos, bool val = true);-14- Throws: out_of_range if pos does not correspond to a valid bit position. […]
-13- Requires: pos is valid
bitset<N>& reset(size_t pos);-20- Throws: out_of_range if pos does not correspond to a valid bit position. […]
-19- Requires: pos is valid
bitset<N>& flip(size_t pos);-28- Throws: out_of_range if pos does not correspond to a valid bit position. […]
-27- Requires: pos is valid
bool test(size_t pos) const;-42- Throws: out_of_range if pos does not correspond to a valid bit position. […]
-41- Requires: pos is valid
Modify 21.4.2 [string.cons] as indicated:
basic_string(const basic_string& str, size_type pos, size_type n = npos, const Allocator& a = Allocator());-4- Throws: out_of_range if pos > str.size().
-3- Requires: pos <= str.size()
Modify 21.4.4 [string.capacity] as indicated:
void resize(size_type n, charT c);-7- Throws: length_error if n > max_size().
-6- Requires: n <= max_size()
Modify 21.4.6.2 [string::append] as indicated:
basic_string& append(const basic_string& str, size_type pos, size_type n = npos);-4- Throws: out_of_range if pos > str.size().
-3- Requires: pos <= str.size()
Modify 21.4.6.3 [string::assign] as indicated:
basic_string& assign(const basic_string& str, size_type pos, size_type n = npos);-6- Throws: out_of_range if pos > str.size().
-5- Requires: pos <= str.size()
Modify 21.4.6.4 [string::insert] as indicated: [Editorial note: The first change suggestion is also a bug fix of the current wording, because (a) the function has parameter pos1 but the semantics refers to pos and (b) it is possible that this function can throw length_error, see p10]
basic_string& insert(size_type pos1, const basic_string& str);
-1- Requires: pos <= size().-2- Throws: out_of_range if pos > size().-3- Effects:CallsEquivalent to: return insert(pos, str.data(), str.size());.-4- Returns: *this.
basic_string& insert(size_type pos1, const basic_string& str, size_type pos2, size_type n = npos);-6- Throws: out_of_range if pos1 > size() or pos2 > str.size(). […]
-5- Requires: pos1 <= size() and pos2 <= str.size().
basic_string& insert(size_type pos, const charT* s, size_type n);-9- Requires: s points to an array of at least n elements of charT
-10- Throws: out_of_range if pos > size() or length_error if size() + n > max_size(). […]and pos <= size().
basic_string& insert(size_type pos, const charT* s);-13- Requires:
-14- Effects: Equivalent to return insert(pos, s, traits::length(s));pos <= size() ands points to an array of at least traits::length(s) + 1 elements of charT..-15- Returns: *this.
Modify 21.4.6.5 [string::erase] as indicated:
basic_string& erase(size_type pos = 0, size_type n = npos);-2- Throws: out_of_range if pos > size(). […]
-1- Requires: pos <= size()
Modify 21.4.6.6 [string::replace] as indicated: [Editorial note: The first change suggestion is also a bug fix of the current wording, because it is possible that this function can throw length_error, see p10]
basic_string& replace(size_type pos1, size_type n1, const basic_string& str);
-1- Requires: pos1 <= size().-2- Throws: out_of_range if pos1 > size().-3- Effects:CallsEquivalent to return replace(pos1, n1, str.data(), str.size());.-4- Returns: *this.
basic_string& replace(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n = npos);-6- Throws: out_of_range if pos1 > size() or pos2 > str.size(). […]
-5- Requires: pos1 <= size() and pos2 <= str.size().
basic_string& replace(size_type pos1, size_type n1, const charT* s, size_type n2);-9- Requires:
-10- Throws: out_of_range if pos1 > size() or length_error if the length of the resulting string would exceed max_size() (see below). […]pos1 <= size() ands points to an array of at least n2 elements of charT.
basic_string& replace(size_type pos, size_type n, const charT* s);-13- Requires:
-14- Effects: Equivalent to return replace(pos, n, s, traits::length(s));pos <= size() ands points to an array of at least traits::length(s) + 1 elements of charT..-15- Returns: *this.
Modify 21.4.6.7 [string::copy] as indicated:
size_type copy(charT* s, size_type n, size_type pos = 0) const;-2- Throws: out_of_range if pos > size(). […]
-1- Requires: pos <= size()
Modify 21.4.7.8 [string::substr] as indicated:
basic_string substr(size_type pos = 0, size_type n = npos) const;-2- Throws: out_of_range if pos > size(). […]
-1- Requires: pos <= size()
Modify 30.3.1.5 [thread.thread.member] as indicated:
void join();[…] -7- Throws: system_error when an exception is required (30.2.2). -8- Error conditions:
-3- Requires: joinable() is true.
[…]
invalid_argument — if the thread is not joinable.
void detach();[…] -12- Throws: system_error when an exception is required (30.2.2). -13- Error conditions:
-9- Requires: joinable() is true.
[…]
invalid_argument — if the thread is not joinable.
Section: 18.2 [support.types] Status: New Submitter: Matt Austern Opened: 2013-04-19 Last modified: 2015-04-08
View all other issues in [support.types].
View all issues with New status.
Discussion:
The C++ standard library defines size_t, a typedef for an implementation defined unsigned integer type that can represent the sizes of objects. The POSIX standard augments this with ssize_t, a typedef for a signed integer type that corresponds to size_t.
The ssize_t typedef is useful — useful enough that the C++ standard even refers to it. (In a non-normative footnote in 27.5.2 [stream.types].) Also, lots of OS vendors add it to their headers anyway, even though it isn't part of the C or C++ standards, because those vendors are trying to define headers that conform to multiple standards at once. We should make users' and implementers' lives easier by adding ssize_t to 18.2 [support.types].[2013-09-29, Suggested wording from Jayson Oldfather]
I decided to use the phrase to describe ssize_t below because of the text describing it in the POSIX standard. In it, it describes ssize_t with the value range of [-1,{SSIZE_MAX}]. SSIZE_MAX is specified in the POSIX standard as a minimum value of _POSIX_SSIZE_MAX. This macro is referenced in the wording below.
Proposed resolution:
Ammend 18.2 [support.types], Table 30 as indicated:
Table 30 — Header <cstddef> synopsis Type Name(s) Macros: NULL offset_t Types: ptrdiff_t ssize_t size_t max_align_t nullptr_t
Add the following paragraph to describe ssize_t
-?- The type ssize_t is an implementation-defined signed integer type that shall contain the minimum range [-1, {SSIZE_MAX}] where SSIZE_MAX is specified at a minimum of _POSIX_SSIZE_MAX.
Ammend p7 as follows:
-7- [Note: It is recommended that implementations choose types for ptrdiff_t, ssize_t, and size_t whose integer conversion ranks …
Section: X [dynarray.overview] Status: Ready Submitter: Jonathan Wakely Opened: 2013-04-23 Last modified: 2015-04-08
View all issues with Ready status.
Discussion:
Addresses: arrays.ts
X [dynarray.overview] p2 says:
"Unless otherwise specified, all dynarray operations have the same requirements and semantics as specified in 23.2 [container.requirements]."
Some differences from 23.2 [container.requirements] are not explicitly specified, including at least the lack of a default constructor, copy assignment and swap member.
The wording could be similar to 23.3.2.1 [array.overview] which says "An array satisfies all of the requirements of a container and of a reversible container (23.2 [container.requirements]), except that a default constructed array object is not empty and that swap does not have constant complexity."[2013-09 Chicago:]
Move to Deferred. This feature will ship after C++14 and should be revisited then.
[2014-06-06 pre-Rapperswil]
This issue has been reopened as arrays-ts.
[2014-06-16 Rapperswil]
Move to Ready
[2014/11 Urbana]
Held at Ready status, pending clarification of Arrays TS
Proposed resolution:
Add to X [dynarray.overview] p2:
-2- A dynarray satisfies all of the requirements of a container and of a reversible container (23.2 [container.requirements]), except for default construction, assignment and swap. Unless otherwise specified, all dynarray operations have the same requirements and semantics as specified in 23.2 [container.requirements].
Section: 23.2.1 [container.requirements.general] Status: Open Submitter: Jonathan Wakely Opened: 2013-04-23 Last modified: 2015-04-08
View other active issues in [container.requirements.general].
View all other issues in [container.requirements.general].
View all issues with Open status.
Discussion:
Addresses: arrays.ts
23.2.1 [container.requirements.general] p3 says:
"All of the containers defined in this Clause and in (21.4) except array meet the additional requirements of an allocator-aware container, as described in Table 99."
Is this true of dynarray? I believe the answer must be no because dynarray has no allocator_type, and morally should be no, so that operations are defined in terms of std::allocator<T>, which p13 says doesn't actually need to be used (which allows the elements to be default-initialized as is intended, rather than "default-inserted into the container" using an allocator.)
The requirement that "each element is constructed with uses-allocator construction" provides roughly equivalent behaviour to the "CopyInsertable into X" requirements for allocator-aware containers, allowing an allocator to control construction of the dynarray elements.[2013-09 Chicago]
Move to Deferred. This feature will ship after C++14 and should be revisited then.
[2014-06-06 pre-Rapperswill]
This issue has been reopened as arrays-ts.
Proposed resolution:
Change to 23.2.1 [container.requirements.general] p13:
-13- All of the containers defined in this Clause and in (21.4) except array and dynarray meet the additional requirements of an allocator-aware container, as described in Table 99.
Section: X [dynarray.cons] Status: Ready Submitter: Jonathan Wakely Opened: 2013-04-23 Last modified: 2015-04-08
View all issues with Ready status.
Discussion:
Addresses: arrays.ts
These constructors can interact badly::
template<class Alloc> dynarray(size_type c, const Alloc& alloc); dynarray(size_type c, const T& v);
Unless the second argument is a value of exactly the type T you will get the first constructor, i.e. all of these will fail to compile:
dynarray<long> dlong(1, 1); // 1 is not long dynarray<float> dflt(1, 1.0); // 1.0 is not float dynarray<int*> dptr(1, nullptr); // nullptr is not int* dynarray<void*> doh(1, 0); // 0 is not void*
The nullptr case is particularly annoying, a user trying to do the right thing by saying nullptr instead of NULL still gets the wrong result.
The constructor taking an allocator requires that "Alloc shall meet the requirements for an Allocator" but doesn't actually say "shall not participate in overload resolution unless ..." I believe we have no precedent for using SFINAE to check "the requirements for an Allocator" because it's a pretty complicated set of requirements. We could say it shall not participate in overload resolution if Alloc is implicitly convertible to value_type. Alternatively, we could follow the same approach used by other types that can be constructed with an unconstrained allocator type and use std::allocator_arg_t as the first argument instead of adding an allocator after the other arguments.[2013-09 Chicago:]
Move to Deferred. This feature will ship after C++14 and should be revisited then.
[2014-06-06 pre-Rapperswil]
This issue has been reopened as arrays-ts.
[2014-06-16 Rapperswil]
Move to Ready for alternative A
Previous resolution [SUPERSEDED]:
Either use the correct way to unambiguously call a constructor taking any type of allocator, i.e. change the constructors to take dynarray(std::allocator_arg_t, const Alloc&, ...) by modifying both the synopsis X [dynarray.overview] p2 and X [dynarray.cons] before p9 like so:
template <class Alloc> dynarray(allocator_arg_t, const Alloc& a, size_type c, const Alloc& alloc); template <class Alloc> dynarray(allocator_arg_t, const Alloc& a, size_type c, const T& v, const Alloc& alloc); template <class Alloc> dynarray(allocator_arg_t, const Alloc& a, const dynarray& d, const Alloc& alloc); template <class Alloc> dynarray(allocator_arg_t, const Alloc& a, initializer_list<T>, const Alloc& alloc);or constrain the problematic constructor by adding a new paragraph to X [dynarray.cons]:
template <class Alloc> dynarray(size_type c, const Alloc& alloc); template <class Alloc> dynarray(size_type c, const T& v, const Alloc& alloc); template <class Alloc> dynarray(const dynarray& d, const Alloc& alloc); template <class Alloc> dynarray(initializer_list<T>, const Alloc& alloc);-9- Requires: Alloc shall meet the requirements for an Allocator (17.6.3.5 [allocator.requirements]).
-10- Effects: Equivalent to the preceding constructors except that each element is constructed with uses-allocator construction (20.7.7.2 [allocator.uses.construction]). -?- Remarks: The first constructor shall not participate in overload resolution unless Alloc is not implicitly convertible to T.
[2014/11 Urbana]
Held at Ready status, pending clarification of Arrays TS
Proposed resolution:
Use the correct way to unambiguously call a constructor taking any type of allocator, i.e. change the constructors to take dynarray(std::allocator_arg_t, const Alloc&, ...) by modifying both the synopsis X [dynarray.overview] p2 and X [dynarray.cons] before p9 like so:
template <class Alloc> dynarray(allocator_arg_t, const Alloc& a, size_type c, const Alloc& alloc); template <class Alloc> dynarray(allocator_arg_t, const Alloc& a, size_type c, const T& v, const Alloc& alloc); template <class Alloc> dynarray(allocator_arg_t, const Alloc& a, const dynarray& d, const Alloc& alloc); template <class Alloc> dynarray(allocator_arg_t, const Alloc& a, initializer_list<T>, const Alloc& alloc);
Section: 23.3.6.5 [vector.modifiers] Status: New Submitter: Howard Hinnant Opened: 2013-04-29 Last modified: 2015-04-08
View other active issues in [vector.modifiers].
View all other issues in [vector.modifiers].
View all issues with New status.
Discussion:
23.3.6.5 [vector.modifiers]/p3 says:
iterator erase(const_iterator position); iterator erase(const_iterator first, const_iterator last);Effects: Invalidates iterators and references at or after the point of the erase.
Consider this example:
#include <vector>
#include <cassert>
int main()
{
typedef std::vector<int> C;
C c = {1, 2, 3, 4};
C::iterator i = c.begin() + 1;
C::iterator j = c.end() - 1;
assert(*i == 2);
assert(*j == 4);
c.erase(c.begin());
assert(*i == 3); // Why is this not perfectly fine?!
}
Why has the iterator i been invalidated? It still refers to a perfectly reasonable, fully constructed object. If vector::iterator were to be implemented as a pointer (which is legal), it is not possible for that last line to do anything but run fine.
The iterator j on the other hand now points at end, and any iterators that may now point beyond end(), into uninitialized memory, are clearly invalid. But why do we say that an iterator that must point to a valid object is invalid? This looks to me like we simply got sloppy in our specification.Proposed resolution:
Section: 17.6.5.5 [member.functions] Status: New Submitter: Richard Smith Opened: 2013-05-12 Last modified: 2015-04-08
View all other issues in [member.functions].
View all issues with New status.
Discussion:
17.6.5.5 [member.functions] p2 says:
"An implementation may declare additional non-virtual member function signatures within a class:
by adding arguments with default values to a member function signature; [Footnote: Hence, the address of a member function of a class in the C++ standard library has an unspecified type.] [Note: An implementation may not add arguments with default values to virtual, global, or non-member functions. — end note]
by replacing a member function signature with default values by two or more member function signatures with equivalent behavior; and
by adding a member function signature for a member function name."
This wording is not using the correct terminology. "by adding arguments with default values" presumably means "by adding parameters with default arguments", and likewise throughout.
This paragraph only allows an implementation to declare "additional" signatures, but the first bullet is talking about replacing a standard signature with one with additional parameters.
None of these bullets allows a member function with no ref-qualifier to be replaced by signatures with ref-qualifiers (a situation which was just discussed on std-proposals), and likewise for cv-qualifiers. Presumably that is not intentional, and such changes should be permissible.
I think the first two items are probably editorial, since the intent is clear.
[2013-12-11 Richard provides concrete wording]
Proposed resolution:
This wording is relative to N3797.
Merge 17.6.5.5 [member.functions]p2+3 as indicated:
-2-
An implementation may declare additional non-virtual member function signatures within a class:
by adding arguments with default values to a member function signature;188 [Note: An implementation may not add arguments with default values to virtual, global, or non-member functions. — end note]
by replacing a member function signature with default values by two or more member function signatures with equivalent behavior; and
by adding a member function signature for a member function name.
-3- A call to a member function signature described in the C++ standard library behaves as if the implementation declares no additional member function signatures.[Footnote: A valid C++ program always calls the expected library member function, or one with equivalent behavior. An implementation may also define additional member functions that would otherwise not be called by a valid C++ program.]For a non-virtual member function described in the C++ standard library, an implementation may declare a different set of member function signatures, provided that any call to the member function that would select an overload from the set of declarations described in this standard behaves as if that overload were selected. [Note: For instance, an implementation may add parameters with default values, or replace a member function with default arguments with two or more member functions with equivalent behavior, or add additional signatures for a member function name. — end note]
Section: 17.6.3.5 [allocator.requirements] Status: Open Submitter: Jonathan Wakely Opened: 2013-05-14 Last modified: 2015-04-08
View other active issues in [allocator.requirements].
View all other issues in [allocator.requirements].
View all issues with Open status.
Discussion:
For an allocator A<T> which defines A<T>::pointer to a class type, i.e. not T*, I see no requirement that A<T>::pointer is convertible to A<U>::pointer, even if T* is convertible to U*. Such conversions are needed in containers to convert from e.g. ListNodeBase* to ListNode<T>*.
The obvious way to do such conversions appears to be pointer_traits::pointer_to(), but that's ill-formed if the static member function A<T>::pointer::pointer_to() doesn't exist and the allocator requirements don't mention that function, so you need to cast A<T>::pointer to A<T>::void_pointer then cast that to A<U>::pointer.
Is converting via void_pointer really intended, or are we missing a requirement that pointer_traits<A<T>::pointer>::pointer_to() be well-formed?
Proposed resolution:
Add to the Allocator requirements table the following requirement:
The expression pointer_traits<XX::pointer>::pointer_to(r) is well-defined.
[2013-09 Chicago]
Pablo to come back with Proposed Wording
Proposed resolution:
Edit Table 28 as indicated:
Table 28 — Allocator requirements (continued) Expression Return type Assertion/note pre-/post-condition Default … static_cast<X::const_pointer>(z) X::const_pointer static_cast<X::const_pointer>(z) == q pointer_traits<X::pointer>::pointer_to(r) X::pointer …
Section: 23.2 [container.requirements] Status: New Submitter: Jonathan Wakely Opened: 2013-05-14 Last modified: 2015-04-08
View other active issues in [container.requirements].
View all other issues in [container.requirements].
View all issues with New status.
Discussion:
Is a container C only supposed to refer to allocated memory (blocks of contiguous storage, nodes, etc.) through objects of type C::pointer rather than C::value_type*?
I don't see anything explicitly requiring this, so a container could immediately convert the result of get_allocator().allocate(1) to a built-in pointer of type value_type* and only deal with the built-in pointer until it needs to deallocate it again, but that removes most of the benefit of allowing allocators to use custom pointer types.
[2014-06-12, Jonathan comments]
This issue is basically the same issue as LWG 1521, which agrees it's an issue, to be dealt with in the future, so I request that 2261 not be closed as a dup unless we reopen 1521.
Proposed resolution:
Section: 20.8.1.2 [unique.ptr.single] Status: New Submitter: Rob Desbois Opened: 2013-05-15 Last modified: 2015-04-08
View all other issues in [unique.ptr.single].
View all issues with New status.
Discussion:
N3337 20.8.1.2.5 [unique.ptr.single.modifiers] contains 2 non-normative notes stating:
[para 4]: "The order of these operations is significant because the call to get_deleter() may destroy *this."
[para 5]: "The postcondition does not hold if the call to get_deleter() destroys *this since this->get() is no longer a valid expression."
It seems this wording was created to resolve 998 due to the possibility that a unique_ptr may be destroyed through deletion of its stored pointer where that directly or indirectly refers to the same unique_ptr. If unique_ptr is required to support circular references then it seems this must be normative text: an implementation is currently allowed to operate on *this after the assignment and deletion specified in para 4, since this is only 'disallowed' by the non-normative note.
I propose the following draft rewording:
[para 4]: Effects: assigns p to the stored pointer, and then if the old value of the stored pointer, old_p, was not
equal to nullptr, calls get_deleter()(old_p). No operation shall be performed after the call to
get_deleter()(old_p) that requires *this to be valid, because the deletion may destroy *this if it is
referred to directly or indirectly by the stored pointer. [Note: The order of these operations is significant
because the call to get_deleter() may destroy *this. — end note]
I expect it will also be necessary to amend the requirements for a deleter, so in addition:
20.8.1.2 [unique.ptr.single] [para 1]: The default type for the template parameter D is default_delete. A client-supplied template argument D shall be a function object type (20.10), lvalue-reference to function, or lvalue-reference to function object type for which, given a value d of type D and a value ptr of type unique_ptr<T, D>::pointer, the expression d(ptr) is valid and has the effect of disposing of the pointer as appropriate for that deleter. Where D is not an lvalue reference type, d(ptr) shall be valid if ptr refers directly or indirectly to the invoking unique_ptr object.
[2013-10-05, Stephan T. Lavavej comments and provides alternative wording]
In Chicago, we determined that the original proposed change to 20.8.1.2 [unique.ptr.single]/1 was insufficient, because d might be a reference to a deleter functor that's destroyed during self-destruction.
We believed that 20.8.1.2.5 [unique.ptr.single.modifiers]/4 was already sufficiently clear. The Standard occasionally prevents implementations of X from doing various things, through the principle of "nothing allows X to fail in that situation". For example, v.push_back(v[0]) is required to work for non-empty vectors because nothing allows that to fail. In this case, the intent to allow self-destruction is already clear. Additionally, we did not believe that 20.8.1.2.5 [unique.ptr.single.modifiers]/5 had to be changed. The current note is slightly squirrely but it does not lead to confusion for implementers or users.Previous resolution from Rob Desbois:
Edit 20.8.1.2 [unique.ptr.single] p1 as indicated:
The default type for the template parameter D is default_delete. A client-supplied template argument D shall be a function object type (20.10), lvalue-reference to function, or lvalue-reference to function object type for which, given a value d of type D and a value ptr of type unique_ptr<T, D>::pointer, the expression d(ptr) is valid and has the effect of disposing of the pointer as appropriate for that deleter. Where D is not an lvalue reference type, d(ptr) shall be valid if ptr refers directly or indirectly to the invoking unique_ptr object.
Edit 20.8.1.2.5 [unique.ptr.single.modifiers] p4+5 as indicated:
void reset(pointer p = pointer()) noexcept;-3- Requires: The expression get_deleter()(get()) shall be well formed, shall have well-defined behavior, and shall not throw exceptions.
-4- Effects: assigns p to the stored pointer, and then if the old value of the stored pointer, old_p, was not equal to nullptr, calls get_deleter()(old_p). No operation shall be performed after the call to get_deleter()(old_p) that requires *this to be valid, because the deletion may destroy *this if it is referred to directly or indirectly by the stored pointer.[Note: The order of these operations is significant because the call to get_deleter() may destroy *this. — end note]-5- Postconditions: If the call get_deleter()(old_p) destroyed *this, none. Otherwise, get() == p.[Note: The postcondition does not hold if the call to get_deleter() destroys *this since this->get() is no longer a valid expression. — end note]
Proposed resolution:
This wording is relative to N3691.
Edit 20.8.1.2 [unique.ptr.single] p1 as indicated:
The default type for the template parameter D is default_delete. A client-supplied template argument D shall be a function object type (20.10), lvalue-reference to function, or lvalue-reference to function object type for which, given a value d of type D and a value ptr of type unique_ptr<T, D>::pointer, the expression d(ptr) is valid and has the effect of disposing of the pointer as appropriate for that deleter. d(ptr) shall be valid even if it triggers the destruction of d or (if D is an lvalue reference to function object type) the function object that d refers to.
Section: X [dynarray], 23.2 [container.requirements] Status: Open Submitter: Povilas Kanapickas Opened: 2013-05-22 Last modified: 2015-04-08
View all issues with Open status.
Discussion:
Addresses: arrays.ts
std::dynarray member listing at X [dynarray.overview] includes this constructor:
dynarray(initializer_list<T>);
Also, X [dynarray.overview] p. 2 says:
Unless otherwise specified, all dynarray operations have the same requirements and semantics as specified in 23.2.
The constructor in question isn't mentioned in X [dynarray.cons] or anywhere else. This means requirements from 23.2 [container.requirements] apply. However, Table 100 in 23.2.3 [sequence.reqmts] says:
X(il) Equivalent to X(il.begin(), il.end())
std::dynarray does not provide this constructor.
The proposed resolution below adds the missing constructor and a complementary constructor with an allocator parameter. The new constructors, differently from the rest of containers, accept iterators that have forward iterator category. This is needed because the size requirements must be known in order to allocate appropriately-sized storage.
An alternative resolution could be to properly specify the initializer-list constructor.[2013-09 Chicago:]
Move to Deferred. This feature will ship after C++14 and should be revisited then.
[2014-06-06 pre-Rapperswill]
This issue has been reopened as arrays-ts.
Proposed resolution:
Add the following to the std::dynarray synopsis at X [dynarray.overview]:
namespace std { template <class T> class dynarray { […] // 23.3.4.2 construct/copy/destroy: […] template <class ForwardIterator> dynarray(ForwardIterator first, ForwardIterator last); template <class ForwardIterator, class Alloc> dynarray(ForwardIterator first, ForwardIterator last, const Alloc& alloc); […] }; }
Add the following to X [dynarray.cons] after p. 8:
template <class ForwardIterator> dynarray(ForwardIterator first, ForwardIterator last);-?- Requires: T shall meet the CopyConstructible requirements.
-?- Effects: Allocates storage for distance(first, last) elements. The distance(first, last) elements of the dynarray are direct-initialized (8.5 [dcl.init]) with the corresponding elements from the range [first,last). May or may not invoke the global operator new. -?- Complexity: distance(first, last). -?- Throws: std::bad_array_length when the size requested is larger than implementable, std::bad_alloc when there is insufficient memory.
Add the following to the list of constructors at X [dynarray.cons] before p. 9:
template <class Alloc> dynarray(size_type c, const Alloc& alloc); template <class Alloc> dynarray(size_type c, const T& v, const Alloc& alloc); template <class Alloc> dynarray(const dynarray& d, const Alloc& alloc); template <class Alloc> dynarray(initializer_list<T>, const Alloc& alloc); template <class ForwardIterator, class Alloc> dynarray(ForwardIterator first, ForwardIterator last, const Alloc& alloc);
Section: 29.3 [atomics.order] Status: SG1 Submitter: Brian Demsky Opened: 2013-06-17 Last modified: 2015-04-08
View other active issues in [atomics.order].
View all other issues in [atomics.order].
View all issues with SG1 status.
Discussion:
I believe that the following variation on IRIW should admit executions in which c1 = d1 = 5 and c2 = d2 = 0. If this is allowed, then what is sequence of program evaluations for 29.3 [atomics.order] p9 that justifies the store to z? It seems that 29.3 [atomics.order] p9 should not allow this execution because one of the stores to x or y has to appear earlier in the sequence, each of the fetch_adds reads the previous load in the thread (and thus must appear later in the sequence), and 29.3 [atomics.order] p9 states that each load must read from the last prior assignment in the sequence.
atomic_int x; atomic_int y; atomic_int z; int c1, c2, d1, d2; static void a(void* obj) { atomic_store_explicit(&x, 5, memory_order_relaxed); } static void b(void* obj) { atomic_store_explicit(&y, 5, memory_order_relaxed); } static void c(void* obj) { c1 = atomic_load_explicit(&x, memory_order_relaxed); // this could also be an atomic load if the address depends on c1: c2 = atomic_fetch_add_explicit(&y, c1, memory_order_relaxed); } static void d(void* obj) { d1 = atomic_load_explicit(&y, memory_order_relaxed); d2 = atomic_fetch_add_explicit(&x, d1, memory_order_relaxed); } int user_main(int argc, char** argv) { thrd_t t1, t2, t3, t4; atomic_init(&x, 0); atomic_init(&y, 0); printf("Main thread: creating 4 threads\n"); thrd_create(&t1, (thrd_start_t)&a, NULL); thrd_create(&t2, (thrd_start_t)&b, NULL); thrd_create(&t3, (thrd_start_t)&c, NULL); thrd_create(&t4, (thrd_start_t)&d, NULL); thrd_join(t1); thrd_join(t2); thrd_join(t3); thrd_join(t4); printf("c1=%d c2=%d\n",c1,c2); printf("d1=%d d2=%d\n",d1,d2); // Can this store write 1000 (i.e., c1=d1=5, c2=d2=0)? atomic_store(&z, (c1+d1)*100+c2+d2); printf("Main thread is finished\n"); return 0; }
It seems that the easiest fix is to allow a load in 29.3 [atomics.order] p9 to read from any prior store in the evaluation order.
That said, I would personally advocate the following: It seems to me that C/C++ atomics are in a bit of different situation than Java because:People are expected to use relaxed C++ atomics in potentially racy situations, so it isn't clear that semantics as complicated as the JMM's causality would be sane.
People who use C/C++ atomics are likely to be experts and use them in a very controlled fashion. I would be really surprised if compilers would find any real wins by optimizing the use of atomics.
Why not do something like:
There is satisfaction DAG of all program evaluations. Each evaluation observes the values of variables as computed by some prior assignment in the DAG. There is an edge x->y between two evaluations x and y if:the evaluation y observes a value computed by the evaluation x or
the evaluation y is an atomic store, the evaluation x is an atomic load, and there is a condition branch c that may depend (intrathread dependence) on x and x-sb->c and c-sb->y.
This seems to allow reordering of relaxed atomics that processors do without extra fence instructions, allows most reorderings by the compiler, and gets rid of satisfaction cycles.
[2015-02 Cologne]
Handed over to SG1.
Proposed resolution:
Section: 25.4.1.4 [partial.sort.copy] Status: New Submitter: Matt Austern Opened: 2013-06-26 Last modified: 2015-04-08
View all issues with New status.
Discussion:
The signature of this function is:
template<class InputIterator, class RandomAccessIterator> RandomAccessIterator partial_sort_copy(InputIterator first, InputIterator last, RandomAccessIterator result_first, RandomAccessIterator result_last);
(and the usual overload for an explicitly provided comparison function). The standard says nothing about requirements in the case where the input type (iterator_traits<InputIterator>::value_type) and the output type (iterator_traits<RandomAccessIterator>::value_type) are different.
Presumably the input type must be convertible to the output type. What's less clear is what the requirements are on the comparison operator. Does the algorithm only perform comparisons on two values of the output type, or does it also perform comparisons on values of the input type, or might it even perform heterogeneous comparisons?Proposed resolution:
Section: 23.2.1 [container.requirements.general] Status: New Submitter: Matt Austern Opened: 2013-06-26 Last modified: 2015-04-08
View other active issues in [container.requirements.general].
View all other issues in [container.requirements.general].
View all issues with New status.
Discussion:
Consider the following code snippet:
#include <vector> #include <algorithm> int main() { std::vector<int> v1(100, 3); std::vector<int> v2(100); copy(v1.begin(), v1.end(), v2.begin()); }
It compiles without error on my desktop. Is it required to? I can't find evidence from the standard that it is. In my test std::copy was found by argument-dependent lookup because the implementation I used made std::vector<int>::iterator a user-defined type defined in namespace std. But the standard only requires std::vector<int>::iterator to be an implementation specified random access iterator type. I can't find anything requiring it to be a user-defined type at all (and in fact there are reasonable implementation where it isn't), let alone a user defined type defined in a specific namespace.
Since the defining namespace of container iterators is visible to users, should the standard say anything about what that namespace is?
Proposed resolution:
Section: 28.11.2 [re.alg.match] Status: Open Submitter: Howard Hinnant Opened: 2013-07-14 Last modified: 2015-04-08
View all other issues in [re.alg.match].
View all issues with Open status.
Discussion:
28.11.2 [re.alg.match] p2 in describing regex_match says:
-2- Effects: Determines whether there is a match between the regular expression e, and all of the character sequence [first,last). The parameter flags is used to control how the expression is matched against the character sequence. Returns true if such a match exists, false otherwise.
It has come to my attention that different people are interpreting the first sentence of p2 in different ways:
If a search of the input string using the regular expression e matches the entire input string, regex_match should return true.
Search the input string using the regular expression e. Reject all matches that do not match the entire input string. If a such a match is found, return true.
The difference between these two subtly different interpretations is found using the following ECMAScript example:
std::regex re("Get|GetValue");
Using regex_search, this re can never match the input string "GetValue", because ECMA specifies that alternations are ordered, not greedy. As soon as "Get" is matched in the left alternation, the matching algorithm stops.
Using definition 1, regex_match would return false for an input string of "GetValue". However definition 2 alters the grammar and appears equivalent to augmenting the regex with a trailing '$', which is an anchor that specifies, reject any matches which do not come at the end of the input sequence. So, using definition 2, regex_match would return true for an input string of "GetValue". My opinion is that it would be strange to have regex_match return true for a string/regex pair that regex_search could never find. I.e. I favor definition 1. John Maddock writes: The intention was always that regex_match would reject any match candidate which didn't match the entire input string. So it would find GetValue in this case because the "Get" alternative had already been rejected as not matching. Note that the comparison with ECMA script is somewhat moot, as ECMAScript defines the regex grammar (the bit we've imported), it does not define anything like regex_match, nor do we import from ECMAScript the behaviour of that function. So IMO the function should behave consistently regardless of the regex dialect chosen. Saying "use awk regexes" doesn't cut it, because that changes the grammar in other ways. (John favors definition 2). We need to clarify 28.11.2 [re.alg.match]/p2 in one of these two directions.[2014-06-21, Rapperswil]
AM: I think there's a clear direction and consensus we agree with John Maddock's position, and if noone else thinks we need the other function I won't ask for it.
Marshall Clow and STL to draft.Proposed resolution:
Section: 23.4.4.3 [map.access], 23.5.4.3 [unord.map.elem] Status: Open Submitter: Andrzej Krzemieński Opened: 2013-07-16 Last modified: 2015-04-08
View other active issues in [map.access].
View all other issues in [map.access].
View all issues with Open status.
Discussion:
Suppose that I provide a custom allocator for type int, that renders value 1 rather than 0 in default-insertion:
struct Allocator1 : std::allocator<int> { using super = std::allocator<int>; template<typename Up, typename... Args> void construct(Up* p, Args&&... args) { super::construct(p, std::forward<Args>(args)...); } template<typename Up> void construct(Up* p) { ::new((void*)p) Up(1); } };
Now, if I use this allocator with std::map, and I use operator[] to access a not-yet-existent value, what value of the mapped_type should be created? 0 (value-initialization) or 1 (default-insertion):
map<string, int, less<string>, Allocator1> map; cout << map["cat"];
N3960 is not very clear. 23.4.4.3 [map.access] in para 1 says:
"If there is no key equivalent to x in the map, inserts value_type(x, T()) into the map."
So, it requires value-initialization.
But para 2 says:"mapped_type shall be DefaultInsertable into *this."
This implies default-insertion, because if not, why the requirement. Also similar functions like vector::resize already require default-insertion wherever they put DefaultInsertable requirements.
Not to mention that default-insertion is more useful, because it allows custom allocators to "override" the default value of mapped_type.[2013-09 Chicago]
Alisdair: Matters only for POD or trivial types
Marshall: issue might show up elsewhere other than map<> Alisdair: initialize elements in any containers — by calling construct on allocator traits Marshall: existing wording is clear Alisdair: main concern is difference in wording, discusses default initialization Nico: different requirement needed Alisdair: gut is issue is NAD, brings up DefaultInsertable definition — discusses definition Nico: why do we have the requirement? Alisdair: other containers have this requirement Marshall: this applies to many other containers Nico: deque<> in particular Alisdair: discusses allocator construct Alisdair: wording raises concerns that aren't said in existing standard Nico: sees no benefit to change Marshall: leery of change Alisdair: can be made clearer; might need to add note to DefaultInsertable; borderline editorial, comfortable without note, willing to wait until other issues arise. close issue as NAD[2015-01-20: Tomasz Kamiński comments]
With the addition of the try_emplace method the behavior of the operator[] for the maps, may be defined as follows:
T& operator[](const key_type& x);Effects: Equivalent to: try_emplace(x).first->second;
T& operator[](key_type&& x);Effects: Equivalent to try_emplace(std::move(x)).first->second;
This would simplify the wording and also after resolution of the issue 2464, this wording would also address this issue.
[2015-02 Cologne]
Wait until 2464 and 2469 are in, which solve this.
Proposed resolution:
This wording is relative to N3691.
Change 23.4.4.3 [map.access] p1+p5 as indicated:
T& operator[](const key_type& x);-1- Effects: If there is no key equivalent to x in the map, inserts
-2- Requires: key_type shall be CopyInsertable and mapped_type shall be DefaultInsertable into *this. […]value_type(x, T()) into the mapinto the map a value with key_type initialized using expression x and mapped_type initialized by default-insertion.T& operator[](key_type&& x);-5- Effects: If there is no key equivalent to x in the map, inserts
-6- Requires: mapped_type shall be DefaultInsertable into *this.value_type(std::move(x), T()) into the mapinto the map a value with key_type initialized using expression std::move(x) and mapped_type initialized by default-insertion.
Change 23.5.4.3 [unord.map.elem] p2 as indicated:
mapped_type& operator[](const key_type& k); mapped_type& operator[](key_type&& k);-1- Requires: mapped_type shall be DefaultInsertable into *this. For the first operator, key_type shall be CopyInsertable into *this. For the second operator, key_type shall be MoveConstructible.
-2- Effects: If the unordered_map does not already contain an element whose key is equivalent to k, the first operator insertsthe value value_type(k, mapped_type())a value with key_type initialized using expression x and mapped_type initialized by default-insertion and the second operator insertsthe value value_type(std::move(k), mapped_type())a value with key_type initialized using expression std::move(x) and mapped_type initialized by default-insertion.
Section: 30.6 [futures] Status: SG1 Submitter: Jonathan Wakely Opened: 2013-07-30 Last modified: 2015-04-08
View all other issues in [futures].
View all issues with SG1 status.
Discussion:
The standard does not specify the behaviour of this program:
#include <future> #include <cassert> struct NonTrivial { NonTrivial() : init(true) { } ~NonTrivial() { assert(init); } bool init; }; int main() { std::promise<NonTrivial> p; auto f = p.get_future(); p.set_exception(std::exception_ptr()); f.get(); }
The standard doesn't forbid making the state ready with a null exception_ptr, so what should get() return? There's no stored exception to throw, but it can't return a value because none was initialized.
A careful reading of the standard shows 30.6.4 [futures.state] p8 says "A shared state is ready only if it holds a value or an exception ready for retrieval." One can infer from the fact that set_exception() makes the state ready that it must store a value or exception, so cannot store "nothing", but that isn't explicit. The promise::set_exception() and promise::set_exception_at_thread_exit() members should require p != nullptr or should state the type of exception thrown if p is null.[2015-02 Cologne]
Handed over to SG1.
Proposed resolution:
Section: 24.7 [iterator.range] Status: Open Submitter: Cassio Neri Opened: 2013-07-31 Last modified: 2015-04-08
View other active issues in [iterator.range].
View all other issues in [iterator.range].
View all issues with Open status.
Discussion:
Addresses: arrays.ts
Section 24.7 [iterator.range] p1 specifies header files that, in addition to <iterator>, make available the function templates in 24.7 (begin, end, etc.) but it fails to mention <dynarray>. This seems to be just an oversight.
[2013-09 Chicago:]
Move to Deferred. This feature will ship after C++14 and should be revisited then.
[2014-06-06 pre-Rapperswill]
This issue has been reopened as arrays-ts.
Proposed resolution:
This wording is relative to N3691.
Modify 24.7 [iterator.range] p1 as indicated:
-1- In addition to being available via inclusion of the <iterator> header, the function templates in 24.7 are available when any of the following headers are included: <array>, <deque>, <dynarray>, <forward_list>, <list>, <map>, <regex>, <set>, <string>, <unordered_map>, <unordered_set>, and <vector>.
Section: 27.8.2.4 [stringbuf.virtuals] Status: New Submitter: Sergey Zubkov Opened: 2013-08-29 Last modified: 2015-04-08
View all other issues in [stringbuf.virtuals].
View all issues with New status.
Discussion:
In 27.8.2.4 [stringbuf.virtuals]/1, basic_stringbuf::underflow() is specified to unconditionally return traits::eof() when a read position is not available.
The semantics of basic_stringbuf require, and existing libraries implement it so that this function makes a read position available if possible to do so, e.g. if some characters were inserted into the stream since the last call to overflow(), resulting in pptr() > egptr(). Compare to the conceptually similar D.7.1.3 [depr.strstreambuf.virtuals]/15.Proposed resolution:
This wording is relative to N3691.
Change 27.8.2.4 [stringbuf.virtuals] as indicated:
int_type underflow();-1- Returns: If the input sequence has a read position available or the function makes a read position available (as described below), returns traits::to_int_type(*gptr()). Otherwise, returns traits::eof(). Any character in the underlying buffer which has been initialized is considered to be part of the input sequence.
-?- The function can make a read position available only if (mode & ios_base::in) != 0 and if the write next pointer pptr() is not null and is greater than the current read end pointer egptr(). To make a read position available, the function alters the read end pointer egptr() to equal pptr().
Section: 20.3.2 [pairs.pair], 20.4.2.1 [tuple.cnstr], 20.12.5 [time.duration] Status: New Submitter: Daniel Krügler Opened: 2013-09-09 Last modified: 2015-04-08
View all other issues in [pairs.pair].
View all issues with New status.
Discussion:
During the acceptance of N3471 and some similar constexpr papers, specific wording was added to pair, tuple, and other templates that were intended to impose implementation constraints that ensure that the observable constexpr "character" of a defaulted function template is solely determined by the required expressions of the user-provided types when instantiated, for example:
The defaulted move and copy constructor, respectively, of pair shall be a constexpr function if and only if all required element-wise initializations for copy and move, respectively, would satisfy the requirements for a constexpr function.
This wording doesn't require enough, especially since the core language via CWG 1358 does now support constexpr function template instantiations, even if such function cannot appear in a constant expression (as specified in 5.20 [expr.const]) or as a constant initializer of that object (as specified in 3.6.2 [basic.start.init]). The wording should be improved and should require valid uses in constant expressions and as constant initializers instead.
Proposed resolution:
This wording is relative to N3691.
Change 20.3.2 [pairs.pair] p2 as indicated:
-2-
The defaulted move and copy constructor, respectively, of pair shall be a constexpr function if and only if all required element-wise initializations for copy and move, respectively, would satisfy the requirements for a constexpr functionAn invocation of the move or copy constructor of pair shall be a constant expression (5.20 [expr.const]) if all required element-wise initializations would be constant expressions. An invocation of the move or copy constructor of pair shall be a constant initializer for that pair object (3.6.2 [basic.start.init]) if all required element-wise initializations would be constant initializers for the respective subobjects.
Change 20.4.2.1 [tuple.cnstr] p2 as indicated:
-2-
The defaulted move and copy constructor, respectively, of tuple shall be a constexpr function if and only if all required element-wise initializations for copy and move, respectively, would satisfy the requirements for a constexpr function. The defaulted move and copy constructor of tuple<> shall be constexpr functionsAn invocation of the move or copy constructor of tuple shall be a constant expression (5.20 [expr.const]) if all required element-wise initializations would be constant expressions. An invocation of the move or copy constructor of tuple shall be a constant initializer for that tuple object (3.6.2 [basic.start.init]) if all required element-wise initializations would be constant initializers for the respective subobjects. An invocation of the move or copy constructor of tuple<> shall be a constant expression, or a constant initializer for that tuple<> object, respectively, if the function argument would be constant expression.
Change 20.12.5 [time.duration] p7 as indicated:
-7- Remarks:
The defaulted copy constructor of duration shall be a constexpr function if and only if the required initialization of the member rep_ for copy and move, respectively, would satisfy the requirements for a constexpr function.An invocation of the copy constructor of duration shall be a constant expression (5.20 [expr.const]) if the required initialization of the member rep_ would be a constant expression. An invocation of the copy constructor of duration shall be a constant initializer for that duration object (3.6.2 [basic.start.init]) if the required initialization of the member rep_ would be constant initializers for this subobject.
Section: 20.10 [meta] Status: New Submitter: Daniel Krügler Opened: 2013-09-02 Last modified: 2015-04-08
View other active issues in [meta].
View all other issues in [meta].
View all issues with New status.
Discussion:
The current library specification uses at several places wording that is intended to refer to core language template deduction failure at the top-level of expressions (aka "SFINAE"), for example:
The expression declval<T>() = declval<U>() is well-formed when treated as an unevaluated operand (Clause 5). Access checking is performed as if in a context unrelated to T and U. Only the validity of the immediate context of the assignment expression is considered. [Note: The compilation of the expression can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note]
Similar wording can be found in the specification of result_of, is_constructible, and is_convertible, being added to resolve an NB comment by LWG 1390 and 1391 through N3142.
This wording is necessary to limit speculative compilations needed to implement these traits, but it is also lengthy and repetitive.[2014-05-19, Daniel suggests a descriptive term]
constrictedly well-formed expression:
An expression e depending on a set of types A1, ..., An which is well-formed when treated as an unevaluated operand (Clause 5). Access checking is performed as if in a context unrelated to A1, ..., An. Only the validity of the immediate context of e is considered. [Note: The compilation of the expression can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note][2014-05-20, Richard and Jonathan suggest better terms]
Richard suggested "locally well-formed"
Jonathan suggested "contextually well-formed" and then "The expression ... is valid in a contrived argument deduction context"[2014-06-07, Daniel comments and improves wording]
The 2014-05-19 suggestion did only apply to expressions, but there are two important examples that are not expressions, but instead are involving an object definition (std::is_constructible) and a function definition (std::is_convertible), respectively, instead. Therefore I suggest to rephrase the usage of "expression" into "program construct" in the definition of Jonathan's suggestion of "valid in a contrived argument deduction context".
I would like to point out that given the new definition of "valid in a contrived argument deduction context", there are several other places of the Library specification that could take advantage of this wording to improve the existing specification, such as 20.9.12.2 [func.wrap.func] p2, most functions in 20.7.8.2 [allocator.traits.members], and the **Insertable, EmplaceConstructible, and Erasable definitions in 23.2.1 [container.requirements.general], but given that these are not fully described in terms of the aforementioned wording yet, I would recommend to fix them by a separate issue once the committee has agreed on following the suggestion presented by this issue.Proposed resolution:
This wording is relative to N3936.
Add the following new definition to 17.3 [definitions] as indicated:
valid in a contrived argument deduction context [defns.valid.contr.context]
A program construct c depending on a set of types A1, ..., An, and treated as an unevaluated operand (Clause 5) when c is an expression, which is well-formed. Access checking is performed as if in a context unrelated to A1, ..., An. Only the validity of the immediate context (14.8.2 [temp.deduct]) of c is considered. [Note: The compilation of c can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note].Change Table 49 ("Type property predicates") as indicated:
Table 49 — Type property predicates Template Condition Preconditions … template <class T, class U>
struct is_assignable;The expression declval<T>() =
declval<U>() is valid in a
contrived argument deduction context
([defns.valid.contr.context]) for types
T and U.well-formed when treated
as an unevaluated operand
(Clause 5). Access
checking is performed as if
in a context unrelated to T
and U. Only the validity of
the immediate context of
the assignment expression
is considered. [Note: The
compilation of the
expression can result in
side effects such as the
instantiation of class
template specializations
and function template
specializations, the
generation of
implicitly-defined
functions, and so on. Such
side effects are not in the
"immediate context" and
can result in the program
being ill-formed. — end
note][…] …
Change 20.10.4.3 [meta.unary.prop] p7 as indicated:
-7- Given the following function prototype:
template <class T> add_rvalue_reference_t<T> create() noexcept;the predicate condition for a template specialization is_constructible<T, Args...> shall be satisfied if and only if the following variable definition
would be well-formedfor some invented variable t would be valid in a contrived argument deduction context ([defns.valid.contr.context]) for types T and Args...:T t(create<Args>()...);[Note: These tokens are never interpreted as a function declaration. — end note]
Access checking is performed as if in a context unrelated to T and any of the Args. Only the validity of the immediate context of the variable initialization is considered. [Note: The evaluation of the initialization can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note]
Change Table 57 ("Other transformations") as indicated:
Table 57 — Other transformations Template Condition Comments … template <class Fn, class... ArgTypes>
struct result_of<Fn(ArgTypes...)>;[…] If the expression
INVOKE(declval<Fn>(),
declval<ArgTypes>()...) is
valid in a contrived argument deduction
context ([defns.valid.contr.context]) for types
Fn and ArgTypes...well, the
formed when treated as an
unevaluated operand (Clause 5)
member typedef type shall name the
type
decltype(INVOKE(declval<Fn>(),
declval<ArgTypes>()...));
otherwise, there shall be no member
type.Access checking is performed as
if in a context unrelated to Fn and
ArgTypes. Only the validity of the
immediate context of the expression is
considered. [Note: The compilation of
the expression can result in side
effects such as the instantiation of
class template specializations and
function template specializations, the
generation of implicitly-defined
functions, and so on. Such side effects
are not in the "immediate context"
and can result in the program being
ill-formed. — end note]…
Change 20.10.6 [meta.rel] p4 as indicated:
-4- Given the following function prototype:
template <class T> add_rvalue_reference_t<T> create() noexcept;the predicate condition for a template specialization is_convertible<From, To> shall be satisfied if and only if the return expression in the following code would be
well-formedvalid in a contrived argument deduction context ([defns.valid.contr.context]) for types To and From, including any implicit conversions to the return type of the function:To test() { return create<From>(); }[Note: This requirement gives well defined results for reference types, void types, array types, and function types. — end note]
Access checking is performed as if in a context unrelated to To and From. Only the validity of the immediate context of the expression of the return-statement (including conversions to the return type) is considered. [Note: The evaluation of the conversion can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. — end note]
Section: 17.5.1.4 [structure.specifications] Status: New Submitter: Jeffrey Yasskin Opened: 2013-09-03 Last modified: 2015-04-08
View all other issues in [structure.specifications].
View all issues with New status.
Discussion:
The C++14 CD has 25 sections including the phrase "X shall not participate in overload resolution ...". Most of these uses are double negatives, which are hard to interpret. "shall not ... unless" tends to be the easiest to read, since the condition is true when the function is available, but we also have a lot of "if X is not Y, then Z shall not participate", which actually means "You can call Z if X is Y." The current wording is also clumsy and long-winded. We should find a better and more concise phrasing.
As an initial proposal, I'd suggest using "X is enabled if and only if Y" in prose and adding an "Enabled If: ..." element to 17.5.1.4 [structure.specifications]. Daniel: I suggest to name this new specification element for 17.5.1.4 [structure.specifications] as "Template Constraints:" instead, because the mentioned wording form was intentionally provided starting with LWG 1237 to give implementations more freedom to realize the concrete constraints. Instead of the original std::enable_if-based specifications we can use better forms of "SFINAE" constraints today and it eases the path to possible language-based constraints in the future.Proposed resolution:
Section: 26.8 [c.math] Status: Open Submitter: Pete Becker Opened: 2013-09-04 Last modified: 2015-04-08
View other active issues in [c.math].
View all other issues in [c.math].
View all issues with Open status.
Discussion:
… and abs(float) and abs(long double). And <cmath> should declare abs(int), abs(long), and abs(long long).
As things currently stand, this program is illegal:#include <cstdlib> int main() { double d = -1.23; double dd = std::abs(d); return 0; }
The call is ambiguous because of the various integer overloads, that's because <cstdlib> provides abs(int) but not abs(double).
This lead one commenter on Stackoverflow to state that abs is dangerous, and to recommend using fabs instead. In general, it makes sense to declare overloaded functions that take user-defined types in the same header as the definition of the user-defined types; it isn't necessary to declare all of the overloads in the same place. But here we're not dealing with any user-defined types; we're dealing with builtin types, which are always defined; all of the overloads should be defined in the same place, to avoid mysterious problems like the one in the code above. The standard library has six overloads for abs:int abs(int); // <cstdlib> long abs(long); // <cstdlib> long long abs(long long); // <cstdlib> float abs(float); // <cmath> double abs(double); // <cmath> long double abs(long double); // <cmath>
These should all be declared in both headers.
I have no opinion on <stdlib.h> and <math.h>.[2013-09 Chicago]
This issue is related to LWG 2192
Move to open[2014-02-13 Issaquah — Nicolai Josuttis suggest wording]
[2015-03-03, Geoffrey Romer provides improved wording]
See proposed resolution of LWG 2192.
Previous resolution from Nicolai [SUPERSEDED]:
Edit 26.8 [c.math] after p7 as indicated:
-6- In addition to the int versions of certain math functions in <cstdlib>, C++ adds long and long long overloaded versions of these functions, with the same semantics.
-7- The added signatures are:long abs(long); // labs() long long abs(long long); // llabs() ldiv_t div(long, long); // ldiv() lldiv_t div(long long, long long); // lldiv()-?- To avoid ambiguities, C++ also adds the following overloads of abs() to <cstdlib>, with the semantics defined in <cmath>:
float abs(float); double abs(double); long double abs(long double);-?- To avoid ambiguities, C++ also adds the following overloads of abs() to <cmath>, with the semantics defined in <cstdlib>:
int abs(int); long abs(long); long long abs(long long);
Proposed resolution:
See proposed resolution of LWG 2192.
Section: 22.3.1.2 [locale.cons] Status: New Submitter: Juan Soulie Opened: 2013-09-04 Last modified: 2015-04-08
View all issues with New status.
Discussion:
22.3.1.2 [locale.cons] p14 ends with:
"[…] If f is null, the resulting object is a copy of other."
but the next line p15 says:
"Remarks: The resulting locale has no name."
But both can't be true when other has a name and f is null.
I've tried it on two implementations (MSVC,GCC) and they are inconsistent with each other on this.Daniel Krügler:
As currently written, the Remarks element applies unconditionally for all cases and thus should "win". The question arises whether the introduction of this element by LWG 424 had actually intended to change the previous Note to a Remarks element. In either case the wording should be improved to clarify this special case.Proposed resolution:
Section: 20.7.12.1 [specialized.addressof] Status: New Submitter: Daryle Walker Opened: 2013-09-08 Last modified: 2015-04-08
View all other issues in [specialized.addressof].
View all issues with New status.
Discussion:
I'm writing a function that needs to be constexpr and I wanted to take the address of its input. I was thinking of using std::addressof to be safe, but it isn't currently constexpr. A sample implementation couldn't be constexpr under the C++11 rules, though.
Daniel Krügler: Indeed the core language clarified by CWG 1312 and by CWG 1384, that such emulations of std::addressof implementations are not valid in constant expressions, therefore it seems more like a defect than a feature request to ask for the guarantee that std::addressof is a constexpr function. It should be added that a similar requirement already exists for offsetof indirectly via the C99 standard as of 7.17 p3:The macros are […]
offsetof(type, member-designator)which expands to an integer constant expression that has type size_t […]
combined with the noted property in C++11 that:
"offsetof is required to work as specified even if unary operator& is overloaded for any of the types involved"
Therefore implementations should already be able without heroic efforts to realize this functionality by some intrinsic. The wording needs at least to ensure that for any lvalue core constant expression e the expression std::addressof(e) is a core constant expression.
[2013-09 Chicago]
[2014-06-08, Daniel improves wording]
It has been ensured that the wording is in sync with the recent working paper and the usage of "any" has been improved to say "every" instead (the fix is similar to that applied by LWG 2150).
Previous resolution from Daniel [SUPERSEDED]:
Change header <memory> synopsis, 20.7.2 [memory.syn] as indicated:
namespace std { […] // 20.7.12 [specialized.algorithms], specialized algorithms: template <class T> constexpr T* addressof(T& r) noexcept; […] }Change 20.7.12.1 [specialized.addressof] as indicated:
template <class T> constexpr T* addressof(T& r) noexcept;-1- Returns: The actual address of the object or function referenced by r, even in the presence of an overloaded operator&.
-?- Remarks: For every lvalue core constant expression e (5.20 [expr.const]), the expression std::addressof(e) is a core constant expression.
[2014-06-09, further improvements]
A new wording form is now used similar to the approach used by LWG 2234, which is a stricter way to impose the necessary implementation requirements.
Proposed resolution:
This wording is relative to N3936.
Introduce the following new definition to the existing list in 17.3 [definitions]: [Drafting note: If LWG 2234 is accepted before this issue, the accepted wording for the new definition should be used instead — end drafting note]
constant subexpression [defns.const.subexpr]
an expression whose evaluation as subexpression of a conditional-expression CE (5.16 [expr.cond]) would not prevent CE from being a core constant expression (5.20 [expr.const]).
Change header <memory> synopsis, 20.7.2 [memory.syn] as indicated:
namespace std { […] // 20.7.12 [specialized.algorithms], specialized algorithms: template <class T> constexpr T* addressof(T& r) noexcept; […] }
Change 20.7.12.1 [specialized.addressof] as indicated:
template <class T> constexpr T* addressof(T& r) noexcept;-1- Returns: The actual address of the object or function referenced by r, even in the presence of an overloaded operator&.
-?- Remarks: An expression std::addressof(E) is a constant subexpression ( [defns.const.subexpr]), if E is an lvalue constant subexpression.
Section: 18.6.1.3 [new.delete.placement] Status: New Submitter: Daniel Krügler Opened: 2013-09-18 Last modified: 2015-04-08
View all other issues in [new.delete.placement].
View all issues with New status.
Discussion:
The library gives explicit permission in 17.6.4.2.1 [namespace.std] p2 that user code may explicitly instantiate a library template provided that the instantiations depend on at least one user-defined type:
A program may explicitly instantiate a template defined in the standard library only if the declaration depends on the name of a user-defined type and the instantiation meets the standard library requirements for the original template.
But it seems that the C++11 library is not specified in a way that guarantees such an instantiation to be well-formed if the minimum requirements of the library is not satisfied.
For example, in general, the first template parameter of std::vector is not required to be DefaultConstructible in general, but due to the split of the single C++03 member function with default argumentvoid resize(size_type sz, T c = T());
into
void resize(size_type sz); void resize(size_type sz, const T& c);
the effect is now that for a type ND that is not DefaultConstructible, such as
struct NP { NP(int); };
the explicit instantiation of std::vector<ND> is no longer well-formed, because the attempt to instantiate the single-argument overload of resize cannot not succeed, because this function imposes the DefaultInsertable requirements and given the default allocator this effectively requires DefaultConstructible.
But DefaultConstructible is not the only point, what about CopyConstructible versus MoveConstructible alone? It turns out that currently the second resize overload would fail during an explicit instantiation for a type like
struct MO { MO() = default; MO(MO&&) = default; };
because it imposes CopyInsertable requirements that end up being equivalent to the CopyConstructible requirements for the default allocator.
Technically a library can solve these issues: For special member functions by defining them in some base class, for others by transforming them effectively into a function template due to the great feature of default template arguments for function templates (At the very moment the validity of the latter approach depends on a resolution of core language issue CWG 1635, though). E.g. the here mentioned resize functions of std::vector could be prevented from instantiation by defining them like this with an implementation:template<class = void> void resize(size_type sz) { […] } template<class = void> void resize(size_type sz, const T& c) { […] }
In this case, these functions could also be defined in a base class, but the latter approach won't work in all cases.
Basically such an implementation is required to constrain all member functions that are not covered by the general requirements imposed on the actual library template parameters. I tested three different C++11 library implementations and but none could instantiate for example std::list, std::vector, or std::deque with value types that are not DefaultConstructible or only MoveConstructible. This issue is raised to clarify the current situation in regard to the actual requirements imposed on user-provided types that are used to explicitly instantiate Library-provided templates. For example, the current Container requirements impose very little requirements on the actual value type and it is unclear to which extend library implementations have to respect that. The minimum solution of this issue should be to at least realize that there is no fundamental requirement on DefaultConstructible for value types of library containers, because we have since C++03 the general statement of 17.6.3.1 [utility.arg.requirements] ("In general, a default constructor is not required."). It is unclear whether CopyConstructible should be required for an explicit instantiation request, but given the careful introduction of move operations in the library it would seem astonishing that a MoveConstructible type wouldn't suffice for value types of the container types. In any case I can envision at least two approaches to solve this issue:As indicated in LWG 2292, those function could get an explicit "Template Constraints:" element, albeit this promises more than needed to solve this issue.
The library could introduce a completely new element form, such as "Instantiation Constraints:" that would handle this situation for explicit instantiation situations. This would allow for simpler techniques to solve the issue when explicit instantiation is required compared to the first bullet, because it would not (necessarily) guarantee SFINAE-friendly expression-wellformedness, such as inspecting the expression std::declval<std::vector<ND>&>.resize(0) in an unevaluated context.
It should be noted that the 2013-08-27 comment to LWG 2193 could be resolved by a similar solution as indicated in this issue here.
Proposed resolution:
Section: 23 [containers] Status: Open Submitter: Zhihao Yuan Opened: 2013-09-26 Last modified: 2015-04-08
View other active issues in [containers].
View all other issues in [containers].
View all issues with Open status.
Discussion:
LWG 2193 yields explicit for default ctors to allow {}, but not for all cases of uniform initialization. For example:
explicit vector(size_type count, const Allocator& alloc = Allocator());
This prevents {n, alloc()}. Although this use is relatively rare, but the behavior is inconsistent with that of
vector(size_type count, const T& value, const Allocator& alloc = Allocator());
[Urbana 2014-11-07: Move to Open]
Proposed resolution:
Section: 30.4.1.2 [thread.mutex.requirements.mutex] Status: SG1 Submitter: Detlef Vollmann Opened: 2013-09-27 Last modified: 2015-04-08
View all other issues in [thread.mutex.requirements.mutex].
View all issues with SG1 status.
Discussion:
As discussed during the Chicago meeting in SG1 the only reasonable reasons for throwing device_or_resource_busy seem to be:
The thread currently already holds the mutex, the mutex is not recursive, and the implementation detects this. In this case resource_deadlock_would_occur should be thrown.
Priority reasons. At least std::mutex (and possibly all standard mutex types) should not be setup this way, otherwise we have real problems with condition_variable::wait().
[2014-06-17 Rapperswil]
Detlef provides wording
[2015-02 Cologne]
Handed over to SG1.
Proposed resolution:
This wording is relative to N3936.
Change 30.4.1.2 [thread.mutex.requirements.mutex] as indicated:
-13- Error conditions:
operation_not_permitted — if the thread does not have the privilege to perform the operation.
resource_deadlock_would_occur — if the implementation detects that a deadlock would occur.
device_or_resource_busy — if the mutex is already locked and blocking is not possible.
Section: 23.3.2.1 [array.overview] Status: Open Submitter: Jonathan Wakely Opened: 2013-09-30 Last modified: 2015-04-08
View all issues with Open status.
Discussion:
23.3.2.1 [array.overview] shows std::array with an "exposition only" data member, elems.
The wording in 17.5.2.3 [objects.within.classes] that defines how "exposition only" is used says it applies to private members, but std::array::elems (or its equivalent) must be public in order for std::array to be an aggregate. If the intention is that std::array::elems places requirements on the implementation to provide "equivalent external behavior" to a public array member, then 17.5.2.3 [objects.within.classes] needs to cover public members too, or some other form should be used in 23.3.2.1 [array.overview].[Urbana 2014-11-07: Move to Open]
Proposed resolution:
Section: 20.4.2.1 [tuple.cnstr] Status: Open Submitter: Stephan T. Lavavej Opened: 2013-09-21 Last modified: 2015-04-08
View other active issues in [tuple.cnstr].
View all other issues in [tuple.cnstr].
View all issues with Open status.
Discussion:
Consider the following code:
void meow(tuple<long, long>) { puts("Two"); } void meow(tuple<long, long, long>) { puts("Three"); } tuple<int, int, int> t(0, 0, 0); meow(t);
This should compile and print "Three" because tuple<long, long>'s constructor from const tuple<int, int, int>& should remove itself from overload resolution. Implementations sensibly do this, but the Standard doesn't actually say it!
In this case, Types is "long, long" and UTypes is "int, int, int". 20.4.2.1 [tuple.cnstr]/3 says "let i be in the range [0,sizeof...(Types)) in order", which is [0, 2). Then /17 says "Remark: This constructor shall not participate in overload resolution unless const Ui& is implicitly convertible to Ti for all i." Interpreted literally, this is true! /15 says "Requires: sizeof...(Types) == sizeof...(UTypes)." but requiring the sizes to be identical doesn't help. Only the special phrase "shall not participate in overload resolution unless" mandates SFINAE/enable_if machinery. The wording that we need is almost available in the Requires paragraphs, except that the Requires paragraphs say "is_constructible" while the Remark paragraphs say "is implicitly convertible", which is the correct thing for the SFINAE constraints to check. My proposed resolution is to unify the Requires and Remark paragraphs, after which there will be no need for Requires (when a constructor participates in overload resolution if and only if X is true, then there's no need for it to Require that X is true). Note: 20.10.4.3 [meta.unary.prop]/6 specifies is_constructible<To, From> and 20.10.6 [meta.rel]/4 specifies is_convertible<From, To>. Both are specified in terms of "template <class T> typename add_rvalue_reference<T>::type create();". Therefore, passing From and From&& is equivalent, regardless of whether From is an object type, an lvalue reference, or an rvalue reference. Also note that 20.4.2.1 [tuple.cnstr]/3 defines T0 and T1 so we don't need to repeat their definitions.[2014-10-05, Daniel comments]
This issue is closely related to LWG 2419.
[2015-02 Cologne]
AM: Howard wants to do something in this space and I want to wait for him to get a paper in.
Postponed.Proposed resolution:
This wording is relative to N3691.
Edit 20.4.2.1 [tuple.cnstr] as indicated:
template <class... UTypes> explicit constexpr tuple(UTypes&&... u);[…] -10- Remark: This constructor shall not participate in overload resolution unless
-8- Requires: sizeof...(Types) == sizeof...(UTypes). is_constructible<Ti, Ui&&>::value is true for all i.each type in UTypes is implicitly convertible to its corresponding type in Typessizeof...(Types) == sizeof...(UTypes) and both is_constructible<Ti, Ui>::value and is_convertible<Ui, Ti>::value are true for all i.[…]
template <class... UTypes> constexpr tuple(const tuple<UTypes...>& u);[…] -17- Remark: This constructor shall not participate in overload resolution unless
-15- Requires: sizeof...(Types) == sizeof...(UTypes). is_constructible<Ti, const Ui&>::value is true for all i.const Ui& is implicitly convertible to Tisizeof...(Types) == sizeof...(UTypes) and both is_constructible<Ti, const Ui&>::value and is_convertible<const Ui&, Ti>::value are true for all i.
template <class... UTypes> constexpr tuple(tuple<UTypes...>&& u);[…] -20- Remark: This constructor shall not participate in overload resolution unless
-18- Requires: sizeof...(Types) == sizeof...(UTypes). is_constructible<Ti, Ui&&>::value is true for all i.each type in UTypes is implicitly convertible to its corresponding type in Typessizeof...(Types) == sizeof...(UTypes) and both is_constructible<Ti, Ui>::value and is_convertible<Ui, Ti>::value are true for all i.
template <class U1, class U2> constexpr tuple(const pair<U1, U2>& u);[…] -23- Remark: This constructor shall not participate in overload resolution unless
-21- Requires: sizeof...(Types) == 2. is_constructible<T0, const U1&>::value is true for the first type T0 in Types and is_constructible<T1, const U2&>::value is true for the second type T1 in Types.const U1& is implicitly convertible to T0 and const U2& is implicitly convertible to T1sizeof...(Types) == 2 && is_constructible<T0, const U1&>::value && is_constructible<T1, const U2&>::value && is_convertible<const U1&, T0>::value && is_convertible<const U2&, T1>::value is true.
template <class U1, class U2> constexpr tuple(pair<U1, U2>&& u);[…] -26- Remark: This constructor shall not participate in overload resolution unless
-24- Requires: sizeof...(Types) == 2. is_constructible<T0, U1&&>::value is true for the first type T0 in Types and is_constructible<T1, U2&&>::value is true for the second type T1 in Types.U1 is implicitly convertible to T0 and U2 is implicitly convertible to T1sizeof...(Types) == 2 && is_constructible<T0, U1>::value && is_constructible<T1, U2>::value && is_convertible<U1, T0>::value && is_convertible<U2, T1>::value is true.
Section: 21.4 [basic.string] Status: New Submitter: Stephan T. Lavavej Opened: 2013-09-21 Last modified: 2015-04-08
View other active issues in [basic.string].
View all other issues in [basic.string].
View all issues with New status.
Discussion:
21.4.4 [string.capacity]/8 specifies basic_string::resize(n, c) with:
Effects: Alters the length of the string designated by *this as follows:
If n <= size(), the function replaces the string designated by *this with a string of length n whose elements are a copy of the initial elements of the original string designated by *this.
If n > size(), the function replaces the string designated by *this with a string of length n whose first size() elements are a copy of the original string designated by *this, and whose remaining elements are all initialized to c.
This wording is a relic of the copy-on-write era. In addition to being extremely confusing, it has undesirable implications. Saying "replaces the string designated by *this with a string of length n whose elements are a copy" suggests that the trimming case can reallocate. Reallocation during trimming should be forbidden, like vector.
At least 7 paragraphs are affected: 21.4.4 [string.capacity]/8, 21.4.6.2 [string::append]/9, 21.4.6.3 [string::assign]/3 and /10, 21.4.6.4 [string::insert]/11, 21.4.6.5 [string::erase]/4, and 21.4.6.6 [string::replace]/11 say "replaces the string [designated/controlled] by *this". (21.4.6.7 [string::copy]/3 is different — it "replaces the string designated by s".) Of the affected paragraphs, resize() and erase() are the most important to fix because they should forbid reallocation during trimming.Proposed resolution:
Section: 23.2.1 [container.requirements.general] Status: Open Submitter: Stephan T. Lavavej Opened: 2013-09-21 Last modified: 2015-04-08
View other active issues in [container.requirements.general].
View all other issues in [container.requirements.general].
View all issues with Open status.
Discussion:
23.2.1 [container.requirements.general]/10 says that unless otherwise specified, "no swap() function invalidates any references, pointers, or iterators referring to the elements of the containers being swapped. [Note: The end() iterator does not refer to any element, so it may be invalidated. — end note]". However, move constructors and move assignment operators aren't given similar invalidation guarantees. The guarantees need several exceptions, so I do not believe that blanket language like /11 "Unless otherwise specified (either explicitly or by defining a function in terms of other functions), invoking a container member function or passing a container as an argument to a library function shall not invalidate iterators to, or change the values of, objects within that container." is applicable.
[2014-02-13 Issaquah]
General agreeement on intent, several wording nits and additional paragraphs to hit.
STL to provide updated wording. Move to Open.
[2015-02, Cologne]
AM: in the proposed wording, I'd like to mention that the iterators now refer to elements of a different container. I think we're saying something like this somewhere. JY: There's some wording like that for swap I think. TK: It's also in list::splice(). DK to JY: 23.2.1p9.
VV: The issue says that STL was going to propose new wording. Has he done that? AM: I believe we're looking at that. GR: The request touches on multiple paragraphs, and this PR has only one new paragraph, so this looks like it's not up-to-date. MC: This was last updated a year ago in Issaquah. Conclusion: Skip, not up to date.Proposed resolution:
This wording is relative to N3691.
In 23.2.1 [container.requirements.general]/10 change as indicated:
-10- Unless otherwise specified (see 23.2.4.1, 23.2.5.1, 23.3.3.4, and 23.3.7.5) all container types defined in this Clause meet the following additional requirements:
[…]
no copy constructor or assignment operator of a returned iterator throws an exception.
no move constructor (or move assignment operator when allocator_traits<allocator_type>::propagate_on_container_move_assignment::value is true) of a container (except for array) invalidates any references, pointers, or iterators referring to the elements of the source container. [Note: The end() iterator does not refer to any element, so it may be invalidated. — end note]
no swap() function throws an exception.
no swap() function invalidates any references, pointers, or iterators referring to the elements of the containers being swapped. [Note: The end() iterator does not refer to any element, so it may be invalidated. — end note]
Section: 26.5.1.1 [rand.req.genl] Status: New Submitter: Stephan T. Lavavej Opened: 2013-09-21 Last modified: 2015-04-08
View all issues with New status.
Discussion:
26.5.1.1 [rand.req.genl]/1 says: "Throughout this subclause 26.5, the effect of instantiating a template [...] that has a template type parameter named IntType is undefined unless the corresponding template argument is cv-unqualified and is one of short, int, long, long long, unsigned short, unsigned int, unsigned long, or unsigned long long." 26.5.8.2.1 [rand.dist.uni.int] specifies template<class IntType = int> class uniform_int_distribution, so this forbids uniform_int_distribution<char/signed char/unsigned char>.
I am not aware of anything in <random> that works with 16-bit integers but fails with 8-bit integers, so I suspect that IntType and UIntType could simply be extended to permit the char family. Alternatively, this change could be limited to uniform_int_distribution alone, where it is definitely safe. A <random> expert should decide which change is best.[2015-04-04 Geoffrey provides wording]
I think it's time to call the question; it's just silly that we have a random number library with no natural way to generate random bytes. However, I don't think it's sufficient to fix only uniform_int_distribution, or even all of IntType. At a bare minimum we need to also fix independent_bits_engine (arguably the cleanest way of generating a random byte) and that's specified in terms of UIntType.
The wording provided below is equivalent to adding unsigned char to item "f" and adding signed char and unsigned char to item "e". That means it still excludes char, but I'm OK with that. If you want to generate a 1-byte number, you should probably pick a signedess, and if you want to generate a raw byte, the "true" raw byte type is unsigned char. This also excludes extended integral types and wide char types, which seem like nice-to-haves at best. I have no objection to supporting any of those types; I just picked this to simplify the wording and hopefully maximize consensus. Note that if we want to broaden IntType to permit any integral type, we'll need to decide if we want to exclude bool. For reference, IntType is used as a parameter of the following templates:uniform_int_distribution binomial_distribution geometric_distribution negative_binomial_distribution poisson_distribution discrete_distribution
and UIntType is used as a parameter of the following templates:
linear_congruential_engine mersenne_twister_engine subtract_with_carry_engine independent_bits_engine
Proposed resolution:
This wording is relative to N4296.
Change in 26.5.1.1 [rand.req.genl] p1 as indicated:
-1- Throughout this subclause 26.5, the effect of instantiating a template:
[…]
that has a template type parameter named IntType is undefined unless the corresponding template
argument is cv-unqualified and is a standard integer type (3.9.1 [basic.fundamental])one of
short, int, long, long long, unsigned short, unsigned int,
unsigned long, or unsigned long long.
that has a template type parameter named UIntType is undefined unless the corresponding template
argument is cv-unqualified and is a standard unsigned integer type (3.9.1 [basic.fundamental])one
of unsigned short, unsigned int, unsigned long, or unsigned long long.
Section: 27.7.2.6 [istream.rvalue] Status: Open Submitter: Stephan T. Lavavej Opened: 2013-09-21 Last modified: 2015-04-08
View all issues with Open status.
Discussion:
27.7.2.6 [istream.rvalue] declares operator>>(basic_istream<charT, traits>&& is, T& x). However, 27.7.2.2.3 [istream::extractors]/7 declares operator>>(basic_istream<charT,traits>& in, charT* s), plus additional overloads for unsigned char* and signed char*. This means that "return_rvalue_istream() >> &arr[0]" won't compile, because T& won't bind to the rvalue &arr[0].
[2014-02-12 Issaquah : recategorize as P3]
Jonathan Wakely: Bill was certain the change is right, I think so with less certainty
Jeffrey Yaskin: I think he's right, hate that we need this
Jonathan Wakely: is this the security issue Jeffrey raised on lib reflector?
Move to P3
Proposed resolution:
This wording is relative to N3691.
Edit 27.7.1 [iostream.format.overview], header <istream> synopsis, as indicated:
namespace std { […] template <class charT, class traits, class T> basic_istream<charT, traits>& operator>>(basic_istream<charT, traits>&& is, T&& x); }
Edit 27.7.2.6 [istream.rvalue] as indicated:
template <class charT, class traits, class T> basic_istream<charT, traits>& operator>>(basic_istream<charT, traits>&& is, T&& x);-1- Effects: is >>
-2- Returns: isxstd::forward<T>(x)
Section: 28.5.1 [re.synopt] Status: Open Submitter: Stephan T. Lavavej Opened: 2013-09-21 Last modified: 2015-04-08
View all other issues in [re.synopt].
View all issues with Open status.
Discussion:
The table in 28.5.1 [re.synopt]/1 says that regex_constants::collate "Specifies that character ranges of the form "[a-b]" shall be locale sensitive.", but 28.13 [re.grammar]/14 says that it affects individual character comparisons too.
[2012-02-12 Issaquah : recategorize as P3]
Marshall Clow: 28.13/14 only applies to ECMAScript
All: we're unsure
Jonathan Wakely: we should ask John Maddock
Move to P3
Proposed resolution:
This wording is relative to N3691.
In 28.5.1 [re.synopt]/1, Table 138 — "syntax_option_type effects", change as indicated:
Table 138 — syntax_option_type effects Element Effect(s) if set … collate Specifies that character ranges of the form "[a-b]"comparisons and character range comparisons shall be locale sensitive.…
Section: 29.6.5 [atomics.types.operations.req] Status: SG1 Submitter: Daniel Krügler Opened: 2013-10-03 Last modified: 2015-04-08
View other active issues in [atomics.types.operations.req].
View all other issues in [atomics.types.operations.req].
View all issues with SG1 status.
Discussion:
According to 29.6.5 [atomics.types.operations.req] p4,
A ::A () noexcept = default;Effects: leaves the atomic object in an uninitialized state. [Note: These semantics ensure compatibility with C. — end note]
This implementation requirement is OK for POD types, like int, but 29.5 [atomics.types.generic] p1 intentionally allows template arguments of atomic with a non-trivial default constructor ("The type of the template argument T shall be trivially copyable (3.9)"), so this wording can be read in a way that makes the behaviour of the following code undefined:
#include <atomic> #include <iostream> struct S { S() noexcept : v(42) {} int v; }; int main() { std::atomic<S> as; // Default-initialization std::cout << as.load().v << std::endl; // ? }
For a user-defined emulation of atomic the expected outcome would be defined and the program would output "42", but existing implementations differ and the result value is a "random number" for at least one implementation. This seems very surprising to me.
To realize that seemingly existing requirement, an implementation is either required to violate normal language rules internally or to perform specific bit-randomization-techniques after the normal default-initialization that called the default constructor of S. According to my understanding, the non-normative note in 29.6.5 [atomics.types.operations.req] p4 is intended to refer to types that are valid C-types, but the example type S is not such a type. To make the mental model of atomic's default constructor more intuitive for user-code, I suggest to clarify the wording to have the effects of default-initialization instead. The current state seems more like an unintended effect of imprecise language used here and has some similarities to wording that was incorrectly used to specify atomic_flag initialization as described by LWG 2159.[2014-05-17, Daniel comments and provides alternative wording]
The current wording was considered controversial as expressed by reflector discussions. To me, the actual problem is not newly introduced by that wording, but instead is already present in basically all paragraphs specifying semantics of atomic types, since the wording never clearly distinguishes the value of the actual atomic type A and the value of the "underlying", corresponding non-atomic type C. The revised proposed wording attempts to improve the current ambiguity of these two kinds of values.
Previous resolution from Daniel [SUPERSEDED]:This wording is relative to N3691.
Modify 29.6.5 [atomics.types.operations.req] p4 as indicated: [Editorial note: There is no exposition-only member in atomic, which makes it a bit hard to specify what actually is initialized, but the usage of the term "value" seems consistent with similar wording used to specify the effects of the atomic load functions]
A ::A () noexcept = default;-4- Effects:
leaves the atomic object in an uninitialized stateThe value of the atomic object is default-initialized (8.5 [dcl.init]). [Note: These semantics ensure compatibility with C. — end note]
[2015-02 Cologne]
Handed over to SG1.
Proposed resolution:
This wording is relative to N3936.
Modify 29.6.5 [atomics.types.operations.req] p2 as indicated: [Editorial note: This is a near-to editorial change not directly affecting this issue, but atomic_address does no longer exist and the pointed to definition is relevant in the context of this issue resolution.]
-2- In the following operation definitions:
an A refers to one of the atomic types.
a C refers to its corresponding non-atomic type.
The atomic_address atomic type corresponds to the void* non-atomic type.[…]
Modify 29.6.5 [atomics.types.operations.req] p4 and the following as indicated: [Editorial note: There is no exposition-only member in atomic, which makes it a bit hard to specify what actually is initialized, but the introductory wording of 29.6.5 [atomics.types.operations.req] p2 b2 defines: "a C refers to its corresponding non-atomic type." which helps to specify the semantics in terms of "the C value referred to by the atomic object"]
A::A() noexcept = default;-4- Effects:
leaves the atomic object in an uninitialized stateDefault-initializes (8.5 [dcl.init]) the C value referred to by the atomic object. [Note: These semantics ensure compatibility with C. — end note]constexpr A::A(C desired) noexcept;-5- Effects: Direct-i
[…]Initializes the C value referred to by the atomic object with the value desired. Initialization is not an atomic operation (1.10). […]void atomic_init(volatile A* object, C desired) noexcept; void atomic_init(A* object, C desired) noexcept;-8- Effects: Non-atomically initializes the C value referred to by *object with value desired. […]
void atomic_store(volatile A* object, C desired) noexcept; […] void A::store(C desired, memory_order order = memory_order_seq_cst) noexcept;-9- […]
-10- Effects: Atomically replaces the C value pointed to by object or by this with the value of desired. […] […]C atomic_load(const volatile A* object) noexcept; […] C A::load(memory_order order = memory_order_seq_cst) const noexcept;-13- […]
-14- […] -15- Returns: Atomically returns the C value pointed to by object or by this. […]C atomic_exchange(volatile A* object, C desired) noexcept; […] C A::exchange(C desired, memory_order order = memory_order_seq_cst) noexcept;-18- Effects: Atomically replaces the C value pointed to by object or by this with desired. […]
-19- Returns: Atomically returns the C value pointed to by object or by this immediately before the effects. […]C atomic_fetch_key(volatile A* object, M operand) noexcept; […] C A::fetch_key(M operand, memory_order order = memory_order_seq_cst) noexcept;-28- Effects: Atomically replaces the C value pointed to by object or by this with the result of the computation applied to the C value pointed to by object or by this and the given operand. […]
-29- Returns: Atomically,returns the C value pointed to by object or by this immediately before the effects. […]
Modify 29.7 [atomics.flag] p5 and the following as indicated:
bool atomic_flag_test_and_set(volatile atomic_flag* object) noexcept; […] bool atomic_flag::test_and_set(memory_order order = memory_order_seq_cst) noexcept;-5- Effects: Atomically sets the bool value pointed to by object or by this to true. […]
-6- Returns: Atomically,returns the bool valueof thepointed to by object or by this immediately before the effects.void atomic_flag_clear(volatile atomic_flag* object) noexcept; […] void atomic_flag::clear(memory_order order = memory_order_seq_cst) noexcept;-7- […]
-8- Effects: Atomically sets the bool value pointed to by object or by this to false. […]
Section: 23.3.2 [array] Status: New Submitter: Jeffrey Yasskin Opened: 2013-10-04 Last modified: 2015-04-08
View other active issues in [array].
View all other issues in [array].
View all issues with New status.
Discussion:
In order to replace some uses of C arrays with std::array, we need it to be possible to cast from a std::array<> to an equivalent C array. Core wording doesn't appear to be in quite the right state to allow casting, but if we specify that appropriate types are layout-compatible, we can at least write:
union { array<array<array<int, 2>, 3>, 4> arr; int carr[4][3][2]; };
to view memory as the other type: C++14 CD [class.mem]p18.
I believe it's sufficient to add "array<T, N> shall be layout-compatible (3.9 [basic.types]) with T[N]." to 23.3.2.1 [array.overview], but we might also need some extension to 9.2 [class.mem] to address the possibility of layout-compatibility between struct and array types.I checked that libc++ on MacOS already implements this, although it would be good for someone else to double-check; I haven't checked any other standard libraries.
Proposed resolution:
Section: 20.10.4.3 [meta.unary.prop] Status: New Submitter: Daniel Krügler Opened: 2013-10-01 Last modified: 2015-04-08
View other active issues in [meta.unary.prop].
View all other issues in [meta.unary.prop].
View all issues with New status.
Discussion:
In 20.10.4.3 [meta.unary.prop] we have traits to allow testing for triviality of specific operations, such as is_trivially_constructible and is_trivially_assignable (and their derived forms), which are specified in terms of the following initialization and assignment, respectively:
T t(create<Args>()...); declval<T>() = declval<U>()
The wording that describes the way how triviality is deduced, is in both cases of the same form:
[… ] and the variable definition/assignment, as defined by is_constructible/is_assignable, is known to call no operation that is not trivial (3.9, 12).
The problematic part of this wording is that both definitions are specified in terms of an "object construction" function create or declval, respectively, (The former being a conceptual function, the latter being a library function), but for none of these functions we can assume that they could be considered as trivial — only special member functions can have this property and none of these is one. This problem became obvious, when the similar issue LWG 2298 in regard to is_nothrow_constructible was opened.
A possible approach to solve this specification problem is to make a blanket statement for sub-clause 20.10.4.3 [meta.unary.prop] that these helper functions are considered trivial for the purpose of defining these traits. Using this kind of wording technique can also be used to get rid of the additional helper function template create, which is currently needed for the is_convertible and the is_constructible traits, because both traits are specified in terms of contexts where technically the corresponding "object construction" function would be considered as odr-used. This is problematic, because these traits are defined in terms of well-formed code and odr-using declval would make the program ill-formed (see 20.2.5 [declval]). So extending above blanket statement to consider std::declval<T>() as not odr-used in the context of the corresponding trait definition would allow for replacing create by declval.Proposed resolution:
This wording is relative to N3936.
Add a new paragraph after 20.10.4.3 [meta.unary.prop] p3 as indicated: [Editorial note: The first change in 20.10.4.3 [meta.unary.prop] p3 is recommended, because technically a Clause is always a "main chapter" — such as Clause 20 — but every child of a Clause or sub-clause is a sub-clause]
[…]
-3- For all of the class templates X declared in thisClausesub-clause, instantiating that template with a template-argument that is a class template specialization may result in the implicit instantiation of the template argument if and only if the semantics of X require that the argument must be a complete type. -?- For the purpose of defining the templates in this sub-clause, a function call expression declval<T>() for any type T is considered to be a trivial (3.9 [basic.types], 12 [special]) function call that is not an odr-use (3.2 [basic.def.odr]) of declval in the context of the corresponding definition notwithstanding the restrictions of 20.2.5 [declval]. […]
Modify 20.10.4.3 [meta.unary.prop] p7 as indicated:
-7-
Given the following function prototype:template <class T> typename add_rvalue_reference<T>::type create();
tThe predicate condition for a template specialization is_constructible<T, Args...> shall be satisfied if and only if the following variable definition would be well-formed for some invented variable t:T t(createdeclval<Args>()...);[…]
Add a new paragraph after 20.10.6 [meta.rel] p2 as indicated: [Editorial note: Technically we don't need the guarantee of "a trivial function call" for the type relationship predicates at the very moment, but it seems more robust and consistent to have the exact same guarantee here as well]
[…]
-2- […] -?- For the purpose of defining the templates in this sub-clause, a function call expression declval<T>() for any type T is considered to be a trivial (3.9 [basic.types], 12 [special]) function call that is not an odr-use (3.2 [basic.def.odr]) of declval in the context of the corresponding definition notwithstanding the restrictions of 20.2.5 [declval]. […]
Modify 20.10.6 [meta.rel] p4 as indicated:
-4-
Given the following function prototype:template <class T> typename add_rvalue_reference<T>::type create();
tThe predicate condition for a template specialization is_convertible<From, To> shall be satisfied if and only if the return expression in the following code would be well-formed, including any implicit conversions to the return type of the function:To test() { returncreatedeclval<From>(); }[…]
Section: 20.8.2.2.5 [util.smartptr.shared.obs] Status: Tentatively NAD Submitter: Stephan T. Lavavej Opened: 2013-10-05 Last modified: 2015-04-08
View other active issues in [util.smartptr.shared.obs].
View all other issues in [util.smartptr.shared.obs].
View all issues with Tentatively NAD status.
Discussion:
20.8.1.2.4 [unique.ptr.single.observers]/3: "pointer operator->() const noexcept; Requires: get() != nullptr."
20.8.2.2.5 [util.smartptr.shared.obs]/2: "T& operator*() const noexcept; Requires: get() != 0." 20.8.2.2.5 [util.smartptr.shared.obs]/5: "T* operator->() const noexcept; Requires: get() != 0." Narrow-contract functions should not be noexcept.[2014-02-15 Issaquah]
Issue is contentious, raise to P2.
[2015-02 Cologne]
AM: This ship has sailed. JM: What's the issue? AM: operator-> has narrow contract and should never have had noexcept. DK: Not quite. We explicitly called out that for shared_ptr this is fine. You said so in your "narrow contract" paper. GR: This would be a fairly major regression in the design of {unique,shared}_ptr over raw pointers; raw pointer dereferencing is noexcept. It's not a performance regression but a usability regression. AM: Do we expect users to query noexpect on dereference expressions? Room: Yes. VV: We don't just expect it, we have seen it. JM: Yes, users may be querying something like noexcept(x->y) and expect to be checking y, but silently end up checking x->.
Close as NAD, with explanation from GR. Previous resolution [SUPERSEDED]:This wording is relative to N3691.
In 20.8.1.2 [unique.ptr.single]/1, class template unique_ptr synopsis for single objects, change as indicated:
pointer operator->() constnoexcept;In 20.8.1.2.4 [unique.ptr.single.observers] change as indicated:
pointer operator->() constnoexcept;-3- Requires: get() != nullptr.
-4- Returns: get(). -?- Throws: Nothing. -5- Note: use typically requires that T be a complete type.In 20.8.2.2 [util.smartptr.shared]/1, class template shared_ptr synopsis, change as indicated:
T& operator*() constnoexcept; T* operator->() constnoexcept;In 20.8.2.2.5 [util.smartptr.shared.obs] change as indicated:
T& operator*() constnoexcept;-2- Requires: get() != 0.
-3- Returns: *get(). -?- Throws: Nothing. -4- Remarks: When T is void, it is unspecified whether this member function is declared. If it is declared, it is unspecified what its return type is, except that the declaration (although not necessarily the definition) of the function shall be well formed.T* operator->() constnoexcept;-5- Requires: get() != 0.
-6- Returns: get(). -?- Throws: Nothing.
[2015-03-03, Geoffrey provides rationale]
Rationale:
It is by design that these members are noexcept, and changing that now would be a substantial regression in functionality. These classes were designed to substitute for plain pointers as transparently as possible, so since those operations are effectively noexcept on plain pointers, they should be noexcept on unique_ptr and shared_ptr as well. This matters in practice because we expect these members to be used fairly often inside the noexcept operator, and such code could be broken by this change. These design considerations override our general policy against noexcept for narrow-contract functions.
It is notable that N3279, which proposed this policy, did not propose striking noexcept from these operations. It's not clear if the omission of operator* and operator-> was an oversight, or an intentional reflection of the above considerations. N3279 was based on N3248 by the same authors, which states that:"Most applications of noexcept for unique_ptr and shared_ptr are on functions with wide contracts. However, there are preconditions on the atomic access functions, so these should lose the specification."
Proposed resolution:
Section: 28.7 [re.traits], 22.3.1.1.2 [locale.facet] Status: New Submitter: Sergey Zubkov Opened: 2013-10-15 Last modified: 2015-04-08
View all other issues in [re.traits].
View all issues with New status.
Discussion:
28.7 [re.traits]/7, begins with "if typeid(use_facet<collate<charT> >) == typeid(collate_byname<charT>)", which appears to be pseudocode with the intention to convey that the collate facet has not been replaced by the user. Cf. the wording in N1429 "there is no portable way to implement transform_primary in terms of std::locale, since even if the sort key format returned by std::collate_byname<>::transform is known and can be converted into a primary sort key, the user can still install their own custom std::collate implementation into the locale object used, and that can use any sort key format they see fit.".
Taken literally, 28.7 [re.traits]/7 appears to imply that named locales are required to hold their collate facets with dynamic type std::collate_byname<charT>, which is in fact true in some implementations (e.g libc++), but not others (e.g. libstdc++). This does not follow from the description of _byname in 22.3.1.1.2 [locale.facet]/4, which is only required to provide equivalent semantics, to the named locale's facet, not to actually be one.Proposed resolution:
This wording is relative to N3691.
Modify 22.3.1.1.2 [locale.facet]/4 as indicated:
For some standard facets a standard "..._byname" class, derived from it, implements the virtual function semantics
equivalent toprovided by that facet of the locale constructed by locale(const char*) with the same name. Each such facet provides a constructor that takes a const char* argument, which names the locale, and a refs argument, which is passed to the base class constructor. Each such facet also provides a constructor that takes a string argument str and a refs argument, which has the same effect as calling the first constructor with the two arguments str.c_str() and refs. If there is no "..._byname" version of a facet, the base class implements named locale semantics itself by reference to other facets. For any locale loc constructed by locale(const char*) and facet Facet that has a corresponding standard Facet_byname class, typeid(use_facet<Facet>(loc)) == typeid(Facet_byname).
Modify 28.7 [re.traits]/7 as indicated:
template <class ForwardIterator> string_type transform_primary(ForwardIterator first, ForwardIterator last) const;-7- Effects: if typeid(use_facet<collate<charT> >(getloc())) == typeid(collate_byname<charT>) and the form of the sort key returned by collate_byname<charT>::transform(first, last) is known and can be converted into a primary sort key then returns that key, otherwise returns an empty string.
Section: 27.7.3.1 [ostream] Status: New Submitter: Alf P. Steinbach Opened: 2013-10-29 Last modified: 2015-04-08
View all other issues in [ostream].
View all issues with New status.
Discussion:
For wide streams argument types wchar_t const* and wchar_t are supported only as template parameters. User defined conversions are not considered for template parameter matching. Hence inappropriate overloads of operator<< are selected when an implicit conversion is required for the argument, which is inconsistent with the behavior for char const* and char, is unexpected, and is a useless result.
Demonstration:#include <iostream> struct Byte_string { operator char const*() const { return "Hurray, it works!"; } }; struct Wide_string { operator wchar_t const*() const { return L"Hurray, it works!"; } }; struct Byte_ch { operator char() const { return 'X'; } }; struct Wide_ch { operator wchar_t() const { return L'X'; } }; auto main() -> int { using namespace std; wcout << "'X' as char value : " << Byte_ch() << endl; wcout << "'X' as wchar_t value: " << Wide_ch() << endl; wcout << "Byte string pointer : " << Byte_string() << endl; wcout << "Wide string pointer : " << Wide_string() << endl; }
Example output:
'X' as char value : X 'X' as wchar_t value: 88 Byte string pointer : Hurray, it works! Wide string pointer : 000803C8
Proposed resolution:
This wording is relative to N3797.
Modify 27.7.3.1 [ostream], class template basic_ostream synopsis, as indicated:
namespace std { […] // 27.7.3.6.4 character inserters template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, charT); template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, char); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, char); template<class traits> basic_ostream<wchar_t,traits>& operator<<(basic_ostream<wchar_t,traits>&, wchar_t); […] template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*); template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const char*); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, const char*); template<class traits> basic_ostream<wchar_t,traits>& operator<<(basic_ostream<wchar_t,traits>&, const wchar_t*); […] }
Modify 27.7.3.6.4 [ostream.inserters.character] as indicated: [Drafting note: The replacement of os by out in p1 and the insertion of "out." in p4 just fix two obvious typos — end drafting note]
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, charT c); template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, char c); // specialization template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, char c); template<class traits> basic_ostream<wchar_t,traits>& operator<<(basic_ostream<wchar_t,traits>& out, wchar_t c); // signed and unsigned template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, signed char c); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, unsigned char c);-1- Effects: Behaves as a formatted output function (27.7.3.6.1 [ostream.formatted.reqmts]) of out. Constructs a character sequence seq. If c has type char and the character type of the stream is not char, then seq consists of out.widen(c); otherwise seq consists of c. Determines padding for seq as described in 27.7.3.6.1 [ostream.formatted.reqmts]. Inserts seq into out. Calls
-2- Returns: out.osout.width(0).template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, const charT* s); template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, const char* s); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const char* s); template<class traits> basic_ostream<wchar_t,traits>& operator<<(basic_ostream<wchar_t,traits>& out, const wchar_t* s); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const signed char* s); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const unsigned char* s);-3- Requires: s shall not be a null pointer.
-4- Effects: Behaves like a formatted inserter (as described in 27.7.3.6.1 [ostream.formatted.reqmts]) of out. Creates a character sequence seq of n characters starting at s, each widened using out.widen() (27.5.5.3), where n is the number that would be computed as if by:
traits::length(s) for the following overloads:
where the first argument is of type basic_ostream<charT, traits>& and the second is of type const charT*,
and also for the overloadwhere the first argument is of type basic_ostream<char, traits>& and the second is of type const char*,where the first argument is of type basic_ostream<wchar_t, traits>& and the second is of type const wchar_t*,
std::char_traits<char>::length(s) for the overload where the first argument is of type basic_ostream<charT, traits>& and the second is of type const char*,
traits::length(reinterpret_cast<const char*>(s)) for the other two overloads.
Determines padding for seq as described in 27.7.3.6.1 [ostream.formatted.reqmts]. Inserts seq into out. Calls out.width(0).
-5- Returns: out.
Section: 28.13 [re.grammar] Status: New Submitter: Nayuta Taga Opened: 2013-10-30 Last modified: 2015-04-08
View all other issues in [re.grammar].
View all issues with New status.
Discussion:
In the following "Multiline" is the value of the ECMA-262 RegExp object's multiline property.
In ECMA-262, there are some definitions that relate to Multiline:ECMA-262 15.10.2.6:
If Multiline is true, ^ matches just after LineTerminator.
If Multiline is false, ^ does not match just after LineTerminator. If Multiline is true, $ matches just before LineTerminator. If Multiline is false, $ does not match just before LineTerminator.
ECMA-262 15.10.4.1, 15.10.7.4:
By default, Multiline is false.
So, the C++11 standard says that Multiline is false. As it is false, ^ matches only the beginning of the string, and $ matches only the end of the string.
However, two flags are defined in 28.5.2 [re.matchflag] Table 139:match_not_bol: the character ^ in the regular expression shall not match [first,first).
match_not_eol: the character "$" in the regular expression shall not match [last,last).
As Multiline is false, the match_not_bol and the match_not_eol are meaningless because they only make ^ and $ match none.
In my opinion, Multiline should be true. FYI, Multiline of the existing implementations are as follows: Multiline=false:libstdc++ r206594
libc++ r199174
Multiline=true:
Visual Studio Express 2013
boost 1.55
Proposed resolution:
Section: 20.6 [template.bitset], 27.7.6 [quoted.manip] Status: New Submitter: Zhihao Yuan Opened: 2013-12-02 Last modified: 2015-04-08
View other active issues in [template.bitset].
View all other issues in [template.bitset].
View all issues with New status.
Discussion:
Example: char16_t('1') != u'1' is possible.
The numeric value of char16_t is defined to be Unicode code point, which is same to the ASCII value and UTF-8 for 7-bit chars. However, char is not guaranteed to have an encoding which is compatible with ASCII. For example, '1' in EBCDIC is 241. I found three places in the standard casting narrow char literals: bitset::bitset, bitset::to_string and quoted. PJ confirmed this issue and says he has a solution used in their <filesystem> implementation, and he may want to propose it to the standard. The solution in my mind, for now, is to make those default arguments magical, where the "magic" can be implemented with a C11 _Generic selection (works in clang):#define _G(T, literal) _Generic(T{}, \ char: literal, \ wchar_t: L ## literal, \ char16_t: u ## literal, \ char32_t: U ## literal) _G(char16_t, '1') == u'1'
Proposed resolution:
This wording is relative to N3797.
[Drafting note: This is a sample wording fixing only one case; I'm just too lazy to copy-paste it before we discussed whether the solution is worth and sufficient (for example, should the other `charT`s like `unsigned char` just don't compile without supplying those arguments? I hope so). — end drafting note]Modify 20.6 [template.bitset] p1, class template bitset synopsis, as indicated:
namespace std { template <size_t N> class bitset { public: […] template<class charT, class traits, class Allocator> explicit bitset( const basic_string<charT,traits,Allocator>& str, typename basic_string<charT,traits,Allocator>::size_type pos = 0, typename basic_string<charT,traits,Allocator>::size_type n = basic_string<charT,traits,Allocator>::npos, charT zero =charT('0')see below, charT one =charT('1')see below); […] }; […] }
Modify 20.6.1 [bitset.cons] as indicated:
template<class charT, class traits, class Allocator> explicit bitset(const basic_string<charT, traits, Allocator>& str, typename basic_string<charT, traits, Allocator>::size_type pos = 0, typename basic_string<charT, traits, Allocator>::size_type n = basic_string<charT, traits, Allocator>::npos, charT zero =charT('0')see below, charT one =charT('1')see below);-?- The default values of zero and one compare equal to the character literals 0 and 1 of type charT, respectively.
-3- Requires:: pos <= str.size(). […]
Section: 27.7.2.2.1 [istream.formatted.reqmts] Status: New Submitter: Zhihao Yuan Opened: 2013-12-06 Last modified: 2015-04-08
View all other issues in [istream.formatted.reqmts].
View all issues with New status.
Discussion:
The formatted input function requirement says in 27.7.2.2.1 [istream.formatted.reqmts]:
"If an exception is thrown during input then ios::badbit is turned on in *this's error state. If (exceptions()&badbit) != 0 then the exception is rethrown."
while some formatted function may throw an exception from basic_ios::clear, for example in 20.6.4 [bitset.operators] p6:
"If no characters are stored in str, calls is.setstate(ios_base::failbit) (which may throw ios_base::failure)"
So should this exception be considered as "an exception [...] thrown during input"? And here is an implementation divergence (or you can read the following as "a bug libc++ only has" :)
cin.exceptions(ios_base::failbit); bitset<N> b; try { cin >> b; // type 'a' and return } catch (...) {}
Now cin.rdstate() is just failbit in libstdc++ (and Dinkumware, by PJ), but failbit & badbit libc++. Similar difference found in other places, like eofbit & badbid after std::getline.
PJ and Matt both agree that the intention (of badbit + rethrow) is "to signify an exception arising in user code, not the iostreams package". In addition, I found the following words in unformatted input function's requirements (27.7.2.3 [istream.unformatted]):If an exception is thrown during input then ios::badbit is turned on in *this's error state. (Exceptions thrown from basic_ios<>::clear() are not caught or rethrown.) If (exceptions()&badbit) != 0 then the exception is rethrown.
The content within the parenthesis is added by LWG defect 61, and does fix the ambiguity. However, it only fixed the 1 of 4 requirements, and it lost some context (the word "rethrown" is not seen before this sentence within this section).
Proposed resolution:
This wording is relative to N3797.
[Drafting note: The editor is kindly asked to introduce additional spaces at the following marked occurrences of operator& — end drafting note]Modify 27.7.2.2.1 [istream.formatted.reqmts] p1 as indicated:
-1- Each formatted input function begins execution by constructing an object of class sentry with the noskipws (second) argument false. If the sentry object returns true, when converted to a value of type bool, the function endeavors to obtain the requested input. If an exception, other than the ones thrown from clear(), if any, is thrown during input then ios::badbit is turned on[Footnote 314] in *this's error state. If (exceptions() & badbit) != 0 then the exception is rethrown. In any case, the formatted input function destroys the sentry object. If no exception has been thrown, it returns *this.
Modify 27.7.3.6.1 [ostream.formatted.reqmts] p1 as indicated:
-1- Each formatted output function begins execution by constructing an object of class sentry. If this object returns true when converted to a value of type bool, the function endeavors to generate the requested output. If the generation fails, then the formatted output function does setstate(ios_base::failbit), which might throw an exception. If an exception, other than the ones thrown from clear(), if any, is thrown during output, then ios::badbit is turned on[Footnote 327] in *this's error state. If (exceptions() & badbit) != 0 then the exception is rethrown. Whether or not an exception is thrown, the sentry object is destroyed before leaving the formatted output function. If no exception is thrown, the result of the formatted output function is *this.
Modify 27.7.3.7 [ostream.unformatted] p1 as indicated:
-1- Each unformatted output function begins execution by constructing an object of class sentry. If this object returns true, while converting to a value of type bool, the function endeavors to generate the requested output. If an exception, other than the ones thrown from clear(), if any, is thrown during output, then ios::badbit is turned on[Footnote 330] in *this's error state. If (exceptions() & badbit) != 0 then the exception is rethrown. In any case, the unformatted output function ends by destroying the sentry object, then, if no exception was thrown, returning the value specified for the unformatted output function.
Modify 27.7.2.3 [istream.unformatted] p1 as indicated:
-1- Each unformatted input function begins execution by constructing an object of class sentry with the default argument noskipws (second) argument true. If the sentry object returns true, when converted to a value of type bool, the function endeavors to obtain the requested input. Otherwise, if the sentry constructor exits by throwing an exception or if the sentry object returns false, when converted to a value of type bool, the function returns without attempting to obtain any input. In either case the number of extracted characters is set to 0; unformatted input functions taking a character array of non-zero size as an argument shall also store a null character (using charT()) in the first location of the array. If an exception, other than the ones thrown from clear(), if any, is thrown during input then ios::badbit is turned on[Footnote 317] in *this's error state.
(Exceptions thrown from basic_ios<>::clear() are not caught or rethrown.)If (exceptions() & badbit) != 0 then the exception is rethrown. It also counts the number of characters extracted. If no exception has been thrown it ends by storing the count in a member object and returning the value specified. In any event the sentry object is destroyed before leaving the unformatted input function.
Section: 26.5.3 [rand.eng] Status: New Submitter: Thomas Plum Opened: 2013-12-02 Last modified: 2015-04-08
View all other issues in [rand.eng].
View all issues with New status.
Discussion:
With regard to Random number engine class templates 26.5.3 [rand.eng], the Standard can be read in two different ways: when the member function
.seed(result_type s = default_seed)
is invoked, is all associated state (such as carry) reset to the same state that would have been created by the constructor
explicit engine-type(result_type s = default_seed)
or is the exact state unspecified?
Implementations differ.[2014-02-13, Issaquah]
Walter Brown says that Table 117 makes this very clear, and that the answer is "Yes"
Suggested resolution: NADProposed resolution:
Suggested resolution: NAD
Section: 26.5.7.1 [rand.util.seedseq] Status: New Submitter: Thomas Plum Opened: 2013-12-02 Last modified: 2015-04-08
View other active issues in [rand.util.seedseq].
View all other issues in [rand.util.seedseq].
View all issues with New status.
Discussion:
With respect to class seed_seq 26.5.7.1 [rand.util.seedseq], is a default-constructed std::seed_seq intended to produce a predictable .generate() sequence?
Implementations differ.Proposed resolution:
Section: 24.4.4 [iterator.operations] Status: New Submitter: Eric Niebler Opened: 2013-12-24 Last modified: 2015-04-08
View all other issues in [iterator.operations].
View all issues with New status.
Discussion:
In LWG 1011, std::next and std::prev were changed from accepting InputIterator to accepting ForwardIterator. This needlessly excludes perfectly legitimate use cases. Consider the following hypothetical range-based implementation of drop, which creates a view of a range without the first n elements:
template<typename Distance, typename InputRange> iterator_range<range_iterator_t<InputRange>> drop(Distance n, InputRange& rng) { return make_iterator_range( std::next(std::begin(rng), n), std::end(rng) ); }
I believe this to be a legitimate use case that is currently outlawed by the standard without cause. See the discussion beginning at c++std-lib-35313 for an in-depth discussion of the issue, in which Howard Hinnant agreed that it was a defect.
(Some discussion then ensued about whether an overload should be added that only accepts rvalue InputIterators to avoid the surprise that issue 1011 sought to address. I make no such attempt, nor do I believe it to be necessary.) Suggested resolution: Back out the resolution of 1011.Proposed resolution:
This wording is relative to N3797.
Change 24.3 [iterator.synopsis], header <iterator> synopsis, and 24.4.4 [iterator.operations] before p.6 as indicated:
template <classForwardInputIterator>ForwardInputIterator next(ForwardInputIterator x, typename std::iterator_traits<ForwardInputIterator>::difference_type n = 1);
Section: 20.10.4.3 [meta.unary.prop] Status: New Submitter: Richard Smith Opened: 2014-02-01 Last modified: 2015-04-08
View other active issues in [meta.unary.prop].
View all other issues in [meta.unary.prop].
View all issues with New status.
Discussion:
The 'Condition' for std::is_empty is listed as:
"T is a class type, but not a union type, with no non-static data members other than bit-fields of length 0, no virtual member functions, no virtual base classes, and no base class B for which is_empty<B>::value is false."
This is incorrect: there is no such thing as a non-static data member that is a bit-field of length 0, since bit-fields of length 0 must be unnamed, and unnamed bit-fields are not members (see 9.6 [class.bit] p2).
It also means that classes such as:struct S { int : 3; };
are empty (because they have no non-static data members). There's implementation divergence on the value of is_empty<S>::value.
I'm not sure what the purpose of is_empty is (or how it could be useful), but if it's desirable for the above type to not be treated as empty, something like this could work:"T is a class type, but not a union type, with no non-static data members
other than, no unnamed bit-fields of non-zero length0, no virtual member functions, no virtual base classes, and no base class B for which is_empty<B>::value is false."
and if the above type should be treated as empty, then this might be appropriate:
"T is a class type, but not a union type, with no (named) non-static data members
other than bit-fields of length 0, no virtual member functions, no virtual base classes, and no base class B for which is_empty<B>::value is false."
Proposed resolution:
Section: 23.2.4 [associative.reqmts], 23.2.5 [unord.req] Status: New Submitter: Jeffrey Yasskin Opened: 2014-02-15 Last modified: 2015-04-08
View other active issues in [associative.reqmts].
View all other issues in [associative.reqmts].
View all issues with New status.
Discussion:
a_uniq.emplace(args) is specified as:
Effects: Inserts a value_type object t constructed with
std::forward<Args>(args)... if and only if there is no element in the
container with key equivalent to the key of t. The bool component of
the returned pair is true if and only if the insertion takes place,
and the iterator component of the pair points to the element with key
equivalent to the key of t.
However, we occasionally find code of the form:
std::unique_ptr<Foo> p(new Foo); auto res = m.emplace("foo", std::move(p));
where we'd like to avoid destroying the Foo if the insertion doesn't take place (if the container already had an element with the specified key).
N3873 includes a partial solution to this in the form of a new emplace_stable member function, but LEWG's discussion strongly agreed that we'd rather have emplace() Just Work: Should map::emplace() be guaranteed not to move/copy its arguments if the insertion doesn't happen? SF: 8 F: 3 N: 0 A: 0 SA: 0 This poll was marred by the fact that we didn't notice or call out that emplace() must construct the key before doing the lookup, and it must not then move the key after it determines whether an insert is going to happen, and the mapped_type instance must live next to the key. The very similar issue 2006 was previously marked NAD, with N3178 as discussion. However, given LEWG's interest in the alternate behavior, we should reopen the question in this issue. We will need a paper that describes how to implement this before we can make more progress.Proposed resolution:
Section: 30.4.1.4.1 [thread.sharedtimedmutex.class] Status: SG1 Submitter: Richard Smith Opened: 2014-02-16 Last modified: 2015-04-08
View all issues with SG1 status.
Discussion:
30.4.1.4.1 [thread.sharedtimedmutex.class] paragraph 2:
The class shared_timed_mutex shall satisfy all of the SharedTimedMutex requirements (30.4.1.4). It shall be a standard layout class (Clause 9).
There's no SharedTimedMutex requirements; this name doesn't appear anywhere else in the standard. (Prior to N3891, this was SharedMutex, which was equally undefined.)
I assume this concept should be defined somewhere? Also, n3891 changes 30.4.1.4 [thread.sharedtimedmutex.requirements] from defining "shared mutex type" to defining "shared timed mutex type", but its paragraph 2 still talks about "shared mutex type". Is that OK? I think you could argue that it's clear enough what it means, but presumably it should use the term that paragraph 1 defined. 30.4.2.3 [thread.lock.shared] paragraph 1 talks about the "shared mutex requirements", which again is a term that isn't defined, and presumably means "the requirements on a shared timed mutex type" or similar (maybe if SharedMutex or SharedTimedMutex were defined it could be reused here).[2014-05-22, Daniel comments]
As for SharedTimedMutex, there exists a similar problem in regard to TimedMutex referred to in 30.4.1.3.1 [thread.timedmutex.class] p2 and in 30.4.1.3.2 [thread.timedmutex.recursive] p2, but nowhere defined.
Another problem is, that according to 30.4.1.2.1 [thread.mutex.class] p3, "The class mutex shall satisfy all the Mutex requirements (30.4.1 [thread.mutex.requirements]).", but there are no concrete Mutex requirements, 30.4.1 [thread.mutex.requirements] — titled as "Mutex requirements" — describes mutex types, timed mutex types, and shared timed mutex types.[2014-06-08, Daniel comments and provides wording]
The presented wording adds to the existing mutex types, timed mutex types, and shared timed mutex types terms a new set of corresponding MutexType, TimedMutexType, and SharedTimedMutexType requirements.
The reason for the change of requirement names is two-fold: First, the new name better matches the intention to have a concrete name for the requirements imposed on the corresponding mutex types (This kind of requirement deviate from the more general Lockable requirements, which are not restricted to a explicitly enumerated set of library types). Second, using **MutexType over **Mutex provides the additional advantage that it reduces the chances of confusing named requirements from template parameters named Mutex (such as for unique_lock or shared_lock). Nonetheless the here presented wording has one unfortunate side-effect: Once applied it would have the effect that types used to instantiate std::shared_lock cannot be user-defined shared mutex types due to 30.4.2.3 [thread.lock.shared]. The reason is based on the currently lack of an existing SharedLockable requirement set, which would complete the existing BasicLockable and Lockable requirements (which are "real" requirements). This restriction is not actually a problem introduced by the provided resolution but instead one that existed before but becomes more obvious now.[2015-02 Cologne]
Handed over to SG1.
Proposed resolution:
This wording is relative to N3936.
Change 30.4.1.2 [thread.mutex.requirements.mutex] as indicated:
-1- The mutex types are the standard library types std::mutex, std::recursive_mutex, std::timed_mutex, std::recursive_timed_mutex, and std::shared_timed_mutex. They shall meet the MutexType requirements set out in this section. In this description, m denotes an object of a mutex type.
Change 30.4.1.2.1 [thread.mutex.class] as indicated:
-3- The class mutex shall satisfy all the MutexType requirements (30.4.1.2 [thread.mutex.requirements.mutex]
30.4.1 [thread.mutex.requirements]). It shall be a standard-layout class (Clause 9).
Change 30.4.1.2.2 [thread.mutex.recursive] as indicated:
-2- The class recursive_mutex shall satisfy all the
MutexMutexType requirements (30.4.1.2 [thread.mutex.requirements.mutex]30.4.1 [thread.mutex.requirements]). It shall be a standard-layout class (Clause 9).
Change 30.4.1.3 [thread.timedmutex.requirements] as indicated:
-1- The timed mutex types are the standard library types std::timed_mutex, std::recursive_timed_mutex, and std::shared_timed_mutex. They shall meet the TimedMutexType requirements set out below. In this description, m denotes an object of a mutex type, rel_time denotes an object of an instantiation of duration (20.12.5), and abs_time denotes an object of an instantiation of time_point (20.12.6).
Change 30.4.1.3.1 [thread.timedmutex.class] as indicated:
-2- The class timed_mutex shall satisfy all of the TimedMutexType requirements (30.4.1.3 [thread.timedmutex.requirements]). It shall be a standard-layout class (Clause 9).
Change 30.4.1.3.2 [thread.timedmutex.recursive] as indicated:
-2- The class recursive_timed_mutex shall satisfy all of the TimedMutexType requirements (30.4.1.3 [thread.timedmutex.requirements]). It shall be a standard-layout class (Clause 9).
Change 30.4.1.4 [thread.sharedtimedmutex.requirements] as indicated: [Drafting note: The reference to the timed mutex types requirements has been moved after introducing the new requirement set to ensure that SharedTimedMutexType refine TimedMutexType.]
-1- The standard library type std::shared_timed_mutex is a shared timed mutex type. Shared timed mutex types shall meet the SharedTimedMutexType requirements
-?- The shared timed mutex types shall meet the TimedMutexType requirements (30.4.1.3 [thread.timedmutex.requirements]).of timed mutex types (30.4.1.3 [thread.timedmutex.requirements]), and additionally shall meet the requirementsset out below. In this description, m denotes an object of a mutex type, rel_type denotes an object of an instantiation of duration (20.12.5), and abs_time denotes an object of an instantiation of time_point (20.12.6).
Change 30.4.1.4.1 [thread.sharedtimedmutex.class] as indicated:
-2- The class shared_timed_mutex shall satisfy all of the SharedTimedMutexType requirements (30.4.1.4 [thread.sharedtimedmutex.requirements]). It shall be a standard-layout class (Clause 9).
Change 30.4.2.3 [thread.lock.shared] as indicated: [Drafting note: Once N3995 has been applied, the following reference should be changed to the new SharedMutexType requirements ([thread.sharedmutex.requirements]) or even better to some new SharedLockable requirements (to be defined) — end drafting note]
-1- […] The supplied Mutex type shall meet the
-2- [Note: shared_lock<Mutex> meets the TimedLockable requirements (30.2.5.4). — end note]shared mutexSharedTimedMutexType requirements (30.4.1.4 [thread.sharedtimedmutex.requirements]).
Section: 23.3.3.4 [deque.modifiers], 23.3.6.5 [vector.modifiers] Status: Ready Submitter: Deskin Miller Opened: 2014-02-17 Last modified: 2015-04-08
View other active issues in [deque.modifiers].
View all other issues in [deque.modifiers].
View all issues with Ready status.
Discussion:
I think it's obvious that vector::pop_back invalidates the path-the-end iterator, but I cannot find language that says so to my satisfaction in the Standard. N3797 23.2.3 [sequence.reqmts] Table 101 lists a.pop_back() semantics as "Destroys the last element", but nowhere do I see this required to invalidate the end iterator (or iterators previously referring to the last element). [container.reqmts.general]/11 states "Unless otherwise specified (either explicitly or by defining a function in terms of other functions), invoking a container member function or passing a container as an argument to a library function shall not invalidate iterators to, or change the values of, objects within that container." 23.3.6.5 [vector.modifiers]/3 says that each flavor of vector::erase "Invalidates iterators and references at or after the point of the erase", but pop_back isn't discussed, and it wasn't specified in terms of erase.
Similarly for std::deque, 23.2.3 [sequence.reqmts] Table 101 and [container.reqmts.general]/11 both apply. Yet 23.3.3.4 [deque.modifiers] likewise doesn't discuss pop_back nor pop_front. Furthermore paragraph 4 fails to specify the iterator-invalidation guarantees when erasing the first element but not the last.
Both std::vector and std::deque are in contrast to std::list, which says in 23.3.5.4 [list.modifiers]/3 regarding pop_back (as well as all forms of erase, pop_front, and clear) "Effects: Invalidates only the iterators and references to the erased elements."[2014-06-16 Jonathan comments and improves wording]
I believe this reflects our preferred form discussed earlier, specifically putting the signatures with the erase signatures, so that the full specification of erase() applies to the pop_xxx() functions. This covers the case for deque where pop_front() erases the only element (which is both the first and last element).
Open question: the "erase" wording talks about "An erase operation" — are pop_front and pop_back clearly covered by "erase operations"? I believe so, as 23.3.3.1 [deque.overview]/1 and other places talk about "insert and erase operations" which covers push/pop functions too. I've added a note which could be used to clarify that if desired. Previous resolution [SUPERSEDED]:This wording is relative to N3936.
Change 23.3.3.4 [deque.modifiers] as indicated:
iterator erase(const_iterator position); iterator erase(const_iterator first, const_iterator last);-4- Effects: An erase operation that erases the last element of a deque invalidates only the past-the-end iterator and all iterators and references to the erased elements. An erase operation that erases the first element of a deque but not the last element invalidates only iterators and references to the erased elements. An erase operation that erases neither the first element nor the last element of a deque invalidates the past-the-end iterator and all iterators and references to all the elements of the deque.
-5- […] -6- […]void pop_front(); void pop_back();-?- Effects: pop_front invalidates iterators and references to the first element of the deque. pop_back invalidates the past-the-end iterator, and all iterators and references to the last element of the deque.
Change 23.3.6.5 [vector.modifiers] as indicated:
-5- […]
void pop_back();-?- Effects: Invalidates the past-the-end iterator, and iterators and references to the last element of the vector.
[2014-06-21 Rapperswil]
Tony van Eerd: Would be good to define "an erase operation is ..." somewhere.
AM: The containers clause is known to be suboptimal in many ways. Looks good[Urbana 2014-11-07: Move to Ready]
Proposed resolution:
This wording is relative to N3936.
Change 23.3.3.4 [deque.modifiers] as indicated:
iterator erase(const_iterator position); iterator erase(const_iterator first, const_iterator last); void pop_front(); void pop_back();-4- Effects: An erase operation that erases the last element of a deque invalidates only the past-the-end iterator and all iterators and references to the erased elements. An erase operation that erases the first element of a deque but not the last element invalidates only iterators and references to the erased elements. An erase operation that erases neither the first element nor the last element of a deque invalidates the past-the-end iterator and all iterators and references to all the elements of the deque. [Note: pop_front and pop_back are erase operations — end note]
Change 23.3.6.5 [vector.modifiers] as indicated:
iterator erase(const_iterator position); iterator erase(const_iterator first, const_iterator last); void pop_back();-3- Effects: Invalidates iterators and references at or after the point of the erase.
Section: 24.6.3 [istreambuf.iterator] Status: New Submitter: Hyman Rosen Opened: 2014-02-19 Last modified: 2015-04-08
View all other issues in [istreambuf.iterator].
View all issues with New status.
Discussion:
Given the following code,
#include <sstream> std::stringbuf buf; std::istreambuf_iterator<char> begin(&buf); std::istreambuf_iterator<char> end;
it is not clear from the wording of the Standard whether begin.equal(end) must be true. In at least one implementation it is not (CC: Sun C++ 5.10 SunOS_sparc Patch 128228-25 2013/02/20) and in at least one implementation it is (gcc version 4.3.2 x86_64-unknown-linux-gnu).
24.6.3 [istreambuf.iterator] says that end is an end-of-stream iterator since it was default constructed. It also says that an iterator becomes equal to an end-of-stream iterator when end of stream is reached by sgetc() having returned eof(). 24.6.3.5 [istreambuf.iterator::equal] says that equal() returns true iff both iterators are end of stream or not end of stream. But there seems to be no requirement that equal check for end-of-stream by calling sgetc(). Jiahan Zi at BloombergLP discovered this issue through his code failing to work correctly. Dietmar Kühl has opined in a private communication that the iterators should compare equal.Proposed resolution:
Section: 20.10.4.3 [meta.unary.prop] Status: New Submitter: Howard Hinnant Opened: 2014-02-19 Last modified: 2015-04-08
View other active issues in [meta.unary.prop].
View all other issues in [meta.unary.prop].
View all issues with New status.
Discussion:
Consider:
struct X { X() = delete; }; int main() { typedef std::pair<int, X> P; static_assert(!std::is_constructible<P>::value, ""); static_assert(!std::is_default_constructible<P>::value, ""); typedef std::tuple<int, X> T; static_assert(!std::is_constructible<T>::value, ""); static_assert(!std::is_default_constructible<T>::value, ""); }
For me these static_asserts fail. And worse than that, even asking the question fails (as opposed to gets the wrong answer):
assert(!std::is_constructible<P>::value);
In file included from test.cpp:2:
error: call to deleted constructor of 'X' pair() : first(), second() {} ^ note: function has been explicitly marked deleted here X() = delete; ^ 1 error generated.
This can be solved by specializing is_constructible on pair and tuple for zero Args:
template <class T, class U> struct is_constructible<pair<T, U>> : integral_constant<bool, is_default_constructible<T>::value && is_default_constructible<U>::value> {}; template <class ...T> struct is_constructible<tuple<T...>> : integral_constant<bool, __all<is_default_constructible<T>::value...>::value> {};
Now everything just works.
[2014-05-14, Daniel comments]
The proposed resolution is incomplete, because it wouldn't work for cv-qualified objects of pair or for references of them during reference-initialization.
I would like to point out that the approach suggested in N3739 can be easily extended to solve the problem without need to muddle with specializing is_constructible:template<class U1 = T1, class U2 = T2, typename enable_if< is_default_constructible<U1>::value && is_default_constructible<U2>::value , bool>::type = false > constexpr pair();
The new wording proposal represents an alternative wording change that I would strongly prefer.
Previous resolution from Howard [SUPERSEDED]:This wording is relative to N3936.
Add to 20.3.3 [pairs.spec]:
template <class T, class U> struct is_constructible<pair<T, U>> : integral_constant<bool, is_default_constructible<T>::value && is_default_constructible<U>::value> {};Add to 20.4.2.9 [tuple.special]:
template <class ...T> struct is_constructible<tuple<T...>> : integral_constant<bool, see below> {};-?- The second argument to integral_constant shall be true if for each T, is_default_constructible<T>::value is true.
Proposed resolution:
This wording is relative to N3936.
Change 20.3.2 [pairs.pair] around p3 as indicated:
constexpr pair();-4- Effects: Value-initializes first and second. -?- Remarks: This constructor shall not participate in overload resolution unless is_default_constructible<first_type>::value is true and is_default_constructible<second_type>::value is true. [Note: This behaviour can be implemented by a constructor template with default template arguments — end note].
-3- Requires: is_default_constructible<first_type>::value is true and is_default_constructible<second_type>::value is true.
Change 20.4.2.1 [tuple.cnstr] around p4 as indicated:
constexpr tuple();-5- Effects: Value initializes each element. -?- Remarks: This constructor shall not participate in overload resolution unless is_default_constructible<Ti>::value is true for all i. [Note: This behaviour can be implemented by a constructor template with default template arguments — end note].
-4- Requires: is_default_constructible<Ti>::value is true for all i.
Section: 18.6.1 [new.delete] Status: New Submitter: Stephen Clamage Opened: 2014-02-20 Last modified: 2015-04-08
View other active issues in [new.delete].
View all other issues in [new.delete].
View all issues with New status.
Discussion:
Section 18.6.1 [new.delete] and subsections shows:
void* operator new(std::size_t size); void* operator new[](std::size_t size);
That is, without exception-specifications. (Recall that C++03 specified these functions with throw(std::bad_alloc).)
Section 17.6.5.12 [res.on.exception.handling] the end of paragraph 4 says:Any other functions defined in the C++ standard library that do not have an exception-specification may throw implementation-defined exceptions unless otherwise specified. An implementation may strengthen this implicit exception-specification by adding an explicit one.
For example, an implementation could provide C++03-compatible declarations of operator new.
Programmers are allowed to replace these operator new functions. But how can you write the definition of these functions when the exception specification can vary among implementations? For example, the declarationsvoid* operator new(std::size_t size) throw(std::bad_alloc); void* operator new(std::size_t size);
are not compatible.
From what I have been able to determine, gcc has a hack for the special case of operator new to ignore the differences in (at least) the two cases I show above. But can users expect all compilers to quietly ignore the incompatibility? The blanket permission to add any explicit exception specification could cause a problem for any user-overridable function. Different implementations could provide incompatible specifications, making portable code impossible to write.Proposed resolution:
Section: 25.4.7 [alg.min.max] Status: Tentatively Ready Submitter: Marc Glisse Opened: 2014-02-21 Last modified: 2015-04-08
View other active issues in [alg.min.max].
View all other issues in [alg.min.max].
View all issues with Tentatively Ready status.
Discussion:
As part of the resolution for LWG issue 2350, max(initializer_list) was marked as constexpr. Looking at two implementations of this function (libstdc++ and libc++), both implement it in terms of max_element, which is not marked as constexpr. This is inconsistent and forces some small amount of code duplication in the implementation. Unless we remove constexpr from this overload of max, I believe we should add constexpr to max_element.
[2015-02 Cologne]
AM: Can we implement this with the C++14 constexpr rules? JM: Yes. AM: Ready? [Yes]
Accepted.Proposed resolution:
This wording is relative to N3936.
In 25.1 [algorithms.general], header <algorithm> synopsis, and 25.4.7 [alg.min.max], change as indicated (add constexpr to every signature from the first min_element to the second minmax_element)::
template<class ForwardIterator> constexpr ForwardIterator min_element(ForwardIterator first, ForwardIterator last); template<class ForwardIterator, class Compare> constexpr ForwardIterator min_element(ForwardIterator first, ForwardIterator last, Compare comp); […] template<class ForwardIterator> constexpr ForwardIterator max_element(ForwardIterator first, ForwardIterator last); template<class ForwardIterator, class Compare> constexpr ForwardIterator max_element(ForwardIterator first, ForwardIterator last, Compare comp); […] template<class ForwardIterator> constexpr pair<ForwardIterator, ForwardIterator> minmax_element(ForwardIterator first, ForwardIterator last); template<class ForwardIterator, class Compare> constexpr pair<ForwardIterator, ForwardIterator> minmax_element(ForwardIterator first, ForwardIterator last, Compare comp);
Section: 20.9.12.2 [func.wrap.func] Status: New Submitter: Pablo Halpern Opened: 2014-02-27 Last modified: 2015-04-08
View other active issues in [func.wrap.func].
View all other issues in [func.wrap.func].
View all issues with New status.
Discussion:
The following constructors in 20.9.12.2 [func.wrap.func] are declared noexcept, even though it is not possible for an implementation to guarantee that they will not throw:
template <class A> function(allocator_arg_t, const A&) noexcept; template <class A> function(allocator_arg_t, const A&, nullptr_t) noexcept;
In addition, the following functions are guaranteed not to throw if the target is a function pointer or a reference_wrapper:
template <class A> function(allocator_arg_t, const A& a, const function& f); template <class F, class A> function(allocator_arg_t, const A& a, F f);
In all of the above cases, the function object might need to allocate memory (an operation that can throw) in order to hold a copy of the type-erased allocator itself. The first two constructors produce an empty function object, but the allocator is still needed in case the object is later assigned to. In this case, we note that the propagation of allocators on assignment is underspecified for std::function. There are three possibilities:
The allocator is never copied on copy-assignment, moved on move-assignment, or swapped on swap.
The allocator is always copied on copy-assignment, moved on move-assignment, and swapped on swap.
Whether or not the allocator is copied, moved, or swapped is determined at run-time based on the propagate_on_container_copy_assignment and propagate_on_container_move_assignment traits of the allocators at construction of the source function, the target function, or both.
Although the third option seems to be the most consistent with existing wording in the containers section of the standard, it is problematic in a number of respects. To begin with, the propagation behavior is determined at run time based on a pair of type-erased allocators, instead of at compile time. Such run-time logic is not consistent with the rest of the standard and is hard to reason about. Additionally, there are two allocator types involved, rather than one. Any set of rules that attempts to rationally interpret the propagation traits of both allocators is likely to be arcane at best, and subtly wrong for some set of codes at worst.
The second option is a non-starter. Historically, and in the vast majority of existing code, an allocator does not change after an object is constructed. The second option, if adopted, would undermine the programmer's ability to construct, e.g., an array of function objects, all using the same allocator.
The first option is (in Pablo's opinion) the simplest and best. It is consistent with historical use of allocators, is easy to understand, and requires minimal wording. It is also consistent with the wording in N3916, which formalizes type-erased allocators.
For cross-referencing purposes: The resolution of this issue should be harmonized with any resolution to LWG 2062, which questions the noexcept specification on the following member functions of std::function:
template <class F> function& operator=(reference_wrapper<F>) noexcept; void swap(function&) noexcept;
Proposed resolution:
This wording is relative to N3936.
Change 20.9.12.2 [func.wrap.func], class template function synopsis, as indicated:
template <class A> function(allocator_arg_t, const A&)noexcept; template <class A> function(allocator_arg_t, const A&, nullptr_t)noexcept;
Change 20.9.12.2.1 [func.wrap.func.con] as indicated:
-1- When any function constructor that takes a first argument of type allocator_arg_t is invoked, the second argument shall have a type that conforms to the requirements for Allocator (Table 17.6.3.5). A copy of the allocator argument is used to allocate memory, if necessary, for the internal data structures of the constructed function object. For the remaining constructors, an instance of allocator<T>, for some suitable type T, is used to allocate memory, if necessary, for the internal data structures of the constructed function object.
function() noexcept; template <class A> function(allocator_arg_t, const A&)noexcept;-2- Postconditions: !*this.
function(nullptr_t) noexcept; template <class A> function(allocator_arg_t, const A&, nullptr_t)noexcept;-3- Postconditions: !*this.
function(const function& f);template <class A> function(allocator_arg_t, const A& a, const function& f);-4- Postconditions: !*this if !f; otherwise, *this targets a copy of f.target().
-5- Throws: shall not throw exceptions if f's target is a callable object passed via reference_wrapper or a function pointer. Otherwise, may throw bad_alloc or any exception thrown by the copy constructor of the stored callable object. [Note: Implementations are encouraged to avoid the use of dynamically allocated memory for small callable objects, for example, where f's target is an object holding only a pointer or reference to an object and a member function pointer. — end note]
template <class A> function(allocator_arg_t, const A& a, const function& f);-?- Postconditions: !*this if !f; otherwise, *this targets a copy of f.target().
function(function&& f); template <class A> function(allocator_arg_t, const A& a, function&& f);-6- Effects: If !f, *this has no target; otherwise, move-constructs the target of f into the target of *this, leaving f in a valid state with an unspecified value. If an allocator is not specified, the constructed function will use the same allocator as f.
template<class F> function(F f); template <class F, class A> function(allocator_arg_t, const A& a, F f);-7- Requires: F shall be CopyConstructible.
-8- Remarks: These constructors shall not participate in overload resolution unless f is Callable (20.9.11.2) for argument types ArgTypes... and return type R.-9- Postconditions: !*this if any of the following hold:
f is a null function pointer value.
f is a null member pointer value.
F is an instance of the function class template, and !f
-10- Otherwise, *this targets a copy of f initialized with std::move(f). [Note: Implementations are encouraged to avoid the use of dynamically allocated memory for small callable objects, for example, where f's target is an object holding only a pointer or reference to an object and a member function pointer. — end note]
-11- Throws: shall not throw exceptions when an allocator is not specified and f is a function pointer or a reference_wrapper<T> for some T. Otherwise, may throw bad_alloc or any exception thrown by F's copy or move constructor or by A's allocate function.
Section: 21.4 [basic.string] Status: New Submitter: Andrzej Krzemieński Opened: 2014-03-13 Last modified: 2015-04-08
View other active issues in [basic.string].
View all other issues in [basic.string].
View all issues with New status.
Discussion:
The following code works in C++:
int i = 300; std::string threeHundred; threeHundred = i;
"Works" == "Compiles and doesn't have an undefined behavior". But it may not be obvious and in fact misleading what it does. This assignment converts an int to char and then uses string's assignment from char. While the assignment from char can be considered a feature, being able to assign from an int looks like a safety gap. Someone may believe C++ works like "dynamically typed" languages and expect a lexical conversion to take place.
Ideally the assignment from char could be deprecated and later removed, but as a less intrusive alternative one could consider adding a SFINAEd deleted function template:template <typename IntT> // enable if is_integral<IntT>::value basic_string& operator=(IntT) = delete;
Proposed resolution:
This wording is relative to N3936.
To 21.4 [basic.string], class template basic_string synopsis, add as indicated:
basic_string& operator=(const basic_string& str); basic_string& operator=(basic_string&& str) noexcept; basic_string& operator=(const charT* s); basic_string& operator=(charT c); template <class IntT> basic_string& operator=(IntT i) = delete; basic_string& operator=(initializer_list<charT>);
Add after 21.4.2 [string.cons] p26 as indicated:
basic_string& operator=(charT c);-26- Returns: *this = basic_string(1,c).
template <class IntT> basic_string& operator=(IntT i) = delete;-?- Remarks: This signature shall not participate in overload resolution unless is_integral<T>::value is true.
Section: 17.6.5 [conforming] Status: New Submitter: Chandler Carruth Opened: 2014-03-22 Last modified: 2015-04-08
View all other issues in [conforming].
View all issues with New status.
Discussion:
Technically, right now, it is not a conforming extension to add a new function to namespace std. Doing so could cause unqualified lookup on the name of that function in the presence of a using directive to find a different function. This seems an unreasonable restriction on library vendors providing conforming extensions, as such a using directive seems inherently risky in unqualified name lookup.
17.6.5.5 [member.functions] implies that adding overloads to a method is a conforming extension, and within some limits the same is true for global functions due to 17.6.5.4 [global.functions].
It would likely be useful to specify that other new entities are valid conforming extensions, or preclude them where they pose serious compatibility problems.Proposed resolution:
Section: 24.2.1 [iterator.requirements.general] Status: New Submitter: Marshall Clow Opened: 2014-03-25 Last modified: 2015-04-08
View all issues with New status.
Discussion:
24.2.1 [iterator.requirements.general] p9 says:
Destruction of an iterator may invalidate pointers and references previously obtained from that iterator.
But the resolution of LWG issue 2360 specifically advocates returning *--temp; where temp is a local variable.
And 24.2.5 [forward.iterators] p6 says:If a and b are both dereferenceable, then a == b if and only if *a and *b are bound to the same object.
which disallows "stashing" iterators (i.e, iterators that refer to data inside themselves).
So, I suspect that the restriction in p9 should only apply to input iterators, and can probably be moved into 24.2.3 [input.iterators] instead of 24.2.1 [iterator.requirements.general].[2014-05-22, Daniel comments]
Given that forward iterators (and beyond) are refinements of input iterator, moving this constraint to input iterators won't help much because it would still hold for all refined forms.
Proposed resolution:
Section: 18.6.2.1 [bad.alloc], 18.6.2.2 [new.badlength], 18.7.2 [bad.cast], 18.7.3 [bad.typeid], 18.8.2 [bad.exception] Status: Tentatively Ready Submitter: Andy Sawyer Opened: 2014-03-31 Last modified: 2015-04-08
View all issues with Tentatively Ready status.
Discussion:
I think we have an issue with the specification of some of the standard exception types. In particular, several of them have default constructors with remarks to the effect that "The result of calling what() on the newly constructed object is implementation-defined". (In some cases this is contradictory to a further specification of what(), which is specified to return an implementation-defined NTBS.)
Previous resolution from Andy [SUPERSEDED]:
This wording is relative to N3936.
Edit 18.6.2.1 [bad.alloc] p3 as indicated:
bad_alloc() noexcept;[…]
-3- Remarks:The result of calling what() on the newly constructed object is implementation-definedwhat() returns an implementation-defined NTBS.Edit 18.6.2.2 [new.badlength] p3 as indicated: [Drafting note: Added the Postcondition, since we don't say anything else about bad_array_new_length::what() — end of note]
bad_array_new_length() noexcept;[…]
-3-RemarksPostcondition:The result of calling what() on the newly constructed object is implementation-definedwhat() returns an implementation-defined NTBS.Edit 18.7.2 [bad.cast] p3 as indicated:
bad_cast() noexcept;[…]
-3- Remarks: The result of calling what() on the newly constructed object is implementation-defined..Edit 18.7.3 [bad.typeid] p3 as indicated:
bad_typeid() noexcept;[…]
-3- Remarks: The result of calling what() on the newly constructed object is implementation-defined..Edit 18.8.2 [bad.exception] p3 as indicated:
bad_exception() noexcept;[…]
-3- Remarks: The result of calling what() on the newly constructed object is implementation-defined..
[2014-06-17, Rapperswil]
Jonathan provides alternative wording.
[2015-02, Cologne]
NJ: I don't know why we need the explict statement about what() here, since bad_array_new_length
already derives.
AM: yes.
NJ: Then "what()" is missing from the synopsis.
AM: Yes, that's an error and it needs to be added.
Proposed resolution:
This wording is relative to N4296.
Edit 18.6.2.1 [bad.alloc] p3 as indicated:
bad_alloc() noexcept;[…]
-3- Remarks: The result of calling what() on the newly constructed object is implementation-defined.
Edit 18.6.2.1 [bad.alloc] p5 as indicated:
virtual const char* what() const noexcept;-5- Returns: An implementation-defined NTBS.
-?- Remarks: The message may be a null-terminated multibyte string (17.5.2.1.4.2), suitable for conversion and display as a wstring (21.3, 22.4.1.4).
Edit class bad_array_new_length synopsis 18.6.2.2 [new.badlength] as indicated:
namespace std { class bad_array_new_length : public bad_alloc { public: bad_array_new_length() noexcept; virtual const char* what() const noexcept; }; }
Edit 18.6.2.2 [new.badlength] as indicated:
bad_array_new_length() noexcept;[…]
-3- Remarks: The result of calling what() on the newly constructed object is implementation-defined.virtual const char* what() const noexcept;-?- Returns: An implementation-defined NTBS.
-?- Remarks: The message may be a null-terminated multibyte string (17.5.2.1.4.2), suitable for conversion and display as a wstring (21.3, 22.4.1.4).
Edit 18.7.2 [bad.cast] p3 as indicated:
bad_cast() noexcept;[…]
-3- Remarks: The result of calling what() on the newly constructed object is implementation-defined..
Edit 18.7.3 [bad.typeid] p3 as indicated:
bad_typeid() noexcept;[…]
-3- Remarks: The result of calling what() on the newly constructed object is implementation-defined..
Edit 18.8.2 [bad.exception] p3 as indicated:
bad_exception() noexcept;[…]
-3- Remarks: The result of calling what() on the newly constructed object is implementation-defined..
Section: 30.2.3 [thread.req.native], 30.3.2 [thread.thread.this] Status: SG1 Submitter: Matt Austern Opened: 2014-03-31 Last modified: 2015-04-08
View all issues with SG1 status.
Discussion:
Class thread contains an implementation-defined type thread::native_handle_type, and an implementation-defined function thread::native_handle() that returns a value of that type. The presence and semantics of those members is implementation-defined; the intention is that they can be used for interoperability with libraries that rely on operating system specific features. (Posix libraries that accept arguments of type pthread_t, for example.)
Unfortunately, there appears to be no native handle support for the equivalent of pthread_self(). We can use this_thread::get_id() to obtain the thread::id of the current thread, but there is no mechanism for converting a thread::id to a thread::native_handle. Proposed wording: In 30.3.2 [thread.thread.this] add:thread::native_handle_type native_handle(); // See 30.2.3
to the this_thread namespace synopsis.
Rationale: Informally, we could address this issue either by adding a new function in this_thread or by providing a mechanism for converting between thread::id and thread::native_handle. I propose the former because it seems more localized, and doesn't involve saying anything more about implementation defined native functionality than we currently do. It's intentional that the proposed resolution adds a declaration of native_handle() without adding a paragraph explaining what it does. This is because everything about native_handle() is implementation-defined. The standard does the same thing in 30.3.1.5 [thread.thread.member].[2015-02 Cologne]
Handed over to SG1.
Proposed resolution:
This wording is relative to N3936.
Change 30.2.3 [thread.req.native] p1 as indicated:
-1-
Several classes described in this Clause have membersThis Clause includes several members named native_handle_type and native_handle. The presence of these members and their semantics is implementation-defined. […]
In 30.3 [thread.threads], header <thread> synopsis, add:
namespace std { […] namespace this_thread { thread::id get_id() noexcept; thread::native_handle_type native_handle(); […] } }
In 30.3.2 [thread.thread.this] add:
namespace std { namespace this_thread { thread::id get_id() noexcept; thread::native_handle_type native_handle(); // See 30.2.3 [thread.req.native] […] } }
Section: 17.6.1.2 [headers] Status: Review Submitter: Richard Smith Opened: 2014-03-31 Last modified: 2015-04-08
View all other issues in [headers].
View all issues with Review status.
Discussion:
D.5 [depr.c.headers] p3 says:
[Example: The header <cstdlib> assuredly provides its declarations and definitions within the namespace std. It may also provide these names within the global namespace. The header <stdlib.h> assuredly provides the same declarations and definitions within the global namespace, much as in the C Standard. It may also provide these names within the namespace std. — end example]
This suggests that <cstdlib> may provide ::abs(long) and ::abs(long long). But this seems like it might contradict the normative wording of 17.6.1.2 [headers] p4:
Except as noted in Clauses 18 through 30 and Annex D, the contents of each header cname shall be the same as that of the corresponding header name.h, as specified in the C standard library (1.2) or the C Unicode TR, as appropriate, as if by inclusion. In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (3.3.6) of the namespace std. It is unspecified whether these names are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (7.3.3).
Note that this allows <cstdlib> to provide ::abs(int), but does not obviously allow ::abs(long) nor ::abs(long long), since they are not part of the header stdlib.h as specified in the C standard library.
26.8 [c.math] p7 adds signatures std::abs(long) and std::abs(long long), but not in a way that seems to allow ::abs(long) and ::abs(long long) to be provided. I think the right approach here would be to allow <cstdlib> to either provide no ::abs declaration, or to provide all three declarations from namespace std, but it should not be permitted to provide only int abs(int). Suggestion: Change in 17.6.1.2 [headers] p4:[…]. It is unspecified whether these names (including any overloads added in Clauses 18 through 30 and Annex D) are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (7.3.3).
Proposed resolution:
This wording is relative to N3936.
Modify 17.6.1.2 [headers] p4 as indicated:
Except as noted in Clauses 18 through 30 and Annex D, the contents of each header cname shall be the same as that of the corresponding header name.h, as specified in the C standard library (1.2) or the C Unicode TR, as appropriate, as if by inclusion. In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (3.3.6) of the namespace std. It is unspecified whether these names (including any overloads added in Clauses 18 through 30 and Annex D) are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (7.3.3).
Section: 22.4.2.1.2 [facet.num.get.virtuals] Status: New Submitter: Marshall Clow Opened: 2014-04-30 Last modified: 2015-04-08
View other active issues in [facet.num.get.virtuals].
View all other issues in [facet.num.get.virtuals].
View all issues with New status.
Discussion:
In 22.4.2.1.2 [facet.num.get.virtuals] we have:
Stage 3: The sequence of chars accumulated in stage 2 (the field) is converted to a numeric value by the rules of one of the functions declared in the header <cstdlib>:
For a signed integer value, the function strtoll.
For an unsigned integer value, the function strtoull.
For a floating-point value, the function strtold.
This implies that for many cases, this routine should return true:
bool is_same(const char* p) { std::string str{p}; double val1 = std::strtod(str.c_str(), nullptr); std::stringstream ss(str); double val2; ss >> val2; return std::isinf(val1) == std::isinf(val2) && // either they're both infinity std::isnan(val1) == std::isnan(val2) && // or they're both NaN (std::isinf(val1) || std::isnan(val1) || val1 == val2); // or they're equal }
and this is indeed true, for many strings:
assert(is_same("0")); assert(is_same("1.0")); assert(is_same("-1.0")); assert(is_same("100.123")); assert(is_same("1234.456e89"));
but not for others
assert(is_same("0xABp-4")); // hex float assert(is_same("inf")); assert(is_same("+inf")); assert(is_same("-inf")); assert(is_same("nan")); assert(is_same("+nan")); assert(is_same("-nan")); assert(is_same("infinity")); assert(is_same("+infinity")); assert(is_same("-infinity"));
These are all strings that are correctly parsed by std::strtod, but not by the stream extraction operators. They contain characters that are deemed invalid in stage 2 of parsing.
If we're going to say that we're converting by the rules of strtold, then we should accept all the things that strtold accepts.Proposed resolution:
Section: 20.12.5.8 [time.duration.literals] Status: Open Submitter: Jonathan Wakely Opened: 2014-05-16 Last modified: 2015-04-08
View all issues with Open status.
Discussion:
20.12.5.8 [time.duration.literals] p3 says:
If any of these suffixes are applied to an integer literal and the resulting chrono::duration value cannot be represented in the result type because of overflow, the program is ill-formed.
Ill-formed requires a diagnostic at compile-time, but there is no way to detect the overflow from unsigned long long to the signed duration<>::rep type.
Overflow could be detected if the duration integer literals were literal operator templates, otherwise overflow can either be undefined or a run-time error, not ill-formed.[Urbana 2014-11-07: Move to Open]
Proposed resolution:
Section: 17.6.3.5 [allocator.requirements] Status: New Submitter: Daniel Krügler Opened: 2014-05-19 Last modified: 2015-04-08
View other active issues in [allocator.requirements].
View all other issues in [allocator.requirements].
View all issues with New status.
Discussion:
According to Table 28, 17.6.3.5 [allocator.requirements], an Allocator's deallocate function is specified as follows:
All n T objects in the area pointed to by p shall be destroyed prior to this call. n shall match the value passed to allocate to obtain this memory. Does not throw exceptions. [Note: p shall not be singular. — end note]
This wording is confusing in regard to the following points:
This specification does not make clear that the result of an allocate call can only be returned once to the deallocate function. This is much clearer expressed for operator delete (18.6.1.1 [new.delete.single] p12, emphasis mine):
Requires: ptr shall be a null pointer or its value shall be a value returned by an earlier call to the (possibly replaced) operator new(std::size_t) or operator new(std::size_t,const std::nothrow_t&) which has not been invalidated by an intervening call to operator delete(void*).
The intended meaning of that wording was to say that deallocate shall accept every result value that had been returned by a corresponding call to allocate, this includes also a possible result of a null pointer value, which is possible ("[Note: If n == 0, the return value is unspecified. — end note]"). Unfortunately the deallocate function uses a non-normative note ("p shall not be singular.") which refers to the fuzzy term singular, that is one of the most unclear and misunderstood terms of the library, as pointed out in 1213. The occurrence of this term has lead to the possible understanding, that this function would never allow null pointer values. Albeit for allocators the intention had not been to require the support in general that a null pointer value can be provided to deallocate (as it is allowed for std::free and operator delete), the mental model was that every returned value of allocate shall be an acceptable argument type of the corresponding deallocate function.
This issue is not intending to enforce a specific meaning of singular iterator values, but the assertion is that this note does more harm than good. In addition to wording from operator delete there is no longer any need to obfuscate the normative wording.
[2014-05-24 Alisdair comments]
Now that I am reading it very precisely, there is another mis-stated assumption as a precondition for deallocate:
All n T objects in the area pointed to by p shall be destroyed prior to this call.
This makes a poor assumption that every possible object in the allocated buffer was indeed constructed, but this is often not the case, e.g., a vector that is not filled to capacity. We should require calling the destructor for only those objects actually constructed in the buffer, which may be fewer than n, or even 0.
I wonder if we really require all objects to be destroyed before calling deallocate though. Are we really so concerned about leaking objects that might not manage resources? Should this not be the proper concern of the library managing the objects and memory?[2014-06-05 Daniel responds and improves wording]
I fully agree with the last comment and I think that this requirement should be removed. We have no such requirements for comparable functions such as operator delete or return_temporary_buffer(), and this wording seems to be a wording rudiment that exists since C++98.
Proposed resolution:
This wording is relative to N3936.
Change Table 28 ("Allocator requirements") as indicated:
Table 28 — Allocator requirements Expression Return type Assertion/note
pre-/post-conditionDefault … a.deallocate(p,n) (not used) Pre: p shall be a value returned by an earlier
call to allocate which has not been invalidated by
an intervening call to deallocate. n shall
match the value passed to allocate to obtain this
memory.All n T objects in the area pointed to by
p shall be destroyed prior to this call.
Throws: Nothing.n
shall match the value passed to
allocate to obtain this
memory. Does not throw
exceptions. [Note: p shall not
be singular. — end note]…
Section: 20.9.12.2 [func.wrap.func] Status: New Submitter: Pablo Halpern Opened: 2014-05-23 Last modified: 2015-04-08
View other active issues in [func.wrap.func].
View all other issues in [func.wrap.func].
View all issues with New status.
Discussion:
The definition of function::assign in N3936 is:
template<class F, class A> void assign(F&& f, const A& a);Effects: function(allocator_arg, a, std::forward<F>(f)).swap(*this)
This definition is flawed in several respects:
The interface implies that the intent is to replace the allocator in *this with the specified allocator, a. Such functionality is unique in the standard and is problematic when creating, e.g. a container of function objects, all using the same allocator.
The current definition of swap() makes it unclear whether the objects being swapped can have different allocators. The general practice is that allocators must be equal in order to support swap, and this practice is reinforced by the proposed library TS. Thus, the definition of assign would have undefined behavior unless the allocator matched the allocator already within function.
The general rule for members of function is to supply the allocator before the functor, using the allocator_arg prefix. Supplying the allocator as a second argument, without the allocator_arg prefix is error prone and confusing.
I believe that this ill-conceived interface was introduced in the effort to add allocators to parts of the standard where it had been missing, when we were unpracticed in the right way to accomplish that. Allocators were added to function at a time when the allocator model was in flux and it was the first class in the standard after shared_ptr to use type-erased allocators, so it is not surprising to see some errors in specification here. (shared_ptr is a special case because of its shared semantics, and so is not a good model.)
The main question is whether this member should be specified with better precision or whether it should be deprecated/removed. The only way I can see to give a "reasonable" meaning to the existing interface is to describe it in terms of destroying and re-constructing *this:function temp(allocator_arg, a, std::forward<F>(f)); this->~function(); ::new(this) function(std::move(temp));
(The temp variable is needed for exception safety). The ugliness of this specification underscores the ugliness of the concept. What is the purpose of this member other than to reconstruct the object from scratch, a facility that library classes do not generally provide? Programmers are always free to destroy and re-construct objects — there is no reason why function should make that especially easy.
I propose, therefore, that we make no attempt at giving the current interface a meaningful definition of questionable utility, but simply get rid of it all together. This leaves us with only two questions:Should we deprecate the interface or just remove it?
Should we replace it with an assign(f) member that doesn't take an allocator?
Of these four combinations of binary answers to the above questions, I think the ones that make the most sense are (remove, no) and (deprecate, yes). The proposed new interface provides nothing that operator= does not already provide. However, if the old (deprecated) interface remains, then having the new interface will guide the programmer away from it.
The proposed wording below assumes deprecation. If we choose removal, then there is no wording needed; simply remove the offending declaration and definition.Proposed resolution:
This wording is relative to N3936.
Change class template function synopsis, 20.9.12.2 [func.wrap.func], as indicated:
template<class R, class... ArgTypes> class function<R(ArgTypes...)> { […] // 20.9.11.2.2, function modifiers: void swap(function&) noexcept; template<class F, class A> void assign(F&&, const A&); […] };
Change 20.9.12.2.2 [func.wrap.func.mod] as indicated:
template<class F, class A> void assign(F&& f, const A& a);Effects: *this = forward<F>(f);
function(allocator_arg, a, std::forward<F>(f)).swap(*this)
To deprecation section [depr.function.objects], add the following new sub-clause:
Old assign member of polymorphic function wrappers [depr.function.objects.assign]
namespace std{ template<class R, class... ArgTypes> class function<R(ArgTypes...)> { // remainder unchanged template<class F, class A> void assign(F&& f, const A& a); […] }; }The two-argument form of assign is defined as follows:
template<class F, class A> void assign(F&& f, const A& a);Requires: a shall be equivalent to the allocator used to construct *this.
Effects: this->assign(forward<F>(f));
Section: 20.9.12.2.1 [func.wrap.func.con] Status: New Submitter: Pablo Halpern Opened: 2014-05-23 Last modified: 2015-04-08
View all other issues in [func.wrap.func.con].
View all issues with New status.
Discussion:
The Effects clauses for the assignment operator for class template function are written as code that constructs a temporary function and then swaps it with *this. The intention appears to be that assignment should have the strong exception guarantee, i.e., *this is not modified if an exception is thrown. However, the current description is incorrect when *this was constructed using an allocator.
Part of the problem is the under-specification of swap, which does not state the allocator requirements or allocator postconditions. If swap behaves like the rest of the standard library, swapping function objects constructed with different allocators would be undefined behavior. Alternatively swap could exchange the allocators, though I would argue against this specification. For either specification of swap, the current Effects clauses for operator= are incorrect. If swap does not exchange the allocators, then operator= would have undefined behavior, which is clearly not desired. If swap does exchange the allocators, then operator= would always leave the left-hand side (lhs) of the assignment with a default allocator. The latter would be surprising behavior, as the allocator instance is normally unchanged for the lifetime of an object (for good reason), and is certainly not reset to default arbitrarily. The desired behavior is that assignment would leave the allocator of the lhs unchanged. The way to achieve this behavior is to construct the temporary function using the original allocator. Unfortunately, we cannot describe the desired behavior in pure code, because there is no way to name the type-erased value of the allocator. (N3916 would improve this situation for the Library Fundamentals TS, but even with those changes, there is no way to recover the original type of the allocator.) The PR below, therefore, uses pseudo-code, inventing a fictitious ALLOCATOR_OF(f) expression that evaluates to the actual allocator type, even if that allocator was type erased. I have implemented this PR successfully.Proposed resolution:
This wording is relative to N3936.
Change 20.9.12.2.1 [func.wrap.func.con] as indicated:
In the following descriptions, ALLOCATOR_OF(f) is a copy of the allocator specified in the construction of function f, or allocator<char>() if no allocator was specified.
function& operator=(const function& f);-12- Effects: function(allocator_arg, ALLOCATOR_OF(*this), f).swap(*this);
-13- Returns: *thisfunction& operator=(function&& f);-14- Effects:
-15- Returns: *thisReplaces the target of *this with the target of f.function(allocator_arg, ALLOCATOR_OF(*this), std::move(f)).swap(*this);function& operator=(nullptr_t);-16- Effects: If *this != nullptr, destroys the target of this.
-17- Postconditions: !(*this). The allocator is unchanged. -18- Returns: *this -?- Throws: Nothing.template<class F> function& operator=(F&& f);-19- Effects: function(allocator_arg, ALLOCATOR_OF(*this), std::forward<F>(f)).swap(*this);
-20- Returns: *this -21- Remarks: This assignment operator shall not participate in overload resolution unless declval<typename decay<F>::type&>() is Callable (20.9.11.2) for argument types ArgTypes... and return type R.template<class F> function& operator=(reference_wrapper<F> f);-22- Effects: function(allocator_arg, ALLOCATOR_OF(*this), f).swap(*this);
-23- Returns: *this
Section: 20.2.3 [utility.exchange] Status: Open Submitter: Nick Calus Opened: 2014-05-09 Last modified: 2015-04-08
View all other issues in [utility.exchange].
View all issues with Open status.
Discussion:
In paper N3668, the addition of a template function std::exchange had been proposed. In the rationale provided by the paper, we find the following:
I chose the name for symmetry with atomic_exchange, since they behave the same except for this function not being atomic.
and:
Atomic objects provide an atomic_exchange function ([atomics.types.operations.req]p18) that assigns a new value to the object and returns the old value. This operation is also useful on non-atomic objects, and this paper proposes adding it to the library.
But the specified semantics of std::exchange is defined as follows:
template <class T, class U=T> T exchange(T& obj, U&& new_val);Effects: Equivalent to:
T old_val = std::move(obj); obj = std::forward<U>(new_val); return old_val;
When looking at the post-condition of the std::exchange function, one would expect the return value to be the old value of obj and also that obj now contains the value of new_value. This post-condition is violated when obj is a reference to the same object as new_value and type T has move semantics.
Given it's specification, it is clear that std::exchange is meant to be used with types that have move semantics. Therefore, the post-condition is violated for self-assignments. Suppose the following situation: You have a vector of objects. The objects implement move semantics and are emptied when moved from. You provide a function that allows you to replace an object at a specific index by a new object (provided by reference as an argument to your function). When replacing an object, your function calls a member-function do_something_fancy on the old object.void your_function(int i, X& new_val) { std::exchange(vec[i], new_val).do_something_fancy(); }
Your function gets called with a given index and the corresponding element of said vector. (by coincidence or by purpose, it doesn't really matter)
your_function(5, vec[5]);
This will cause the object at vec[5] to be in an empty state. If this object would not implement move semantics, assignment performance is potentially worse, but at least it is not in an empty (to my business logic, invalid) state.
So to me, the current reference implementation of std::exchange does not have the behavior it is expected to have.[2014-12-18 Telecon]
MC: does this resolution solve the problem?
JW: and is the cost of the extra construction and move acceptable? AM: not all moves are cheap VV: seems like a design change JW: maybe this should be rolled into my unwritten paper on self-swap, so we deal with them consistently VV: we should update the issue saying something like that and maybe NAD Future MC: instead, add Requires clause saying the arguments are not the same. JW: interesting, that can even be checked in a debug mode assertion MC: ACTION: send alternative P/R that we can considerPrevious resolution [SUPERSEDED]:
This wording is relative to N3936.
Change 20.2.3 [utility.exchange] as indicated:
template <class T, class U=T> T exchange(T& obj, U&& new_val);-1- Effects: Equivalent to:
T tmp = std::forward<U>(new_val); T old_val = std::move(obj); obj =std::forward<U>(new_val)std::move(tmp); return old_val;
[2015-03-30, Marshall provides alternative wording]
Proposed resolution:
This wording is relative to N4296.
Change 20.2.3 [utility.exchange] as indicated:
template <class T, class U=T> T exchange(T& obj, U&& new_val);-?- Requires: obj and new_val shall not refer to the same object.
-1- Effects: Equivalent to:T old_val = std::move(obj); obj = std::forward<U>(new_val); return old_val;
Section: 21.4 [basic.string] Status: LEWG Submitter: Michael Bradshaw Opened: 2014-05-27 Last modified: 2015-04-08
View other active issues in [basic.string].
View all other issues in [basic.string].
View all issues with LEWG status.
Discussion:
Regarding 21.4 [basic.string], std::basic_string<charT>::data() returns a const charT* 21.4.7.1 [string.accessors]. While this method is convenient, it doesn't quite match std::array<T>::data() 23.3.2.5 [array.data] or std::vector<T>::data() 23.3.6.4 [vector.data], both of which provide two versions (that return T* or const T*). An additional data() method can be added to std::basic_string that returns a charT* so it can be used in similar situations that std::array and std::vector can be used. Without a non-const data() method, std::basic_string has to be treated specially in code that is otherwise oblivious to the container type being used.
Adding a charT* return type to data() would be equivalent to doing &str[0] or &str.front(). Small discussion on the issue can be found here and in the std-discussion thread (which didn't get too much attention). This requires a small change to std::basic_string's definition in 21.4 [basic.string] to add the method to std::basic_string, and another small change in 21.4.7.1 [string.accessors] to define the new method.[2015-02 Cologne]
Back to LEWG.
Proposed resolution:
This wording is relative to N3936.
Change class template basic_string synopsis, 21.4 [basic.string], as indicated:
namespace std { template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> > class basic_string { public: […] // 21.4.7, string operations: const charT* c_str() const noexcept; const charT* data() const noexcept; charT* data() noexcept; allocator_type get_allocator() const noexcept; […] }; }
Add the following sequence of paragraphs following 21.4.7.1 [string.accessors] p3, as indicated:
charT* data() noexcept;-?- Returns: A pointer p such that p + i == &operator[](i) for each i in [0,size()].
-?- Complexity: Constant time. -?- Requires: The program shall not alter the value stored at p + size().
Section: 17.3 [defns.ntcts], 22.3.1.1.1 [locale.category], 27.2.2 [iostreams.limits.pos], 27.7.3.6.1 [ostream.formatted.reqmts], 27.7.3.6.4 [ostream.inserters.character] Status: New Submitter: Jeffrey Yasskin Opened: 2014-06-01 Last modified: 2015-04-08
View all issues with New status.
Discussion:
The term "character type" is used in 17.3 [defns.ntcts], 22.3.1.1.1 [locale.category], 27.2.2 [iostreams.limits.pos], 27.7.3.6.1 [ostream.formatted.reqmts], and 27.7.3.6.4 [ostream.inserters.character], but the core language only defines "narrow character types" (3.9.1 [basic.fundamental]).
"wide-character type" is used in 22.5 [locale.stdcvt], but the core language only defines a "wide-character set" and "wide-character literal".Proposed resolution:
Section: 20.9.12.2 [func.wrap.func] Status: Open Submitter: Daniel Krügler Opened: 2014-06-03 Last modified: 2015-04-08
View other active issues in [func.wrap.func].
View all other issues in [func.wrap.func].
View all issues with Open status.
Discussion:
The existing definition of std::function's Callable requirements provided in 20.9.12.2 [func.wrap.func] p2,
A callable object f of type F is Callable for argument types ArgTypes and return type R if the expression INVOKE(f, declval<ArgTypes>()..., R), considered as an unevaluated operand (Clause 5), is well formed (20.9.2).
is defective in several aspects:
The wording can be read to be defined in terms of callable objects, not of callable types.
Contrary to that, 20.9.12.2.5 [func.wrap.func.targ] p2 speaks of "T shall be a type that is Callable (20.9.11.2) for parameter types ArgTypes and return type R."
The required value category of the callable object during the call expression (lvalue or rvalue) strongly depends on an interpretation of the expression f and therefore needs to be specified unambiguously.
The intention of original proposal (see IIIa. Relaxation of target requirements) was to refer to both types and values ("we say that the function object f (and its type F) is Callable […]"), but that mental model is not really deducible from the existing wording. An improved type-dependence wording would also make the sfinae-conditions specified in 20.9.12.2.1 [func.wrap.func.con] p8 and p21 ("[…] shall not participate in overload resolution unless f is Callable (20.9.11.2) for argument types ArgTypes... and return type R.") easier to interpret.
My understanding always had been (see e.g. Howard's code example in the 2009-05-01 comment in LWG 815), that std::function invokes the call operator of its target via an lvalue. The required value-category is relevant, because it allows to reflect upon whether an callable object such asstruct RVF { void operator()() const && {} };
would be a feasible target object for std::function<void()> or not.
Clarifying the current Callable definition seems also wise to make a future transition to language-based concepts easier. A local fix of the current wording is simple to achieve, e.g. by rewriting it as follows:A callable
object f oftype (20.9.1 [func.def]) F is Callable for argument types ArgTypes and return type R if the expression INVOKE(fdeclval<F&>(), declval<ArgTypes>()..., R), considered as an unevaluated operand (Clause 5), is well formed (20.9.2).
It seems appealing to move such a general Callable definition to a more "fundamental" place (e.g. as another paragraph of 20.9.1 [func.def]), but the question arises, whether such a more general concept should impose the requirement that the call expression is invoked on an lvalue of the callable object — such a special condition would also conflict with the more general definition of the result_of trait, which is defined for either lvalues or rvalues of the callable type Fn. In this context I would like to point out that "Lvalue-Callable" is not the one and only Callable requirement in the library. Counter examples are std::thread, call_once, or async, which depend on "Rvalue-Callable", because they all act on functor rvalues, see e.g. 30.3.1.2 [thread.thread.constr]:
[…] The new thread of execution executes INVOKE(DECAY_COPY(std::forward<F>(f)), DECAY_COPY(std::forward<Args>(args))...) […]
For every callable object F, the result of DECAY_COPY is an rvalue. These implied rvalue function calls are no artifacts, but had been deliberately voted for by a Committee decision (see LWG 2021, 2011-06-13 comment) and existing implementations respect these constraints correctly. Just to give an example,
#include <thread> struct LVF { void operator()() & {} }; int main() { LVF lf; std::thread t(lf); t.join(); }
is supposed to be rejected.
The below presented wording changes are suggested to be minimal (still local to std::function), but the used approach would simplify a future (second) conceptualization or any further generalization of Callable requirements of the Library.[2015-02 Cologne]
Related to N4348. Don't touch with a barge pole.
Proposed resolution:
This wording is relative to N3936.
Change 20.9.12.2 [func.wrap.func] p2 as indicated:
-2- A callable
object f oftype (20.9.1 [func.def]) F is Lvalue-Callable for argument types ArgTypes and return type R if the expression INVOKE(fdeclval<F&>(), declval<ArgTypes>()..., R), considered as an unevaluated operand (Clause 5), is well formed (20.9.2).
Change 20.9.12.2.1 [func.wrap.func.con] p8+p21 as indicated:
template<class F> function(F f); template <class F, class A> function(allocator_arg_t, const A& a, F f);[…]
-8- Remarks: These constructors shall not participate in overload resolution unlessfF is Lvalue-Callable (20.9.11.2) for argument types ArgTypes... and return type R.[…]
template<class F> function& operator=(F&& f);[…]
-21- Remarks: This assignment operator shall not participate in overload resolution unlessdeclval<typename decay<F>::type&>()decay_t<F> is Lvalue-Callable (20.9.11.2) for argument types ArgTypes... and return type R.
Change 20.9.12.2.5 [func.wrap.func.targ] p2 as indicated: [Editorial comment: Instead of adapting the preconditions for the naming change I recommend to strike it completely, because the target() functions do not depend on it; the corresponding wording exists since its initial proposal and it seems without any advantage to me. Assume that some template argument T is provided, which does not satisfy the requirements: The effect will be that the result is a null pointer value, but that case can happen in other (valid) situations as well. — end comment]
template<class T> T* target() noexcept; template<class T> const T* target() const noexcept;-3- Returns: If target_type() == typeid(T) a pointer to the stored function target; otherwise a null pointer.
-2- Requires: T shall be a type that is Callable (20.9.11.2) for parameter types ArgTypes and return type R.
Section: 22.3.1.3 [locale.members] Status: New Submitter: Richard Smith Opened: 2014-06-09 Last modified: 2015-04-08
View all other issues in [locale.members].
View all issues with New status.
Discussion:
22.3.1.3 [locale.members] p5 says:
Returns: The name of *this, if it has one; otherwise, the string "*". If *this has a name, then locale(name().c_str()) is equivalent to *this. Details of the contents of the resulting string are otherwise implementation-defined.
So… what is implementation-defined here, exactly? The first sentence completely defines the behavior of this function in all cases.
Also, the second sentence says (effectively) that all locales with the same name are equivalent: given L1 and L2 that have the same name N, they are both equivalent to locale(N), and since there is no definition of "equivalent" specific to locale, I assume it's the normal transitive equivalence property, which would imply that L1 is equivalent to L2. I'm not sure why this central fact is in the description of locale::name, nor why it's written in this roundabout way.Proposed resolution:
Section: 20.10.7.6 [meta.trans.other] Status: Open Submitter: Peter Dimov Opened: 2014-06-12 Last modified: 2015-04-08
View other active issues in [meta.trans.other].
View all other issues in [meta.trans.other].
View all issues with Open status.
Discussion:
Please consider the following example:
#include <map> #include <atomic> int main() { std::map<int, std::atomic<int>> map_; map_.emplace(1, 0); // fail map_.emplace(1); // fail map_.emplace(1, {}); // fail map_.emplace(std::piecewise_construct, std::tuple<int>(1), std::tuple<>()); // OK }
The first three calls represent attempts by an ordinary programmer (in which role I appear today) to construct a map element. Since std::atomic<int> is non-copyable and immovable, I was naturally drawn to emplace() because it constructs in-place and hence doesn't need to copy or move. The logic behind the attempts was that K=int would be constructed from '1', and V=std::atomic<int> would be (directly) constructed by '0', default constructed, or constructed by '{}'.
Yet none of the obvious attempts worked. I submit that at least two of the three ought to have worked, and that we have therefore a defect in either map::emplace or pair. Ville: There exists a related EWG issue for this. Daniel: If the proposal N4387 would be accepted, it would solve the first problem mentioned above.[2015-02, Cologne]
AM: I think Peter's expectation is misguided that the second and third "//fail" cases should work.
DK: Howard's paper [note: which hasn't been written yet] will make the second case work... AM: ...but
the third one will never work without core changes.
Proposed resolution:
Section: 18.7.1 [type.info] Status: New Submitter: Stephan T. Lavavej Opened: 2014-06-14 Last modified: 2015-04-08
View all other issues in [type.info].
View all issues with New status.
Discussion:
type_info's destructor is depicted as being virtual, which is nearly unobservable to users (since they can't construct or copy this class, they can't usefully derive from it). However, it's technically observable (via is_polymorphic and has_virtual_destructor). It also imposes real costs on implementations, requiring them to store one vptr per type_info object, when RTTI space consumption is a significant concern.
Making this implementation-defined wouldn't affect users (who can observe this only if they're specifically looking for it) and wouldn't affect implementations who need virtual here, but it would allow other implementations to drop virtual and improve their RTTI space consumption. Richard Smith: It's observable in a few other ways.std::map<void*, something> m; m[dynamic_cast<void*>(&typeid(blah))] = stuff;
... is broken by this change, because you can't dynamic_cast a non-polymorphic class type to void*.
type_info& f(); typeid(f());
... evaluates f() at runtime without this change, and might not do so with this change.
These are probably rare things, but I can imagine at least some forms of the latter being used in SFINAE tricks.Proposed resolution:
This wording is relative to N3936.
Change 18.7.1 [type.info] as indicated:
namespace std { class type_info { public:virtualsee below ~type_info(); […] }; }-1- The class type_info describes type information generated by the implementation. Objects of this class effectively store a pointer to a name for the type, and an encoded value suitable for comparing two types for equality or collating order. The names, encoding rule, and collating sequence for types are all unspecified and may differ between programs. Whether ~type_info() is virtual is implementation-defined.
Section: 21.4.2 [string.cons] Status: New Submitter: Stephan T. Lavavej Opened: 2014-06-14 Last modified: 2015-04-08
View all other issues in [string.cons].
View all issues with New status.
Discussion:
21.4.2 [string.cons] p3 specifies:
basic_string(const basic_string& str, size_type pos, size_type n = npos, const Allocator& a = Allocator());But this implies that basic_string(str, pos) and basic_string(str, pos, n) use Allocator() instead of getting an allocator from str.
21.4.1 [string.require] p3 says "The Allocator object used shall be obtained as described in 23.2.1." 23.2.1 [container.requirements.general] p8 says "Copy constructors for these container types obtain an allocator by calling allocator_traits<allocator_type>::select_on_container_copy_construction on the allocator belonging to the container being copied.", but this isn't exactly a copy constructor. Then it talks about move constructors (which this definitely isn't), and finally says that "All other constructors for these container types take a const allocator_type& argument. […] A copy of this allocator is used for any memory allocation performed".
Proposed resolution:
This wording is relative to N3936.
Change 21.4 [basic.string] p5, class template basic_string synopsis, as indicated:
[…] // 21.4.2, construct/copy/destroy: […] basic_string(basic_string&& str) noexcept; basic_string(const basic_string& str, size_type pos, size_type n = npos); basic_string(const basic_string& str, size_type pos, size_type n= npos, const Allocator& a= Allocator()); […]
Change 21.4.2 [string.cons] around p3 as indicated:
basic_string(const basic_string& str, size_type pos, size_type n = npos); basic_string(const basic_string& str, size_type pos, size_type n= npos, const Allocator& a= Allocator());[…]
-5- Effects: Constructs an object of class basic_string and determines the effective length rlen of the initial string value as the smaller of n and str.size() - pos, as indicated in Table 65. The first constructor obtains an allocator by calling allocator_traits<allocator_type>::select_on_container_copy_construction on the allocator belonging to str. Table 65 — basic_string(const basic_string&, size_type, size_type) and basic_string(const basic_string&, size_type, size_type, const Allocator&) effects
Section: 21.5 [string.conversions] Status: Ready Submitter: Stephan T. Lavavej Opened: 2014-06-14 Last modified: 2015-04-08
View all other issues in [string.conversions].
View all issues with Ready status.
Discussion:
stof() is currently specified to call strtod()/wcstod() (which converts the given string to double) and then it's specified to convert that double to float. This performs rounding twice, which introduces error. Here's an example written up by James McNellis:
Consider the following number X:1.999999821186065729339276231257827021181583404541015625 (X)
This number is exactly representable in binary as:
1.111111111111111111111101000000000000000000000000000001 * ^1st ^23rd ^52nd
I've marked the 23rd and 52nd fractional bits. These are the least significant bits for float and double, respectively.
If we convert this number directly to float, we take the 23 most significant bits:1.11111111111111111111110
The next bit is a one and the tail is nonzero (the 54th fractional bit is a one), so we round up. This gives us the correctly rounded result:
1.11111111111111111111111
So far so good. But... If we convert X to double, we take the 52 most significant bits:
1.1111111111111111111111010000000000000000000000000000 (Y)
The next bit is a zero, so we round down (truncating the value). If we then convert Y to float, we take its 23 most significant bits:
1.11111111111111111111110
The next bit is a one and the tail is zero, so we round to even (leaving the value unchanged). This is off by 1ulp from the correctly rounded result.
[2014-06 Rapperswil]
Marshall Clow will look at this.
[Urbana 2014-11-07: Move to Ready]
Proposed resolution:
This wording is relative to N3936.
Change 21.5 [string.conversions] p4+p6 as indicated:
float stof(const string& str, size_t* idx = 0); double stod(const string& str, size_t* idx = 0); long double stold(const string& str, size_t* idx = 0);-4- Effects:
[…] -6- Throws: invalid_argument if strtof, strtod, or strtold reports that no conversion could be performed. Throws out_of_range if strtof, strtod, or strtold sets errno to ERANGE or if the converted value is outside the range of representable values for the return type.the first twoThese functions call strtof(str.c_str(), ptr), strtod(str.c_str(), ptr), andthe third function callsstrtold(str.c_str(), ptr), respectively. Each function returns the converted result, if any. […]
Change 21.5 [string.conversions] p11+p13 as indicated:
float stof(const wstring& str, size_t* idx = 0); double stod(const wstring& str, size_t* idx = 0); long double stold(const wstring& str, size_t* idx = 0);-11- Effects:
[…] -13- Throws: invalid_argument if wcstof, wcstod, or wcstold reports that no conversion could be performed. Throws out_of_range if wcstof, wcstod, or wcstold sets errno to ERANGE.the first twoThese functions call wcstof(str.c_str(), ptr), wcstod(str.c_str(), ptr), andthe third function callswcstold(str.c_str(), ptr), respectively. Each function returns the converted result, if any. […]
Section: 26.5.8.3.4 [rand.dist.bern.negbin] Status: Ready Submitter: Stephan T. Lavavej Opened: 2014-06-14 Last modified: 2015-04-08
View all issues with Ready status.
Discussion:
26.5.8.3.4 [rand.dist.bern.negbin] p2 requires "0 < p <= 1". Consider what happens when p == 1. The discrete probability function specified by p1 involves "* p^k * (1 - p)^i". For p == 1, this is "* 1^k * 0^i", so every integer i >= 0 is produced with zero probability. (Let's avoid thinking about 0^0.)
Wikipedia states that p must be within (0, 1), exclusive on both sides. Previous resolution [SUPERSEDED]:
Change 26.5.8.3.4 [rand.dist.bern.negbin] p2 as indicated: [Drafting note: This should be read as: Replace the symbol "≤" by "<" — end drafting note]
explicit negative_binomial_distribution(IntType k = 1, double p = 0.5);-2- Requires: 0 < p
≤< 1 and 0 < k.
[2014-11 Urbana]
SG6 suggests better wording.
[2014-11-08 Urbana]
Moved to Ready with the node.
There remains concern that the constructors are permitting values that may (or may not) be strictly outside the domain of the function, but that is a concern that affects the design of the random number facility as a whole, and should be addressed by a paper reviewing and addressing the whole clause, not picked up in the issues list one distribution at a time. It is still not clear that such a paper would be uncontroversial.
Proposed resolution:
This wording is relative to N4140.
Add a note after paragraph 1 before the synopsis in 26.5.8.3.4 [rand.dist.bern.negbin]:
A negative_binomial_distribution random number distribution produces random integers distributed according to the discrete probability function
.
[Note: This implies that is undefined when p == 1. — end note]
Drafting note: should be in math font, and p == 1 should be in code font.
Section: 30.6.9.1 [futures.task.members] Status: SG1 Submitter: Stephan T. Lavavej Opened: 2014-06-14 Last modified: 2015-04-08
View other active issues in [futures.task.members].
View all other issues in [futures.task.members].
View all issues with SG1 status.
Discussion:
LWG 2097's resolution was slightly too aggressive. It constrained packaged_task(allocator_arg_t, const Allocator&, F&&), but that's unnecessary because packaged_task doesn't have any other three-argument constructors. Additionally, it's marked as explicit (going back to WP N2798 when packaged_task first appeared) which is unnecessary.
[2015-02 Cologne]
Handed over to SG1.
Proposed resolution:
This wording is relative to N3936.
Change 30.6.9 [futures.task] p2, class template packaged_task as indicated:
template <class F> explicit packaged_task(F&& f); template <class F, class Allocator>explicitpackaged_task(allocator_arg_t, const Allocator& a, F&& f);
Change 30.6.9.1 [futures.task.members] as indicated:
template <class F> packaged_task(F&& f); template <class F, class Allocator>explicitpackaged_task(allocator_arg_t, const Allocator& a, F&& f);[…]
-3- Remarks:These constructorsThe first constructor shall not participate in overload resolution if decay_t<F> is the same type as std::packaged_task<R(ArgTypes...)>.
Section: X [mods.util.smartptr.shared.const] Status: Tentatively Ready Submitter: Jeffrey Yasskin Opened: 2014-06-16 Last modified: 2015-04-08
View all issues with Tentatively Ready status.
Discussion:
Addresses: fund.ts
The proposed resolution for LWG 2399 doesn't apply cleanly to the Fundamentals TS, but the issue is still present.
[2015-02, Cologne]
Unanimous consent.
Proposed resolution:
This wording is relative to N4023 in regard to fundamental-ts changes.
In fundamental-ts, change [mods.util.smartptr.shared.const] p34 as indicated:
template <class Y, class D> shared_ptr(unique_ptr<Y, D>&& r);-34-
-35- Effects: Equivalent to shared_ptr(r.release(), r.get_deleter()) when D is not a reference type, otherwise shared_ptr(r.release(), ref(r.get_deleter())). -36- Exception safety: If an exception is thrown, the constructor has no effect.RequiresRemarks: This constructor shall not participate in overload resolution unless Y*shall beis compatible with T*.
Section: 20.8.2.2 [util.smartptr.shared] Status: Ready Submitter: Jonathan Wakely Opened: 2014-06-21 Last modified: 2015-04-08
View other active issues in [util.smartptr.shared].
View all other issues in [util.smartptr.shared].
View all issues with Ready status.
Discussion:
N3920 made this edit, which is correct but unrelated to the support for arrays:
Change 20.7.2.2 [util.smartptr.shared] p2 as follows:
Specializations of shared_ptr shall be CopyConstructible, CopyAssignable, and LessThanComparable, allowing their use in standard containers. Specializations of shared_ptr shall be contextually convertible to bool, allowing their use in boolean expressions and declarations in conditions. […]
That change is actually fixing a defect in the current wording and should be applied directly to the working paper, not just to the Library Fundamentals TS. The declarations of the conversion operator in 20.8.2.2 [util.smartptr.shared] and 20.8.2.2.5 [util.smartptr.shared.obs] are explicit which contradicts the "convertible to bool" statement. The intention is definitely for shared_ptr to only be contextually convertible to bool.
[Urbana 2014-11-07: Move to Ready]
Proposed resolution:
This wording is relative to N3936.
Change 20.8.2.2 [util.smartptr.shared] p2 as indicated:
-2- Specializations of shared_ptr shall be CopyConstructible, CopyAssignable, and LessThanComparable, allowing their use in standard containers. Specializations of shared_ptr shall be contextually convertible to bool, allowing their use in boolean expressions and declarations in conditions. The template parameter T of shared_ptr may be an incomplete type.
Section: 30.6.5 [futures.promise], 30.6.9.1 [futures.task.members] Status: SG1 Submitter: Jonathan Wakely Opened: 2014-06-23 Last modified: 2015-04-08
View other active issues in [futures.promise].
View all other issues in [futures.promise].
View all issues with SG1 status.
Discussion:
The following code has a data race according to the standard:
std::promise<void> p; std::thread t{ []{ p.get_future().wait(); }}; p.set_value(); t.join();
The problem is that both promise::set_value() and promise::get_future() are non-const member functions which modify the same object, and we only have wording saying that the set_value() and wait() calls (i.e. calls setting and reading the shared state) are synchronized.
The calls don't actually access the same memory locations, so the standard should allow it. My suggestion is to state that calling get_future() does not conflict with calling the various functions that make the shared state ready, but clarify with a note that this does not imply any synchronization or "happens before", only being free from data races.[2015-02 Cologne]
Handed over to SG1.
Proposed resolution:
This wording is relative to N3936.
Change 30.6.5 [futures.promise] around p12 as indicated:
future<R> get_future();-12- Returns: A future<R> object with the same shared state as *this.
-?- Synchronization: Calls to this function do not conflict (1.10 [intro.multithread]) with calls to set_value, set_exception, set_value_at_thread_exit, or set_exception_at_thread_exit. [Note: Such calls need not be synchronized, but implementations must ensure they do not introduce data races. — end note] -13- Throws: future_error if *this has no shared state or if get_future has already been called on a promise with the same shared state as *this. -14- Error conditions: […]
Change 30.6.9.1 [futures.task.members] around p13 as indicated:
future<R> get_future();-13- Returns: A future<R> object that shares the same shared state as *this.
-?- Synchronization: Calls to this function do not conflict (1.10 [intro.multithread]) with calls to operator() or make_ready_at_thread_exit. [Note: Such calls need not be synchronized, but implementations must ensure they do not introduce data races. — end note] -14- Throws: a future_error object if an error occurs. -15- Error conditions: […]
Section: 19.3 [assertions] Status: New Submitter: David Krauss Opened: 2014-06-25 Last modified: 2015-04-08
View other active issues in [assertions].
View all other issues in [assertions].
View all issues with New status.
Discussion:
When NDEBUG is defined, assert must expand exactly to the token sequence ((void)0), with no whitespace (C99 §7.2/1 and also C11 §7.2/1). This is a lost opportunity to pass the condition along to the optimizer.
The user may observe the token sequence using the stringize operator or discriminate it by making a matching #define directive. There is little chance of practical code doing such things. It's reasonable to allow any expansion that is a void expression with no side effects or semantic requirements, for example, an extension keyword or an attribute-specifier finagled into the context. Conforming optimizations would still be limited to treating the condition as hint, not a requirement. Nonconformance on this point is quite reasonable though, given user preferences. Anyway, it shouldn't depend on preprocessor quirks. As for current practice, Darwin OS <assert.h> provides a GCC-style compiler hint __builtin_expect but only in debug mode. Shouldn't release mode preserve hints? Daniel: The corresponding resolution should take care not to conflict with the intention behind LWG 2234.Proposed resolution:
Section: 17.6.5.8 [reentrancy] Status: Open Submitter: Stephan T. Lavavej Opened: 2014-07-01 Last modified: 2015-04-08
View all other issues in [reentrancy].
View all issues with Open status.
Discussion:
N3936 17.6.5.8 [reentrancy]/1 talks about "functions", but that doesn't address the scenario of calling different member functions of a single object. Member functions often have to violate and then re-establish invariants. For example, vectors often have "holes" during insertion, and element constructors/destructors/etc. shouldn't be allowed to observe the vector while it's in this invariant-violating state. The [reentrancy] Standardese should be extended to cover member functions, so that implementers can either say that member function reentrancy is universally prohibited, or selectively allowed for very specific scenarios.
(For clarity, this issue has been split off from LWG 2382.)[2014/11/03 Urbana]
AJM confirmed with SG1 that they had no special concerns with this issue, and LWG should retain ownership.
Move to Open
Proposed resolution:
This wording is relative to N3936.
Change 17.6.5.8 [reentrancy] p1 as indicated:
-1- Except where explicitly specified in this standard, it is implementation-defined which functions (including different member functions called on a single object) in the Standard C++ library may be recursively reentered.
Section: 20.8.2.2.1 [util.smartptr.shared.const] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2014-07-03 Last modified: 2015-04-08
View all other issues in [util.smartptr.shared.const].
View all issues with Tentatively Ready status.
Discussion:
unique_ptr guarantees that it will not invoke its deleter if it stores a null pointer, which is useful for deleters that must not be called with a null pointer e.g.
unique_ptr<FILE, int(*)(FILE*)> fptr(file, &::fclose);
However, shared_ptr does invoke the deleter if it owns a null pointer, which is a silent change in behaviour when transferring ownership from unique_ptr to shared_ptr. That means the following leads to undefined behaviour:
std:shared_ptr<FILE> fp = std::move(fptr);
Peter Dimov's suggested fix is to construct an empty shared_ptr from a unique_ptr that contains a null pointer.
[2015-01-18 Library reflector vote]
The issue has been identified as Tentatively Ready based on eight votes in favour.
Proposed resolution:
This wording is relative to N4296.
Change 20.8.2.2.1 [util.smartptr.shared.const] p29 as indicated:
template <class Y, class D> shared_ptr(unique_ptr<Y, D>&& r);[…]
-29- Effects: If r.get() == nullptr, equivalent to shared_ptr(). Otherwise, if D is not a reference type, equivalent to shared_ptr(r.release(), r.get_deleter()). Otherwise, equivalent to shared_ptr(r.release(), ref(r.get_deleter()))Equivalent to shared_ptr(r.release(), r.get_deleter()) when D is not a reference type, otherwise shared_ptr(r.release(), ref(r.get_deleter())).
Section: X [optional.relops], X [optional.comp_with_t] Status: LEWG Submitter: Daniel Krügler Opened: 2014-06-20 Last modified: 2015-04-08
View all issues with LEWG status.
Discussion:
Addresses: fund.ts
Currently, std::experimental::optional::operator== imposes the EqualityComparable requirement which provides two guarantees: It ensures that operator!= can rely on the equivalence-relation property and more importantly, that the BooleanTestable requirements suggested by issue 2114 are automatically implied.
std::experimental::optional::operator< doesn't provide a LessThanComparable requirement, but there was quite an historic set of changes involved with that family of types: As of N3527 this operator was defined in terms of operator< of the contained type T and imposed the LessThanComparable requirement. In the final acceptance step of optional by the committee, the definition was expressed in terms of std::less and the LessThanComparable requirement had been removed. The inconsistency between operator== and operator< should be removed. One possible course of action would be to add the LessThanComparable to std::experimental::optional::operator<. The EqualityComparable requirement of operator== could also be removed, but in that case both operators would at least need to require the BooleanTestable requirements (see 2114) for the result type of T's operator== and operator<. Arguably, corresponding operators for pair and tuple do not impose LessThanComparable (nor EqualityComparable), albeit the definition of the "derived" relation functions depend on properties ensured by LessThanComparable. According to the SGI definition, the intention was to imposed both EqualityComparable and LessThanComparable. If this is not intended, the standard should clarify this position.[2015-02 Cologne]
VV, DK, JY discuss why and when LessThanComparable was removed. AM: Move to LEWG. Please tell LWG when you look at it.
Proposed resolution:
Section: X [tuple.apply] Status: Tentatively Ready Submitter: Zhihao Yuan Opened: 2014-07-08 Last modified: 2015-04-08
View all issues with Tentatively Ready status.
Discussion:
Addresses: fund.ts
The definition of apply present in §3.2.2 [tuple.apply] prevents this function template to be used with pointer to members type passed as the first argument.
Effects: […] return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
This makes this utility inconsistent with other standard library components and limits its usability.
We propose to define its functionally in terms of INVOKE.[2015-02, Cologne]
DK: We should use the new std::invoke.
TK: Is this a defect?
AM: std::invoke goes into C++17, and this is a defect against a TS based on C++14. We can change this later,
but now leave it as INVOKE.
GR: The TS lets you have Editor's Notes, so leave a note to make that change for C++17.
Proposed resolution:
This wording is relative to N4081 in regard to fundamental-ts changes.
Edit §3.2.2 [tuple.apply] paragraph 2:
template <class F, class Tuple> constexpr decltype(auto) apply(F&& f, Tuple&& t);-2- Effects: Given the exposition only function
template <class F, class Tuple, size_t... I> constexpr decltype(auto) apply_impl( // exposition only F&& f, Tuple&& t, index_sequence<I...>) { return INVOKE(std::forward<F>(f)(, std::get<I>(std::forward<Tuple>(t))...); }[…]
Section: 20.4.2.1 [tuple.cnstr] Status: LEWG Submitter: Akim Demaille Opened: 2014-07-11 Last modified: 2015-04-08
View other active issues in [tuple.cnstr].
View all other issues in [tuple.cnstr].
View all issues with LEWG status.
Discussion:
The issue has been submitted after exchanges with the clang++ team as a consequence of two PR I sent:
Issue 20174 Issue 20175 The short version is shown in the program below:#include <iostream> #include <tuple> struct base { void out(const std::tuple<char, char>& w) const { std::cerr << "Tuple: " << std::get<0>(w) << std::get<1>(w) << '\n'; } }; struct decorator { base b_; template <typename... Args> auto out(Args&&... args) -> decltype(b_.out(args...)) { return b_.out(args...); } void out(const char& w) { std::cerr << "char: " << w << '\n'; } }; int main() { decorator d{base{}}; char l = 'a'; d.out(l); }
This is a stripped down version of a real world case where I wrap objects in decorators. These decorators contributes some functions, and forward all the rest of the API to the wrapped object using perfect forwarding. There can be overloaded names.
Here the inner object provides anout(const std::tuple<char, char>&) -> void
function, and the wrappers, in addition to perfect forwarding, provides
out(const char&) -> void
The main function then call out(l) where l is a char lvalue.
With (GCC's) libstdc++ I get the expected result: the char overload is run. With (clang++'s) libc++ it is the tuple version which is run.$ g++-mp-4.9 -std=c++11 bar.cc && ./a.out char: a $ clang++-mp-3.5 -std=c++11 bar.cc -Wall && ./a.out Tuple: a
It turns out that this is the result of an extension of std::tuple in libc++ where they accept constructors with fewer values that tuple elements.
The purpose of this issue is to ask the standard to forbid that this extension be allowed to participate in overload resolution.[2014-10-05, Daniel comments]
This issue is closely related to LWG 2312.
[2014-11 Urbana]
Moved to LEWG.
Extensions to tuple's design are initially a question for LEWG.
Proposed resolution:
Section: 20.9.12.2 [func.wrap.func] Status: New Submitter: Agustín Bergé Opened: 2014-07-12 Last modified: 2015-04-08
View other active issues in [func.wrap.func].
View all other issues in [func.wrap.func].
View all issues with New status.
Discussion:
function<void(ArgTypes...)> should discard the return value of the target object. This behavior was in the original proposal, and it was removed (accidentally?) by the resolution of LWG 870.
[2014-10-05 Daniel comments]
This side-effect was indeed not intended by 870.
Proposed resolution:
Edit 20.9.12.2 [func.wrap.func] paragraph 2:
A callable object f of type F is Callable for argument types ArgTypes and return type R if the expression INVOKE(f, declval<ArgTypes>()...
, R), considered as an unevaluated operand (Clause 5), is well formed (20.9.2 [func.require]) and, if R is not void, implicitly convertible to R.
Section: 20.7.5 [ptr.align] Status: New Submitter: Melissa Mears Opened: 2014-08-06 Last modified: 2015-04-08
View all other issues in [ptr.align].
View all issues with New status.
Discussion:
The specification of std::align does not appear to specify what happens when the value of the size parameter is 0. (The question of what happens when alignment is 0 is mentioned in another Defect Report, 2377; it would change the behavior to be undefined rather than potentially implementation-defined.)
The case of size being 0 is interesting because the result is ambiguous. Consider the following code's output:#include <cstdio> #include <memory> int main() { alignas(8) char buffer[8]; void *ptr = &buffer[1]; std::size_t space = sizeof(buffer) - sizeof(char[1]); void *result = std::align(8, 0, ptr, space); std::printf("%d %td\n", !!result, result ? (static_cast<char*>(result) - buffer) : std::ptrdiff_t(-1)); }
There are four straightforward answers as to what the behavior of std::align with size 0 should be:
The behavior is undefined because the size is invalid.
The behavior is implementation-defined. This seems to be the status quo, with current implementations using #3.
Act the same as size == 1, except that if size == 1 would fail but would be defined and succeed if space were exactly 1 larger, the result is a pointer to the byte past the end of the ptr buffer. That is, the "aligned" version of a 0-byte object can be one past the end of an allocation. Such pointers are, of course, valid when not dereferenced (and a "0-byte object" shouldn't be), but whether that is desired is not specified in the Standard's definition of std::align, it appears. The output of the code sample is "1 8" in this case.
Act the same as size == 1; this means that returning "one past the end" is not a possible result. In this case, the code sample's output is "0 -1".
The two compilers I could get working with std::align, Visual Studio 2013 and Clang 3.4, implement #3. (Change %td to %Id on Visual Studio 2013 and earlier. 2014 and later will have %td.)
Proposed resolution:
Section: 18.3.2.4 [numeric.limits.members] Status: New Submitter: Melissa Mears Opened: 2014-08-06 Last modified: 2015-04-08
View all other issues in [numeric.limits.members].
View all issues with New status.
Discussion:
The seemingly non-normative (?) paragraph 61 (referring to N3936) describing how "most machines" define std::numeric_limits<T>::is_modulo in [numeric.limits.members] appears to have some issues, in my opinion.
-61- On most machines, this is false for floating types, true for unsigned integers, and true for signed integers.
Issues I see:
Very minor: change clause 2 to "this is false for floating point types". Other uses of the term say "floating point types" rather than just "floating types" — see nearby is_iec559, tinyness_before, etc.
is_modulo must be true for unsigned integers in order to be compliant with the Standard; this is not just for "most machines". For reference, this requirement is from [basic.fundamental] paragraph 4 with its footnote 48.
Depending on the definition of "most machines", is_modulo could be false for most machines' signed integer types. GCC, Clang and Visual Studio, the 3 most popular C++ compilers by far, by default treat signed integer overflow as undefined.
As an additional note regarding the definition of is_modulo, it seems like it should be explicitly mentioned that on an implementation for which signed integer overflow is undefined, is_modulo shall be false for signed integer types. It took bugs filed for all three of these compilers before they finally changed (or planned to change) is_modulo to false for signed types.
Proposed resolution:
Edit 18.3.2.4 [numeric.limits.members] around p60 as indicated:
static constexpr bool is_modulo;-60- True if the type is modulo.(footnote) A type is modulo if, for any operation involving +, -, or * on values of that type whose result would fall outside the range [min(),max()], the value returned differs from the true value by an integer multiple of max() - min() + 1.
-??- [Note: is_modulo shall be true for unsigned integer types (3.9.1 [basic.fundamental]). — end note] -??- [Note: is_modulo shall be false for types for which overflow is undefined on the implementation, because such types cannot meet the modulo requirement. Often, signed integer overflow is left undefined on implementations. — end note] -61- On most machines, this is false for floating point types, true for unsigned integers, and true for signed integers. -62- Meaningful for all specializations.
Section: 26.6.5 [template.slice.array], 26.6.7 [template.gslice.array], 26.6.8 [template.mask.array], 26.6.9 [template.indirect.array] Status: New Submitter: Akira Takahashi Opened: 2014-08-12 Last modified: 2015-04-08
View all other issues in [template.slice.array].
View all issues with New status.
Discussion:
I found a missing specification of the copy constructor of the following class templates:
slice_array (26.6.5 [template.slice.array])
gslice_array (26.6.7 [template.gslice.array])
mask_array (26.6.8 [template.mask.array])
indirect_array (26.6.9 [template.indirect.array])
Proposed resolution:
Before 26.6.5.2 [slice.arr.assign] insert a new sub-clause as indicated:
-?- slice_array constructors [slice.arr.cons]
slice_array(const slice_array&);-?- Effects: The constructed slice refers to the same valarray<T> object to which the argument slice refers.
Before 26.6.7.2 [gslice.array.assign] insert a new sub-clause as indicated:
-?- gslice_array constructors [gslice.array.cons]
gslice_array(const gslice_array&);-?- Effects: The constructed slice refers to the same valarray<T> object to which the argument slice refers.
Before 26.6.8.2 [mask.array.assign] insert a new sub-clause as indicated:
-?- mask_array constructors [mask.array.cons]
mask_array(const mask_array&);-?- Effects: The constructed slice refers to the same valarray<T> object to which the argument slice refers.
Before 26.6.9.2 [indirect.array.assign] insert a new sub-clause as indicated:
-?- indirect_array constructors [indirect.array.cons]
indirect_array(const indirect_array&);-?- Effects: The constructed slice refers to the same valarray<T> object to which the argument slice refers.
Section: 29.5 [atomics.types.generic] Status: Review Submitter: Jens Maurer Opened: 2014-08-14 Last modified: 2015-04-08
View other active issues in [atomics.types.generic].
View all other issues in [atomics.types.generic].
View all issues with Review status.
Discussion:
Otherwise, one could use memcpy to save and restore the value according to 3.9p2.
It seems the core language rules in 9 [class]p6 with 12.8 [class.copy]p12 (trivial copy constructor) etc. and 8.4.2 [dcl.fct.def.default]p5 (user-provided) say that the atomic types are trivially copyable, which is bad. We shouldn't rely on future core changes in that area and simply say in the library section 29.5 [atomics.types.generic] that these very special types are not trivially copyable.[2014-11 Urbana]
Lawrence:Definition of "trivially copyable" has been changing.
Doesn't hurt to add proposed change, even if the sentence is redundant
Move to Review.
[2015-02 Cologne]
GR has a minor problem with the style of the wording. VV has major issues with implementability.
[2015-03-22, Jens Maurer responses to Cologne discussion]
A library implementation could provide a partial specialization for is_trivially_copyable<atomic<T>>, to ensure that any such type query would return false.
Assuming such a specialization would be provided, how could a conforming program observe that per language rules an atomic specialization would actually be trivially copyable if there is no way to call the (deleted) copy constructor or copy assignment operator? The sole effect of the suggested addition of the constraining sentence is that it would make a user program non-conforming that attempts to invoke memcpy (and the like) on atomic types, since that would invoke undefined behaviour.Proposed resolution:
Change 29.5 [atomics.types.generic]p3 as indicated:
Specializations and instantiations of the atomic template shall have a deleted copy constructor, a deleted copy assignment operator, and a constexpr value constructor. They are not trivially copyable types (3.9 [basic.types]).
Section: 18.6.1 [new.delete] Status: Ready Submitter: Richard Smith Opened: 2014-08-29 Last modified: 2015-04-08
View other active issues in [new.delete].
View all other issues in [new.delete].
View all issues with Ready status.
Discussion:
18.6.1.1 [new.delete.single]/12 says:
Requires: ptr shall be a null pointer or its value shall be a value returned by an earlier call to the (possibly replaced) operator new(std::size_t) or operator new(std::size_t,const std::nothrow_t&) which has not been invalidated by an intervening call to operator delete(void*).
This should say:
[…] by an intervening call to operator delete(void*) or operator delete(void*, std::size_t).
Likewise at the end of 18.6.1.2 [new.delete.array]/11, operator delete[](void*, std::size_t).
[Urbana 2014-11-07: Move to Ready]
Proposed resolution:
Change 18.6.1.1 [new.delete.single]p12 as indicated:
-12- Requires: ptr shall be a null pointer or its value shall be a value returned by an earlier call to the (possibly replaced) operator new(std::size_t) or operator new(std::size_t,const std::nothrow_t&) which has not been invalidated by an intervening call to operator delete(void*) or operator delete(void*, std::size_t).
Change 18.6.1.2 [new.delete.array]p11 as indicated:
-11- Requires: ptr shall be a null pointer or its value shall be the value returned by an earlier call to operator new[](std::size_t) or operator new[](std::size_t,const std::nothrow_t&) which has not been invalidated by an intervening call to operator delete[](void*) or operator delete[](void*, std::size_t).
Section: 29.6.5 [atomics.types.operations.req] Status: SG1 Submitter: Hans Boehm Opened: 2014-08-25 Last modified: 2015-04-08
View other active issues in [atomics.types.operations.req].
View all other issues in [atomics.types.operations.req].
View all issues with SG1 status.
Discussion:
The standard is either ambiguous or misleading about the nature of accesses through the expected argument to the compare_exchange_* functions in 29.6.5 [atomics.types.operations.req]p21.
It is unclear whether the access to expected is itself atomic (intent clearly no) and exactly when the implementation is allowed to read or write it. These affect the correctness of reasonable code. Herb Sutter, summarizing a complaint from Duncan Forster wrote:Thanks Duncan,
I think we have a bug in the standardese wording and the implementations are legal, but let's check with the designers of the feature. Let me try to summarize the issue as I understand it:
What I think was intended: Lawrence, I believe you championed having compare_exchange_* take the expected value by reference, and update expected on failure to expose the old value, but this was only for convenience to simplify the calling loops which would otherwise always have to write an extra "reload" line of code. Lawrence, did I summarize your intent correctly?
What I think Duncan is trying to do: However, it turns out that, now that expected is an lvalue, it has misled(?) Duncan into trying to use the success of compare_exchange_* to hand off ownership of expected itself to another thread. For that to be safe, if the compare_exchange_* succeeds then the thread that performed it must no longer read or write from expected else his technique contains a race. Duncan, did I summarize your usage correctly? Is that the only use that is broken?
What the standard says: I can see why Duncan thinks the standard supports his use, but I don't think this was intended (I don't remember this being discussed but I may have been away for that part) and unless you tell me this was intended I think it's a defect in the standard. From 29.6.5 [atomics.types.operations.req]/21:
-21- Effects: Atomically, compares the contents of the memory pointed to by object or by this for equality with that in expected, and if true, replaces the contents of the memory pointed to by object or by this with that in desired, and if false, updates the contents of the memory in expected with the contents of the memory pointed to by object or by this. […]
I think we have a wording defect here in any case, because the "atomically" should not apply to the entire sentence — I'm pretty sure we never intended the atomicity to cover the write to expected.
As a case in point, borrowing from Duncan's mail below, I think the following implementation is intended to be legal:inline int _Compare_exchange_seq_cst_4(volatile _Uint4_t *_Tgt, _Uint4_t *_Exp, _Uint4_t _Value) { /* compare and exchange values atomically with sequentially consistent memory order */ int _Res; _Uint4_t _Prev = _InterlockedCompareExchange((volatile long *)_Tgt, _Value, *_Exp); if (_Prev == *_Exp) //!!!!! Note the unconditional read from *_Exp here _Res = 1; else { /* copy old value */ _Res = 0; *_Exp = _Prev; } return (_Res); }
I think this implementation is intended to be valid — I think the only code that could be broken with the "!!!!!" read of *_Exp is Duncan's use of treating a.compare_exchange_*(expected, desired) == true as implying expected got handed off, because then another thread could validly be using *_Exp — but we never intended this use, right?
In a different thread Richard Smith wrote about the same problem:
The atomic_compare_exchange functions are described as follows:
"Atomically, compares the contents of the memory pointed to by object or by this for equality with that in expected, and if true, replaces the contents of the memory pointed to by object or by this with that in desired, and if false, updates the contents of the memory in expected with the contents of the memory pointed to by object or by this. Further, if the comparison is true, memory is affected according to the value of success, and if the comparison is false, memory is affected according to the value of failure."
I think this is less clear than it could be about the effects of these operations on *expected in the failure case:
We have "Atomically, compares […] and updates the contents of the memory in expected […]". The update to the memory in expected is clearly not atomic, and yet this wording parallels the success case, in which the memory update is atomic.
The wording suggests that memory (including *expected) is affected according to the value of failure. In particular, the failure order could be memory_order_seq_cst, which might lead someone to incorrectly think they'd published the value of *expected.
I think this can be clarified with no change in meaning by reordering the wording a little:
"Atomically, compares the contents of the memory pointed to by object or by this for equality with that in expected, and if true, replaces the contents of the memory pointed to by object or by this with that in desired
, and if. If the comparison is true, memory is affected according to the value of success, and if the comparison is false, memory is affected according to the value of failure. Further, if the comparison is false,updatesreplaces the contents of the memory in expected with thecontents ofvalue that was atomically read from the memory pointed to by object or by this.Further, if the comparison is true, memory is affected according to the value of success, and if the comparison is false, memory is affected according to the value of failure."
Jens Maurer add:
I believe this is an improvement.
I like to see the following additional improvements:
"contents of the memory" is strange phrasing, which doesn't say how large the memory block is. Do we compare the values or the value representation of the lvalue *object (or *this)?
29.3 [atomics.order] defines memory order based on the "affected memory location". It would be better to say something like "If the comparison is true, the memory synchronization order for the affected memory location *object is […]"
There was also a discussion thread involving Herb Sutter, Hans Boehm, and Lawrence Crowl, resulting in proposed wording along the lines of:
-21- Effects: Atomically with respect to expected and the memory pointed to by object or by this, compares the contents of the memory pointed to by object or by this for equality with that in expected, and if and only if true, replaces the contents of the memory pointed to by object or by this with that in desired, and if and only if false, updates the contents of the memory in expected with the contents of the memory pointed to by object or by this.
At the end of paragraph 23, perhaps add
[Example: Because the expected value is updated only on failure, code releasing the memory containing the expected value on success will work. E.g. list head insertion will act atomically and not have a data race in the following code.
do { p->next = head; // make new list node point to the current head } while(!head.compare_exchange_weak(p->next, p)); // try to insert— end example]
Hans objected that this still gives the misimpression that the update to expected is atomic.
[2014-11 Urbana]
Proposed resolution was added after Redmond.
Recommendations from SG1:
(wording edits not yet applied)
[2015-02 Cologne]
Handed over to SG1.
Proposed resolution:
Edit 29.6.5 [atomics.types.operations.req] p21 as indicated:
-21- Effects: Retrieves the value in expected. It then a
Atomically,compares the contents of the memory pointed to by object or by this for equality with thatinpreviously retrieved from expected, and if true, replaces the contents of the memory pointed to by object or by this with that in desired, and if false, updates the contents of the memory in expected with the contents of the memory pointed to by object or by this. Further, if. If and only if the comparison is true, memory is affected according to the value of success, and if the comparison is false, memory is affected according to the value of failure. When only one memory_order argument is supplied, the value of success is order, and the value of failure is order except that a value of memory_order_acq_rel shall be replaced by the value memory_order_acquire and a value of memory_order_release shall be replaced by the value memory_order_relaxed. If the comparison is false then, after the atomic operation, the contents of the memory in expected are replaced by the value read from object or by this during the atomic comparison. If the operation returns true, these operations are atomic read-modify-write operations (1.10) on the memory pointed to by this or object. Otherwise, these operations are atomic load operations on that memory.
Add the following example to the end of 29.6.5 [atomics.types.operations.req] p23:
-23- [Note: […] — end note] [Example: […] — end example]
[Example: Because the expected value is updated only on failure, code releasing the memory containing the expected value on success will work. E.g. list head insertion will act atomically and would not introduce a data race in the following code:do { p-i>next = head; // make new list node point to the current head } while(!head.compare_exchange_weak(p->next, p)); // try to insert— end example]
Section: 23.3.1 [sequences.general] Status: Ready Submitter: Tim Song Opened: 2014-08-29 Last modified: 2015-04-08
View all issues with Ready status.
Discussion:
LWG 2194 removed "These container adaptors meet the requirements for sequence containers." from 23.6.1 [container.adaptors.general].
However, N3936 23.3.1 [sequences.general]/p2 still says "The headers <queue> and <stack> define container adaptors (23.6) that also meet the requirements for sequence containers." I assume this is just an oversight.[Urbana 2014-11-07: Move to Ready]
Proposed resolution:
Delete paragraph 2 of 23.3.1 [sequences.general] as indicated:
-2- The headers <queue> and <stack> define container adaptors (23.6) that also meet the requirements for sequence containers.
Section: 17.6.2.2 [using.headers] Status: Ready Submitter: Tim Song Opened: 2014-09-03 Last modified: 2015-04-08
View all other issues in [using.headers].
View all issues with Ready status.
Discussion:
17.6.2.2 [using.headers]/3 says
A translation unit shall include a header only outside of any external declaration or definition […]
This wording appears to be borrowed from the C standard. However, the term "external declaration" is not defined in the C++ standard, and in fact is only used here as far as I can tell, so it is unclear what it means. The C standard does define external declarations as (WG14 N1570 6.9 External definitions/4-5):
As discussed in 5.1.1.1, the unit of program text after preprocessing is a translation unit, which consists of a sequence of external declarations. These are described as "external" because they appear outside any function (and hence have file scope). [...] An external definition is an external declaration that is also a definition of a function (other than an inline definition) or an object.
The corresponding description of a translation unit in C++ is "A translation unit consists of a sequence of declarations." (3.5 [basic.link]/3).
So it appears that the C++ counterpart of "external declaration" in C is simply a "declaration" at file scope. There is no need to specifically limit the statement in 17.6.2.2 [using.headers]/3 to file-scope declarations, however, since every non-file-scope declaration is necessarily inside a file-scope declaration, so banning including a header inside file-scope declarations necessarily bans including one inside non-file-scope declarations as well.[Urbana 2014-11-07: Move to Ready]
Proposed resolution:
This wording is relative to N3936.
Edit 17.6.2.2 [using.headers] as indicated:
A translation unit shall include a header only outside of any
externaldeclaration or definition, and shall include the header lexically before the first reference in that translation unit to any of the entities declared in that header. No diagnostic is required.
Section: 23.2.4 [associative.reqmts] Status: LEWG Submitter: Tomasz Kamiński Opened: 2014-07-14 Last modified: 2015-04-08
View other active issues in [associative.reqmts].
View all other issues in [associative.reqmts].
View all issues with LEWG status.
Discussion:
Currently the heterogeneous lookup in associative container are enabled by presence of is_transparent nested type in the comparator type (23.2.4 [associative.reqmts]). This complicates the definition of call wrapper types that want to define is_transparent if they wrap a callable type that defines is_transparent, and requires the target to be a complete type in cases where an incomplete type would otherwise be ok.
Another problem is that users cannot add the is_transparent member to a third-party comparison type that they do not control, even if they know it supports heterogeneous comparisons. If the associative containers used a trait instead of checking for an is_transparent member type then it would avoid the requirement for complete types, and would allow customization of the trait without modifying the comparator type. This would also be consistent with the traits is_placeholder and is_bind_expression. For backward compatibility with the existing design, the default implementation of the is_transparent trait could depend on the presence of the is_transparent nested type.[2014-11 Urbana]
Move to LEWG
Request for a new metafunction should first be responded to by LEWG.
Proposed resolution:
Section: 28.3 [re.req] Status: New Submitter: Jonathan Wakely Opened: 2014-09-30 Last modified: 2015-04-08
View all issues with New status.
Discussion:
The requirements on the traits class in 28.3 [re.req] do not say whether a regular expression traits class is required to be DefaultConstructible, CopyConstructible, CopyAssignable etc.
The std::regex_traits class appears to be all of the above, but can basic_regex assume that for user-defined traits classes? Should the following statements all leave u in equivalent states?X u{v}; X u; u = v; X u; u.imbue(v.getloc();
Whether they are equivalent has implications for basic_regex copy construction and assignment.
Proposed resolution:
Section: 18.9 [support.initlist] Status: New Submitter: David Krauss Opened: 2014-09-30 Last modified: 2015-04-08
View other active issues in [support.initlist].
View all other issues in [support.initlist].
View all issues with New status.
Discussion:
std::initializer_list::operator= 18.9 [support.initlist] is horribly broken and it needs deprecation:
std::initializer_list<foo> a = {{1}, {2}, {3}}; a = {{4}, {5}, {6}}; // New sequence is already destroyed.
Assignability of initializer_list isn't explicitly specified, but most implementations supply a default assignment operator. I'm not sure what 17.5 [description] says, but it probably doesn't matter.
Proposed resolution:
Edit 18.9 [support.initlist] p1, class template initializer_list synopsis, as indicated:
namespace std { template<class E> class initializer_list { public: […] constexpr initializer_list() noexcept; initializer_list(const initializer_list&) = default; initializer_list(initializer_list&&) = default; initializer_list& operator=(const initializer_list&) = delete; initializer_list& operator=(initializer_list&&) = delete; constexpr size_t size() const noexcept; […] }; […] }
Section: 20.7.12 [specialized.algorithms] Status: Ready Submitter: Stephan T. Lavavej Opened: 2014-10-01 Last modified: 2015-04-08
View all other issues in [specialized.algorithms].
View all issues with Ready status.
Discussion:
This restriction isn't necessary anymore. In fact, this is the section that defines addressof().
(Editorial note: We can depict these algorithms as calling addressof() instead of std::addressof() thanks to 17.6.1.1 [contents]/3 "Whenever a name x defined in the standard library is mentioned, the name x is assumed to be fully qualified as ::std::x, unless explicitly described otherwise.")
[Urbana 2014-11-07: Move to Ready]
Proposed resolution:
This wording is relative to N3936.
Change 20.7.12 [specialized.algorithms] p1 as depicted:
-1-
All the iterators that are used as formal template parameters in the following algorithms are required to have their operator* return an object for which operator& is defined and returns a pointer to T.In the algorithm uninitialized_copy, the formal template parameter InputIterator is required to satisfy the requirements of an input iterator (24.2.3). In all of the following algorithms, the formal template parameter ForwardIterator is required to satisfy the requirements of a forward iterator (24.2.5), and is required to have the property that no exceptions are thrown from increment, assignment, comparison, or indirection through valid iterators. In the following algorithms, if an exception is thrown there are no effects.
Change 20.7.12.2 [uninitialized.copy] p1 as depicted:
-1- Effects:
for (; first != last; ++result, ++first) ::new (static_cast<void*>(addressof(&*result))) typename iterator_traits<ForwardIterator>::value_type(*first);
Change 20.7.12.2 [uninitialized.copy] p3 as depicted:
-3- Effects:
for (; n > 0; ++result, ++first, --n) { ::new (static_cast<void*>(addressof(&*result))) typename iterator_traits<ForwardIterator>::value_type(*first); }
Change 20.7.12.3 [uninitialized.fill] p1 as depicted:
-1- Effects:
for (; first != last; ++first) ::new (static_cast<void*>(addressof(&*first))) typename iterator_traits<ForwardIterator>::value_type(x);
Change 20.7.12.4 [uninitialized.fill.n] p1 as depicted:
-1- Effects:
for (; n--; ++first) ::new (static_cast<void*>(addressof(&*first))) typename iterator_traits<ForwardIterator>::value_type(x); return first;
Section: 20.8.2.2.5 [util.smartptr.shared.obs] Status: Ready Submitter: Stephan T. Lavavej Opened: 2014-10-01 Last modified: 2015-04-08
View other active issues in [util.smartptr.shared.obs].
View all other issues in [util.smartptr.shared.obs].
View all issues with Ready status.
Discussion:
shared_ptr and weak_ptr have Notes that their use_count() might be inefficient. This is an attempt to acknowledge reflinked implementations (which can be used by Loki smart pointers, for example). However, there aren't any shared_ptr implementations that use reflinking, especially after C++11 recognized the existence of multithreading. Everyone uses atomic refcounts, so use_count() is just an atomic load.
[Urbana 2014-11-07: Move to Ready]
Proposed resolution:
This wording is relative to N3936.
Change 20.8.2.2.5 [util.smartptr.shared.obs] p7-p10 as depicted:
long use_count() const noexcept;-7- Returns: the number of shared_ptr objects, *this included, that share ownership with *this, or 0 when *this is empty.
-8- [Note: use_count() is not necessarily efficient. — end note]bool unique() const noexcept;-9- Returns: use_count() == 1.
-10- [Note:unique() may be faster than use_count().If you are using unique() to implement copy on write, do not rely on a specific value when get() == 0. — end note]
Change 20.8.2.3.5 [util.smartptr.weak.obs] p1-p4 as depicted:
long use_count() const noexcept;-1- Returns: 0 if *this is empty; otherwise, the number of shared_ptr instances that share ownership with *this.
-2- [Note: use_count() is not necessarily efficient. — end note]bool expired() const noexcept;-3- Returns: use_count() == 0.
-4- [Note: expired() may be faster than use_count(). — end note]
Section: 20.9.4.4 [refwrap.invoke] Status: New Submitter: Stephan T. Lavavej Opened: 2014-10-01 Last modified: 2015-04-08
View all issues with New status.
Discussion:
20.9.4.4 [refwrap.invoke]/2 is no longer useful. (It was originally TR1 2.1.2.4 [tr.util.refwrp.invoke]/2.) First, we already have the As If Rule (1.9 [intro.execution]/1) and the STL Implementers Can Be Sneaky Rule (17.6.5.5 [member.functions]). Second, with variadic templates and other C++11/14 tech, this can be implemented exactly as depicted.
Proposed resolution:
This wording is relative to N3936.
Change 20.9.4.4 [refwrap.invoke] p2 as depicted:
template <class... ArgTypes> result_of_t<T&(ArgTypes&&...)> operator()(ArgTypes&&... args) const;-1- Returns: INVOKE(get(), std::forward<ArgTypes>(args)...). (20.9.2)
-2- Remark: operator() is described for exposition only. Implementations are not required to provide an actual reference_wrapper::operator(). Implementations are permitted to support reference_wrapper function invocation through multiple overloaded operators or through other means.
Section: 23.2.4 [associative.reqmts], 23.2.5 [unord.req] Status: LEWG Submitter: Stephan T. Lavavej Opened: 2014-10-01 Last modified: 2015-04-08
View other active issues in [associative.reqmts].
View all other issues in [associative.reqmts].
View all issues with LEWG status.
Discussion:
The associative container requirements attempt to permit comparators that are DefaultConstructible but non-CopyConstructible. However, the Standard contradicts itself. 23.4.4.1 [map.overview] depicts map() : map(Compare()) { } which requires both DefaultConstructible and CopyConstructible.
Unlike fine-grained element requirements (which are burdensome for implementers, but valuable for users), such fine-grained comparator requirements are both burdensome for implementers (as the Standard's self-contradiction demonstrates) and worthless for users. We should unconditionally require CopyConstructible comparators. (Note that DefaultConstructible should remain optional; this is not problematic for implementers, and allows users to use lambdas.) Key equality predicates for unordered associative containers are also affected. However, 17.6.3.4 [hash.requirements]/1 already requires hashers to be CopyConstructible, so 23.2.5 [unord.req]'s redundant wording should be removed.[2015-02, Cologne]
GR: I prefer to say "Compare" rather than "X::key_compare", since the former is what the user supplies. JY: It makes sense to use "Compare" when we talk about requirements but "key_compare" when we use it.
AM: We're adding requirements here, which is a breaking change, even though nobody will ever have had a non-CopyConstructible comparator. But the simplification is probably worth it. GR: I don't care about unmovable containers. But I do worry that people might want to move they comparators. MC: How do you reconcile that with the function that says "give me the comparator"? GR: That one returns by value? JY: Yes. [To MC] You make it a requirement of that function. [To GR] And it [the key_comp() function] is missing its requirements. We need to add them everywhere. GR: map already has the right requirements. JM: I dispute this. If in C++98 a type wasn't copyable, it had some interesting internal state, but in C++98 you wouldn't have been able to pass it into the container since you would have had to make a copy. JY: No, you could have default-constructed it and never moved it, e.g. a mutex. AM: So, it's a design change, but one that we should make. That's probably an LEWG issue. AM: There's a contradiction in the Standard here, and we need to fix it one way or another. Conclusion: Move to LEWGProposed resolution:
This wording is relative to N3936.
Change 23.2.4 [associative.reqmts] Table 102 as indicated (Editorial note: For "expression" X::key_compare "defaults to" is redundant with the class definitions for map/etc.):
Table 102 — Associative container requirements Expression Return type Assertion/note pre-/post-condition Complexity … X::key_compare Compare defaults to less<key_type>
Requires: key_compare is CopyConstructible.compile time … X(c)
X a(c);Requires: key_compare is CopyConstructible.
Effects: Constructs an empty container. Uses a copy of c as a comparison object.constant … X(i,j,c)
X a(i,j,c);Requires: key_compare is CopyConstructible.
value_type is EmplaceConstructible into X from *i.
Effects: Constructs […][…] …
Change 23.2.5 [unord.req] Table 103 as indicated:
Table 103 — Unordered associative container requirements (in addition to container) Expression Return type Assertion/note pre-/post-condition Complexity … X::key_equal Pred Requires: Pred is CopyConstructible.
Pred shall be a binary predicate that takes two arguments of type Key.
Pred is an equivalence relation.compile time … X(n, hf, eq)
X a(n, hf, eq);X Requires: hasher and key_equal are CopyConstructible.
Effects: Constructs […][…] … X(n, hf)
X a(n, hf);X Requires: hasher is CopyConstructible and
key_equal is DefaultConstructible
Effects: Constructs […][…] … X(i, j, n, hf, eq)
X a(i, j, n, hf, eq);X Requires: hasher and key_equal are CopyConstructible.
value_type is EmplaceConstructible into X from *i.
Effects: Constructs […][…] … X(i, j, n, hf)
X a(i, j, n, hf);X Requires: hasher is CopyConstructible and
key_equal is DefaultConstructible
value_type is EmplaceConstructible into X from *i.
Effects: Constructs […][…] …
Section: 24.2.2 [iterator.iterators] Status: Tentatively Ready Submitter: Stephan T. Lavavej Opened: 2014-10-01 Last modified: 2015-04-08
View all other issues in [iterator.iterators].
View all issues with Tentatively Ready status.
Discussion:
24.2.2 [iterator.iterators]/2 requires an Iterator's *r to return reference, i.e. iterator_traits<X>::reference according to 24.2.1 [iterator.requirements.general]/11.
24.2.4 [output.iterators]/1 requires an OutputIterator's *r = o to do its job, so *r clearly can't return void. 24.4.1 [iterator.traits]/1 says: "In the case of an output iterator, the typesiterator_traits<Iterator>::difference_type iterator_traits<Iterator>::value_type iterator_traits<Iterator>::reference iterator_traits<Iterator>::pointer
may be defined as void."
This is contradictory. I suggest fixing this by moving the offending requirement down from Iterator to InputIterator, and making Iterator say that *r returns an unspecified type. This will have the following effects:Output-only iterators will inherit Iterator's "*r returns unspecified" requirement, while 24.4.1 [iterator.traits]/1 clearly permits reference/etc. to be void.
Input-or-stronger iterators (whether constant or mutable) are unaffected — they still have to satisfy "*r returns reference", they're just getting that requirement from InputIterator instead of Iterator.
[2015-02 Cologne]
EF: This is related to 2438. MC: I'd like to take up 2438 right after this.
AM: Does anyone think this is wrong? GR: Why do we give output iterators to have reference type void? AM: we've mandated that certain output iterators define it as void since 1998. GR: Oh OK, I'm satisfied. Accepted. And 2438 is already Ready.Proposed resolution:
This wording is relative to N3936.
In 24.2.2 [iterator.iterators] Table 106 "Iterator requirements" change as indicated:
Table 106 — Iterator requirements Expression Return type Operational
semanticsAssertion/note pre-/post-condition *r referenceunspecifiedpre: r is dereferenceable. …
In 24.2.3 [input.iterators] Table 107 "Input iterator requirements" change as indicated:
Table 107 — Input iterator requirements (in addition to Iterator) Expression Return type Operational
semanticsAssertion/note pre-/post-condition … *a reference, convertible to T […] …
Section: 24.4.2 [iterator.basic] Status: Ready Submitter: Stephan T. Lavavej Opened: 2014-10-01 Last modified: 2015-04-08
View all issues with Ready status.
Discussion:
For LWG convenience, nine STL iterators are depicted as deriving from std::iterator to get their iterator_category/etc. typedefs. Unfortunately (and unintentionally), this also mandates the inheritance, which is observable (not just through is_base_of, but also overload resolution). This is unfortunate because it confuses users, who can be misled into thinking that their own iterators must derive from std::iterator, or that overloading functions to take std::iterator is somehow meaningful. This is also unintentional because the STL's most important iterators, the container iterators, aren't required to derive from std::iterator. (Some are even allowed to be raw pointers.) Finally, this unnecessarily constrains implementers, who may not want to derive from std::iterator. (For example, to simplify debugger views.)
We could add wording to 24.4.2 [iterator.basic] saying that any depicted inheritance is for exposition only, but that wouldn't really solve reader confusion. Replacing the depicted inheritance with direct typedefs will prevent confusion. Note that implementers won't be required to change their code — they are free to continue deriving from std::iterator if they want. (Editorial note: The order of the typedefs follows the order of std::iterator's template parameters.)[Urbana 2014-11-07: Move to Ready]
Proposed resolution:
This wording is relative to N3936.
Change 20.7.10 [storage.iterator], class template raw_storage_iterator synopsis, as depicted:
template <class OutputIterator, class T> class raw_storage_iterator: public iterator<output_iterator_tag,void,void,void,void>{ public: typedef output_iterator_tag iterator_category; typedef void value_type; typedef void difference_type; typedef void pointer; typedef void reference; explicit raw_storage_iterator(OutputIterator x); […] };
Change 24.5.1.1 [reverse.iterator], class template reverse_iterator synopsis, as depicted (editorial note: this reorders "reference, pointer" to "pointer, reference" and aligns whitespace):
template <class Iterator> class reverse_iterator: public iterator<typename iterator_traits<Iterator>::iterator_category, typename iterator_traits<Iterator>::value_type, typename iterator_traits<Iterator>::difference_type, typename iterator_traits<Iterator>::pointer, typename iterator_traits<Iterator>::reference>{ public:typedef Iterator iterator_type; typedef typename iterator_traits<Iterator>::difference_type difference_type; typedef typename iterator_traits<Iterator>::reference reference; typedef typename iterator_traits<Iterator>::pointer pointer;typedef Iterator iterator_type; typedef typename iterator_traits<Iterator>::iterator_category iterator_category; typedef typename iterator_traits<Iterator>::value_type value_type; typedef typename iterator_traits<Iterator>::difference_type difference_type; typedef typename iterator_traits<Iterator>::pointer pointer; typedef typename iterator_traits<Iterator>::reference reference; reverse_iterator(); […] };
Change 24.5.2.1 [back.insert.iterator], class template back_insert_iterator synopsis, as depicted:
template <class Container> class back_insert_iterator: public iterator<output_iterator_tag,void,void,void,void>{ protected: Container* container; public: typedef output_iterator_tag iterator_category; typedef void value_type; typedef void difference_type; typedef void pointer; typedef void reference; typedef Container container_type; explicit back_insert_iterator(Container& x); […] };
Change 24.5.2.3 [front.insert.iterator], class template front_insert_iterator synopsis, as depicted:
template <class Container> class front_insert_iterator: public iterator<output_iterator_tag,void,void,void,void>{ protected: Container* container; public: typedef output_iterator_tag iterator_category; typedef void value_type; typedef void difference_type; typedef void pointer; typedef void reference; typedef Container container_type; explicit front_insert_iterator(Container& x); […] };
Change 24.5.2.5 [insert.iterator], class template insert_iterator synopsis, as depicted:
template <class Container> class insert_iterator: public iterator<output_iterator_tag,void,void,void,void>{ protected: Container* container; typename Container::iterator iter; public: typedef output_iterator_tag iterator_category; typedef void value_type; typedef void difference_type; typedef void pointer; typedef void reference; typedef Container container_type; insert_iterator(Container& x, typename Container::iterator i); […] };
Change 24.6.1 [istream.iterator], class template istream_iterator synopsis, as depicted:
template <class T, class charT = char, class traits = char_traits<charT>, class Distance = ptrdiff_t> class istream_iterator: public iterator<input_iterator_tag, T, Distance, const T*, const T&>{ public: typedef input_iterator_tag iterator_category; typedef T value_type; typedef Distance difference_type; typedef const T* pointer; typedef const T& reference; […] };
Change 24.6.2 [ostream.iterator], class template ostream_iterator synopsis, as depicted:
template <class T, class charT = char, class traits = char_traits<charT>> class ostream_iterator: public iterator<output_iterator_tag, void, void, void, void>{ public: typedef output_iterator_tag iterator_category; typedef void value_type; typedef void difference_type; typedef void pointer; typedef void reference; […] };
Change 24.6.3 [istreambuf.iterator], class template istreambuf_iterator synopsis, as depicted:
template <class charT = char, class traits = char_traits<charT> > class istreambuf_iterator: public iterator<input_iterator_tag, charT, typename traits::off_type, unspecified, charT>{ public: typedef input_iterator_tag iterator_category; typedef charT value_type; typedef typename traits::off_type difference_type; typedef unspecified pointer; typedef charT reference; […] };
Change 24.6.4 [ostreambuf.iterator], class template ostreambuf_iterator synopsis, as depicted (editorial note: this removes a redundant "public:"):
template <class charT = char, class traits = char_traits<charT>> class ostreambuf_iterator: public iterator<output_iterator_tag, void, void, void, void>{ public: typedef output_iterator_tag iterator_category; typedef void value_type; typedef void difference_type; typedef void pointer; typedef void reference; […]public:[…] };
Section: 25.3.9 [alg.unique] Status: Ready Submitter: Stephan T. Lavavej Opened: 2014-10-01 Last modified: 2015-04-08
View all other issues in [alg.unique].
View all issues with Ready status.
Discussion:
unique_copy()'s wording says that if it's given input-only and output-only iterators, it needs the input's value type to be copyable. This is correct, because in this case the algorithm must have a local element copy in order to detect duplicates.
The wording also says that if it's given an InputIterator that's forward or stronger, the input's value type doesn't have to be copyable. This is also correct, because in this case the algorithm can reread the input in order to detect duplicates. Finally, the wording says that if it's given an input-only iterator with an OutputIterator that's forward or stronger, the input's value type doesn't have to be copyable. This is telling the algorithm to compare its input to its output in order to detect duplicates, but that isn't always possible! If the input and output have the same value type, then they can be compared (as long as *result = *first behaves sanely; see below). If they have different value types, then we can't compare them. This could be resolved by requiring heterogeneous value types to be comparable in this situation, but that would be extremely tricky to wordsmith (as it would challenge the concept of "group of equal elements" used by the Effects). It will be vastly simpler and more effective to extend the "local element copy" requirement to this scenario. Note that the input-only, output forward-or-stronger, identical value types scenario needs a bit of work too. We always require *result = *first to be "valid", but in this case we need to additionally require that the assignment actually transfers the value. (Otherwise, we'd be allowing an op=() that ignores *first and always sets *result to zero, or other unacceptable behavior.) This is just CopyAssignable. (What happens when unique_copy() is given a move_iterator is a separate issue.) To summarize:input forward+: no additional requirements
input-only, output forward+, same value types: needs CopyAssignable input-only, output forward+, different value types: needs CopyConstructible and CopyAssignable input-only, output-only: needs CopyConstructible and CopyAssignable
[Urbana 2014-11-07: Move to Ready]
Proposed resolution:
This wording is relative to N3936.
Change 25.3.9 [alg.unique] p5, as depicted:
template<class InputIterator, class OutputIterator> OutputIterator unique_copy(InputIterator first, InputIterator last, OutputIterator result); template<class InputIterator, class OutputIterator, class BinaryPredicate> OutputIterator unique_copy(InputIterator first, InputIterator last, OutputIterator result, BinaryPredicate pred);-5- Requires: The comparison function shall be an equivalence relation. The ranges [first,last) and [result,result+(last-first)) shall not overlap. The expression *result = *first shall be valid.
If neither InputIterator nor OutputIterator meets the requirements of forward iterator then the value type of InputIterator shall be CopyConstructible (Table 21) and CopyAssignable (Table 23). Otherwise CopyConstructible is not required.Let T be the value type of InputIterator. If InputIterator meets the forward iterator requirements, then there are no additional requirements for T. Otherwise, if OutputIterator meets the forward iterator requirements and its value type is the same as T, then T shall be CopyAssignable (Table 23). Otherwise, T shall be both CopyConstructible (Table 21) and CopyAssignable.
Section: 26.5.7.1 [rand.util.seedseq] Status: Ready Submitter: Stephan T. Lavavej Opened: 2014-10-01 Last modified: 2015-04-08
View other active issues in [rand.util.seedseq].
View all other issues in [rand.util.seedseq].
View all issues with Ready status.
Discussion:
Obvious.
[Urbana 2014-11-07: Move to Ready]
Proposed resolution:
This wording is relative to N3936.
Change 26.5.7.1 [rand.util.seedseq], class seed_seq synopsis, as depicted:
class seed_seq { public: […] size_t size() const noexcept; […] };
Change 26.5.7.1 [rand.util.seedseq] around p10, as depicted:
size_t size() const noexcept;-10- Returns: The number of 32-bit units that would be returned by a call to param().
-11- Throws: Nothing.-12- Complexity: Constant time.
Section: 29.5 [atomics.types.generic] Status: SG1 Submitter: Stephan T. Lavavej Opened: 2014-10-01 Last modified: 2015-04-08
View other active issues in [atomics.types.generic].
View all other issues in [atomics.types.generic].
View all issues with SG1 status.
Discussion:
<atomic> doesn't provide counterparts for <inttypes.h>'s most useful typedefs, possibly because they're quasi-optional. We can easily fix this.
[2014-11, Urbana]
Typedefs were transitional compatibility hack. Should use _Atomic macro or template. E.g. _Atomic(int8_t). BUT _Atomic disappeared!
Detlef will look for _Atomic macro. If missing, will open issue.
[2014-11-25, Hans comments]
There is no _Atomic in C++. This is related to the much more general unanswered question of whether C++17 should reference C11, C99, or neither.
[2015-02 Cologne]
AM: I think this is still an SG1 issue; they need to deal with it before we do.
Proposed resolution:
This wording is relative to N3936.
Change 29.5 [atomics.types.generic] p8 as depicted:
-8- There shall be atomic typedefs corresponding to the typedefs in the header <inttypes.h> as specified in Table 147. atomic_intN_t, atomic_uintN_t, atomic_intptr_t, and atomic_uintptr_t shall be defined if and only if intN_t, uintN_t, intptr_t, and uintptr_t are defined, respectively.
Change 29.6.5 [atomics.types.operations.req], Table 147 ("atomic <inttypes.h> typedefs"), as depicted:
Table 147 — atomic <inttypes.h> typedefs Atomic typedef <inttypes.h> type atomic_int8_t int8_t atomic_uint8_t uint8_t atomic_int16_t int16_t atomic_uint16_t uint16_t atomic_int32_t int32_t atomic_uint32_t uint32_t atomic_int64_t int64_t atomic_uint64_t uint64_t …
Section: 30.4.4.2 [thread.once.callonce] Status: SG1 Submitter: Stephan T. Lavavej Opened: 2014-10-01 Last modified: 2015-04-08
View all other issues in [thread.once.callonce].
View all issues with SG1 status.
Discussion:
When LWG 891 overhauled call_once()'s specification, it used decay_copy(), following LWG 929's overhaul of thread's constructor.
In thread's constructor, this is necessary and critically important. 30.3.1.2 [thread.thread.constr]/5 "The new thread of execution executes INVOKE(DECAY_COPY(std::forward<F>(f)), DECAY_COPY(std::forward<Args>(args))...) with the calls to DECAY_COPY being evaluated in the constructing thread." requires the parent thread to copy arguments for the child thread to access. In call_once(), this is unnecessary and harmful. It's unnecessary because call_once() doesn't transfer arguments between threads. It's harmful because:decay_copy() returns a prvalue. Given meow(int&), meow(i) can be called directly, but call_once(flag, meow, i) won't compile.
decay_copy() moves from modifiable rvalues. Given purr(const unique_ptr<int>&), purr(move(up)) won't modify up. (This is observable, because moved-from unique_ptrs are guaranteed empty.) However, call_once(flag, purr, move(up)) will leave up empty after the first active execution. Observe the behavioral difference — if purr() is directly called like this repeatedly until it doesn't throw an exception, each call will observe up unchanged. With call_once(), the second active execution will observe up to be empty.
call_once() should use perfect forwarding without decay_copy(), in order to avoid interfering with the call like this.
[2015-02 Cologne]
Handed over to SG1.
Proposed resolution:
This wording is relative to N3936.
Change 30.4.4.2 [thread.once.callonce] p1+p2 as depicted:
template<class Callable, class ...Args> void call_once(once_flag& flag, Callable&& func, Args&&... args);-1- Requires:
-2- Effects; […] An active execution shall call INVOKE(Callable and each Ti in Args shall satisfy the MoveConstructible requirements.INVOKE(DECAY_COPY(std::forward<Callable>(func)),DECAY_COPY(std::forward<Args>(args))...) (20.9.2) shall be a valid expression.DECAY_COPY(std::forward<Callable>(func)),DECAY_COPY(std::forward<Args>(args))...). […]
Section: 23.3.2 [array] Status: LEWG Submitter: Peter Sommerlad Opened: 2014-10-06 Last modified: 2015-04-08
View other active issues in [array].
View all other issues in [array].
View all issues with LEWG status.
Discussion:
When experimenting with C++14 relaxed constexpr functions I made the observation that I couldn't use std::array to create a table of data at compile time directly using loops in a function. However, a simple substitute I could use instead:
template <typename T, size_t n> struct ar { T a[n]; constexpr ar() : a{{}}{} constexpr auto data() const { return &a[0];} constexpr T const & operator[](size_t i) const { return a[i]; } constexpr T & operator[](size_t i) { return a[i]; } }; template <size_t n> using arr = ar<size_t, n>; // std::array<size_t, n>; template <size_t n> constexpr auto make_tab(){ arr<n> result; for(size_t i=0; i < n; ++i) result[i] = (i+1)*(i+1); // cannot define operator[] for mutable array... return result; } template <size_t n> constexpr auto squares=make_tab< n>(); int main() { int dummy[squares<5>[3]]; }
Therefore, I suggest that all member functions of std::array should be made constexpr to make the type usable in constexpr functions.
Wording should be straight forward, may be with the exception of fill, which would require fill_n to be constexpr as well.[2014-11 Urbana]
Move to LEWG
The extent to which constexpr becomes a part of the Library design is a policy matter best handled initially by LEWG.
Proposed resolution:
Section: 25.4.6.4 [sort.heap] Status: Open Submitter: François Dumont Opened: 2014-10-07 Last modified: 2015-04-08
View all issues with Open status.
Discussion:
While creating complexity tests for the GNU libstdc++ implementation I stumbled across a surprising requirement for the std::sort_heap algorithm.
In 25.4.6.4 [sort.heap] p3 the Standard states:Complexity: At most N log(N) comparisons (where N == last - first).
As stated on the libstdc++ mailing list by Marc Glisse sort_heap can be implemented by N calls to pop_heap. As max number of comparisons of pop_heap is 2 * log(N) then sort_heap max limit should be 2 * log(1) + 2 * log(2) + .... + 2 * log(N) that is to say 2 * log(N!). In terms of log(N) we can also consider that this limit is also cap by 2 * N * log(N) which is surely what the Standard wanted to set as a limit.
This is why I would like to propose to replace paragraph 3 by:Complexity: At most 2N log(N) comparisons (where N == last - first).
[2015-02 Cologne]
Marshall will research the maths and report back in Lenexa.
Proposed resolution:
This wording is relative to N3936.
In 25.4.6.4 [sort.heap] p3 the Standard states:
template<class RandomAccessIterator> void sort_heap(RandomAccessIterator first, RandomAccessIterator last); template<class RandomAccessIterator, class Compare> void sort_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp);[…]
-3- Complexity: At most 2N log(N) comparisons (where N == last - first).
Section: 20.8.2.6 [util.smartptr.shared.atomic], 29.6.5 [atomics.types.operations.req] Status: SG1 Submitter: JF Bastien Opened: 2014-10-08 Last modified: 2015-04-08
View all other issues in [util.smartptr.shared.atomic].
View all issues with SG1 status.
Discussion:
The definitions of compare and exchange in 20.8.2.6 [util.smartptr.shared.atomic] p32 and 29.6.5 [atomics.types.operations.req] p20 state:
Requires: The failure argument shall not be memory_order_release nor memory_order_acq_rel. The failure argument shall be no stronger than the success argument.
The term "stronger" isn't defined by the standard.
It is hinted at by 29.6.5 [atomics.types.operations.req] p21:When only one memory_order argument is supplied, the value of success is order, and the value of failure is order except that a value of memory_order_acq_rel shall be replaced by the value memory_order_acquire and a value of memory_order_release shall be replaced by the value memory_order_relaxed.
Should the standard define a partial ordering for memory orders, where consume and acquire are incomparable with release?
[2014-11 Urbana]
Move to SG1.
Proposed resolution:
Section: 20.4.1 [tuple.general] Status: LEWG Submitter: Nevin Liber Opened: 2014-10-10 Last modified: 2015-04-08
View all issues with LEWG status.
Discussion:
In 20.4.1 [tuple.general] paragraph 2, the unspecialized std::tuple_size is undefined. It would be a lot more useful with SFINAE if it were defined as an empty struct; that way, it can be used with enable_if for determining whether or not it is valid to use tuple_size, tuple_element and get on the corresponding data structure.
[2014-11 Urbana]
Moved to LEWG 42.
This request goes beyond simply making an API respond well to SFINAE, but coupling that with an implication for other tuple APIs. The proper place for such design discussions is LEWG.
Proposed resolution:
This wording is relative to N3936.
Change 20.4.1 [tuple.general] p2, header <tuple> synopsis, as indicated
[…] // 20.4.2.5, tuple helper classes: template <class T> class tuple_size;// undefined[…]
Change 20.4.2.5 [tuple.helper] as indicated
[…] template <class T> struct tuple_size { }; […]
Section: 17.6.3.5 [allocator.requirements] Status: Open Submitter: Daniel Krügler Opened: 2014-10-16 Last modified: 2015-04-08
View other active issues in [allocator.requirements].
View all other issues in [allocator.requirements].
View all issues with Open status.
Discussion:
According to Table 27 — "Descriptive variable definitions" which is used to define the symbols used in the allocator requirements table within 17.6.3.5 [allocator.requirements] we have the following constraints for the types T, U, C:
any non-const object type (3.9)
This wording can be read to allow instead a volatile-qualified value type such as volatile int.
The nearest-by way of fixing this would be to add "non-volatile" as additional constraint to this table row. Another choice would be to think of requiring that allocators must be capable to handle any cv-qualified value types. This would make all currently existing allocators non-conforming that can't handle cv-qualified value types, so I'm not suggesting to follow that route. A less radical step would be to allow[2015-02 Cologne]
GR: It makes me nervous that someone at some point decided to not add "non-volatile".
AM: That was over ten years ago. It was a deliberate, minuted choice to support volatile. We are now reversing that decision.
It would be good to poll our vendors, none of which are in the room. This is a bit more work than we expect of a P0 issue.
VV: libstdc++ and libc++ seem to support volatile template parameters for the standard allocator.
AM: To clarify, the proposed resolution here would remove the requirement to support volatile. Implementations could still
choose to support volatile.
DK: I'm happy to drop this and open a new issue in regard to the destroy member specification.
AM: I just think this is harder than a P0. Let's reprioritize.
[2015-04-01 Daniel comments]
The less controversial part of the issue related to constraints imposed on destroy has be handed over to the new issue 2470.
Proposed resolution:
This wording is relative to N4140.
Change 17.6.3.5 [allocator.requirements], Table 27 — "Descriptive variable definitions", as indicated:
Table 27 — Descriptive variable definitions Variable Definition T, U , Cany non- constconst and non-volatile object type (3.9)C any object type …
Change 17.6.3.5 [allocator.requirements] p8 as indicated: (This wording change is intended to fix an obvious asymmetry between construct and destroy which I believe is not intended)
-8- An allocator may constrain the types on which it can be instantiated and the arguments for which its construct or destroy members may be called. If a type cannot be used with a particular allocator, the allocator class or the call to construct or destroy may fail to instantiate.
Section: 23.2.1 [container.requirements.general] Status: Tentatively Ready Submitter: Daniel Krügler Opened: 2014-10-18 Last modified: 2015-04-08
View other active issues in [container.requirements.general].
View all other issues in [container.requirements.general].
View all issues with Tentatively Ready status.
Discussion:
According to Table 96 — "Container requirements" the specification:
note: the destructor is applied to every element of a; any memory obtained is deallocated.
The initial "note:" can be read as if that part of the specification would not be normative (This note form differs from footnotes in tables, which have normative meaning).
It seems that this initial part of the specification exists since C++98. But comparing with the similar SGI Container specification there is no evidence for that being intended to be non-normative.[2015-02, Cologne]
NJ: If we fix this, we should also fix it elsewhere. Oh, this is the only place?
GR: If this is intended to be different from elsewhere, we should make sure.
AM: valarray specifies this without the "note:".
DK: valarray requires trivially destructible types!
GR: That's good enough for me.
NJ: First time valarray has been useful for something!
Proposed resolution:
This wording is relative to N4140.
Change 23.2.1 [container.requirements.general], Table 96 — "Container requirements", as indicated:
Table 96 — Container requirements Expression Return type Operational
semanticsAssertion/note
pre-/post-conditionComplexity … (&a)->~X() void note:the destructor
is applied to every
element of a; any
memory obtained is deallocated.linear …
Section: 23.3.6.5 [vector.modifiers] Status: New Submitter: Marc Glisse Opened: 2014-10-21 Last modified: 2015-04-08
View other active issues in [vector.modifiers].
View all other issues in [vector.modifiers].
View all issues with New status.
Discussion:
this issue is based on the discussion here.
23.3.6.5 [vector.modifiers] says about vector::insert: "If no reallocation happens, all the iterators and references before the insertion point remain valid." This doesn't seem to guarantee anything about the iterator at the point of insertion. The question comes from people asking if the following is valid, assuming a sufficient call to reserve() was done first:v.insert(v.end(), v.begin(), v.end());
It could fail for an implementation using a sentinel for the end of the vector, but I don't know of any (it would be quite inconvenient). And for any implementation using a simple position as iterator (pointer (possibly in a wrapper), or base+offset), this is needlessly restrictive. The fact that this alternative:
v.insert(v.end(), &v[0], &v[0]+v.size())
is arguably valid (again assuming a large enough reserve()) makes it a bit confusing that the first version isn't (23.2.3 [sequence.reqmts] has a precondition that iterator arguments to insert() do not point into the sequence, but vector::insert is more refined and seems to give enough guarantees that it cannot fail).
Then we might as well say that vector iterators act as positions, and that after a reallocation-free operation an iterator points to the same position, whatever may be there now…Proposed resolution:
Section: 20.9.6 [comparisons] Status: New Submitter: Joaquín M López Muñoz Opened: 2014-10-30 Last modified: 2015-04-08
View other active issues in [comparisons].
View all other issues in [comparisons].
View all issues with New status.
Discussion:
less<void>::operator(t, u) (and the same applies to the rest of void specializations for standard comparison function objects) returns t < u even if t and u are pointers, which by 5.9 [expr.rel]/3 is undefined except if both pointers point to the same array or object. This might be regarded as a specification defect since the intention of N3421 is that less<> can substitute for less<T> in any case where the latter is applicable. less<void> can be rewritten in the following manner to cope with pointers:
template<> struct less<void> { typedef unspecified is_transparent; template <class T, class U> struct pointer_overload : std::is_pointer<std::common_type_t<T, U>> {}; template < class T, class U, typename std::enable_if<!pointer_overload<T, U>::value>::type* = nullptr > auto operator()(T&& t, U&& u) const -> decltype(std::forward<T>(t) < std::forward<U>(u)) { return std::forward<T>(t) < std::forward<U>(u); } template < class T, class U, typename std::enable_if<pointer_overload<T, U>::value>::type* = nullptr > auto operator()(T&& t, U&& u) const -> decltype(std::declval<std::less<std::common_type_t<T, U>>>()(std::forward<T>(t), std::forward<U>(u))) { std::less<std::common_type_t<T, U>> l; return l(std::forward<T>(t), std::forward<U>(u)); } };
This wording is relative to N4140.
Change 20.9.6 [comparisons] p14 as indicated:
-14- For templates greater, less, greater_equal, and less_equal, the specializations for any pointer type yield a total order, even if the built-in operators <, >, <=, >= do not. For template specializations greater<void>, less<void>, greater_equal<void>, and less_equal<void>, the call operator with arguments whose common type CT is a pointer yields the same value as the corresponding comparison function object class specialization for CT.
[2015-02, Cologne]
AM: Is there any way this will be resolved elsewhere? VV: No. AM: Then we should bite the bullet and deal with it here.
MC: These diamond operators are already ugly. Making them more ugly isn't a big problem. JY found some issue with types that are convertible, and will reword. Jeffrey suggests improved wording.Proposed resolution:
This wording is relative to N4296.
Change 20.9.6 [comparisons] p14 as indicated:
-14- For templates greater, less, greater_equal, and less_equal, the specializations for any pointer type yield a total order, even if the built-in operators <, >, <=, >= do not. For template specializations greater<void>, less<void>, greater_equal<void>, and less_equal<void>, if the call operator calls a built-in operator comparing pointers, the call operator yields a total order.
Section: X [optional.object] Status: LEWG Submitter: Geoffrey Romer Opened: 2014-10-31 Last modified: 2015-04-08
View all issues with LEWG status.
Discussion:
Addresses: fund.ts
Code such as the following is currently ill-formed (thanks to STL for the compelling example):
optional<string> opt_str = "meow";
This is because it would require two user-defined conversions (from const char* to string, and from string to optional<string>) where the language permits only one. This is likely to be a surprise and an inconvenience for users.
optional<T> should be implicitly convertible from any U that is implicitly convertible to T. This can be implemented as a non-explicit constructor template optional(U&&), which is enabled via SFINAE only if is_convertible_v<U, T> and is_constructible_v<T, U>, plus any additional conditions needed to avoid ambiguity with other constructors (see N4064, particularly the "Odd" example, for why is_convertible and is_constructible are both needed; thanks to Howard Hinnant for spotting this). In addition, we may want to support explicit construction from U, which would mean providing a corresponding explicit constructor with a complementary SFINAE condition (this is the single-argument case of the "perfect initialization" pattern described in N4064).Proposed resolution:
Section: 20.10 [meta] Status: Core Submitter: Hubert Tong Opened: 2014-11-04 Last modified: 2015-04-08
View other active issues in [meta].
View all other issues in [meta].
View all issues with Core status.
Discussion:
The BaseCharacteristic for is_constructible is defined in terms of the well-formedness of a declaration for an invented variable. The well-formedness of the described declaration itself may change for the same set of arguments because of the introduction of default arguments.
In the following program, there appears to be conflicting definitions of a specialization of std::is_constructible; however, it seems that this situation is caused without a user violation of the library requirements or the ODR. There is a similar issue with is_convertible, result_of and others. a.cc:#include <type_traits> struct A { A(int, int); }; const std::false_type& x1 = std::is_constructible<A, int>(); int main() { }
b.cc:
#include <type_traits> struct A { A(int, int); }; inline A::A(int, int = 0) { } const std::true_type& x2 = std::is_constructible<A, int>();
Presumably this program should invoke undefined behaviour, but the Library specification doesn't say that.
[2015-02 Cologne]
Core wording should say "this kind of thing is ill-formed, no diagnostic required"
Proposed resolution:
Section: 18.9 [support.initlist], 24.7 [iterator.range], 24.8 [iterator.container] Status: New Submitter: Richard Smith Opened: 2014-11-11 Last modified: 2015-04-08
View other active issues in [support.initlist].
View all other issues in [support.initlist].
View all issues with New status.
Discussion:
These sections define helper functions, some of which apply to initializer_list<T>. And they're available if you include one of a long list of header files, many of which include <initializer_list>. But they are not available if you include <initializer_list>. This seems very odd.
#include <initializer_list> auto x = {1, 2, 3}; const int *p = data(x); // error, undeclared #include <vector> const int *q = data(x); // ok
Proposed resolution:
Section: 20.7.10 [storage.iterator] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2014-11-11 Last modified: 2015-04-08
View other active issues in [storage.iterator].
View all other issues in [storage.iterator].
View all issues with Tentatively Ready status.
Discussion:
Eric Niebler pointed out that raw_storage_iterator should give access to the OutputIterator it wraps.
This helps alleviate the exception-safety issue pointed out in the discussion of LWG 2127, as an exception can be caught and then destructors can be run for the constructed elements in the range [begin, raw.base())[2015-02 Cologne]
NJ: Is this "const" correct [in "base()"]? DK: Yes, we always do that. NJ: And the output iterator is not qualifying in any way? AM/DK: That wouldn't make sense. NJ: OK.
VV: What did LEWG say about this feature request? In other words, why is this a library issue? AM: LEWG/JY thought this wouldn't be a contentious issue. NJ: I really hope the split of LEWG and LWG will be fixed soon, since it's only wasting time. VV: So you want to spend even more of your time on discussions that LEWG has? AM: I think this specified correctly. I'm not wild about it. But no longer bothered to stand in its way. GR: Why do we need to repeat the type in "Returns" even though it's part of the synopsis? AM: Good point, but not worth fixing. NJ: Why is "base()" for reverse_iterator commented with "// explicit"? AM: I guess in 1998 that was the only way to say this. AM: So, it's tentatively ready.Proposed resolution:
This wording is relative to N4140.
Add a new function to the synopsis in 20.7.10 [storage.iterator] p1:
namespace std { template <class OutputIterator, class T> class raw_storage_iterator : public iterator<output_iterator_tag,void,void,void,void> { public: explicit raw_storage_iterator(OutputIterator x); raw_storage_iterator<OutputIterator,T>& operator*(); raw_storage_iterator<OutputIterator,T>& operator=(const T& element); raw_storage_iterator<OutputIterator,T>& operator++(); raw_storage_iterator<OutputIterator,T> operator++(int); OutputIterator base() const; }; }
Insert the new function and a new paragraph series after p7:
OutputIterator base() const;-?- Returns: An iterator of type OutputIterator that points to the same value as *this points to.
Section: 17.6.3.5 [allocator.requirements] Status: Tentatively Ready Submitter: Pablo Halpern Opened: 2014-11-11 Last modified: 2015-04-08
View other active issues in [allocator.requirements].
View all other issues in [allocator.requirements].
View all issues with Tentatively Ready status.
Discussion:
17.6.3.5 [allocator.requirements]/4 in the 2014-10 WP (N4140), says:
An allocator type X shall satisfy the requirements of CopyConstructible (17.6.3.1). The X::pointer, X::const_pointer, X::void_pointer, and X::const_void_pointer types shall satisfy the requirements of NullablePointer (17.6.3.3). No constructor, comparison operator, copy operation, move operation, or swap operation on these types shall exit via an exception. X::pointer and X::const_pointer shall also satisfy the requirements for a random access iterator (24.2).
The words "these types" would normally apply only to the previous sentence only, i.e., only to the pointer types. However, an alternative reading would be that the allocator constructors themselves cannot throw. The change to the vector and string default constructors, making them unconditionally noexcept depends on this alternative reading.
I believe that the wording in the standard is not intended to forbid throwing default constructors for allocators. Indeed, I believe that allocators do not require default constructors and that if they provide a default constructor they should be allowed to throw. In addition, the noexcept specifications for the string and vector default constructors should be changed to make them conditional.[2015-01-18 Library reflector vote]
The issue has been identified as Tentatively Ready based on six votes in favour.
Proposed resolution:
Change 17.6.3.5 [allocator.requirements] p4 as indicated:
An allocator type X shall satisfy the requirements of CopyConstructible (17.6.3.1). The X::pointer, X::const_pointer, X::void_pointer, and X::const_void_pointer types shall satisfy the requirements of NullablePointer (17.6.3.3). No constructor, comparison operator, copy operation, move operation, or swap operation on these pointer types shall exit via an exception. X::pointer and X::const_pointer shall also satisfy the requirements for a random access iterator (24.2).
Change 21.4 [basic.string] following p5, class template basic_string synopsis, as indicated: (This change assumes that N4258 has been applied, as voted on in Urbana on 2014-11-08)
// 21.4.2, construct/copy/destroy: basic_string() noexcept(noexcept(Allocator())) : basic_string(Allocator()) { }
An alternative formulation of the above would be:
// 21.4.2, construct/copy/destroy: basic_string() noexcept(is_nothrow_default_constructible<Allocator>{}) : basic_string(Allocator()) { }
Change 23.3.6.1 [vector.overview] following p2, class template vector synopsis, as indicated: (This change assumes that N4258 has been applied, as voted on in Urbana on 2014-11-08)
// 23.3.6.2, construct/copy/destroy: vector() noexcept(noexcept(Allocator())) : vector(Allocator()) { }
An alternative formulation of the above would be:
// 23.3.6.2, construct/copy/destroy: vector() noexcept(is_nothrow_default_constructible<Allocator>{}) : vector(Allocator()) { }
Section: 20.2 [utility], 20.3.2 [pairs.pair], 20.4 [tuple], 23.3.2 [array], 23.6.3 [queue], 23.6.4 [priority.queue], 23.6.5 [stack] Status: New Submitter: Richard Smith Opened: 2014-11-14 Last modified: 2015-04-08
View other active issues in [utility].
View all other issues in [utility].
View all issues with New status.
Discussion:
We have this antipattern in various library classes:
void swap(priority_queue& q) noexcept( noexcept(swap(c, q.c)) && noexcept(swap(comp, q.comp)))
This doesn't work. The unqualified lookup for 'swap' finds the member named 'swap', and that suppresses ADL, so the exception specification is always ill-formed because you can't call the member 'swap' with two arguments.
Relevant history on the core language side: This used to be ill-formed due to 3.3.7 [basic.scope.class] p1 rule 2: "A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. No diagnostic is required for a violation of this rule." Core issue 1330 introduced delay-parsing for exception specifications. Due to the 3.3.7 [basic.scope.class] rules, this shouldn't have changed the behavior of any conforming programs. But it changes the behavior in the non-conforming case from "no diagnostic required" to "diagnostic required", so implementations that implement core issue 1330 are now required to diagnose the ill-formed declarations in the standard library. Suggested resolution: Add an is_nothrow_swappable trait, and use it throughout the library in place of these noexcept expressions.[2015-02, Cologne]
No action for now; we intend to have papers for Lenexa.
Proposed resolution:
Section: 24.7 [iterator.range] Status: New Submitter: Janez Žemva Opened: 2014-11-16 Last modified: 2015-04-08
View other active issues in [iterator.range].
View all other issues in [iterator.range].
View all issues with New status.
Discussion:
The following code:
#include <algorithm> #include <iterator> #include <iostream> #include <cassert> int main() { int a[2][3][4] = { { { 1, 2, 3, 4}, { 5, 6, 7, 8}, { 9, 10, 11, 12} }, { {13, 14, 15, 16}, {17, 18, 19, 20}, {21, 22, 23, 24} } }; int b[2][3][4]; assert(std::distance(std::begin(a), std::end(a)) == 2 * 3 * 4); std::copy(std::begin(a), std::end(a), std::begin(b)); std::copy(std::begin(b), std::end(b), std::ostream_iterator<int>(std::cout, ",")); }
does not compile.
A possible way to remedy this would be to add the following overloads of begin, end, rbegin, and rend to 24.7 [iterator.range], relying on recursive evaluation:namespace std { template <typename T, size_t M, size_t N> constexpr remove_all_extents_t<T>* begin(T (&array)[M][N]) { return begin(*array); } template <typename T, size_t M, size_t N> constexpr remove_all_extents_t<T>* end(T (&array)[M][N]) { return end(array[M - 1]); } template <typename T, size_t M, size_t N> reverse_iterator<remove_all_extents_t<T>*> rbegin(T (&array)[M][N]) { return decltype(rbegin(array))(end(array[M - 1])); } template <typename T, size_t M, size_t N> reverse_iterator<remove_all_extents_t<T>*> rend(T (&array)[M][N]) { return decltype(rend(array))(begin(*array)); } }
Proposed resolution:
Section: 18.6 [support.dynamic], 18.6.1.1 [new.delete.single], 18.6.1.2 [new.delete.array] Status: Tentatively Ready Submitter: Richard Smith Opened: 2014-11-23 Last modified: 2015-04-08
View all issues with Tentatively Ready status.
Discussion:
N3778 added the following sized deallocation signatures to the library:
void operator delete(void* ptr, std::size_t size) noexcept; void operator delete[](void* ptr, std::size_t size) noexcept; void operator delete(void* ptr, std::size_t size, const std::nothrow_t&) noexcept; void operator delete[](void* ptr, std::size_t size, const std::nothrow_t&) noexcept;
The former two are an essential part of the proposal. The latter two seem spurious — they are not called when new (std::nothrow) X fails due to X::X() throwing, because the core language rules for selecting a placement deallocation function do not consider passing a size argument. Instead, the above would be the matching deallocation functions for:
void *operator new(std::size_t size, std::size_t size_again, const std::nothrow_t&) noexcept; void *operator new[](std::size_t size, std::size_t size_again, const std::nothrow_t&) noexcept;
... which don't exist.
Since they're not implicitly called, the only other possible use for those functions would be to perform an explicitly non-throwing deallocation. But... the first two overloads are already explicitly non-throwing and are required to be semantically identical to the second two. So there's no point in making an explicit call to the second pair of functions either. It seems to me that we should remove the (void*, size_t, nothrow_t) overloads, because the core working group decided during the Urbana 2014 meeting, that no change to the core language was warranted.[2014-11-23, Daniel suggests concrete wording changes]
[2015-02 Cologne]
Nobody can call those overloads, since the nothrow allocation functions cannot throw. JY: Ship it. GR: Should we do due diligence and make sure we're deleting what we mean to be deleting? [Some checking, everything looks good.]
Accepted.Proposed resolution:
This wording is relative to N4140.
Change 18.6 [support.dynamic], header <new> synopsis, as indicated:
[…] void operator delete(void* ptr, std::size_t size) noexcept;void operator delete(void* ptr, std::size_t size, const std::nothrow_t&) noexcept;[…] void operator delete[](void* ptr, std::size_t size) noexcept;void operator delete[](void* ptr, std::size_t size, const std::nothrow_t&) noexcept;[…]
Change 18.6.1.1 [new.delete.single], starting before p19, as indicated:
void operator delete(void* ptr, const std::nothrow_t&) noexcept;void operator delete(void* ptr, std::size_t size, const std::nothrow_t&) noexcept;[…]
-20- Replaceable: a C++ program may define a function with signature void operator delete(void* ptr, const std::nothrow_t&) noexcept that displaces the default version defined by the C++ standard library.If this function (without size parameter) is defined, the program should also define void operator delete(void* ptr, std::size_t size, const std::nothrow_t&) noexcept. If this function with size parameter is defined, the program shall also define the version without the size parameter. [Note: The default behavior below may change in the future, which will require replacing both deallocation functions when replacing the allocation function. — end note][…]-22- Requires: If present, the std::size_t size argument must equal the size argument passed to the allocation function that returned ptr.-23- Required behavior: Calls to operator delete(void* ptr, std::size_t size, const std::nothrow_t&) may be changed to calls to operator delete(void* ptr, const std::nothrow_t&) without affecting memory allocation. [Note: A conforming implementation is for operator delete(void* ptr, std::size_t size, const std::nothrow_t&) to simply call operator delete(void* ptr, const std::nothrow_t&). — end note]-24- Default behavior:operator delete(void* ptr, std::size_t size, const std::nothrow_t&) calls operator delete(ptr, std::nothrow), andoperator delete(void* ptr, const std::nothrow_t&) calls operator delete(ptr).
Change 18.6.1.2 [new.delete.array], starting before p16, as indicated:
void operator delete[](void* ptr, const std::nothrow_t&) noexcept;void operator delete[](void* ptr, std::size_t size, const std::nothrow_t&) noexcept;[…]
-17- Replaceable: a C++ program may define a function with signature void operator delete[](void* ptr, const std::nothrow_t&) noexcept that displaces the default version defined by the C++ standard library.If this function (without size parameter) is defined, the program should also define void operator delete[](void* ptr, std::size_t size, const std::nothrow_t&) noexcept. If this function with size parameter is defined, the program shall also define the version without the size parameter. [Note: The default behavior below may change in the future, which will require replacing both deallocation functions when replacing the allocation function. — end note][…]-19- Requires: If present, the std::size_t size argument must equal the size argument passed to the allocation function that returned ptr.-20- Required behavior: Calls to operator delete[](void* ptr, std::size_t size, const std::nothrow_t&) may be changed to calls to operator delete[](void* ptr, const std::nothrow_t&) without affecting memory allocation. [Note: A conforming implementation is for operator delete[](void* ptr, std::size_t size, const std::nothrow_t&) to simply call operator delete[](void* ptr, const std::nothrow_t&). — end note]-21- Default behavior:operator delete[](void* ptr, std::size_t size, const std::nothrow_t&) calls operator delete[](ptr, std::nothrow), andoperator delete[](void* ptr, const std::nothrow_t&) calls operator delete[](ptr).
Section: 26.4.7 [complex.value.ops] Status: Tentatively Ready Submitter: Marshall Clow Opened: 2014-10-22 Last modified: 2015-04-08
View all other issues in [complex.value.ops].
View all issues with Tentatively Ready status.
Discussion:
Different implementations give different answers for the following code:
#include <iostream> #include <complex> int main () { std::cout << std::polar(-1.0, -1.0) << '\n'; return 0; }
One implementation prints:
(nan, nan)
Another:
(-0.243068, 0.243068)
Which is correct? Or neither?
In this list, Howard Hinnant wrote:I've read this over several times. I've consulted C++11, C11, and IEC 10967-3. [snip]
I'm finding:
The magnitude of a complex number == abs(c) == hypot(c.real(), c.imag()) and is always non-negative (by all three of the above standards).
Therefore no complex number exists for which abs(c) < 0.
Therefore when the first argument to std::polar (which is called rho) is negative, no complex number can be formed which meets the post-conidtion that abs(c) == rho.
One could argue that this is already covered in 26.4 [complex.numbers]/3, but I think it's worth making explicit.
[2015-02, Cologne]
Discussion on whether theta should also be constrained.
TK: infinite theta doesn't make sense, whereas infinite rho does (theta is on a compact domain, rho is on a non-compact domain).
AM: We already have a narrow contract, so I don't mind adding further requirements. Any objections to requiring that theta be finite?
Some more discussion, but general consensus. Agreement that if someone finds the restrictions problematic, they should write
a proper paper to address how std::polar should behave. For now, we allow infinite rho (but not NaN and not negative),
and require finite theta.
Proposed resolution:
This wording is relative to N4296.
Change 26.4.7 [complex.value.ops] around p9 as indicated
template<class T> complex<T> polar(const T& rho, const T& theta = 0);-?- Requires: rho shall be non-negative and non-NaN. theta shall be finite.
-9- Returns: The complex value corresponding to a complex number whose magnitude is rho and whose phase angle is theta.
Section: 20.10.7.6 [meta.trans.other], 24.4.1 [iterator.traits] Status: New Submitter: Richard Smith Opened: 2014-11-19 Last modified: 2015-04-08
View other active issues in [meta.trans.other].
View all other issues in [meta.trans.other].
View all issues with New status.
Discussion:
LWG issue 2408 changes the meat of the specification of common_type to compute:
[..] the type, if any, of an unevaluated conditional expression (5.16) whose first operand is an arbitrary value of type bool, whose second operand is an xvalue of type T1, and whose third operand is an xvalue of type T2.
This has an effect on the specification that I think was unintended. It used to be the case that common_type<T&, U&&> would consider the type of a conditional between an lvalue of type T and an xvalue of type U. It's now either invalid (because there is no such thing as an xvalue of reference type) or considers the type of a conditional between an xvalue of type T and an xvalue of type U, depending on how you choose to read it.
Put another way, this has the effect of changing the usual definition from:typedef decay_t<decltype(true ? declval<T>() : declval<U>())> type;
to:
typedef decay_t<decltype(true ? declval<remove_reference_t<T>>() : declval<remove_reference_t<U>>())> type;
It also makes common_type underspecified in the case where one of the operands is of type void; in that case, the resulting type depends on whether the expression is a throw-expression, which is not specified (but used to be).
Also on the subject of this wording: the changes to 24.4.1 [iterator.traits] say that iterator_traits<T> "shall have no members" in some cases. That's wrong. It's a class type; it always has at least a copy constructor, a copy assignment operator, and a destructor. Plus this removes the usual library liberty to add additional members with names that don't collide with normal usage (for instance, if a later version of the standard adds members, they can't be present here as a conforming extension). Perhaps this should instead require that the class doesn't have members with any of those five names? That's what 2408 does for common_type's type member.Proposed resolution:
Section: 17.6.3.5 [allocator.requirements], 23.3.6.3 [vector.capacity], 23.3.6.5 [vector.modifiers] Status: New Submitter: dyp Opened: 2014-12-06 Last modified: 2015-04-08
View other active issues in [allocator.requirements].
View all other issues in [allocator.requirements].
View all issues with New status.
Discussion:
When resizing a vector, the accessibility and exception specification of the value type's constructors determines whether the elements are copied or moved to the new buffer. However, the copy/move is performed via the allocator's construct member function, which is assumed, but not required, to call the copy/move constructor and propagate only exceptions from the value type's copy/move constructor. The issue might also affect other classes.
The current wording in N4296 relevant here is from Table 28 — "Allocator requirements" in 17.6.3.5 [allocator.requirements]:
Table 28 — Allocator requirements Expression Return type Assertion/note
pre-/post-conditionDefault … a.construct(c, args) (not used) Effect: Constructs an object of type C at c ::new ((void*)c) C(forward<Args>(args)...) …
and from 17.6.3.5 [allocator.requirements] p9:
An allocator may constrain the types on which it can be instantiated and the arguments for which its construct member may be called. If a type cannot be used with a particular allocator, the allocator class or the call to construct may fail to instantiate.
I conclude the following from the wording:
The allocator is not required to call the copy constructor if the arguments (args) is a single (potentially const) lvalue of the value type. Similarly for a non-const rvalue + move constructor. See also 23.2.1 [container.requirements.general] p15 which seems to try to require this, but is not sufficient: That paragraph specifies the semantics of the allocator's operations, but not which constructors of the value type are used, if any.
The allocator may throw exceptions in addition to the exceptions propagated by the constructors of the value type; it can also propagate exceptions from constructors other than a copy/move constructor.
This leads to an issue with the wording of the exception safety guarantees for vector modifiers in 23.3.6.5 [vector.modifiers] p1:
[…]
void push_back(const T& x); void push_back(T&& x);Remarks: Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid. If an exception is thrown other than by the copy constructor, move constructor, assignment operator, or move assignment operator of T or by any InputIterator operation there are no effects. If an exception is thrown while inserting a single element at the end and T is CopyInsertable or is_nothrow_move_constructible<T>::value is true, there are no effects. Otherwise, if an exception is thrown by the move constructor of a non-CopyInsertable T, the effects are unspecified.
The wording leads to the following problem: Copy and move assignment are invoked directly from vector. For intermediary objects (see 2164), vector also directly invokes the copy and move constructor of the value type. However, construction of the actual element within the buffer is invoked via the allocator abstraction. As discussed above, the allocator currently is not required to call a copy/move constructor. If is_nothrow_move_constructible<T>::value is true for some value type T, but the allocator uses modifying operations for MoveInsertion that do throw, the implementation is required to ensure that "there are no effects", even if the source buffer has been modified.
Similarly, the vector capacity functions specify exception safety guarantees referring to the move constructor of the value type. For example, vector::resize in 23.3.6.3 [vector.capacity] p14:Remarks: If an exception is thrown other than by the move constructor of a non-CopyInsertable T there are no effects.
The wording leads to the same issue as described above.
Code example:template<class T> class allocator; class pot_reg_type // a type which creates // potentially registered instances { private: friend class allocator<pot_reg_type>; struct register_t {}; static std::set<pot_reg_type*>& get_registry() { static std::set<pot_reg_type*> registry; return registry; } void enregister() noexcept(false) { get_registry().insert(this); } void deregister() { get_registry().erase(this); } public: pot_reg_type(void ) noexcept(true) {} pot_reg_type(pot_reg_type const&) noexcept(true) {} pot_reg_type(pot_reg_type&& ) noexcept(true) {} private: pot_reg_type(register_t ) noexcept(false) { enregister(); } pot_reg_type(register_t, pot_reg_type const&) noexcept(false) { enregister(); } pot_reg_type(register_t, pot_reg_type&& ) noexcept(false) { enregister(); } }; template<class T> class allocator { public: using value_type = T; value_type* allocate(std::size_t p) { return (value_type*) ::operator new(p); } void deallocate(value_type* p, std::size_t) { ::operator delete(p); } void construct(pot_reg_type* pos) { new((void*)pos) pot_reg_type((pot_reg_type::register_t())); } void construct(pot_reg_type* pos, pot_reg_type const& source) { new((void*)pos) pot_reg_type(pot_reg_type::register_t(), source); } template<class... Args> void construct(T* p, Args&&... args) { new((void*)p) T(std::forward<Args>(args)...); } };
The construct member function template is only required for rebinding, which can be required e.g. to store additional debug information in the allocated memory (e.g. VS2013).
Even though the value type has an accessible and noexcept(true) move constructor, this allocator won't call that constructor for rvalue arguments. In any case, it does not call a constructor for which vector has formulated its requirements. An exception thrown by a constructor called by this allocator is not covered by the specification in 23.3.6.5 [vector.modifiers] and therefore is guaranteed not to have any effect on the vector object when resizing. For an example how this might invalidate the exception safety guarantees, see this post on the std-discussion mailing list. Another problem arises for value types whose constructors are private, but may be called by the allocator e.g. via friendship. Those value types are not MoveConstructible (is_move_constructible is false), yet they can be MoveInsertable. It is not possible for vector to create intermediary objects (see 2164) of such a type by directly using the move constructor. Current implementations of the single-element forms of vector::insert and vector::emplace do create intermediary objects by directly calling one of the value type's constructors, probably to allow inserting objects from references that alias other elements of the container. As far as I can see, Table 100 — "Sequence container requirements" in 23.2.3 [sequence.reqmts] does not require that the creation of such intermediare objects can be performed by containers using the value type's constructor directly. It is unclear to me if the allocator's construct function could be used to create those intermediary objects, given that they have not been allocated by the allocator. Two possible solutions:Add the following requirement to the allocator_traits::construct function: If the parameter pack args consists of a single parameter of the type value_type&&, the function may only propagate exceptions if is_nothrow_move_constructible<value_type>::value is false.
Requiring alloctor_traits::construct to call a true copy/move constructor of the value type breaks std::scoped_allocator_adapter, as pointed out by Casey Carter in a post on the std-discussion mailing list.Change vector's criterion whether to move or copy when resizing:
Instead of testing the value type's constructors via is_move_constructible, check the value of noexcept( allocator_traits<Allocator>::construct(alloc, ptr, rval) ) where alloc is an lvalue of type Allocator, ptr is an expression of type allocator_traits<Allocator>::pointer and rval is a non-const rvalue of type value_type.A short discussion of the two solutions:
Solution 1 allows keeping is_nothrow_move_constructible<value_type> as the criterion for vector to decide between copying and moving when resizing. It restricts what can be done inside the construct member function of allocators, and requires implementers of allocators to pay attention to the value types used. One could conceive allocators checking the following with a static_assert: If the value type is_nothrow_move_constructible, then the constructor actually called for MoveInsertion within the construct member function is also declared as noexcept. Solution 2 requires changing both the implementation of the default allocator (add a conditional noexcept) and vector (replace is_move_constructible with an allocator-targeted check). It does not impose additional restrictions on the allocator (other than 23.2.1 [container.requirements.general] p15), and works nicely even if the move constructor of a MoveInsertable type is private or deleted (the allocator might be a friend of the value type). In both cases, an addition might be required to provide the basic exception safety guarantee. A short discussion on this topic can be found in the std-discussion mailing list. Essentially, if allocator_traits<Allocator>::construct throws an exception, the object may or may not have been constructed. Two solutions are mentioned in that discussion:allocator_traits<Allocator>::construct needs to tell its caller whether or not the construction was successful, in case of an exception.
If allocator_traits<Allocator>::construct propagates an exception, it shall either not have constructed an object at the specified location, or that object shall have been destroyed (or it shall ensure otherwise that no resources are leaked).
Proposed resolution:
Section: 27.5.3 [ios.base], 27.5.3.1.1 [ios::failure] Status: New Submitter: Jonathan Wakely Opened: 2014-12-15 Last modified: 2015-04-08
View all other issues in [ios.base].
View all issues with New status.
Discussion:
27.5.3 [ios.base] defines ios_base::failure as a nested class:
namespace std { class ios_base { public: class failure; […] }; […] }
This means it is valid to use an elaborated-type-specifier to refer to ios_base::failure:
using F = class std::ios_base::failure; throw F();
Therefore implementations are not permitted to define ios_base::failure as a typedef e.g.
class ios_base { public: #if __cplusplus < 201103L class failure_cxx03 : public exception {...}; typedef failure_cxx03 failure; #else class failure_cxx11 : public system_error {...}; typedef failure_cxx11 failure; #endif […] };
This constrains implementations, making it harder to manage the ABI change to ios_base::failure between C++03 and C++11.
Proposed resolution:
This wording is relative to N4296.
Change the synopsis in 27.5.3 [ios.base] as indicated:
namespace std { class ios_base { public: class failure; // see below […] }; […] };
Change 27.5.3 [ios.base] paragraph 1:
ios_base defines several member types:
a
class failuretype failure, defined as either a class derived from system_error or a synonym for a class derived from system_error;
Change 27.5.3.1.1 [ios::failure] paragraph 1:
-1- An implementation is permitted to define ios_base::failure as a synonym for a class with equivalent functionality to class ios_base::failure shown in this subclause. [Note: When ios_base::failure is a synonym for another type it shall provide a nested type failure, to emulate the injected class name. — end note] The class failure defines the base class for the types of all objects thrown as exceptions, by functions in the iostreams library, to report errors detected during stream buffer operations.
Section: X [alg.random.sample] Status: Tentatively Ready Submitter: Joe Gottman Opened: 2014-12-17 Last modified: 2015-04-08
View all issues with Tentatively Ready status.
Discussion:
Addresses: fund.ts
According to paragraph 10.1 of the Library Fundamentals 1 draft, the complexity of the new std::experimental::sample template function is O(n). Note that n is actually a parameter of this function, corresponding to the sample size. But both common algorithms for sampling, the selection algorithm and the reservoir algorithm, are linear with respect to the population size, which is often many orders of magnitude bigger than the sample size.
[2015-02, Cologne]
AM: I suggest we make this a DR against the Fundamentals TS.
GR: Agreed, this is a no-brainer.
Proposed resolution:
This wording is relative to N4335 in regard to fundamental-ts changes.
Change X [alg.random.sample] p5 to read:
-5- Complexity: O(
nlast - first).
Section: 23.4.4.4 [map.modifiers], 23.5.4.4 [unord.map.modifiers] Status: New Submitter: Thomas Koeppe Opened: 2014-12-17 Last modified: 2015-04-08
View all other issues in [map.modifiers].
View all issues with New status.
Discussion:
The specification of the try_emplace and insert_or_assign member functions in N4279 contains the following errors and omissions:
In insert_or_assign, each occurrence of std::forward<Args>(args)... should be std::forward<M>(obj); this is was a mistake introduced in editing.
In try_emplace, the construction of the value_type is misspecified, which is a mistake that was introduced during the evolution from a one-parameter to a variadic form. As written, value_type(k, std::forward<Args>(args)...) does not do the right thing; it can only be used with a single argument, which moreover must be convertible to a mapped_type. The intention is to allow direct-initialization from an argument pack, and the correct constructor should be value_type(piecewise_construct, forward_as_tuple(k), forward_as_tuple(std::forward<Args>(args)...).
Both try_emplace and insert_or_assign are missing requirements on the argument types. Since the semantics of these functions are specified independent of other functions, they need to include their requirements.
[2015-02, Cologne]
This issue is related to 2469.
AM: The repeated references to "first and third forms" and "second and fourth forms" is a bit cumbersome. Maybe split the four functions?[2015-03-26, Thomas provides improved wording]
The approach is to split the descriptions of the various blocks of four functions into two blocks each so as to make the wording easier to follow.
Previous resolution [SUPERSEDED]:This wording is relative to N4296.
Apply the following changes to section 23.4.4.4 [map.modifiers] p3:
template <class... Args> pair<iterator, bool> try_emplace(const key_type& k, Args&&... args); template <class... Args> pair<iterator, bool> try_emplace(key_type&& k, Args&&... args); template <class... Args> iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); template <class... Args> iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);-?- Requires: For the first and third forms, value_type shall be EmplaceConstructible into map from piecewise_construct, forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...). For the second and fourth forms, value_type shall be EmplaceConstructible into map from piecewise_construct, forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...).
-3- Effects:If the key k already exists in the map, there is no effect. Otherwise, inserts an element into the map. In the first and third forms, the element is constructed from the arguments as value_type(k, std::forward<Args>(args)...). In the second and fourth forms, the element is constructed from the arguments as value_type(std::move(k), std::forward<Args>(args)...). In the first two overloads, the bool component of the returned pair is true if and only if the insertion took place. The returned iterator points to the element of the map whose key is equivalent to kIf the map does already contain an element whose key is equivalent to k, there is no effect. Otherwise for the first and third forms inserts a value_type object t constructed with piecewise_construct, forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...), for the second and fourth forms inserts a value_type object t constructed with piecewise_construct, forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...). -?- Returns: In the first two overloads, the bool component of the returned pair is true if and only if the insertion took place. The returned iterator points to the map element whose key is equivalent to k.Apply the following changes to section 23.4.4.4 [map.modifiers] p5:
template <class M> pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj); template <class M> pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj); template <class M> iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); template <class M> iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);-?- Requires: is_assignable<mapped_type&, M&&>::value shall be true. For the first and third forms, value_type shall be EmplaceConstructible into map from k, forward<M>(obj). For the second and fourth forms, value_type shall be EmplaceConstructible into map from move(k), forward<M>(obj).
-5- Effects:If the key k does not exist in the map, inserts an element into the map. In the first and third forms, the element is constructed from the arguments as value_type(k, std::forward<Args>(args)...). In the second and fourth forms, the element is constructed from the arguments as value_type(std::move(k), std::forward<Args>(args)...). If the key already exists, std::forward<M>(obj) is assigned to the mapped_type corresponding to the key. In the first two overloads, the bool component of the returned value is true if and only if the insertion took place. The returned iterator points to the element that was inserted or updatedIf the map does already contain an element whose key is equivalent to k, forward<M>(obj) is assigned to the mapped_type corresponding to the key. Otherwise the first and third forms inserts a value_type object t constructed with k, forward<M>(obj), the second and fourth forms inserts a value_type object t constructed with move(k), forward<M>(obj). -?- Returns: In the first two overloads, the bool component of the returned pair is true if and only if the insertion took place. The returned iterator points to the element of the map whose key is equivalent to k.Apply the following changes to section 23.5.4.4 [unord.map.modifiers] p5:
template <class... Args> pair<iterator, bool> try_emplace(const key_type& k, Args&&... args); template <class... Args> pair<iterator, bool> try_emplace(key_type&& k, Args&&... args); template <class... Args> iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); template <class... Args> iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);-?- Requires: For the first and third forms, value_type shall be EmplaceConstructible into unordered_map from piecewise_construct, forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...). For the second and fourth forms, value_type shall be EmplaceConstructible into unordered_map from piecewise_construct, forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...).
-5- Effects:If the key k already exists in the map, there is no effect. Otherwise, inserts an element into the map. In the first and third forms, the element is constructed from the arguments as value_type(k, std::forward<Args>(args)...). In the second and fourth forms, the element is constructed from the arguments as value_type(std::move(k), std::forward<Args>(args)...). In the first two overloads, the bool component of the returned pair is true if and only if the insertion took place. The returned iterator points to the element of the map whose key is equivalent to kIf the unordered_map does already contain an element whose key is equivalent to k, there is no effect. Otherwise for the first and third forms inserts a value_type object t constructed with piecewise_construct, forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...), for the second and fourth forms inserts a value_type object t constructed with piecewise_construct, forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...). -?- Returns: In the first two overloads, the bool component of the returned pair is true if and only if the insertion took place. The returned iterator points to the element of the unordered_map whose key is equivalent to k.Apply the following changes to section 23.5.4.4 [unord.map.modifiers] p7:
template <class M> pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj); template <class M> pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj); template <class M> iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); template <class M> iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);-?- Requires: is_assignable<mapped_type&, M&&>::value shall be true. For the first and third forms, value_type shall be EmplaceConstructible into unordered_map from k, forward<M>(obj). For the second and fourth forms, value_type shall be EmplaceConstructible into unordered_map from move(k), forward<M>(obj).
-7- Effects:If the key k does not exist in the map, inserts an element into the map. In the first and third forms, the element is constructed from the arguments as value_type(k, std::forward<Args>(args)...). In the second and fourth forms, the element is constructed from the arguments as value_type(std::move(k), std::forward<Args>(args)...). If the key already exists, std::forward<M>(obj) is assigned to the mapped_type corresponding to the key. In the first two overloads, the bool component of the returned value is true if and only if the insertion took place. The returned iterator points to the element that was inserted or updatedIf the unordered_map does already contain an element whose key is equivalent to k, forward<M>(obj) is assigned to the mapped_type corresponding to the key. Otherwise the first and third forms inserts a value_type object t constructed with k, forward<M>(obj), the second and fourth forms inserts a value_type object t constructed with move(k), forward<M>(obj). -?- Returns: In the first two overloads, the bool component of the returned pair is true if and only if the insertion took place. The returned iterator points to the element of the unordered_map whose key is equivalent to k.
Proposed resolution:
This wording is relative to N4296.
Apply the following changes to 23.4.4.4 [map.modifiers] p3+p4:
template <class... Args> pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);template <class... Args> pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);template <class... Args> iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);template <class... Args> iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);-?- Requires: value_type shall be EmplaceConstructible into map from piecewise_construct, forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...).
-3- Effects:If the key k already exists in the map, there is no effect. Otherwise, inserts an element into the map. In the first and third forms, the element is constructed from the arguments as value_type(k, std::forward<Args>(args)...). In the second and fourth forms, the element is constructed from the arguments as value_type(std::move(k), std::forward<Args>(args)...). In the first two overloads, the bool component of the returned pair is true if and only if the insertion took place. The returned iterator points to the element of the map whose key is equivalent to kIf the map already contains an element whose key is equivalent to k, there is no effect. Otherwise inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...). -?- Returns: In the first overload, the bool component of the returned pair is true if and only if the insertion took place. The returned iterator points to the map element whose key is equivalent to k. -4- Complexity: The same as emplace and emplace_hint, respectively.template <class... Args> pair<iterator, bool> try_emplace(key_type&& k, Args&&... args); template <class... Args> iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);-?- Requires: value_type shall be EmplaceConstructible into map from piecewise_construct, forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...).
-?- Effects: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...). -?- Returns: In the first overload, the bool component of the returned pair is true if and only if the insertion took place. The returned iterator points to the map element whose key is equivalent to k. -?- Complexity: The same as emplace and emplace_hint, respectively.
Apply the following changes to 23.4.4.4 [map.modifiers] p5+p6:
template <class M> pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);template <class M> pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);template <class M> iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);template <class M> iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);-?- Requires: is_assignable<mapped_type&, M&&>::value shall be true. value_type shall be EmplaceConstructible into map from k, forward<M>(obj).
-5- Effects:If the key k does not exist in the map, inserts an element into the map. In the first and third forms, the element is constructed from the arguments as value_type(k, std::forward<Args>(args)...). In the second and fourth forms, the element is constructed from the arguments as value_type(std::move(k), std::forward<Args>(args)...). If the key already exists, std::forward<M>(obj) is assigned to the mapped_type corresponding to the key. In the first two overloads, the bool component of the returned value is true if and only if the insertion took place. The returned iterator points to the element that was inserted or updatedIf the map already contains an element e whose key is equivalent to k, assigns forward<M>(obj) to e.second. Otherwise inserts an object of type value_type constructed with k, forward<M>(obj). -?- Returns: In the first overload, the bool component of the returned pair is true if and only if the insertion took place. The returned iterator points to the map element whose key is equivalent to k. -6- Complexity: The same as emplace and emplace_hint, respectively.template <class M> pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj); template <class M> iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);-?- Requires: is_assignable<mapped_type&, M&&>::value shall be true. value_type shall be EmplaceConstructible into map from move(k), forward<M>(obj).
-?- Effects: If the map already contains an element e whose key is equivalent to k, assigns forward<M>(obj) to e.second. Otherwise inserts an object of type value_type constructed with move(k), forward<M>(obj). -?- Returns: In the first overload, the bool component of the returned pair is true if and only if the insertion took place. The returned iterator points to the map element whose key is equivalent to k. -?- Complexity: The same as emplace and emplace_hint, respectively.
Apply the following changes to 23.5.4.4 [unord.map.modifiers] p5+p6:
template <class... Args> pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);template <class... Args> pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);template <class... Args> iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);template <class... Args> iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);-?- Requires: value_type shall be EmplaceConstructible into unordered_map from piecewise_construct, forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...).
-5- Effects:If the key k already exists in the map, there is no effect. Otherwise, inserts an element into the map. In the first and third forms, the element is constructed from the arguments as value_type(k, std::forward<Args>(args)...). In the second and fourth forms, the element is constructed from the arguments as value_type(std::move(k), std::forward<Args>(args)...). In the first two overloads, the bool component of the returned pair is true if and only if the insertion took place. The returned iterator points to the element of the map whose key is equivalent to kIf the map already contains an element whose key is equivalent to k, there is no effect. Otherwise inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...). -?- Returns: In the first overload, the bool component of the returned pair is true if and only if the insertion took place. The returned iterator points to the map element whose key is equivalent to k. -6- Complexity: The same as emplace and emplace_hint, respectively.template <class... Args> pair<iterator, bool> try_emplace(key_type&& k, Args&&... args); template <class... Args> iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);-?- Requires: value_type shall be EmplaceConstructible into unordered_map from piecewise_construct, forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...).
-?- Effects: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...). -?- Returns: In the first overload, the bool component of the returned pair is true if and only if the insertion took place. The returned iterator points to the map element whose key is equivalent to k. -?- Complexity: The same as emplace and emplace_hint, respectively.
Apply the following changes to 23.5.4.4 [unord.map.modifiers] p7+p8:
template <class M> pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);template <class M> pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);template <class M> iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);template <class M> iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);-?- Requires: is_assignable<mapped_type&, M&&>::value shall be true. value_type shall be EmplaceConstructible into unordered_map from k, forward<M>(obj).
-7- Effects:If the key k does not exist in the map, inserts an element into the map. In the first and third forms, the element is constructed from the arguments as value_type(k, std::forward<Args>(args)...). In the second and fourth forms, the element is constructed from the arguments as value_type(std::move(k), std::forward<Args>(args)...). If the key already exists, std::forward<M>(obj) is assigned to the mapped_type corresponding to the key. In the first two overloads, the bool component of the returned value is true if and only if the insertion took place. The returned iterator points to the element that was inserted or updatedIf the map already contains an element e whose key is equivalent to k, assigns forward<M>(obj) to e.second. Otherwise inserts an object of type value_type constructed with k, forward<M>(obj). -?- Returns: In the first overload, the bool component of the returned pair is true if and only if the insertion took place. The returned iterator points to the map element whose key is equivalent to k. -8- Complexity: The same as emplace and emplace_hint, respectively.template <class M> pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj); template <class M> iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);-?- Requires: is_assignable<mapped_type&, M&&>::value shall be true. value_type shall be EmplaceConstructible into unordered_map from move(k), forward<M>(obj).
-?- Effects: If the map already contains an element e whose key is equivalent to k, assigns forward<M>(obj) to e.second. Otherwise inserts an object of type value_type constructed with move(k), forward<M>(obj). -?- Returns: In the first overload, the bool component of the returned pair is true if and only if the insertion took place. The returned iterator points to the map element whose key is equivalent to k. -?- Complexity: The same as emplace and emplace_hint, respectively.
Section: 20.10.7.6 [meta.trans.other] Status: New Submitter: Eric Niebler Opened: 2015-01-12 Last modified: 2015-04-08
View other active issues in [meta.trans.other].
View all other issues in [meta.trans.other].
View all issues with New status.
Discussion:
I think there's a defect regarding common_type and its specializations. Unless I've missed it, there is nothing preventing folks from instantiating common_type with cv-qualified types or reference types. In fact, the wording in N3797 explicitly mentions cv void, so presumably at least cv qualifications are allowed.
Users are given license to specialize common_type when at least of of the types is user-defined. (A separate issue is the meaning of user-defined. In core, I believe this is any class/struct/union/enum, but in lib, I think it means any type not defined in std, right?) There is at least one place in the standard that specializes common_type (time.traits.specializations) on time_point and duration. But the specializations are only for non-cv-qualified and non-reference specializations of time_point and duration. If the user uses, say, common_type<duration<X,Y> const, duration<A,B> const>, they're not going to get the behavior they expect. Suggest we clarify the requirements of common_type's template parameters. Also, perhaps we can add blanket wording that common_type<A [cv][&], B [cv][&]> is required to be equivalent to common_type<A,B> (if that is in fact the way we intent this to work). Also, the change to make common_type SFINAE-friendly regressed key functionality, as noted by Agustín K-ballo Bergé in c++std-lib-37178. Since decay_t is not applied until the very end of the type computation, user specializations are very likely to to be found. Agustín says:Consider the following snippet:
struct X {}; struct Y { explicit Y(X){} }; namespace std { template<> struct common_type<X, Y> { typedef Y type; }; template<> struct common_type<Y, X> { typedef Y type; }; } static_assert(is_same<common_type_t<X, Y>, Y>()); // (A) static_assert(is_same<common_type_t<X, Y, Y>, Y>()); // (B) static_assert(is_same<common_type_t<X, X, Y>, Y>()); // (C)Under the original wording, all three assertion holds. Under the current wording,
(A) picks the user-defined specialization, so the assertion holds.
(B) goes to the third bullet and, ignoring the user-defined specialization, looks for decltype(true ? declval<X>() : declval<Y>()); since it is ill-formed there is no common type.
(C) goes to the third bullet and yields common_type_t<X&&, Y>, which again misses the user-defined specialization.
The discussion following c++std-lib-35636 seemed to cohere around the idea that the primary common_type specialization should have the effect of stripping top-level ref and cv qualifiers by applying std::decay_t to its arguments and, if any of them change as a result of that transformation, re-dispatching to common_type on those transformed arguments, thereby picking up any user-defined specializations. This change to common_type would make the specializations in time.traits.specializations sufficient.
Suggested wording: I'm afraid I don't know enough to suggest wording. But for exposition, the following is my best shot at implementing the suggested resolution. I believe it also fixes the regression noted by Agustín K-ballo Bergé in c++std-lib-37178.namespace detail { template<typename T, typename U> using default_common_t = decltype(true? std::declval<T>() : std::declval<U>()); template<typename T, typename U, typename Enable = void> struct common_type_if {}; template<typename T, typename U> struct common_type_if<T, U, void_t<default_common_t<T, U>>> { using type = decay_t<default_common_t<T, U>>; }; template<typename T, typename U, typename TT = decay_t<T>, typename UU = decay_t<U>> struct common_type2 : common_type<TT, UU> // Recurse to catch user specializations {}; template<typename T, typename U> struct common_type2<T, U, T, U> : common_type_if<T, U> {}; template<typename Meta, typename Enable = void> struct has_type : std::false_type {}; template<typename Meta> struct has_type<Meta, void_t<typename Meta::type>> : std::true_type {}; template<typename Meta, typename...Ts> struct common_type_recurse : common_type<typename Meta::type, Ts...> {}; template<typename Meta, typename...Ts> struct common_type_recurse_if : std::conditional< has_type<Meta>::value, common_type_recurse<Meta, Ts...>, empty >::type {}; } template<typename ...Ts> struct common_type {}; template<typename T> struct common_type<T> { using type = std::decay_t<T>; }; template<typename T, typename U> struct common_type<T, U> : detail::common_type2<T, U> {}; template<typename T, typename U, typename... Vs> struct common_type<T, U, Vs...> : detail::common_type_recurse_if<common_type<T, U>, Vs...> {};
Proposed resolution:
Section: 17.6.3.5 [allocator.requirements], 20.7.8.2 [allocator.traits.members] Status: New Submitter: Howard Hinnant Opened: 2015-01-17 Last modified: 2015-04-08
View other active issues in [allocator.requirements].
View all other issues in [allocator.requirements].
View all issues with New status.
Discussion:
Table 28 — "Allocator requirements" says that default behavior for a.max_size() is numeric_limits<size_type>::max(). And this is consistent with the matching statement for allocator_traits in 20.7.8.2 [allocator.traits.members]/p7:
static size_type max_size(const Alloc& a) noexcept;Returns: a.max_size() if that expression is well-formed; otherwise, numeric_limits<size_type>::max().
However, when allocating memory, an allocator must allocate n*sizeof(value_type) bytes, for example:
value_type* allocate(std::size_t n) { return static_cast<value_type*>(::operator new (n * sizeof(value_type))); }
When n == numeric_limits<size_type>::max(), n * sizeof(value_type) is guaranteed to overflow except when sizeof(value_type) == 1.
A more useful default would be numeric_limits<size_type>::max() / sizeof(value_type).Proposed resolution:
This wording is relative to N4296.
Change 17.6.3.5 [allocator.requirements], Table 28 — "Allocator requirements", as indicated:
Table 28 — Allocator requirements Expression Return type Assertion/note
pre-/post-conditionDefault … a.max_size() X::size_type the largest value that can
meaningfully be passed to
X::allocate()numeric_limits<size_type>::max()/sizeof(value_type) …
Change 20.7.8.2 [allocator.traits.members]/p7 as indicated:
static size_type max_size(const Alloc& a) noexcept;Returns: a.max_size() if that expression is well-formed; otherwise, numeric_limits<size_type>::max()/sizeof(value_type).
Section: 17.6.3.5 [allocator.requirements], 20.7.8.1 [allocator.traits.types] Status: Tentatively Ready Submitter: Howard Hinnant Opened: 2015-01-18 Last modified: 2015-04-08
View other active issues in [allocator.requirements].
View all other issues in [allocator.requirements].
View all issues with Tentatively Ready status.
Discussion:
Table 28 — "Allocator requirements" says that X::is_always_equal has a default value of is_empty<X>, and this is consistent with the return type description:
Identical to or derived from true_type or false_type
is_empty<X> is guaranteed to be derived from either true_type or false_type. So far so good.
20.7.8.1 [allocator.traits.types]/p10 says:typedef see below is_always_equal;Type: Alloc::is_always_equal if the qualified-id Alloc::is_always_equal is valid and denotes a type (14.8.2); otherwise is_empty<Alloc>::type.
This is subtly different than what Table 28 says is the default: is_empty<Alloc>::type is not is_empty<Alloc>, but is rather one of true_type or false_type.
There are two ways to fix this:Change Table 28 to say: is_empty<X>::type.
orChange 20.7.8.1 [allocator.traits.types]/p10:
Type: Alloc::is_always_equal if the qualified-id Alloc::is_always_equal is valid and denotes a type (14.8.2); otherwise is_empty<Alloc>
::type.
Both options are correct, and I see no reason to prefer one fix over the other. But Table 28 and 20.7.8.1 [allocator.traits.types]/p10 should be consistent with one another.
[2015-02 Cologne]
DK: We should accept the first bullet. GR: Why does is_empty even have a type member? AM: All type traits have a type member. I agree with DK's preference for the first type.
Proposed resolution:
This wording is relative to N4296.
Change 17.6.3.5 [allocator.requirements], Table 28 — "Allocator requirements" as presented:
Table 28 — Allocator requirements Expression Return type Assertion/note
pre-/post-conditionDefault … X::is_always_equal Identical to or derived
from true_type or
false_type[…] is_empty<X>::type …
Section: 17.6.4.9 [res.on.arguments], 17.6.3.1 [utility.arg.requirements], 17.6.5.15 [lib.types.movedfrom], 23.2.1 [container.requirements.general] Status: New Submitter: Matt Austern Opened: 2015-01-22 Last modified: 2015-04-08
View all other issues in [res.on.arguments].
View all issues with New status.
Discussion:
Suppose we write
vector<string> v{"a", "b", "c", "d"}; v = move(v);
What should be the state of v be? The standard doesn't say anything specific about self-move-assignment. There's relevant text in several parts of the standard, and it's not clear how to reconcile them.
17.6.4.9 [res.on.arguments] writes that, for all functions in the standard library, unless explicitly stated otherwise, "If a function argument binds to an rvalue reference parameter, the implementation may assume that this parameter is a unique reference to this argument." The MoveAssignable requirements table in 17.6.3.1 [utility.arg.requirements] writes that, given t = rv, t's state is equivalent to rv's from before the assignment and rv's state is unspecified (but valid). For containers specifically, the requirements table in 23.2.1 [container.requirements.general] says that, given a = rv, a becomes equal to what rv was before the assignment (and doesn't say anything about rv's state post-assignment). Taking each of these pieces in isolation, without reference to the other two:17.6.4.9 [res.on.arguments] would clearly imply that the effect of v = move(v) is undefined.
17.6.3.1 [utility.arg.requirements] would clearly imply that v = move(v) has defined behavior. It might be read to imply that this is a no-op, or might be read to imply that it leaves v in a valid but unspecified state; I'm not sure which reading is more natural.
23.2.1 [container.requirements.general] would clearly imply that v = move(v) is a no-op.
It's not clear from the text how to put these pieces together, because it's not clear which one takes precedence. Maybe 17.6.4.9 [res.on.arguments] wins (it imposes an implicit precondition that isn't mentioned in the MoveAssignable requirements, so v = move(v) is undefined), or maybe 23.2.1 [container.requirements.general] wins (it explicitly gives additional guarantees for Container::operator= beyond what's guaranteed for library functions in general, so v = move(v) is a no-op), or maybe something else.
On the existing implementations that I checked, for what it's worth, v = move(v) appeared to clear the vector; it didn't leave the vector unchanged and it didn't cause a crash. Proposed wording: Informally: change the MoveAssignable and Container requirements tables (and any other requirements tables that mention move assignment, if any) to make it explicit that x = move(x) is defined behavior and it leaves x in a valid but unspecified state. That's probably not what the standard says today, but it's probably what we intended and it's consistent with what we've told users and with what implementations actually do.Proposed resolution:
Section: 23.4.4.3 [map.access], 23.5.4.3 [unord.map.elem] Status: Open Submitter: Tomasz Kamiński Opened: 2015-01-21 Last modified: 2015-04-08
View other active issues in [map.access].
View all other issues in [map.access].
View all issues with Open status.
Discussion:
The "Requires:" clause for the operator[] for the unordered_map and map, are defining separate requirements for insertability into container of mapped_type and key_type.
23.4.4.3 [map.access] p2: // T& operator[](const key_type& x); Requires: key_type shall be CopyInsertable and mapped_type shall be DefaultInsertable into *this. 23.4.4.3 [map.access] p6: // T& operator[](key_type&& x) Requires: mapped_type shall be DefaultInsertable into *this. 23.5.4.3 [unord.map.elem] p1: // mapped_type& operator[](const key_type& k); mapped_type& operator[](key_type&& k); Requires: mapped_type shall be DefaultInsertable into *this. For the first operator, key_type shall be CopyInsertable into *this. For the second operator, key_type shall be MoveConstructible. Definition of the appropriate requirements: 23.2.1 [container.requirements.general] p15. T is DefaultInsertable into X means that the following expression is well-formed: //p15.1 allocator_traits<A>::construct(m, p) T is MoveInsertable into X means that the following expression is well-formed: //p15.3 allocator_traits<A>::construct(m, p, rv) T is CopyInsertable into X means that, in addition to T being MoveInsertable into X, the following expression is well-formed: //p15.4 allocator_traits<A>::construct(m, p, v) In the context of above definition the requirement "key_type shall be CopyInsertable into *this" would mean that the key element of the pair<const key_type, mapped_type> (value_type of the map) should be constructed using separate call to the construct method, the same applies for the mapped_type. Such behavior is explicitly prohibited by 23.2.1 [container.requirements.general] p3.For the components affected by this sub-clause that declare an allocator_type, objects stored in these components shall be constructed using the allocator_traits<allocator_type>::construct function and destroyed using the allocator_traits<allocator_type>::destroy function (20.7.8.2). These functions are called only for the container's element type, not for internal types used by the container.
It clearly states that element_type of the map, must be constructed using allocator for value type, which disallows using of separate construction of first and second element, regardless of the fact if it can be actually performed without causing undefined behavior.
That means that the MoveInsertable and similar requirements may only be expressed in terms of value_type, not its members types.[2015-02 Cologne]
This issue is related to 2464.
GR: Effects should say "returns ...". DK: Or just have a Returns clause? MC: A Returns clause is a directive to implementers. TK/DK: This PR fails to address the requirements about which it complained in the first place. DK: I can reword this. TK can help.[2015-03-29, Daniel provides improved wording]
The revised wording fixes the proper usage of the magic "Equivalent to" wording, which automatically induces Requires:, Returns:, and Complexity: elements (and possibly more). This allows us to strike all the remaining elements, because they fall out from the semantics of the wording defined by 2464. In particular it is important to realize that the wording form
value_type shall be EmplaceConstructible into map from piecewise_construct, forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...)
degenerates for the empty pack expansion args to:
value_type shall be EmplaceConstructible into map from piecewise_construct, forward_as_tuple(k), forward_as_tuple()
which again means that such a pair construction (assuming std::allocator) would copy k into member first and would value-initialize member second.
Previous resolution [SUPERSEDED]:
This wording is relative to N4296.
Accept resolution of the issue issue 2464 and define operator[] as follows (This would also address issue 2274):
Change 23.4.4.3 [map.access] as indicated:
T& operator[](const key_type& x);-1- Effects:
[…]If there is no key equivalent to x in the map, inserts value_type(x, T()) into the mapEquivalent to: try_emplace(x).first->second.T& operator[](key_type&& x);-5- Effects:
If there is no key equivalent to x in the map, inserts value_type(std::move(x), T()) into the mapEquivalent to: try_emplace(move(x)).first->second.Change 23.5.4.3 [unord.map.elem] as indicated:
mapped_type& operator[](const key_type& k); mapped_type& operator[](key_type&& k);[…]
-2- Effects:If the unordered_map does not already contain an element whose key is equivalent to k, the first operator inserts the value value_type(k, mapped_type()) and the second operator inserts the value value_type(std::move(k), mapped_type())For the first operator, equivalent to: try_emplace(k).first->second; for the second operator, equivalent to: try_emplace(move(k)).first->second.
Proposed resolution:
This wording is relative to N4296.
Accept resolution of the issue issue 2464 and define operator[] as follows (This would also address issue 2274):
Change 23.4.4.3 [map.access] as indicated:
T& operator[](const key_type& x);-1- Effects:
If there is no key equivalent to x in the map, inserts value_type(x, T()) into the map.Equivalent to: return try_emplace(x).first->second;-2- Requires: key_type shall be CopyInsertable and mapped_type shall be DefaultInsertable into *this.-3- Returns: A reference to the mapped_type corresponding to x in *this.-4- Complexity: Logarithmic.T& operator[](key_type&& x);-5- Effects:
If there is no key equivalent to x in the map, inserts value_type(std::move(x), T()) into the map.Equivalent to: return try_emplace(move(x)).first->second;-6- Requires: mapped_type shall be DefaultInsertable into *this.-7- Returns: A reference to the mapped_type corresponding to x in *this.-8- Complexity: Logarithmic.
Change 23.5.4.3 [unord.map.elem] as indicated:
mapped_type& operator[](const key_type& k); mapped_type& operator[](key_type&& k);-2- Effects:
-1- Requires: mapped_type shall be DefaultInsertable into *this. For the first operator, key_type shall be CopyInsertable into *this. For the second operator, key_type shall be MoveConstructible.If the unordered_map does not already contain an element whose key is equivalent to k, the first operator inserts the value value_type(k, mapped_type()) and the second operator inserts the value value_type(std::move(k), mapped_type())For the first operator, equivalent to:return try_emplace(k).first->second;for the second operator, equivalent to:
return try_emplace(move(k)).first->second;
-3- Returns: A reference to x.second, where x is the (unique) element whose key is equivalent to k.-4- Complexity: Average case 𝒪(1), worst case 𝒪(size()).
Section: 17.6.3.5 [allocator.requirements] Status: Tentatively Ready Submitter: Daniel Krügler Opened: 2015-03-22 Last modified: 2015-04-08
View other active issues in [allocator.requirements].
View all other issues in [allocator.requirements].
View all issues with Tentatively Ready status.
Discussion:
This issue is a spin-off of issue LWG 2447: It focuses on the observation that 17.6.3.5 [allocator.requirements] p9 (based on the numbering of working draft N4296) gives the template member construct more relaxations than the template member destroy:
An allocator may constrain the types on which it can be instantiated and the arguments for which its construct member may be called. If a type cannot be used with a particular allocator, the allocator class or the call to construct may fail to instantiate.
Construction and destruction of a type T are usually intimately related to each other, so it seems similarly useful to allow the destroy member to fail to instantiate for a possible sub-set of instantiation types.
[2015-04-01 Library reflector vote]
The issue has been identified as Tentatively Ready based on six votes in favour.
Proposed resolution:
This wording is relative to N4296.
Change 17.6.3.5 [allocator.requirements] p9 as indicated:
-8- An allocator may constrain the types on which it can be instantiated and the arguments for which its construct or destroy members may be called. If a type cannot be used with a particular allocator, the allocator class or the call to construct or destroy may fail to instantiate.
Section: 25.3.1 [alg.copy] Status: New Submitter: Jonathan Wakely Opened: 2015-01-28 Last modified: 2015-04-08
View other active issues in [alg.copy].
View all other issues in [alg.copy].
View all issues with New status.
Discussion:
It's unspecified how many times copy_n increments the InputIterator. uninitialized_copy_n is specified to increment it exactly n times, which means if an istream_iterator is used then the next character after those copied is read from the stream and then discarded, losing data.
I believe all three of Dinkumware, libc++ and libstdc++ implement copy_n with n - 1 increments of the InputIterator, which avoids reading and discarding a character when used with istream_iterator, but is inconsistent with uninitialized_copy_n and causes surprising behaviour with istreambuf_iterator instead, because copy_n(in, 2, copy_n(in, 2, out)) is not equivalent to copy_n(in, 4, out)Proposed resolution:
Section: 20.4.2.7 [tuple.rel], 20.7.9.2 [allocator.globals], 20.8.1.5 [unique.ptr.special], 20.8.2.2.7 [util.smartptr.shared.cmp], 20.12.5.6 [time.duration.comparisons], 20.12.6.6 [time.point.comparisons], 20.13.5 [scoped.adaptor.operators], 24.5.1.3.13 [reverse.iter.op==], 24.5.3.3.13 [move.iter.op.comp] Status: New Submitter: Richard Smith Opened: 2015-02-07 Last modified: 2015-04-08
View other active issues in [tuple.rel].
View all other issues in [tuple.rel].
View all issues with New status.
Discussion:
The standard library specifies a lot of heterogeneous comparison operators. For instance:
template<class... TTypes, class... UTypes> constexpr bool operator!=(const tuple<TTypes...>&, const tuple<UTypes...>&);
This has an unfortunate consequence:
#include <tuple> #include <utility> using namespace std::rel_ops; std::tuple<int> a(0); bool b = a != a;
The last line here is ill-formed due to ambiguity: it might be rel_ops::operator!=, and it might be the heterogeneous tuple operator!=. These are not partially ordered, because they have different constraints: rel_ops requires the types to match, whereas the tuple comparison requires both types to be tuples (but not to match). The same thing happens for user code that defines its own unconstrained 'template<typename T> operator!=(const T&, const T&)' rather than using rel_ops.
One straightforward fix would be to add a homogeneous overload for each heterogeneous comparison:template<class... TTypes> constexpr bool operator!=(const tuple<TTypes...>&, const tuple<TTypes...>&);This is then unambiguously chosen over the other options in the preceding case. FWIW, libstdc++ already does this in some cases.
Proposed resolution:
Section: 27.9.1.5 [filebuf.virtuals] Status: New Submitter: Aaron Ballman Opened: 2015-02-09 Last modified: 2015-04-08
View all other issues in [filebuf.virtuals].
View all issues with New status.
Discussion:
The restrictions on reading and writing a sequence controlled by an object of class basic_filebuf<charT, traits> are the same as for reading and writing with the Standard C library FILEs. One of the restrictions placed by C is on the behavior of a stream that is opened for input and output. See the C99 standard, 7.19.5.3p6 for more details, but the gist is that when opened in update mode, reads and writes must have an intervening file positioning or flushing call to not trigger UB.
27.9.1.5 [filebuf.virtuals] p13 specifies that basic_filebuf::seekoff() calls std::fseek(). However, there is no mention of std::fseek() in basic_filebuf::seekpos(), and no mention of std::fflush() in basic_filebuf::sync(), which seem like an oversight.
Proposed resolution:
This wording is relative to N4296.
Change 27.9.1.5 [filebuf.virtuals] p16 as follows [Editorial note: A footnote referring to fseek is not needed, because this is already covered by the existing footnote 334]:
-16- Alters the file position, if possible, to correspond to the position stored in sp (as described below). Altering the file position performs as follows:
if (om & ios_base::out) != 0, then update the output sequence and write any unshift sequence;
set the file position to sp as if by calling std::fseek(file, sp, SEEK_SET);
if (om & ios_base::in) != 0, then update the input sequence;
where om is the open mode passed to the last call to open(). The operation fails if is_open() returns false.
Change 27.9.1.5 [filebuf.virtuals] p19 as follows and add a new footnote that mimics comparable footnotes in 27.9.1.4 [filebuf.members] and 27.9.1.5 [filebuf.virtuals]:
-19- Effects: If a put area exists, calls filebuf::overflow to write the characters to the file, then flushes the file as if by calling std::fflush(file) [Footnote: The function signature fflush(FILE*) is declared in <cstdio> (27.9.2).]. If a get area exists, the effect is implementation-defined.
Section: 26.8 [c.math] Status: New Submitter: Matheus Izvekov Opened: 2015-02-13 Last modified: 2015-04-08
View other active issues in [c.math].
View all other issues in [c.math].
View all issues with New status.
Discussion:
Using numeric wrappers with <cmath> functions is currently troublesome. Code such as: "std::exp2(std::integral_constant<int, 5>{})" will fail to compile because of ambiguity.
Arguments which are implicitly convertible to an arithmetic type should be accepted whenever the latter would be accepted. David Krauss pointed out that some issue may present itself with numeric libraries which provide <cmath> equivalents in their own namespace which are not more specialized than the ones provided in <cmath>. If the changes proposed are implemented, then cases where the user brings those into scope through ADL might become ambiguous. It's hard to assess how much breakage this would cause in the wild, and how much work it would take to fix. Should this be determined to be a problem, it's possible to make the new behaviour optional, and disabled by default for all user-defined types.Proposed resolution:
This wording is relative to N4296.
Change 26.8 [c.math] p11 b2 as indicated:
-11- Moreover, there shall be additional overloads sufficient to ensure:
[…]
Otherwise, if any arithmetic argument corresponding to a double parameter has type double or
an integer typea type which is not floating-point, but which is implicitly convertible to double, then all arithmetic arguments corresponding to double parameters are effectively cast to double.[…]
Section: 21.4.5 [string.access] Status: New Submitter: Matt Weber Opened: 2015-02-21 Last modified: 2015-04-08
View all other issues in [string.access].
View all issues with New status.
Discussion:
It is often desirable to use a std::basic_string object as a buffer when interoperating with libraries that mutate null-terminated arrays of characters. In many cases, these legacy APIs write a null terminator at the specified end of the provided buffer. Providing such a function with an appropriately-sized std::basic_string results in undefined behavior when the charT object at the size() position is overwritten, even if the value remains unchanged.
Absent the ability to allow for this, applications are forced into pessimizations such as: providing appropriately-sized std::vectors of charT for interoperating with the legacy API, and then copying the std::vector to a std::basic_string; providing an oversized std::basic_string object and then calling resize() later. A trivial example:#include <string> #include <vector> void legacy_function(char *out, size_t count) { for (size_t i = 0; i < count; ++i) { *out++ = '0' + (i % 10); } *out = '\0'; // if size() == count, this results in undefined behavior } int main() { std::string s(10, '\0'); legacy_function(&s[0], s.size()); // undefined behavior std::vector<char> buffer(11); legacy_function(&buffer[0], buffer.size() - 1); std::string t(&buffer[0], buffer.size() - 1); // potentially expensive copy std::string u(11, '\0'); legacy_function(&u[0], u.size() - 1); u.resize(u.size() - 1); // needlessly complicates the program's logic }
A slight relaxation of the requirement on the returned object from the element access operator would allow for this interaction with no semantic change to existing programs.
Proposed resolution:
This wording is relative to N4296.
Edit 21.4.5 [string.access] as indicated:
const_reference operator[](size_type pos) const; reference operator[](size_type pos);-1- Requires: […]
-2- Returns: *(begin() + pos) if pos < size(). Otherwise, returns a reference to an object of type charT with value charT(), where modifying the object to any value other than charT() leads to undefined behavior. […]
Section: 20.13.1 [allocator.adaptor.syn] Status: New Submitter: Jonathan Wakely Opened: 2015-03-02 Last modified: 2015-04-08
View all issues with New status.
Discussion:
The class definition in 20.13.1 [allocator.adaptor.syn] declares a move constructor, which means that the copy assignment operator is defined as deleted, and no move assignment operator is declared.
This means a scoped_allocator_adaptor is not assignable, and a container using scoped_allocator_adaptor<A...> may not be CopyAssignable or MoveAssignable (depending on the propagate_on_container_xxxx_assignment traits of the outer and inner allocator types).[2015-04-03 Howard comments]
If the contained allocators are not assignable, I think we need the ability of = default to automagically become = delete. My concern is that is_copy_assignable<scoped_allocator_adaptor<CustomAllocator>>::value get the right answer for both cases:
is_copy_assignable<CustomAllocator>::value is true.
is_copy_assignable<CustomAllocator>::value is false.
If we allow the vendor to declare and provide the copy assignment operator, the chance of getting #2 correct goes to zero.
Previous resolution [SUPERSEDED]:
This wording is relative to N4296.
Add to the synopsis in 20.13.1 [allocator.adaptor.syn]/1 [Editorial remark: The proposed wording does not explicitly specify the semantics of the added copy/move assignment operators, based on 17.5.2.2 [functions.within.classes] p1, which says:
"For the sake of exposition, Clauses 18 through 30 and Annex D do not describe copy/move constructors, assignment operators, or (non-virtual) destructors with the same apparent semantics as those that can be generated by default (12.1, 12.4, 12.8)." — end remark]:[…] template <class OuterA2> scoped_allocator_adaptor( scoped_allocator_adaptor<OuterA2, InnerAllocs...>&& other) noexcept; scoped_allocator_adaptor& operator=(const scoped_allocator_adaptor&); scoped_allocator_adaptor& operator=(scoped_allocator_adaptor&&); ~scoped_allocator_adaptor(); […]
Proposed resolution:
This wording is relative to N4296.
Add to the synopsis in 20.13.1 [allocator.adaptor.syn]/1:
[…] template <class OuterA2> scoped_allocator_adaptor( scoped_allocator_adaptor<OuterA2, InnerAllocs...>&& other) noexcept; scoped_allocator_adaptor& operator=(const scoped_allocator_adaptor&) = default; scoped_allocator_adaptor& operator=(scoped_allocator_adaptor&&) = default; ~scoped_allocator_adaptor(); […]
Section: 23.3.3.4 [deque.modifiers], 23.3.6.5 [vector.modifiers] Status: New Submitter: Anton Savin Opened: 2015-03-03 Last modified: 2015-04-08
View other active issues in [deque.modifiers].
View all other issues in [deque.modifiers].
View all issues with New status.
Discussion:
In the latest draft N4296, and in all drafts up to at least N3337:
23.3.3.4 [deque.modifiers]/5 (regarding deque::erase()):Complexity: The number of calls to the destructor is the same as the number of elements erased, but the number of calls to the assignment operator is no more than the lesser of the number of elements before the erased elements and the number of elements after the erased elements.
23.3.6.5 [vector.modifiers]/4 (regarding vector::erase()):
Complexity: The destructor of T is called the number of times equal to the number of the elements erased, but the move assignment operator of T is called the number of times equal to the number of elements in the vector after the erased elements.
Is there any reason for explicit mentioning of move assignment for std::vector::erase()? Shouldn't these two wordings be the same with this regard?
Also, for std::deque, it's not clear from the text which destructors and assignment operators are called.Proposed resolution:
This wording is relative to N4296.
Change 23.3.3.4 [deque.modifiers]/5 to:
-5- Complexity: The number of calls to the destructor of T is the same as the number of elements erased, but the number of calls to the assignment operator of T is no more than the lesser of the number of elements before the erased elements and the number of elements after the erased elements.
Change 23.3.6.5 [vector.modifiers]/4 to:
-4- Complexity: The destructor of T is called the number of times equal to the number of the elements
erased, but the move assignment operator of T is called the number of times equal to the number of
elements in the vector after the erased elements.
Section: 22.3.3.2.2 [conversions.string] Status: New Submitter: Jonathan Wakely Opened: 2015-03-04 Last modified: 2015-04-08
View other active issues in [conversions.string].
View all other issues in [conversions.string].
View all issues with New status.
Discussion:
How do wstring_convert::from_bytes and wstring_convert::to_bytes use the cvtstate member?
Is it passed to the codecvt member functions? Is a copy of it passed to the member functions? "Otherwise it shall be left unchanged" implies a copy is used, but if that's really what's intended there are simpler ways to say so.Proposed resolution:
Section: 22.3.3.2.3 [conversions.buffer] Status: New Submitter: Jonathan Wakely Opened: 2015-03-04 Last modified: 2015-04-08
View other active issues in [conversions.buffer].
View all other issues in [conversions.buffer].
View all issues with New status.
Discussion:
How does wbuffer_convert use the cvtstate member?
Is the same conversion state object used for converting both the get and put areas? That means a read which runs out of bytes halfway through a multibyte character will leave some shift state in cvtstate, which would then be used by a following write, even though the shift state of the get area is unrelated to the put area.Proposed resolution:
Section: 22.3.3.2.3 [conversions.buffer] Status: New Submitter: Jonathan Wakely Opened: 2015-03-04 Last modified: 2015-04-08
View other active issues in [conversions.buffer].
View all other issues in [conversions.buffer].
View all issues with New status.
Discussion:
If a codecvt conversion returns codecvt_base::error should that be treated as EOF? An exception? Should all the successfully converted characters before a conversion error be available to the users of the wbuffer_convert and/or the internal streambuf, or does a conversion error lose information?
Proposed resolution:
Section: 22.3.3.2.2 [conversions.string] Status: New Submitter: Jonathan Wakely Opened: 2015-03-04 Last modified: 2015-04-08
View other active issues in [conversions.string].
View all other issues in [conversions.string].
View all issues with New status.
Discussion:
Paragraph 4 of 22.3.3.2.2 [conversions.string] introduces byte_err_string as "a byte string to display on errors". What does display mean? The string is returned on error, it's not displayed anywhere.
Paragraph 14 says "Otherwise, if the object was constructed with a byte-error string, the member function shall return the byte-error string." The term byte-error string is not used anywhere else. Paragraph 17 talks about storing "default values in byte_err_string". What default value? Is "Hello, world!" allowed? If it means default-construction it should say so. If paragraph 14 says it won't be used what does it matter how it's initialized? The end of the paragraph refers to storing "byte_err in byte_err_string". This should be more clearly related to the wording in paragraph 14. It might help if the constructor (and destructor) was specified before the other member functions, so it can more formally define the difference between being "constructed with a byte-error string" and not. All the same issues apply to the wide_err_string member.Proposed resolution:
Section: 21.8 [c.strings] Status: Tentatively Ready Submitter: S. B.Tam Opened: 2015-01-18 Last modified: 2015-04-08
View other active issues in [c.strings].
View all other issues in [c.strings].
View all issues with Tentatively Ready status.
Discussion:
N4296 Table 73 mentions the functions mbsrtowc and wcsrtomb, which are not defined in ISO C or ISO C++. Presumably they should be mbsrtowcs and wcsrtombs instead.
[2015-04-02 Library reflector vote]
The issue has been identified as Tentatively Ready based on six votes in favour.
Proposed resolution:
This wording is relative to N4296.
Table 33 — Potential mbstate_t data races mbrlen mbrtowc mbsrtowcs mbtowc wcrtomb wcsrtombs wctomb
Section: 18.8.6 [except.nested] Status: New Submitter: Stephan T. Lavavej Opened: 2015-03-27 Last modified: 2015-04-08
View other active issues in [except.nested].
View all other issues in [except.nested].
View all issues with New status.
Discussion:
When N2559 was voted into the Working Paper, it said "This function template must take special case to handle non-class types, unions and [[final]] classes that cannot be derived from, and [...]". However, its Standardese didn't handle final classes, and this was never revisited. Now that we have is_final, we can achieve this proposal's original intention.
Additionally, we need to handle the case where U is nested_exception itself. is_base_of's wording handles this and ignores cv-qualifiers. (Note that is_class detects "non-union class type".)Proposed resolution:
This wording is relative to N4296.
Change 18.8.6 [except.nested] as depicted:
template <class T> [[noreturn]] void throw_with_nested(T&& t);-6- Let U be remove_reference_t<T>.
-7- Requires: U shall be CopyConstructible. -8- Throws: ifU is a non-union class type not derived from nested_exceptionis_class<U>::value && !is_final<U>::value && !is_base_of<nested_exception, U>::value is true, an exception of unspecified type that is publicly derived from both U and nested_exception and constructed from std::forward<T>(t), otherwise std::forward<T>(t).
Section: 18.8.6 [except.nested] Status: New Submitter: Stephan T. Lavavej Opened: 2015-03-27 Last modified: 2015-04-08
View other active issues in [except.nested].
View all other issues in [except.nested].
View all issues with New status.
Discussion:
rethrow_if_nested() wants to determine "If the dynamic type of e is publicly and unambiguously derived from nested_exception", but 5.2.7 [expr.dynamic.cast] specifies that dynamic_cast has a couple of limitations.
First, nonpolymorphic inputs. These could be non-classes, or nonpolymorphic classes. The Standardese handles non-classes, although implementers need special logic. (If E is int, the dynamic type can't possibly derive from nested_exception. Implementers need to detect this and avoid dynamic_cast, which would be ill-formed due to 5.2.7 [expr.dynamic.cast]/2.) The Standardese is defective when E is a nonpolymorphic class. Consider the following example:struct Nonpolymorphic { }; struct MostDerived : Nonpolymorphic, nested_exception { }; MostDerived md; const Nonpolymorphic& np = md; rethrow_if_nested(np);
According to 1.3 [defns.dynamic.type], the dynamic type of np is MostDerived. However, it's physically impossible to discover this, and attempting to do so will lead to an ill-formed dynamic_cast (5.2.7 [expr.dynamic.cast]/6). The Standardese must be changed to say that if E is nonpolymorphic, nothing happens.
Second, statically good but dynamically bad inputs. Consider the following example:struct Nested1 : nested_exception { }; struct Nested2 : nested_exception { }; struct Ambiguous : Nested1, Nested2 { }; Ambiguous amb; const Nested1& n1 = amb; rethrow_if_nested(n1);
Here, the static type Nested1 is good (i.e. publicly and unambiguously derived from nested_exception), but the dynamic type Ambiguous is bad. The Standardese currently says that we have to detect the dynamic badness, but dynamic_cast won't let us. 5.2.7 [expr.dynamic.cast]/3 and /5 are special cases (identity-casting and upcasting, respectively) that activate before the "run-time check" behavior that we want (/6 and below). Statically good inputs succeed (regardless of the dynamic type) and statically bad inputs are ill-formed (implementers must use type traits to avoid this).
It might be possible to implement this with clever trickery involving virtual base classes, but implementers shouldn't be asked to do that. It would definitely be possible to implement this with a compiler hook (a special version of dynamic_cast), but implementers shouldn't be asked to do so much work for such an unimportant case. (This case is pathological because the usual way of adding nested_exception inheritance is throw_with_nested(), which avoids creating bad inheritance.) The Standardese should be changed to say that statically good inputs are considered good. Finally, we want is_base_of's "base class or same class" semantics. If the static type is nested_exception, we have to consider it good due to dynamic_cast's identity-casting behavior. And if the dynamic type is nested_exception, it is definitely good.Proposed resolution:
This wording is relative to N4296.
Change 18.8.6 [except.nested] as depicted:
template <class E> void rethrow_if_nested(const E& e);-9- Effects: If E is not a polymorphic class type, there is no effect. Otherwise, if the static type or the dynamic type of e is nested_exception or is publicly and unambiguously derived from nested_exception, calls dynamic_cast<const nested_exception&>(e).rethrow_nested().
Section: 20.4.2.6 [tuple.elem] Status: New Submitter: Stephan T. Lavavej Opened: 2015-03-27 Last modified: 2015-04-08
View all other issues in [tuple.elem].
View all issues with New status.
Discussion:
const rvalues are weird, but they're part of the type system. Consider the following code:
#include <functional> #include <string> #include <tuple> using namespace std; string str1() { return "one"; } const string str2() { return "two"; } tuple<string> tup3() { return make_tuple("three"); } const tuple<string> tup4() { return make_tuple("four"); } int main() { // cref(str1()); // BAD, properly rejected // cref(str2()); // BAD, properly rejected // cref(get<0>(tup3())); // BAD, properly rejected cref(get<0>(tup4())); // BAD, but improperly accepted! }
As tuple is a fundamental building block (and the only convenient way to have variadic data members), it should not open a hole in the type system. get() should imitate 5.2.5 [expr.ref]'s rules for accessing data members. (This is especially true for pair, where both get<0>() and .first are available.)
While we're in the neighborhood, we can dramatically simplify the wording here. All we need to do is follow 20.4.2.6 [tuple.elem]/9's example of saying "Returns: A reference to STUFF", and allow implementers to figure out how to achieve that with the given return types.Proposed resolution:
This wording is relative to N4296.
Change 20.2 [utility]/2 "Header <utility> synopsis" as depicted:
[…] template<size_t I, class T1, class T2> constexpr tuple_element_t<I, pair<T1, T2>>& get(pair<T1, T2>&) noexcept; template<size_t I, class T1, class T2> constexpr tuple_element_t<I, pair<T1, T2>>&& get(pair<T1, T2>&&) noexcept; template<size_t I, class T1, class T2> constexpr const tuple_element_t<I, pair<T1, T2>>& get(const pair<T1, T2>&) noexcept; template<size_t I, class T1, class T2> constexpr const tuple_element_t<I, pair<T1, T2>>&& get(const pair<T1, T2>&&) noexcept; template <class T, class U> constexpr T& get(pair<T, U>& p) noexcept; template <class T, class U> constexpr const T& get(const pair<T, U>& p) noexcept; template <class T, class U> constexpr T&& get(pair<T, U>&& p) noexcept; template <class T, class U> constexpr const T&& get(const pair<T, U>&& p) noexcept; template <class T, class U> constexpr T& get(pair<U, T>& p) noexcept; template <class T, class U> constexpr const T& get(const pair<U, T>& p) noexcept; template <class T, class U> constexpr T&& get(pair<U, T>&& p) noexcept; template <class T, class U> constexpr const T&& get(const pair<U, T>&& p) noexcept; […]
Change 20.4.1 [tuple.general]/2 "Header <tuple> synopsis" as depicted:
[…] // 20.4.2.6, element access: template <size_t I, class... Types> constexpr tuple_element_t<I, tuple<Types...>>& get(tuple<Types...>&) noexcept; template <size_t I, class... Types> constexpr tuple_element_t<I, tuple<Types...>>&& get(tuple<Types...>&&) noexcept; template <size_t I, class... Types> constexpr const tuple_element_t<I, tuple<Types...>>& get(const tuple<Types...>&) noexcept; template <size_t I, class... Types> constexpr const tuple_element_t<I, tuple<Types...>>&& get(const tuple<Types...>&&) noexcept; template <class T, class... Types> constexpr T& get(tuple<Types...>& t) noexcept; template <class T, class... Types> constexpr T&& get(tuple<Types...>&& t) noexcept; template <class T, class... Types> constexpr const T& get(const tuple<Types...>& t) noexcept; template <class T, class... Types> constexpr const T&& get(const tuple<Types...>&& t) noexcept; […]
Change 23.3.1 [sequences.general]/2 "Header <array> synopsis" as depicted:
[…] template <size_t I, class T, size_t N> constexpr T& get(array<T, N>&) noexcept; template <size_t I, class T, size_t N> constexpr T&& get(array<T, N>&&) noexcept; template <size_t I, class T, size_t N> constexpr const T& get(const array<T, N>&) noexcept; template <size_t I, class T, size_t N> constexpr const T&& get(const array<T, N>&&) noexcept; […]
Change 20.3.4 [pair.astuple] as depicted:
template<size_t I, class T1, class T2> constexpr tuple_element_t<I, pair<T1, T2>>& get(pair<T1, T2>& p) noexcept; template<size_t I, class T1, class T2> constexpr const tuple_element_t<I, pair<T1, T2>>& get(const pair<T1, T2>& p) noexcept;
-3- Returns: If I == 0 returns p.first; if I == 1 returns p.second; otherwise the program is ill-formed.template<size_t I, class T1, class T2> constexpr tuple_element_t<I, pair<T1, T2>>&& get(pair<T1, T2>&& p) noexcept; template<size_t I, class T1, class T2> constexpr const tuple_element_t<I, pair<T1, T2>>&& get(const pair<T1, T2>&& p) noexcept;-4- Returns: If I == 0 returns a reference to
std::forward<T1&&>(p.first); if I == 1 returns a reference tostd::forward<T2&&>(p.second); otherwise the program is ill-formed.template <class T, class U> constexpr T& get(pair<T, U>& p) noexcept; template <class T, class U> constexpr const T& get(const pair<T, U>& p) noexcept;
-5- Requires: T and U are distinct types. Otherwise, the program is ill-formed.-6- Returns: get<0>(p);template <class T, class U> constexpr T&& get(pair<T, U>&& p) noexcept; template <class T, class U> constexpr const T&& get(const pair<T, U>&& p) noexcept;-7- Requires: T and U are distinct types. Otherwise, the program is ill-formed.
-8- Returns: A reference to p.first.get<0>(std::move(p));template <class T, class U> constexpr T& get(pair<U, T>& p) noexcept; template <class T, class U> constexpr const T& get(const pair<U, T>& p) noexcept;
-9- Requires: T and U are distinct types. Otherwise, the program is ill-formed.-10- Returns: get<1>(p);template <class T, class U> constexpr T&& get(pair<U, T>&& p) noexcept; template <class T, class U> constexpr const T&& get(const pair<U, T>&& p) noexcept;-11- Requires: T and U are distinct types. Otherwise, the program is ill-formed.
-12- Returns: A reference to p.second.get<1>(std::move(p));
Change 20.4.2.6 [tuple.elem] as depicted:
template <size_t I, class... Types> constexpr tuple_element_t<I, tuple<Types...> >& get(tuple<Types...>& t) noexcept;
-1- Requires: I < sizeof...(Types). The program is ill-formed if I is out of bounds.-2- Returns: A reference to the Ith element of t, where indexing is zero-based.template <size_t I, class... Types> constexpr tuple_element_t<I, tuple<Types...> >&& get(tuple<Types...>&& t) noexcept; // Note A
-3- Effects: Equivalent to return std::forward<typename tuple_element<I, tuple<Types...> >::type&&>(get<I>(t));-4- Note: if a T in Types is some reference type X&, the return type is X&, not X&&. However, if the element type is a non-reference type T, the return type is T&&.template <size_t I, class... Types> constexpr tuple_element_t<I, tuple<Types...> > const& get(const tuple<Types...>& t) noexcept; // Note B template <size_t I, class... Types> constexpr const tuple_element_t<I, tuple<Types...> >&& get(const tuple<Types...>&& t) noexcept;-5- Requires: I < sizeof...(Types). The program is ill-formed if I is out of bounds.
-6- Returns: Aconstreference to the Ith element of t, where indexing is zero-based. -?- [Note A: if a T in Types is some reference type X&, the return type is X&, not X&&. However, if the element type is a non-reference type T, the return type is T&&. — end note] -7- [Note B: Constness is shallow. If a T in Types is some reference type X&, the return type is X&, not const X&. However, if the element type is non-reference type T, the return type is const T&. This is consistent with how constness is defined to work for member variables of reference type. — end note]template <class T, class... Types> constexpr T& get(tuple<Types...>& t) noexcept; template <class T, class... Types> constexpr T&& get(tuple<Types...>&& t) noexcept; template <class T, class... Types> constexpr const T& get(const tuple<Types...>& t) noexcept; template <class T, class... Types> constexpr const T&& get(const tuple<Types...>&& t) noexcept;-8- Requires: The type T occurs exactly once in Types.... Otherwise, the program is ill-formed.
-9- Returns: A reference to the element of t corresponding to the type T in Types.... […]
Change 23.3.2.9 [array.tuple] as depicted:
template <size_t I, class T, size_t N> constexpr T& get(array<T, N>& a) noexcept;
-3- Requires: I < N. The program is ill-formed if I is out of bounds.-4- Returns: A reference to the Ith element of a, where indexing is zero-based.template <size_t I, class T, size_t N> constexpr T&& get(array<T, N>&& a) noexcept;
-5- Effects: Equivalent to return std::move(get<I>(a));template <size_t I, class T, size_t N> constexpr const T& get(const array<T, N>& a) noexcept; template <size_t I, class T, size_t N> constexpr const T&& get(const array<T, N>&& a) noexcept;-6- Requires: I < N. The program is ill-formed if I is out of bounds.
-7- Returns: Aconstreference to the Ith element of a, where indexing is zero-based.
Section: 20.9.2 [func.require] Status: New Submitter: Stephan T. Lavavej Opened: 2015-03-27 Last modified: 2015-04-08
View other active issues in [func.require].
View all other issues in [func.require].
View all issues with New status.
Discussion:
20.9.2 [func.require]/4 defines "simple call wrapper" and "forwarding call wrapper". Only mem_fn() is specified to be a "simple call wrapper", by 20.9.11 [func.memfn]/1: "A simple call wrapper (20.9.1) fn such that the expression fn(t, a2, ..., aN) is equivalent to INVOKE(pm, t, a2, ..., aN) (20.9.2)."
This suggests, but doesn't outright state, that perfect forwarding is involved. It matters for PMFs like R (T::*)(Arg) where Arg is passed by value — if the mem_fn() wrapper's function call operator takes Arg by value, an extra copy/move will be observable. We should require perfect forwarding here.Proposed resolution:
This wording is relative to N4296.
Change 20.9.2 [func.require] as depicted [Editorial remark: This simply adds "A simple call wrapper is a forwarding call wrapper", then moves the sentence. — end of remark]:
-4- Every call wrapper (20.9.1) shall be MoveConstructible.
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 arbitrary argument list and delivers the arguments to the wrapped callable object as references. This forwarding step shall ensure that rvalue arguments are delivered as rvalue-references and lvalue arguments are delivered as lvalue-references. A simple call wrapper is a forwarding call wrapper that is CopyConstructible and CopyAssignable and whose copy constructor, move constructor, and assignment operator do not throw exceptions. [Note: In a typical implementation […] — end note]
Section: 20.9.10.3 [func.bind.bind] Status: New Submitter: Stephan T. Lavavej Opened: 2015-03-27 Last modified: 2015-04-08
View all other issues in [func.bind.bind].
View all issues with New status.
Discussion:
The Standard currently requires bind() to return something with a cv-overloaded function call operator. const is great, but volatile is not. First, the Library almost always ignores volatile's existence (with <type_traits> and <atomic> being rare exceptions). Second, implementations typically store bound arguments in a tuple, but get() isn't overloaded for volatile tuple. Third, when a bound argument is a reference_wrapper, we have to call tid.get(), but that won't compile for a volatile reference_wrapper. Finally, const and volatile don't always have to be handled symmetrically — for example, lambda function call operators are const by default, but they can't ever be volatile.
Implementers shouldn't be required to provide cv-overloading here. (They can provide it as a conforming extension if they want.)Proposed resolution:
This wording is relative to N4296.
Change 20.9.10.3 [func.bind.bind] as depicted:
template<class F, class... BoundArgs> unspecified bind(F&& f, BoundArgs&&... bound_args);-2- Requires: is_constructible<FD, F>::value shall be true. For each Ti in BoundArgs, is_constructible<TiD, Ti>::value shall be true. INVOKE(fd, w1, w2, ..., wN) (20.9.2) shall be a valid expression for some values w1, w2, ..., wN, where N == sizeof...(bound_args). The cv-qualifiers cv of the call wrapper g, as specified below, shall be neither volatile nor const volatile.
[…]template<class R, class F, class... BoundArgs> unspecified bind(F&& f, BoundArgs&&... bound_args);-6- Requires: is_constructible<FD, F>::value shall be true. For each Ti in BoundArgs, is_constructible<TiD, Ti>::value shall be true. INVOKE(fd, w1, w2, ..., wN) shall be a valid expression for some values w1, w2, ..., wN, where N == sizeof...(bound_args). The cv-qualifiers cv of the call wrapper g, as specified below, shall be neither volatile nor const volatile.
[…]
Section: 20.9.10.4 [func.bind.place] Status: New Submitter: Stephan T. Lavavej Opened: 2015-03-27 Last modified: 2015-04-08
View all issues with New status.
Discussion:
piecewise_construct (20.3.5 [pair.piecewise]), allocator_arg (20.7.6 [allocator.tag]), and adopt_lock/defer_lock/try_to_lock (30.4.2 [thread.lock]) are all required to be constexpr with internal linkage. bind()'s placeholders should be allowed to follow this modern practice, for increased consistency and reduced implementer headaches (header-only is easier than separately-compiled).
Proposed resolution:
This wording is relative to N4296.
Change 20.9 [function.objects] p2 "Header <functional> synopsis" as depicted:
namespace placeholders { // M is the implementation-defined number of placeholders see belowextern unspecified_1; see belowextern unspecified_2; ... see belowextern unspecified_M; }
Change 20.9.10.4 [func.bind.place] p2 as depicted:
namespace std::placeholders { // M is the implementation-defined number of placeholders see belowextern unspecified_1; see belowextern unspecified_2; . . . see belowextern unspecified_M; }-1- All placeholder types shall be DefaultConstructible and CopyConstructible, and their default constructors and copy/move constructors shall not throw exceptions. It is implementation-defined whether placeholder types are CopyAssignable. CopyAssignable placeholders' copy assignment operators shall not throw exceptions.
-?- Placeholders should be defined as:constexpr unspecified _1{};If they are not, they shall be declared as:
extern unspecified _1;
Section: 20.9.11 [func.memfn] Status: New Submitter: Stephan T. Lavavej Opened: 2015-03-27 Last modified: 2015-04-08
View all other issues in [func.memfn].
View all issues with New status.
Discussion:
mem_fn() is wide contract and doesn't do anything that could throw exceptions, so it should be marked noexcept.
Note that mem_fn() is perfectly happy to wrap a null PMF/PMD, it just can't be invoked later. This is exactly like std::function, which can be constructed from null PMFs/PMDs. Therefore, mem_fn() will remain wide contract forever.Proposed resolution:
This wording is relative to N4296.
Change 20.9 [function.objects] p2 "Header <functional> synopsis" as depicted:
[…] // 20.9.11, member function adaptors: template<class R, class T> unspecified mem_fn(R T::*) noexcept; […]
Change 20.9.11 [func.memfn] as depicted:
template<class R, class T> unspecified mem_fn(R T::* pm) noexcept;[…]
-4- Throws: Nothing.
Section: 28 [re] Status: New Submitter: Stephan T. Lavavej Opened: 2015-03-27 Last modified: 2015-04-08
View other active issues in [re].
View all other issues in [re].
View all issues with New status.
Discussion:
Only 4 functions are marked noexcept in all of Clause 28. Many more need to be marked — for example, regex_error::code(), basic_regex::swap(), and sub_match::length().
Proposed resolution:
Section: 20.9.6 [comparisons] Status: New Submitter: Agustín K-ballo Bergé Opened: 2015-04-01 Last modified: 2015-04-08
View other active issues in [comparisons].
View all other issues in [comparisons].
View all issues with New status.
Discussion:
It is not entirely clear if and when the specializations of std::less (and friends) for pointer types can be used in a constant expression. Consider the following code:
#include <functional> struct foo {}; foo x, y; constexpr bool b = std::less<foo*>{}(&x, &y); // [1] foo z[] = {{}, {}}; constexpr bool ba = std::less<foo*>{}(&z[0], &z[1]); // [2]
Comparing the address of unrelated objects is not a constant expression since the result is unspecified, so it could be expected for [1] to fail and [2] to succeed. However, std::less specialization for pointer types is well-defined and yields a total order, so it could just as well be expected for [1] to succeed. Finally, since the implementation of such specializations is not mandated, [2] could fail as well (This could happen, if an implementation would provide such a specialization and if that would use built-in functions that would not be allowed in constant expressions, for example). In any case, the standard should be clear so as to avoid implementation-defined constexpr-ness.
Proposed resolution: