Doc. no. | D???? |
Date: | 2024-10-05 |
Project: | Programming Language C++ |
Reply to: | Jonathan Wakely <lwgchair@gmail.com> |
Revised 2024-10-05 at 11:58:06 UTC
Reference ISO/IEC IS 14882:2020(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:2020(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 and Accepted Issues 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:2020(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++20 - (C++ Standard, as revised for 2020) - The full WG21/PL22.16 committee has voted to accept the Defect Report's Proposed Resolution into the published 2020 revision to the C++ standard, ISO/IEC IS 14882:2020(E).
C++17 - (C++ Standard, as revised for 2017) - The full WG21/PL22.16 committee has voted to accept the Defect Report's Proposed Resolution into the published 2017 revision to the C++ standard, ISO/IEC IS 14882:2017(E).
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 2014 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.
TS - (TS - various) - The full WG21/PL22.16 committee has voted to accept the Defect Report's Proposed Resolution into a published Technical Specification.
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 explicit 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.
NAD Arrays - This status reflects an evolution of the language during the development of C++14/17, where work on a Technical Specification, called the Arrays TS was begun. In early 2016, this work was abandoned, and the work item was officially withdrawn. During development of the TS, a number of issues were opened the features in the TS. 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.
streamsize
in iostreamsSection: 31 [input.output] Status: Open Submitter: Martin Sebor Opened: 2003-09-18 Last modified: 2018-12-09
Priority: 3
View all other issues in [input.output].
View all issues with Open status.
Discussion:
A third party test suite tries to exercise istream::ignore(N)
with a negative value of
N
and expects that the implementation will treat N
as if it were 0
. Our
implementation asserts that (N >= 0
) holds and aborts the test.
I can't find anything in section 27 that prohibits such values but I don't
see what the effects of such calls should be, either (this applies to
a number of unformatted input functions as well as some member functions
of the basic_streambuf
template).
[ 2009-07 Frankfurt ]
This is related to LWG 255(i).
Move to NAD Future.
[LEWG Kona 2017]
Recommend Open: We agree that we should require N >= 0
for the selected functions
[2018-12-04 Reflector prioritization]
Set Priority to 3
Proposed resolution:
I propose that we add to each function in clause 27 that takes an argument, say N
, of type
streamsize
a Requires clause saying that "N >= 0
." The intent is to allow
negative streamsize values in calls to precision()
and width()
but disallow it in
calls to streambuf::sgetn()
, istream::ignore()
, or ostream::write()
.
[Kona: The LWG agreed that this is probably what we want. However, we
need a review to find all places where functions in clause 27 take
arguments of type streamsize
that shouldn't be allowed to go
negative. Martin will do that review.]
T
Section: 25.3.5.3 [input.iterators] Status: Open Submitter: Chris Jefferson Opened: 2004-09-16 Last modified: 2023-06-25
Priority: 3
View other active issues in [input.iterators].
View all other issues in [input.iterators].
View all issues with Open status.
Discussion:
From comp.std.c++:
I note that given an input iterator a for type T
,
then *a
only has to be "convertable to T
",
not actually of type T
.
Firstly, I can't seem to find an exact definition of "convertable to T
".
While I assume it is the obvious definition (an implicit conversion), I
can't find an exact definition. Is there one?
Slightly more worryingly, there doesn't seem to be any restriction on
the this type, other than it is "convertable to T
". Consider two input
iterators a
and b
. I would personally assume that most people would
expect *a==*b
would perform T(*a)==T(*b)
, however it doesn't seem that
the standard requires that, and that whatever type *a
is (call it U
)
could have == defined on it with totally different symantics and still
be a valid inputer iterator.
Is this a correct reading? When using input iterators should I write
T(*a)
all over the place to be sure that the object I'm using is the
class I expect?
This is especially a nuisance for operations that are defined to be
"convertible to bool
". (This is probably allowed so that
implementations could return say an int
and avoid an unnecessary
conversion. However all implementations I have seen simply return a
bool
anyway. Typical implementations of STL algorithms just write
things like while(a!=b && *a!=0)
. But strictly
speaking, there are lots of types that are convertible to T
but
that also overload the appropriate operators so this doesn't behave
as expected.
If we want to make code like this legal (which most people seem to
expect), then we'll need to tighten up what we mean by "convertible
to T
".
[Lillehammer: The first part is NAD, since "convertible" is well-defined in core. The second part is basically about pathological overloads. It's a minor problem but a real one. So leave open for now, hope we solve it as part of iterator redesign.]
[ 2009-07-28 Reopened by Alisdair. No longer solved by concepts. ]
[ 2009-10 Santa Cruz: ]
Mark as NAD Future. We agree there's an issue, but there is no proposed solution at this time and this will be solved by concepts in the future.
[2017-02 in Kona, LEWG recommends NAD]
Has been clarified by 14. By design. Ranges might make it go away. Current wording for input iterators is more constrained.
[2017-06-02 Issues Telecon]
Move to Open. This is very similar to 2962(i), possibly a duplicate.
Marshall to research
[2017-07 Toronto Thurs Issue Prioritization]
Previous resolution [SUPERSEDED]:
Rationale:
[ San Francisco: ]
Solved by N2758.
[2023-06; Varna]
During LWG discussion of this issue it was decided to reduce the priority to 3.
Furthermore, the still presented "Solved by" comment has been recognized as being no longer true, since the referred to pre-C++11 concept paper wording N2758 is no longer part of the working paper. It also has been observed, that the "convertible tobool
" part has since been resolved
by P1964 and the follow-up paper P2167.
Also LWG 3105(i) has a lot of overlap with this issue.
Proposed resolution:
Section: 32 [re] Status: Open Submitter: Eric Niebler Opened: 2005-07-01 Last modified: 2020-07-17
Priority: 4
View other active issues in [re].
View all other issues in [re].
View all issues with Open status.
Discussion:
A problem with TR1 regex is currently being discussed on the Boost
developers list. It involves the handling of case-insensitive matching
of character ranges such as [Z-a]. The proper behavior (according to the
ECMAScript standard) is unimplementable given the current specification
of the TR1 regex_traits<>
class template. John Maddock, the author of
the TR1 regex proposal, agrees there is a problem. The full discussion
can be found at http://lists.boost.org/boost/2005/06/28850.php (first
message copied below). We don't have any recommendations as yet.
-- Begin original message --
The situation of interest is described in the ECMAScript specification (ECMA-262), section 15.10.2.15:
"Even if the pattern ignores case, the case of the two ends of a range is significant in determining which characters belong to the range. Thus, for example, the pattern /[E-F]/i matches only the letters E, F, e, and f, while the pattern /[E-f]/i matches all upper and lower-case ASCII letters as well as the symbols [, \, ], ^, _, and `."
A more interesting case is what should happen when doing a case-insensitive match on a range such as [Z-a]. It should match z, Z, a, A and the symbols [, \, ], ^, _, and `. This is not what happens with Boost.Regex (it throws an exception from the regex constructor).
The tough pill to swallow is that, given the specification in TR1, I
don't think there is any effective way to handle this situation.
According to the spec, case-insensitivity is handled with
regex_traits<>::translate_nocase(CharT)
— two characters are equivalent
if they compare equal after both are sent through the translate_nocase
function. But I don't see any way of using this translation function to
make character ranges case-insensitive. Consider the difficulty of
detecting whether "z" is in the range [Z-a]. Applying the transformation
to "z" has no effect (it is essentially std::tolower
). And we're not
allowed to apply the transformation to the ends of the range, because as
ECMA-262 says, "the case of the two ends of a range is significant."
So AFAICT, TR1 regex is just broken, as is Boost.Regex. One possible fix is to redefine translate_nocase to return a string_type containing all the characters that should compare equal to the specified character. But this function is hard to implement for Unicode, and it doesn't play nice with the existing ctype facet. What a mess!
-- End original message --
[ John Maddock adds: ]
One small correction, I have since found that ICU's regex package does implement this correctly, using a similar mechanism to the current TR1.Regex.
Given an expression [c1-c2] that is compiled as case insensitive it:
Enumerates every character in the range c1 to c2 and converts it to it's case folded equivalent. That case folded character is then used a key to a table of equivalence classes, and each member of the class is added to the list of possible matches supported by the character-class. This second step isn't possible with our current traits class design, but isn't necessary if the input text is also converted to a case-folded equivalent on the fly.
ICU applies similar brute force mechanisms to character classes such as [[:lower:]] and [[:word:]], however these are at least cached, so the impact is less noticeable in this case.
Quick and dirty performance comparisons show that expressions such as "[X-\\x{fff0}]+" are indeed very slow to compile with ICU (about 200 times slower than a "normal" expression). For an application that uses a lot of regexes this could have a noticeable performance impact. ICU also has an advantage in that it knows the range of valid characters codes: code points outside that range are assumed not to require enumeration, as they can not be part of any equivalence class. I presume that if we want the TR1.Regex to work with arbitrarily large character sets enumeration really does become impractical.
Finally note that Unicode has:
Three cases (upper, lower and title). One to many, and many to one case transformations. Character that have context sensitive case translations - for example an uppercase sigma has two different lowercase forms - the form chosen depends on context(is it end of a word or not), a caseless match for an upper case sigma should match either of the lower case forms, which is why case folding is often approximated by tolower(toupper(c)).
Probably we need some way to enumerate character equivalence classes, including digraphs (either as a result or an input), and some way to tell whether the next character pair is a valid digraph in the current locale.
Hoping this doesn't make this even more complex that it was already,
[ Portland: Alisdair: Detect as invalid, throw an exception. Pete: Possible general problem with case insensitive ranges. ]
[ 2009-07 Frankfurt ]
We agree that this is a problem, but we do not know the answer.
We are going to declare this NAD until existing practice leads us in some direction.
No objection to NAD Future.
Move to NAD Future.
[LEWG Kona 2017]
Recommend Open: Tim Shen proposes: forbid use of case-insensitive ranges with regex traits other than
std::regex_traits<{char, wchar_t, char16_t, char32_t}>
when regex_constants::collate is specified.
[2020-07-17; Priority set to 4 in telecon]
Proposed resolution:
Section: 22.4.9 [tuple.rel], 99 [tr.tuple.rel] Status: LEWG Submitter: David Abrahams Opened: 2005-11-29 Last modified: 2016-01-28
Priority: Not Prioritized
View other active issues in [tuple.rel].
View all other issues in [tuple.rel].
View all issues with LEWG status.
Duplicate of: 348
Discussion:
Where possible, tuple
comparison operators <,<=,=>, and > ought to be
defined in terms of std::less
rather than operator<
, in order to
support comparison of tuples of pointers.
[ 2009-07-28 Reopened by Alisdair. No longer solved by concepts. ]
[ 2009-10 Santa Cruz: ]
If we solve this for
tuple
we would have to solve it forpair
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.
std::array
is a sequence that doesn't satisfy the sequence requirements?Section: 24.3.8 [array] Status: Open Submitter: Bo Persson Opened: 2006-12-30 Last modified: 2022-11-12
Priority: 3
View all other issues in [array].
View all issues with Open status.
Discussion:
The <array>
header is given under 24.3 [sequences].
24.3.8 [array]/paragraph 3 says:
"Unless otherwise specified, all array operations are as described in 24.2 [container.requirements]".
However, array
isn't mentioned at all in section 24.2 [container.requirements].
In particular, Table 82 "Sequence requirements" lists several operations (insert, erase, clear)
that std::array
does not have in 24.3.8 [array].
Also, Table 83 "Optional sequence operations" lists several operations that
std::array
does have, but array isn't mentioned.
[ 2009-07 Frankfurt ]
The real issue seems to be different than what is described here. Non-normative text says that
std::array
is a sequence container, but there is disagreement about what that really means. There are two possible interpretations:
- a sequence container is one that satisfies all sequence container requirements
- a sequence container is one that satisfies some of the sequence container requirements. Any operation that the container supports is specified by one or more sequence container requirements, unless that operation is specifically singled out and defined alongside the description of the container itself.
Move to Tentatively NAD.
[ 2009-07-15 Loïc Joly adds: ]
The section 24.2.4 [sequence.reqmts]/1 states that array is a sequence. 24.2.4 [sequence.reqmts]/3 introduces table 83, named Sequence container requirements. This seems to me to be defining the requirements for all sequences. However, array does not follow all of this requirements (this can be read in the array specific section, for the standard is currently inconsistent).
Proposed resolution 1 (minimal change):
Say that array is a container, that in addition follows only some of the sequence requirements, as described in the array section:
The library provides
fivethree basic kinds of sequence containers:,array
vector
,,forward_list
list
, anddeque
. In addition,array
andforward_list
follows some of the requirements of sequences, as described in their respective sections.Proposed resolution 2 (most descriptive description, no full wording provided):
Introduce the notion of a Fixed Size Sequence, with it requirement table that would be a subset of the current Sequence container. array would be the only Fixed Size Sequence (but dynarray is in the queue for TR2). Sequence requirements would now be requirements in addition to Fixed Size Sequence requirements (it is currently in addition to container).
[ 2009-07 Frankfurt: ]
Move to NAD Editorial
[ 2009 Santa Cruz: ]
This will require a lot of reorganization. Editor doesn't think this is really an issue, since the description of array can be considered as overriding what's specified about sequences. Move to NAD.
[2022-10-27; Hubert Tong comments and requests to reopen]
This issue appears to be unresolved (should not be NAD).
As noted in 24.3.8.1 [array.overview] paragraph 3,array
does not meet 24.2.2.2 [container.reqmts] paragraph 10. This means that
array
does not meet the container requirements, never mind the requirements
for sequence containers or contiguous containers.
However, there is wording that claims the opposite.
24.2.4 [sequence.reqmts] paragraph 1:
In addition,
array
is provided as a sequence container which provides limited sequence operations because it has a fixed number of elements.
(Perhaps the above should be worded with "except".)
24.3.1 [sequences.general] paragraph 1:The headers
<array>
[…] define class templates that meet the requirements for sequence containers.
24.3.8.1 [array.overview] paragraph 1:
[…] An
array
is a contiguous container (24.2.2 [container.requirements.general]).
In this comment,
Casey suggests that the requirements be changed so that array
does meet the requirements.
[Kona 2022-11-12; Set Priority to 3]
Proposed resolution:
Section: 33.6.4 [thread.mutex.requirements] Status: LEWG Submitter: Pete Becker Opened: 2008-12-05 Last modified: 2017-03-01
Priority: Not Prioritized
View other active issues in [thread.mutex.requirements].
View all other issues in [thread.mutex.requirements].
View all issues with LEWG status.
Duplicate of: 961
Discussion:
33.6.4 [thread.mutex.requirements] describes the requirements for a type to be
a "Mutex type". A Mutex type can be used as the template argument for
the Lock
type that's passed to condition_variable_any::wait
(although
Lock
seems like the wrong name here, since Lock
is given a different
formal meaning in 33.6.5 [thread.lock]) and, although the WD doesn't quite say
so, as the template argument for lock_guard
and unique_lock
.
The requirements for a Mutex type include:
m.lock()
shall be well-formed and have [described] semantics, including a return type of void
.
m.try_lock()
shall be well-formed and have [described] semantics, including a return type of bool
.
m.unlock()
shall be well-formed and have [described] semantics, including a return type of void
.
Also, a Mutex type "shall not be copyable nor movable".
The latter requirement seems completely irrelevant, and the three
requirements on return types are tighter than they need to be. For
example, there's no reason that lock_guard
can't be instantiated with a
type that's copyable. The rule is, in fact, that lock_guard
, etc. won't
try to copy objects of that type. That's a constraint on locks, not on
mutexes. Similarly, the requirements for void
return types are
unnecessary; the rule is, in fact, that lock_guard
, etc. won't use any
returned value. And with the return type of bool
, the requirement should
be that the return type is convertible to bool
.
[ Summit: ]
Move to open. Related to conceptualization and should probably be tackled as part of that.
- The intention is not only to place a constraint on what types such as
lock_guard
may do with mutex types, but on what any code, including user code, may do with mutex types. Thus the constraints as they are apply to the mutex types themselves, not the current users of mutex types in the standard.- This is a low priority issue; the wording as it is may be overly restrictive but this may not be a real issue.
[ Post Summit Anthony adds: ]
Section 33.6.4 [thread.mutex.requirements] conflates the requirements on a generic Mutex type (including user-supplied mutexes) with the requirements placed on the standard-supplied mutex types in an attempt to group everything together and save space.
When applying concepts to chapter 30, I suggest that the concepts
Lockable
andTimedLockable
embody the requirements for *use* of a mutex type as required byunique_lock/lock_guard/condition_variable_any
. These should be relaxed as Pete describes in the issue. The existing words in 33.6.4 [thread.mutex.requirements] are requirements on all ofstd::mutex
,std::timed_mutex
,std::recursive_mutex
andstd::recursive_timed_mutex
, and should be rephrased as such.
[2017-03-01, Kona]
SG1: Agreement that we need a paper.
Proposed resolution:
Section: 33.6.4 [thread.mutex.requirements] Status: LEWG Submitter: Pete Becker Opened: 2009-01-07 Last modified: 2017-03-01
Priority: Not Prioritized
View other active issues in [thread.mutex.requirements].
View all other issues in [thread.mutex.requirements].
View all issues with LEWG status.
Duplicate of: 936
Discussion:
33.6.4 [thread.mutex.requirements] describes required member functions of mutex types, and requires that they throw exceptions under certain circumstances. This is overspecified. User-defined types can abort on such errors without affecting the operation of templates supplied by standard-library.
[ Summit: ]
Move to open. Related to conceptualization and should probably be tackled as part of that.
[ 2009-10 Santa Cruz: ]
Would be OK to leave it as is for time constraints, could loosen later.
Mark as NAD Future.
[2017-03-01, Kona]
SG1: Agreement that we need a paper.
Proposed resolution:
std::vector
's reallocation policy still unclearSection: 24.3.12.3 [vector.capacity] Status: Open Submitter: Daniel Krügler Opened: 2009-04-20 Last modified: 2020-07-17
Priority: 3
View other active issues in [vector.capacity].
View all other issues in [vector.capacity].
View all issues with Open status.
Discussion:
I have the impression that even the wording of current draft
N2857
does insufficiently express the intent of vector
's
reallocation strategy. This has produced not too old library
implementations which release memory in the clear()
function
and even modern articles about C++ programming cultivate
the belief that clear
is allowed to do exactly this. A typical
example is something like this:
const int buf_size = ...; std::vector<T> buf(buf_size); for (int i = 0; i < some_condition; ++i) { buf.resize(buf_size); write_or_read_data(buf.data()); buf.clear(); // Ensure that the next round get's 'zeroed' elements }
where still the myth is ubiquitous that buf
might be
allowed to reallocate it's memory inside the for
loop.
IMO the problem is due to the fact, that
std::vector
is explained in 24.3.12.3 [vector.capacity]/3 and /6 which
are describing just the effects of the reserve
function, but in many examples (like above) there
is no explicit call to reserve
involved. Further-more
24.3.12.3 [vector.capacity]/6 does only mention insertions
and never mentions the consequences of erasing elements.
the effects clause of std::vector
's erase
overloads in
24.3.12.5 [vector.modifiers]/4 is silent about capacity changes. This
easily causes a misunderstanding, because the counter
parting insert functions described in 24.3.12.5 [vector.modifiers]/2
explicitly say, that
Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid.
It requires a complex argumentation chain about four
different places in the standard to provide the — possibly
weak — proof that calling clear()
also does never change
the capacity of the std::vector
container. Since std::vector
is the de-facto replacement of C99's dynamic arrays this
type is near to a built-in type and it's specification should
be clear enough that usual programmers can trust their
own reading.
[ Batavia (2009-05): ]
Bill believes paragraph 1 of the proposed resolution is unnecessary because it is already implied (even if tortuously) by the current wording.
Move to Review.
[ 2009-10 Santa Cruz: ]
Mark as NAD. Rationale: there is no consensus to clarify the standard, general consensus that the standard is correct as written.
[2020-05-08; Reopen after reflector discussions]
"correct as written" has been disputed.
[2020-07-17; Priority set to 3 in telecon]
Proposed resolution:
[
This is a minimum version. I also
suggest that the wording explaining the allocation strategy
of std::vector
in 24.3.12.3 [vector.capacity]/3 and /6 is moved into
a separate sub paragraph of 24.3.12.3 [vector.capacity] before
any of the prototype's are discussed, but I cannot provide
reasonable wording changes now.
]
Change 24.3.12.3 [vector.capacity]/6 as follows:
It is guaranteed that no reallocation takes place during insertions or erasures that happen after a call to
reserve()
until the time when an insertion would make the size of the vector greater than the value ofcapacity()
.
Change 24.3.12.5 [vector.modifiers]/4 as follows:
Effects: The capacity shall remain unchanged and no reallocation shall happen. Invalidates iterators and references at or after the point of the erase.
unordered
complexitySection: 24.2.8 [unord.req] Status: Open Submitter: Pablo Halpern Opened: 2009-07-17 Last modified: 2020-09-06
Priority: 3
View other active issues in [unord.req].
View all other issues in [unord.req].
View all issues with Open status.
Discussion:
When I look at the unordered_*
constructors, I think the complexity is poorly
described and does not follow the style of the rest of the standard.
The complexity for the default constructor is specified as constant.
Actually, it is proportional to n
, but there are no invocations of
value_type
constructors or other value_type
operations.
For the iterator-based constructor the complexity should be:
Complexity: exactly
n
calls to constructvalue_type
fromInputIterator::value_type
(wheren = distance(f,l)
). The number of calls tokey_equal::operator()
is proportional ton
in the average case andn*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 yourn
is 10^6, so I think adding this change makes people
aware there might be a large cost in initializing the hash table, even though it doesn't show up in user-visible constructions.
HH: one way to avoid that problem is make the default ctor noexcept
. Then the container isn't allowed to create
an arbitrarily large hash table
AM: but this is the constructor where the user provides n
MC: happy with the changes, except I agree with the editorial recommendation to keep the two 𝒪s separate.
JW: yes, the constant 'k
' is different in 𝒪(n) and 𝒪(N)
GR: do we want to talk about buckets at all
JM: yes, good to highlight that bucket construction might be a significant cost
HH: suggest we take the suggestion to split 𝒪(n+N) to 𝒪(n)+𝒪(N) and move to Tentatively Ready
GR: 23.2.1p2 says all complexity requirements are stated solely in terms of the number of operations on the contained
object, so we shouldn't be stating complexity in terms of the hash table initialization
HH: channeling Pete, there's an implicit "unless otherwise specified" everywhere.
VV: seem to be requesting modifications that render this not Tentatively Ready
GR: I think it can't be T/R
AM: make the editorial recommendation, consider fixing 23.2.1/3 to give us permission to state complexity in terms
of bucket initialization
HH: only set it to Review after we get new wording to review
[2015-02 Cologne]
Update wording, revisit later.
Previous resolution [SUPERSEDED]:
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 leastn
buckets, usinghf
as the hash function andeq
as the key
equality predicate, and inserts elements from[i, j)
into it.Average case 𝒪( n + N
) (N
isdistance(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 leastn
buckets, usinghf
as the hash function andkey_equal()
as the key
equality predicate, and inserts elements from[i, j)
into it.Average case 𝒪( n + N
) (N
isdistance(i, j)
),
worst case 𝒪(n + N2
)X(i, j, n)
X a(i, j, n)
X
…
Effects: Constructs an empty container with at leastn
buckets, usinghasher()
as the hash function andkey_equal()
as the key
equality predicate, and inserts elements from[i, j)
into it.Average case 𝒪( n + N
) (N
isdistance(i, j)
),
worst case 𝒪(n + N2
)… Modify 24.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 leastn
buckets. Ifn
is not provided, the number of buckets is unspecifiedimpldefdefault number of buckets in.unordered_map
max_load_factor()
returns1.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 leastn
buckets. Ifn
is not provided, the number of buckets is unspecifiedimpldefdefault number of buckets in. Then inserts elements from the rangeunordered_map
[f, l)
.max_load_factor()
returns1.0
.4 Complexity:
Average case linear, worst case quadraticLinear in the number of buckets. In the average case linear inN
and in the worst case quadratic inN
to insert the elements, whereN
is equal to number of elements in the range[f,l)
.Modify 24.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 leastn
buckets. Ifn
is not provided, the number of buckets is unspecifiedimpldefdefault number of buckets in.unordered_multimap
max_load_factor()
returns1.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 leastn
buckets. Ifn
is not provided, the number of buckets is unspecifiedimpldefdefault number of buckets in. Then inserts elements from the rangeunordered_multimap
[f, l)
.max_load_factor()
returns1.0
.4 Complexity:
Average case linear, worst case quadraticLinear in the number of buckets. In the average case linear inN
and in the worst case quadratic inN
to insert the elements, whereN
is equal to number of elements in the range[f,l)
.Modify 24.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 leastn
buckets. Ifn
is not provided, the number of buckets is unspecifiedimpldefdefault number of buckets in.unordered_set
max_load_factor()
returns1.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 leastn
buckets. Ifn
is not provided, the number of buckets is unspecifiedimpldefdefault number of buckets in. Then inserts elements from the rangeunordered_set
[f, l)
.max_load_factor()
returns1.0
.4 Complexity:
Average case linear, worst case quadraticLinear in the number of buckets. In the average case linear inN
and in the worst case quadratic inN
to insert the elements, whereN
is equal to number of elements in the range[f,l)
.Modify 24.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 leastn
buckets. Ifn
is not provided, the number of buckets is unspecifiedimpldefdefault number of buckets in.unordered_multiset
max_load_factor()
returns1.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 leastn
buckets. Ifn
is not provided, the number of buckets is unspecifiedimpldefdefault number of buckets in. Then inserts elements from the rangeunordered_multiset
[f, l)
.max_load_factor()
returns1.0
.4 Complexity:
Average case linear, worst case quadraticLinear in the number of buckets. In the average case linear inN
and in the worst case quadratic inN
to insert the elements, whereN
is equal to number of elements in the range[f,l)
.
[2019-03-17; Daniel comments and provides revised wording]
The updated wording ensures that we can now specify complexity requirements for containers even when they are not
expressed in terms of the number on the contained objects by an exception of the rule. This allows us to say that
𝒪(n)
describes the complexity in terms of bucket initialization instead.
Proposed resolution:
This wording is relative to N4810.
Modify 24.2.2 [container.requirements.general] as indicated:
-2- Unless otherwise specified,
All of thecomplexity requirements in this Clause are stated solely in terms of the number of operations on the contained objects. [Example: The copy constructor of typevector<vector<int>>
has linear complexity, even though the complexity of copying each containedvector<int>
is itself linear. — end example]
Modify 24.2.8 [unord.req] as indicated:
-11- In Table 70:
(11.1) — […]
[…]
(11.23) — […]
(11.?) — Notwithstanding the complexity requirements restrictions of 24.2.2 [container.requirements.general], the complexity form
𝒪(n)
describes the number of operations on buckets.
Modify the following rows in Table 70 — "Unordered associative container requirements" to add the explicit bucket allocation overhead of some constructions.
[Drafting note: It is kindly suggested to the Project Editor not to shorten the sum
𝒪(n) + 𝒪(N)
to𝒪(n + N)
, because two different work units are involved. — end drafting note]
Table 70 — Unordered associative container requirements (in addition to container) Expression Return type Assertion/note pre-/post-condition Complexity … X()
X a;
X
Expects: […]
Effects: Constructs an empty container with an unspecified numbern
of
buckets, usinghasher()
as the hash function andkey_equal()
as the key
equality predicate.constant𝒪(n
)X(i, j, n, hf, eq)
X a(i, j, n, hf, eq)
X
Expects: […]
Effects: Constructs an empty container with at leastn
buckets, usinghf
as the hash function andeq
as the key
equality predicate, and inserts elements from[i, j)
into it.Average case 𝒪( n
) + 𝒪(N
) (N
isdistance(i, j)
), worst case
𝒪(n
) + 𝒪(N2
)X(i, j, n, hf)
X a(i, j, n, hf)
X
Expects: […]
Effects: Constructs an empty container with at leastn
buckets, usinghf
as the hash function andkey_equal()
as the key
equality predicate, and inserts elements from[i, j)
into it.Average case 𝒪( n
) + 𝒪(N
) (N
isdistance(i, j)
), worst case
𝒪(n
) + 𝒪(N2
)X(i, j, n)
X a(i, j, n)
X
Expects: […]
Effects: Constructs an empty container with at leastn
buckets, usinghasher()
as the hash function andkey_equal()
as the key
equality predicate, and inserts elements from[i, j)
into it.Average case 𝒪( n
) + 𝒪(N
) (N
isdistance(i, j)
), worst case
𝒪(n
) + 𝒪(N2
)X(i, j)
X a(i, j)
X
Expects: […]
Effects: Constructs an empty container with an unspecified numbern
of
buckets, usinghasher()
as the hash function andkey_equal()
as the key
equality predicate, and inserts elements from[i, j)
into it.Average case 𝒪( n
) + 𝒪(N
) (N
isdistance(i, j)
), worst case
𝒪(n
) + 𝒪(N2
)…
Modify 24.5.4.1 [unord.map.overview], class template unordered_map
, as indicated:
// 24.5.4.2 [unord.map.cnstr], construct/copy/destroy […] template <class InputIterator> unordered_map(InputIterator f, InputIterator l, size_type n =see belowunspecified, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type()); […] unordered_map(initializer_list<value_type> il, size_type n =see belowunspecified, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type()); […]
Modify 24.5.4.2 [unord.map.cnstr] as indicated:
unordered_map() : unordered_map(size_type(see belowunspecified)) { } explicit unordered_map(size_type n, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());-1- Effects: Constructs an empty
-?- Ensures:unordered_map
using the specified hash function, key equality predicate, and allocator, and using at leastn
buckets.For the default constructor, the number of buckets is implementation-defined.max_load_factor()
returns1.0
.max_load_factor() == 1.0
-2- Complexity:ConstantLinear in the number of buckets.template <class InputIterator> unordered_map(InputIterator f, InputIterator l, size_type n =see belowunspecified, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type()); unordered_map(initializer_list<value_type> il, size_type n =see belowunspecified, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());-3- Effects: Constructs an empty
-?- Ensures:unordered_map
using the specified hash function, key equality predicate, and allocator, and using at leastn
buckets.IfThen inserts elements from the rangen
is not provided, the number of buckets is implementation-defined.[f, l)
for the first form, or from the range[il.begin(), il.end())
for the second form.max_load_factor()
returns1.0
.max_load_factor() == 1.0
-4- Complexity:Average case linear, worst case quadraticLinear in the number of buckets, plus 𝒪(N
) (average case) or 𝒪(N2
) (worst case) whereN
is the number of insertions.
Modify 24.5.5.1 [unord.multimap.overview], class template unordered_multimap
, as indicated:
// 24.5.5.2 [unord.multimap.cnstr], construct/copy/destroy […] template <class InputIterator> unordered_multimap(InputIterator f, InputIterator l, size_type n =see belowunspecified, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type()); […] unordered_multimap(initializer_list<value_type> il, size_type n =see belowunspecified, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type()); […]
Modify 24.5.5.2 [unord.multimap.cnstr] as indicated:
unordered_multimap() : unordered_multimap(size_type(see belowunspecified)) { } explicit unordered_multimap(size_type n, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());-1- Effects: Constructs an empty
-?- Ensures:unordered_multimap
using the specified hash function, key equality predicate, and allocator, and using at leastn
buckets.For the default constructor, the number of buckets is implementation-defined.max_load_factor()
returns1.0
.max_load_factor() == 1.0
-2- Complexity:ConstantLinear in the number of buckets.template <class InputIterator> unordered_multimap(InputIterator f, InputIterator l, size_type n =see belowunspecified, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type()); unordered_multimap(initializer_list<value_type> il, size_type n =see belowunspecified, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());-3- Effects: Constructs an empty
-?- Ensures:unordered_multimap
using the specified hash function, key equality predicate, and allocator, and using at leastn
buckets.IfThen inserts elements from the rangen
is not provided, the number of buckets is implementation-defined.[f, l)
for the first form, or from the range[il.begin(), il.end())
for the second form.max_load_factor()
returns1.0
.max_load_factor() == 1.0
-4- Complexity:Average case linear, worst case quadraticLinear in the number of buckets, plus 𝒪(N
) (average case) or 𝒪(N2
) (worst case) whereN
is the number of insertions.
Modify 24.5.6.1 [unord.set.overview], class template unordered_set
, as indicated:
// 24.5.6.2 [unord.set.cnstr], construct/copy/destroy […] template <class InputIterator> unordered_set(InputIterator f, InputIterator l, size_type n =see belowunspecified, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type()); […] unordered_set(initializer_list<value_type> il, size_type n =see belowunspecified, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type()); […]
Modify 24.5.6.2 [unord.set.cnstr] as indicated:
unordered_set() : unordered_set(size_type(see belowunspecified)) { } explicit unordered_set(size_type n, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());-1- Effects: Constructs an empty
-?- Ensures:unordered_set
using the specified hash function, key equality predicate, and allocator, and using at leastn
buckets.For the default constructor, the number of buckets is implementation-defined.max_load_factor()
returns1.0
.max_load_factor() == 1.0
-2- Complexity:ConstantLinear in the number of buckets.template <class InputIterator> unordered_set(InputIterator f, InputIterator l, size_type n =see belowunspecified, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type()); unordered_set(initializer_list<value_type> il, size_type n =see belowunspecified, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());-3- Effects: Constructs an empty
-?- Ensures:unordered_set
using the specified hash function, key equality predicate, and allocator, and using at leastn
buckets.IfThen inserts elements from the rangen
is not provided, the number of buckets is implementation-defined.[f, l)
for the first form, or from the range[il.begin(), il.end())
for the second form.max_load_factor()
returns1.0
.max_load_factor() == 1.0
-4- Complexity:Average case linear, worst case quadraticLinear in the number of buckets, plus 𝒪(N
) (average case) or 𝒪(N2
) (worst case) whereN
is the number of insertions.
Modify 24.5.6.1 [unord.set.overview], class template unordered_multiset
, as indicated:
// 24.5.7.2 [unord.multiset.cnstr], construct/copy/destroy […] template <class InputIterator> unordered_multiset(InputIterator f, InputIterator l, size_type n =see belowunspecified, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type()); […] unordered_multiset(initializer_list<value_type> il, size_type n =see belowunspecified, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type()); […]
Modify 24.5.7.2 [unord.multiset.cnstr] as indicated:
unordered_multiset() : unordered_multiset(size_type(see belowunspecified)) { } explicit unordered_multiset(size_type n, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());-1- Effects: Constructs an empty
-?- Ensures:unordered_multiset
using the specified hash function, key equality predicate, and allocator, and using at leastn
buckets.For the default constructor, the number of buckets is implementation-defined.max_load_factor()
returns1.0
.max_load_factor() == 1.0
-2- Complexity:ConstantLinear in the number of buckets.template <class InputIterator> unordered_multiset(InputIterator f, InputIterator l, size_type n =see belowunspecified, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type()); unordered_multiset(initializer_list<value_type> il, size_type n =see belowunspecified, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());-3- Effects: Constructs an empty
-?- Ensures:unordered_multiset
using the specified hash function, key equality predicate, and allocator, and using at leastn
buckets.IfThen inserts elements from the rangen
is not provided, the number of buckets is implementation-defined.[f, l)
for the first form, or from the range[il.begin(), il.end())
for the second form.max_load_factor()
returns1.0
.max_load_factor() == 1.0
-4- Complexity:Average case linear, worst case quadraticLinear in the number of buckets, plus 𝒪(N
) (average case) or 𝒪(N2
) (worst case) whereN
is the number of insertions.
Section: 25.3 [iterator.requirements] Status: Open Submitter: Daniel Krügler Opened: 2009-09-19 Last modified: 2016-01-28
Priority: 4
View all other issues in [iterator.requirements].
View all issues with Open status.
Discussion:
The terms valid iterator and singular aren't properly defined. The fuzziness of those terms became even worse after the resolution of 208(i) (including further updates by 278(i)). In 25.3 [iterator.requirements] as of N2723 the standard says now:
5 - These values are called past-the-end values. Values of an iterator
i
for which the expression*i
is defined are called dereferenceable. The library never assumes that past-the-end values are dereferenceable. Iterators can also have singular values that are not associated with any container. [...] Results of most expressions are undefined for singular values; the only exceptions are destroying an iterator that holds a singular value and the assignment of a non-singular value to an iterator that holds a singular value. [...] Dereferenceable values are always non-singular.10 - An invalid iterator is an iterator that may be singular.
First, issue 208(i) 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. 27.11 [specialized.algorithms]/1 says:
In all of the following algorithms, the formal template parameter
ForwardIterator
is required to satisfy the requirements of a forward iterator (24.1.3) [..], and is required to have the property that no exceptions are thrown from [..], or dereference of valid iterators.
The standard should make better clear what "singular pointer" and "valid iterator" means. The fact that the meaning of a valid value has a core language meaning doesn't imply that for an iterator concept the term "valid iterator" has the same meaning.
Let me add a final example: In 99 [allocator.concepts.members] of N2914 we find:
pointer X::allocate(size_type n);11 Returns: a pointer to the allocated memory. [Note: if
n == 0
, the return value is unspecified. —end note][..]
void X::deallocate(pointer p, size_type n);Preconditions:
p
shall be a non-singular pointer value obtained from a call toallocate()
on this allocator or one that compares equal to it.
If singular pointer value would include null pointers this make the
preconditions
unclear if the pointer value is a result of allocate(0)
: Since the return value
is unspecified, it could be a null pointer. Does that mean that programmers
need to check the pointer value for a null value before calling deallocate?
[ 2010-11-09 Daniel comments: ]
A later paper is in preparation.
[ 2010 Batavia: ]
Doesn't need to be resolved for Ox
[2014-02-20 Re-open Deferred issues as Priority 4]
Consider to await the paper.
Proposed resolution:
Section: 27 [algorithms] Status: Open Submitter: Alisdair Meredith Opened: 2009-10-15 Last modified: 2020-09-06
Priority: 3
View other active issues in [algorithms].
View all other issues in [algorithms].
View all issues with Open status.
Discussion:
The library has many algorithms that take a source range represented by a pair of iterators, and the start of some second sequence given by a single iterator. Internally, these algorithms will produce undefined behaviour if the second 'range' is not as large as the input range, but none of the algorithms spell this out in Requires clauses, and there is no catch-all wording to cover this in clause 17 or the front matter of 25.
There was an attempt to provide such wording in paper n2944 but this seems incidental to the focus of the paper, and getting the wording of this issue right seems substantially more difficult than the simple approach taken in that paper. Such wording will be removed from an updated paper, and hopefully tracked via the LWG issues list instead.
It seems there are several classes of problems here and finding wording to solve all in one paragraph could be too much. I suspect we need several overlapping requirements that should cover the desired range of behaviours.
Motivating examples:
A good initial example is the swap_ranges
algorithm. Here there is a
clear requirement that first2
refers to the start of a valid range at
least as long as the range [first1, last1)
. n2944 tries to solve this
by positing a hypothetical last2
iterator that is implied by the
signature, and requires distance(first2,last2) < distance(first1,last1)
.
This mostly works, although I am uncomfortable assuming that last2
is
clearly defined and well known without any description of how to obtain
it (and I have no idea how to write that).
A second motivating example might be the copy
algorithm. Specifically,
let us image a call like:
copy(istream_iterator<int>(is),istream_iterator(),ostream_iterator<int>(os));
In this case, our input iterators are literally simple InputIterators
,
and the destination is a simple OutputIterator
. In neither case am I
happy referring to std::distance
, in fact it is not possible for the
ostream_iterator
at all as it does not meet the requirements. However,
any wording we provide must cover both cases. Perhaps we might deduce
last2 == ostream_iterator<int>{}
, but that might not always be valid for
user-defined iterator types. I can well imagine an 'infinite range'
that writes to /dev/null
and has no meaningful last2
.
The motivating example in n2944 is std::equal
,
and that seems to fall somewhere between the two.
Outlying examples might be partition_copy
that takes two output
iterators, and the _n
algorithms where a range is specified by a
specific number of iterations, rather than traditional iterator pair.
We should also not accidentally apply inappropriate constraints to
std::rotate
which takes a third iterator that is not intended to be a
separate range at all.
I suspect we want some wording similar to:
For algorithms that operate on ranges where the end iterator of the second range is not specified, the second range shall contain at least as many elements as the first.
I don't think this quite captures the intent yet though. I am not sure
if 'range' is the right term here rather than sequence. More awkwardly,
I am not convinced we can describe an Output sequence such as produce by
an ostream_iterator
as "containing elements", at least not as a
precondition to the call before they have been written.
Another idea was to describe require that the trailing iterator support
at least distance(input range) applications of operator++
and may be
written through the same number of times if a mutable/output iterator.
We might also consider handling the case of an output range vs. an input range in separate paragraphs, if that simplifies how we describe some of these constraints.
[ 2009-11-03 Howard adds: ]
Moved to Tentatively NAD Future after 5 positive votes on c++std-lib.
[LEWG Kona 2017]
Recommend Open: The design is clear here; we just need wording
[2019-01-20 Reflector prioritization]
Set Priority to 3
Rationale:
Does not have sufficient support at this time. May wish to reconsider for a future standard.
Proposed resolution:
vector<bool>
iterators are not random accessSection: 24.3.13 [vector.bool] Status: Open Submitter: BSI Opened: 2010-08-25 Last modified: 2020-09-06
Priority: 3
View other active issues in [vector.bool].
View all other issues in [vector.bool].
View all issues with Open status.
Discussion:
Addresses GB-118
vector<bool>
iterators are not random access iterators
because their reference type is a special class, and not
bool &
. All standard libary operations taking iterators
should treat this iterator as if it was a random access iterator, rather
than a simple input iterator.
[ Resolution proposed in ballot comment ]
Either revise the iterator requirements to support proxy iterators
(restoring functionality that was lost when the Concept facility was
removed) or add an extra paragraph to the vector<bool>
specification requiring the library to treat vector<bool>
iterators as-if they were random access iterators, despite having the wrong
reference type.
[ Rapperswil Review ]
The consensus at Rapperswil is that it is too late for full support for
proxy iterators, but requiring the library to respect vector<bool>
iterators as-if they were random access would be preferable to flagging
this container as deliberately incompatible with standard library algorithms.
Alisdair to write the note, which may become normative Remark depending on the preferences of the project editor.
[ Post-Rapperswil Alisdair provides wording ]
Initial wording is supplied, deliberately using Note in preference to
Remark although the author notes his preference for Remark. The
issue of whether iterator_traits<vector<bool>>::iterator_category
is permitted to report random_access_iterator_tag
or must report
input_iterator_tag
is not addressed.
[ Old Proposed Resolution: ]
Insert a new paragraph into 24.3.13 [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 thereference
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 tovector<bool>
now.
[2017-02 in Kona, LEWG recommends NAD]
D0022 Proxy Iterators for the Ranges Extensions - as much a fix as we’re going to get for vector<bool>.
[2017-06-02 Issues Telecon]
P0022 is exploring a resolution. We consider this to be fairly important issue
Move to Open, set priority to 3
Proposed resolution:
Rationale:
No consensus to make this change at this time.
Section: 33.5.4 [atomics.order] Status: LEWG Submitter: Canada Opened: 2010-08-25 Last modified: 2016-01-28
Priority: Not Prioritized
View other active issues in [atomics.order].
View all other issues in [atomics.order].
View all issues with LEWG status.
Duplicate of: 1458
Discussion:
Addresses CA-21, GB-131
33.5.5 [atomics.lockfree] p.8 states:
An atomic store shall only store a value that has been computed from constants and program input values by a finite sequence of program evaluations, such that each evaluation observes the values of variables as computed by the last prior assignment in the sequence.
... but 6.9.1 [intro.execution] p.13 states:
If A is not sequenced before B and B is not sequenced before A, then A and B are unsequenced. [ Note: The execution of unsequenced evaluations can overlap. — end note ]
Overlapping executions can make it impossible to construct the sequence described in 33.5.5 [atomics.lockfree] p.8. We are not sure of the intention here and do not offer a suggestion for change, but note that 33.5.5 [atomics.lockfree] p.8 is the condition that prevents out-of-thin-air reads.
For an example, suppose we have a function invocation f(e1,e2). The evaluations of e1 and e2 can overlap. Suppose that the evaluation of e1 writes y and reads x whereas the evaluation of e2 reads y and writes x, with reads-from edges as below (all this is within a single thread).
e1 e2 Wrlx y-- --Wrlx x rf\ /rf X / \ Rrlx x<- ->Rrlx y
This seems like it should be allowed, but there seems to be no way to produce a sequence of evaluations with the property above.
In more detail, here the two evaluations, e1 and e2, are being executed as the arguments of a function and are consequently not sequenced-before each other. In practice we'd expect that they could overlap (as allowed by 6.9.1 [intro.execution] p.13), with the two writes taking effect before the two reads. However, if we have to construct a linear order of evaluations, as in 33.5.5 [atomics.lockfree] p.8, then the execution above is not permited. Is that really intended?
[ Resolution proposed by ballot comment ]
Please clarify.
[2011-03-09 Hans comments:]
I'm not proud of 33.5.4 [atomics.order] p9 (formerly p8), and I agree with the comments that this
isn't entirely satisfactory. 33.5.4 [atomics.order] p9 was designed to preclude
out-of-thin-air results for races among memory_order_relaxed
atomics, in spite of
the fact that Java experience has shown we don't really know how to do that adequately. In
the long run, we probably want to revisit this.
6.9.1 [intro.execution] p15 states: "If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined." I think the examples presented here have undefined behavior as a result. It's not completely clear to me whether examples can be constructed that exhibit this problem, and don't have undefined behavior.
This comment seems to be using a different meaning of "evaluation"
from what is used elsewhere in the standard. The sequence of evaluations
here doesn't have to consist of full expression evaluations. They
can be evaluations of operations like lvalue to rvalue conversion,
or individual assignments. In particular, the reads and writes
executed by e1
and e2
in the example could be treated as separate
evaluations for purposes of producing the sequence.
The definition of "sequenced before" in 6.9.1 [intro.execution] makes
little sense if the term "evaluation" is restricted to any notion
of complete expression. Perhaps we should add yet another note
to clarify this? 33.5.4 [atomics.order] p10 probably leads to
the wrong impression here.
[2011-03-24 Madrid]
Moved to NAD Future
Proposed resolution:
Section: 33.4.3 [thread.thread.class] Status: LEWG Submitter: INCITS Opened: 2010-08-25 Last modified: 2017-03-01
Priority: Not Prioritized
View all issues with LEWG status.
Discussion:
Addresses US-183
There is no way to join a thread with a timeout.
[ Resolution proposed by ballot comment: ]
Add
join_for
andjoin_until
. Or decide one should never join a thread with a timeout sincepthread_join
doesn't have a timeout version.
[ 2010 Batavia ]
The concurrency working group deemed this an extension beyond the scope of C++0x.
Rationale:
The LWG does not wish to make a change at this time.
[2017-03-01, Kona]
SG1 recommends: Close as NAD
There has not been much demand for it, and it would usually be difficult to deal withthread_local
destructor races.
It can be approximated with a condition variable wait followed by an unconditional join
. Adding it would create
implementation issues on Posix. As always, this may be revisited if we have a paper exploring the issues in detail.
Proposed resolution:
Section: 33.6 [thread.mutex] Status: LEWG Submitter: INCITS Opened: 2010-08-25 Last modified: 2017-03-01
Priority: Not Prioritized
View all other issues in [thread.mutex].
View all issues with LEWG status.
Discussion:
Addresses US-185
Cooperate with WG14 to improve interoperability between
the C++0x
and C1x
threads APIs. In particular, C1x
mutexes should be conveniently usable with a C++0x
lock_guard
. Performance overheads for this combination
should be considered.
[ Resolution proposed by ballot comment: ]
Remove
C++0x
timed_mutex
andtimed_recursive_mutex
if that facilitates development of more compatible APIs.
[ 2010 Batavia ]
The concurrency sub-group reviewed the options, and decided that closer harmony should wait until both standards are published.
Rationale:
The LWG does not wish to make any change at this time.
[2017-03-01, Kona]
SG1 recommends: Close as NAD
Papers about C compatibility are welcome, but there may be more pressing issues. C threads are not consistently available at this point, so there seems to be little demand to fix this particular problem.Proposed resolution:
mutex
, recursive_mutex
, is_locked
functionSection: 33.6.4 [thread.mutex.requirements] Status: LEWG Submitter: INCITS Opened: 2010-08-25 Last modified: 2017-03-01
Priority: Not Prioritized
View other active issues in [thread.mutex.requirements].
View all other issues in [thread.mutex.requirements].
View all issues with LEWG status.
Discussion:
Addresses US-189
mutex
and recursive_mutex
should have an is_locked()
member function. is_locked
allows a user to test a lock
without acquiring it and can be used to implement a lightweight
try_try_lock
.
[ Resolution proposed by ballot comment: ]
Add a member function:
bool is_locked() const;to
std::mutex
andstd::recursive_mutex
. These functions return true if the current thread would not be able to obtain a mutex. These functions do not synchronize with anything (and, thus, can avoid a memory fence).
[ 2010 Batavia ]
The Concurrency subgroup reviewed this issue and deemed it to be an extension to be handled after publishing C++0x.
Rationale:
The LWG does not wish to make a change at this time.
[2017-03-01, Kona]
SG1 recommends: Close as NAD
Several participants voiced strong objections, based on either memory model issues or lock elision. No support. It is already possible to write a wrapper that explicitly tracks ownership for testing in the owning thread, which may have been part of the intent here.Proposed resolution:
Section: 24.2.2 [container.requirements.general] Status: Open Submitter: Mike Spertus Opened: 2010-10-16 Last modified: 2019-01-20
Priority: 3
View other active issues in [container.requirements.general].
View all other issues in [container.requirements.general].
View all issues with Open status.
Discussion:
Addresses US-104, US-141
The standard doesn't say that containers should use abstract pointer types internally. Both Howard and Pablo agree that this is the intent. Further, it is necessary for containers to be stored, for example, in shared memory with an interprocess allocator (the type of scenario that allocators are intended to support).
In spite of the (possible) agreement on intent, it is necessary to make this explicit:
An implementations may like to store the result of dereferencing the pointer (which is a raw reference) as an optimization, but that prevents the data structure from being put in shared memory, etc. In fact, a container could store raw references to the allocator, which would be a little weird but conforming as long as it has one by-value copy. Furthermore, pointers to locales, ctypes, etc. may be there, which also prevents the data structure from being put in shared memory, so we should make explicit that a container does not store raw pointers or references at all.
[ Pre-batavia ]
This issue is being opened as part of the response to NB comments US-104/141. See paper N3171 in the pre-Batavia mailing.
[2011-03-23 Madrid meeting]
Deferred
[ 2011 Batavia ]
This may be an issue, but it is not clear. We want to gain a few years experience with the C++11 allocator model to see if this is already implied by the existing specification.
[LEWG Kona 2017]
Status to Open: Acknowledged, need wording: (N4618 numbering) 23.2.1 container.requirements.general p8 first sentence. Replace non-normative note with requirement.
See discussion on LEWG Wiki
[2019-01-20 Reflector prioritization]
Set Priority to 3
Proposed resolution:
Add to the end of 24.2.2 [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 formT *
orT &
except insofar as they are part of the item type or members.
Section: 25.3.5.4 [output.iterators] Status: Open Submitter: Daniel Krügler Opened: 2011-02-27 Last modified: 2016-01-28
Priority: 3
View other active issues in [output.iterators].
View all other issues in [output.iterators].
View all issues with Open status.
Discussion:
During the Pittsburgh meeting the proposal N3066 became accepted because it fixed several severe issues related to the iterator specification. But the current working draft (N3225) does not reflect all these changes. Since I'm unaware whether every correction can be done editorial, this issue is submitted to take care of that. To give one example: All expressions of Table 108 — "Output iterator requirements" have a post-condition that the iterator is incrementable. This is impossible, because it would exclude any finite sequence that is accessed by an output iterator, such as a pointer to a C array. The N3066 wording changes did not have these effects.
[2011-03-01: Daniel comments:]
This issue has some overlap with the issue 2038(i) 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
25.3.1 [iterator.requirements.general] and to let all previous usages of these terms refer to this
sub-clause. Since the same problem occurs with the past-the-end iterator, this proposal suggest providing
similar references to usages that precede its definition as well.
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(i): 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 iteratori, 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.
++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 25.3.1 [iterator.requirements.general] to the following parts of the library preceding Clause 24 Iterators library: (I stopped from 24.2.8 [unord.req] on, because the remaining references are the concrete containers)
16.4.4.3 [swappable.requirements] p5:
-5- A type
X
satisfying any of the iterator requirements (24.2) isValueSwappable
if, for any dereferenceable (25.3.1 [iterator.requirements.general]) objectx
of typeX
,*x
is swappable.
16.4.4.6 [allocator.requirements], Table 27 — "Descriptive variable definitions",
row with the expression c
:
a dereferenceable (25.3.1 [iterator.requirements.general]) pointer of type
C*
20.2.3.3 [pointer.traits.functions]:
Returns: The first template function returns a dereferenceable (25.3.1 [iterator.requirements.general]) pointer to
r
obtained by callingPtr::pointer_to(r)
; […]
23.4.3.4 [string.iterators] p. 2:
Returns: An iterator which is the past-the-end value (25.3.1 [iterator.requirements.general]).
30.4.6.2.3 [locale.time.get.virtuals] p. 11:
iter_type do_get(iter_type s, iter_type end, ios_base& f, ios_base::iostate& err, tm *t, char format, char modifier) const;Requires:
t
shall be dereferenceable (25.3.1 [iterator.requirements.general]).
24.2.2 [container.requirements.general] p. 6:
[…]
end()
returns an iterator which is the past-the-end (25.3.1 [iterator.requirements.general]) value for the container. […]
24.2.4 [sequence.reqmts] p. 3:
[…]
q
denotes a valid dereferenceable (25.3.1 [iterator.requirements.general]) const iterator toa
, […]
24.2.7 [associative.reqmts] p. 8 (I omit intentionally one further reference in the same sub-clause):
[…]
q
denotes a valid dereferenceable (25.3.1 [iterator.requirements.general]) const iterator toa
, […]
24.2.8 [unord.req] p. 10 (I omit intentionally one further reference in the same sub-clause):
[…]
q
andq1
are valid dereferenceable (25.3.1 [iterator.requirements.general]) const iterators toa
, […]
Edit 25.3.1 [iterator.requirements.general] p. 5 as indicated (The intent is to properly define incrementable and to ensure some further library guarantee related to past-the-end iterator values):
-5- Just as a regular pointer to an array guarantees that there is a pointer value pointing past the last element of the array, so for any iterator type there is an iterator value that points past the last element of a corresponding sequence. These values are called past-the-end values. Values of an iterator
i
for which the expression*i
is defined are called dereferenceable. Values of an iteratori
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", 25.3.5.2 [iterator.iterators], as indicated:
Table 106 — Iterator requirements Expression Return type Operational semantics Assertion/note
pre-/post-condition*r
reference
pre: r
is dereferenceable.++r
X&
pre: r
is incrementable.
Modify the column contents of Table 107 — "Input iterator requirements",
25.3.5.3 [input.iterators], as indicated [Rationale: The wording changes attempt
to define a minimal "independent" set of operations, namely *a
and ++r
, and
to specify the semantics of the remaining ones. This approach seems to be in agreement with the
original SGI specification
— end rationale]:
Table 107 — Input iterator requirements (in addition to Iterator) Expression Return type Operational semantics Assertion/note
pre-/post-conditiona != b
contextually
convertible tobool
!(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
.
Ifa == 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
isdereferenceableincrementable.
post:r
is dereferenceable or
r
is past-the-end.
post: any copies of the
previous value ofr
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",
25.3.5.4 [output.iterators], as indicated [Rationale: The wording changes attempt
to define a minimal "independent" set of operations, namely *r = o
and ++r
,
and to specify the semantics of the remaining ones. This approach seems to be in agreement with
the original SGI specification
— end rationale]:
Table 108 — Output iterator requirements (in addition to Iterator) Expression Return type Operational semantics Assertion/note
pre-/post-condition*r = o
result is not used
pre: r
is dereferenceable.
Remark: After this operation
r
is not required to be
dereferenceable and any copies of
the previous value ofr
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 ofr
are no
longer required to be dereferenceable
or incrementable.
post:r
is dereferenceable
orr
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",
25.3.5.5 [forward.iterators], as indicated [Rationale: Since the return type of the
expression *r++
is now guaranteed to be type reference
, the implied operational
semantics from input iterator based on value copies is wrong — end rationale]
Table 109 — Forward iterator requirements (in addition to input iterator) Expression Return type Operational semantics Assertion/note
pre-/post-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", 25.3.5.6 [bidirectional.iterators], as indicated:
Table 110 — Bidirectional iterator requirements (in addition to forward iterator) Expression Return type Operational semantics Assertion/note
pre-/post-condition--r
X&
pre: there exists s
such that
r == ++s
.
post:r
isdereferenceableincrementable.
--(++r) == r
.
--r == --s
impliesr == s
.
&r == &--r
.r--
convertible to const X&
{ X tmp = r;
--r;
return tmp; }
*r--
reference { reference tmp = *r;
--r;
return tmp; }
incrementable
iteratorSection: 25.3.5.4 [output.iterators] Status: Open Submitter: Pete Becker Opened: 2011-02-27 Last modified: 2016-01-28
Priority: 3
View other active issues in [output.iterators].
View all other issues in [output.iterators].
View all issues with Open status.
Discussion:
In comp.lang.c++, Vicente Botet raises the following questions:
"In "24.2.4 Output iterators" there are 3 uses of incrementable. I've not found the definition. Could some one point me where it is defined?
Something similar occurs with dereferenceable. While the definition is given in "24.2.1 In general" it is used several times before. Shouldn't these definitions be moved to some previous section?"
He's right: both terms are used without being properly defined.
There is no definition of "incrementable". While there is a definition of "dereferenceable", it is, in fact, a definition of "dereferenceable iterator". "dereferenceable" is used throughout Clause 23 (Containers) before its definition in Clause 24. In almost all cases it's referring to iterators, but in 16.4.4.3 [swappable.requirements] there is a mention of "dereferenceable object"; in 16.4.4.6 [allocator.requirements] the table of Descriptive variable definitions refers to a "dereferenceable pointer"; 20.2.3.3 [pointer.traits.functions] refers to a "dereferenceable pointer"; in 30.4.6.2.3 [locale.time.get.virtuals]/11 (do_get
)
there is a requirement that a pointer "shall be dereferenceable". In those specific cases
it is not defined.
[2011-03-02: Daniel comments:]
I believe that the currently proposed resolution of issue 2035(i) solves this issue as well.
[ 2011 Bloomington ]
Agree with Daniel, this will be handled by the resolution of 2035(i).
Proposed resolution:
Section: 21.3.5.4 [meta.unary.prop] Status: Open Submitter: Daniel Krügler Opened: 2011-08-20 Last modified: 2016-01-28
Priority: 3
View other active issues in [meta.unary.prop].
View all other issues in [meta.unary.prop].
View all issues with Open status.
Discussion:
The currently agreed on proposed wording for 2015(i) 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:
std::terminate
problemSection: 17.9.5 [exception.terminate] Status: Open Submitter: Daniel Krügler Opened: 2011-09-25 Last modified: 2016-01-28
Priority: 3
View all issues with Open status.
Discussion:
Andrzej Krzemienski reported the following on comp.std.c++:
In N3290, which is to become the official standard, in 17.9.5.4 [terminate], paragraph 1 reads
Remarks: Called by the implementation when exception handling must be abandoned for any of several reasons (15.5.1), in effect immediately after evaluating the throw-expression (18.8.3.1). May also be called directly by the program.
It is not clear what is "in effect". It was clear in previous drafts where paragraphs 1 and 2 read:
Called by the implementation when exception handling must be abandoned for any of several reasons (15.5.1). May also be called directly by the program.
Effects: Calls theterminate_handler
function in effect immediately after evaluating the throw-expression (18.8.3.1), if called by the implementation, or calls the currentterminate_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 "unlessstd::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 tostd::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 casestd::nested_exception::rethrow_nested
is called for an object that has captured no exception, there is no throw-expression involved directly (and may no throw be involved even indirectly). Next, 17.9.5.1 [terminate.handler], paragraph 2 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 functionstd::terminate
is violated, andstd::terminate
would be called recursively - shouldstd::abort
not be called in case of recursivestd::terminate
call? On the other hand some controlled recursion could be useful, like in the following technique.
The here mentioned wording changes by N3189 in regard to 17.9.5.4 [terminate] p1
were done for a better separation of effects (Effects element) and additional normative
wording explanations (Remarks element), there was no meaning change intended. Further,
there was already a defect existing in the previous wording, which was not updated when
further situations where defined, when std::terminate
where supposed to be
called by the implementation.
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]
[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:
promise
and packaged_task
missing constructors needed for uses-allocator constructionSection: 33.10.6 [futures.promise], 33.10.10 [futures.task] Status: LEWG Submitter: Jonathan Wakely Opened: 2011-11-01 Last modified: 2019-06-03
Priority: 4
View other active issues in [futures.promise].
View all other issues in [futures.promise].
View all issues with LEWG status.
Discussion:
This example is ill-formed according to C++11 because uses_allocator<promise<R>, A>::value
is true, but
is_constructible<promise<R>, A, promise<R>&&>::value
is false. Similarly for packaged_task
.
#include <future> #include <memory> #include <tuple> using namespace std; typedef packaged_task<void()> task; typedef promise<void> prom; allocator<task> a; tuple<task, prom> t1{ allocator_arg, a }; tuple<task, prom> t2{ allocator_arg, a, task{}, prom{} };
[2012, Portland]
This is an allocator issue, and should be dealt with directly by LWG.
[2013-03-06]
Jonathan suggests to make the new constructors non-explicit and makes some representational improvements.
[2013-09 Chicago]
Move to deferred.
This issue has much in common with similar problems with std::function
that are being addressed
by the polymorphic allocators proposal currently under evaluation in LEWG. Defer further discussion on
this topic until the final outcome of that paper and its proposed resolution is known.
[2014-02-20 Re-open Deferred issues as Priority 4]
[2016-08 Chicago]
Fri PM: Send to LEWG - and this also applies to function
in LFTS.
[2019-06-03 Jonathan Wakely provides updated wording]
Jonathan updates wording post-2976(i) and observes that this resolution conflicts with 3003(i).
Previous resolution [SUPERSEDED]:
[This wording is relative to the FDIS.]
Add to 33.10.6 [futures.promise], class template
promise
synopsis, as indicated:namespace std { template <class R> class promise { public: promise(); template <class Allocator> promise(allocator_arg_t, const Allocator& a); template <class Allocator> promise(allocator_arg_t, const Allocator& a, promise&& rhs) noexcept; promise(promise&& rhs) noexcept; promise(const promise& rhs) = delete; ~promise(); […] }; […] }Change 33.10.6 [futures.promise] as indicated:
promise(promise&& rhs) noexcept; template <class Allocator> promise(allocator_arg_t, const Allocator& a, promise&& rhs) noexcept;-5- Effects: constructs a new
-6- Postcondition:promise
object and transfers ownership of the shared state ofrhs
(if any) to the newly-constructed object.rhs
has no shared state. -?- [Note:a
is not used — end note]Add to 33.10.10 [futures.task], class template
packaged_task
synopsis, as indicated:namespace std { template<class> class packaged_task; // undefined template<class R, class... ArgTypes> class packaged_task<R(ArgTypes...)> { public: // construction and destruction packaged_task() noexcept; template <class Allocator> packaged_task(allocator_arg_t, const Allocator& a) noexcept; template <class F> explicit packaged_task(F&& f); template <class F, class Allocator> explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f); ~packaged_task(); // no copy packaged_task(const packaged_task&) = delete; template<class Allocator> packaged_task(allocator_arg_t, const Allocator& a, const packaged_task&) = delete; packaged_task& operator=(const packaged_task&) = delete; // move support packaged_task(packaged_task&& rhs) noexcept; template <class Allocator> packaged_task(allocator_arg_t, const Allocator& a, packaged_task&& rhs) noexcept; packaged_task& operator=(packaged_task&& rhs) noexcept; void swap(packaged_task& other) noexcept; […] }; […] }Change 33.10.10.2 [futures.task.members] as indicated:
packaged_task() noexcept; template <class Allocator> packaged_task(allocator_arg_t, const Allocator& a) noexcept;-1- Effects: constructs a
-?- [Note:packaged_task
object with no shared state and no stored task.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
-6- Postcondition:packaged_task
object and transfers ownership ofrhs
's shared state to*this
, leavingrhs
with no shared state. Moves the stored task fromrhs
to*this
.rhs
has no shared state. -?- [Note:a
is not used — end note]
Proposed resolution:
[This wording is relative to N4810.]
Add to 33.10.6 [futures.promise], class template promise
synopsis,
as indicated:
namespace std { template <class R> class promise { public: promise(); template <class Allocator> promise(allocator_arg_t, const Allocator& a); template <class Allocator> promise(allocator_arg_t, const Allocator& a, promise&& rhs) noexcept; promise(promise&& rhs) noexcept; promise(const promise& rhs) = delete; ~promise(); […] }; […] }
Change 33.10.6 [futures.promise] as indicated:
promise(promise&& rhs) noexcept; template <class Allocator> promise(allocator_arg_t, const Allocator& a, promise&& rhs) noexcept;-5- Effects: constructs a new
-6- Postcondition:promise
object and transfers ownership of the shared state ofrhs
(if any) to the newly-constructed object.rhs
has no shared state. -?- [Note:a
is not used — end note]
valarray
assignments with mask_array
index?Section: 28.6.8 [template.mask.array] Status: Open Submitter: Thomas Plum Opened: 2011-12-10 Last modified: 2016-01-28
Priority: 4
View all issues with Open status.
Discussion:
Recently I received a Service Request (SR) alleging that one of our testcases causes an
undefined behavior. The complaint is that 28.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.
"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 ofv
is not equal to the length of*this
, resizes*this
to make the two arrays the same length, as if by callingresize(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
[Plum Hall:]mask_array
assignment hence target the C++03 26.3.8 paragraph. Correct?
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 sizedvalarray
and I perfectly agree with you. But, as already stated, this is not a simplevalarray
assignment but amask_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 ofb
to the masked elements ina
(those for which the corresponding element inmask
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
That is why I reported the test t263.dir/_26322Y31.cpp having an undefined behaviour. [Plum Hall:]b
".
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:
is_nothrow_constructible
and destructorsSection: 21.3.5.4 [meta.unary.prop] Status: Open Submitter: Dave Abrahams Opened: 2011-12-09 Last modified: 2023-05-25
Priority: 3
View other active issues in [meta.unary.prop].
View all other issues in [meta.unary.prop].
View all issues with Open status.
Discussion:
IMO if we specified is_[nothrow_]constructible
in terms of a variable
declaration whose validity requires destructibility, it is clearly a bug
in our specification and a failure to realize the actual original
intent. The specification should have been in terms of placement-new.
is_constructible
.
The design of is_constructible
was also impacted by the previous
Constructible
concept that explicitly contained destruction semantics,
because during conceptification of the library it turned out to simplify
the constraints in the library because you did not need to add
Destructible
all the time. It often was implied but never spoken out
in C++03.
Pure construction semantics was considered as useful as well, so HasConstructor
did also exist and would surely be useful as trait as well.
Another example that is often overlooked: This also affects wrapper types like pair
,
tuple
, array
that contain potentially more than one type:
This is easy to understand if you think of T1
having a deleted destructor
and T2
having a constructor that may throw: Obviously the compiler has
potentially need to use the destructor
of T1
in the constructor
of std::pair<T1, T2>
to ensure that the core language requirements
are satisfied (All previous fully constructed sub-objects must be destructed).
The core language also honors this fact in [class.copy] p11:
A defaulted copy/move constructor for a class
X
is defined as deleted (9.5.3 [dcl.fct.def.delete]) ifX
has:
[…]
— any direct or virtual base class or non-static data member of a type with a destructor that is deleted or inaccessible from the defaulted constructor,
[…]
Dave:
This is about is_nothrow_constructible
in particular. The fact that it is
foiled by not having a noexcept
dtor is a defect.
[2012, Kona]
Move to Open.
is_nothrow_constructible
is defined in terms of is_constructible
, which is defined
by looking at a hypothetical variable and asking whether the variable definition is known not to
throw exceptions. The issue claims that this also examines the type's destructor, given the context,
and thus will return false
if the destructor can potentially throw. At least one
implementation (Howard's) does return false
if the constructor is noexcept(true)
and the destructor is noexcept(false)
. So that's not a strained interpretation.
The issue is asking for this to be defined in terms of placement new
, instead of in terms
of a temporary object, to make it clearer that is_nothrow_constructible
looks at the
noexcept
status of only the constructor, and not the destructor.
Sketch of what the wording would look like:
require is_constructible
, and then also require that a placement new
operation
does not throw. (Remembering the title of this issue... What does this imply for swap
?
If we accept this resolution, do we need any changes to swap
?
STL argues: no, because you are already forbidden from passing anything with a throwing
destructor to swap
.
Dietmar argues: no, not true. Maybe statically the destructor can conceivably throw for some
values, but maybe there are some values known not to throw. In that case, it's correct to
pass those values to swap
.
[2017-01-27 Telecon]
Gave the issue a better title
This issue interacts with 2827(i)
Ville would like "an evolution group" to take a look at this issue.
[2020-08; LWG reflector]
A poll was taken to close the issue as NAD, but only gained three votes in favour (and one vote against, which was subsequently withdrawn).
[2022-03; LWG reflector]
A poll was taken to close the issue as NAD, with six votes in favour. (and one vote against, subsequently withdrawn).
"Write a paper if you want something else. These traits have well established meaning now." "Minimizing requirements is not as important a concern for standard library concepts as as minimizing the number of concepts. Requirements like 'I need to construct but not destroy an object' are niche enough that we don't need to support them."
[2022-11-30; LWG telecon]
Alisdair intends to write a paper for this.
[2023-05-25; May 2023 mailing]
Alisdair provided P2842R0.
Proposed resolution:
ios_base
manipulators should have showgrouping/noshowgrouping
Section: 30.4.3.3.3 [facet.num.put.virtuals], 31.5.2.2.2 [ios.fmtflags], 31.5.5.1 [fmtflags.manip] Status: Open Submitter: Benjamin Kosnik Opened: 2011-12-15 Last modified: 2023-02-07
Priority: 3
View other active issues in [facet.num.put.virtuals].
View all other issues in [facet.num.put.virtuals].
View all issues with Open status.
Discussion:
Iostreams should include a manipulator to toggle grouping on/off for locales that support grouped digits. This has come up repeatedly and been deferred. See LWG 826(i) 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 30.4.3.3.3 [facet.num.put.virtuals] paragraph 5:
Stage 1: The first action of stage 1 is to determine a conversion specifier. The tables that describe this determination use the following local variables
fmtflags flags = str.flags() ; fmtflags basefield = (flags & (ios_base::basefield)); fmtflags uppercase = (flags & (ios_base::uppercase)); fmtflags floatfield = (flags & (ios_base::floatfield)); fmtflags showpos = (flags & (ios_base::showpos)); fmtflags showbase = (flags & (ios_base::showbase)); fmtflags showgrouping = (flags & (ios_base::showgrouping));Change header
<ios>
synopsis, [iostreams.base.overview] as indicated:#include <iosfwd> namespace std { […] // 27.5.6, manipulators: […] ios_base& showpoint (ios_base& str); ios_base& noshowpoint (ios_base& str); ios_base& showgrouping (ios_base& str); ios_base& noshowgrouping(ios_base& str); ios_base& showpos (ios_base& str); ios_base& noshowpos (ios_base& str); […] }Change class
ios_base
synopsis, 31.5.2 [ios.base] as indicated:namespace std { class ios_base { public: class failure; // 27.5.3.1.2 fmtflags typedef T1 fmtflags; […] static constexpr fmtflags showpoint = unspecified ; static constexpr fmtflags showgrouping = unspecified ; static constexpr fmtflags showpos = unspecified ; […] }; }Add a new entry to Table 122 — "
fmtflags
effects" as indicated:
Table 122 — fmtflags
effectsElement Effect(s) if set […]
showpoint
generates a decimal-point character unconditionally in generated floatingpoint output showgrouping
generates grouping characters unconditionally in generated output […]
After [ios::fmtflags] p12 insert the following:
ios_base& showgrouping(ios_base& str);-?- Effects: Calls
-?- Returns:str.setf(ios_base::showgrouping)
.str
.ios_base& noshowgrouping(ios_base& str);-?- Effects: Calls
-?- Returns:str.unsetf(ios_base::showgrouping)
.str
.
Proposed resolution:
Section: 16.3.2 [structure] Status: Open Submitter: Jens Maurer Opened: 2012-03-08 Last modified: 2024-10-05
Priority: 3
View all issues with Open status.
Discussion:
The front matter in clause 17 should clarify that postconditions will not hold if a standard library function exits via an exception. Postconditions or guarantees that apply when an exception is thrown (beyond the basic guarantee) are described in an "Exception safety" section.
[ 2012-10 Portland: Move to Open ]
Consensus that we do not clearly say this, and that we probably should. A likely location to describe the guarantees of postconditions could well be a new sub-clause following 99 [res.on.required] which serves the same purpose for requires clauses. However, we need such wording before we can make progress.
Also, see 2137(i) for a suggestion that we want to see a paper resolving both issues together.
[2015-05-06 Lenexa: EricWF to write paper addressing 2136 and 2137]
MC: Idea is to replace all such "If no exception" postconditions with "Exception safety" sections.
[2021-06-20; Daniel comments]
An informal editorial change suggestion has recently been made whose editorial implementation would promote the idea that the default assumption is that Postconditions: are only met if the function doesn't exit with an exception.
After analyzing all current existing Postconditions: elements the following seems to hold: Affected by this issue are only non-noexcept
functions and mostly non-constructor functions (unless the
Postconditions: element says something about the value of its arguments). Most existing
Postconditions seem to be intended to apply only in non-exceptional cases. I found some where
this is presumably not intended, namely those of the expressions os << x
and
is >> v
in Tables [tab:rand.req.eng] and [tab:rand.req.dist], maybe also
29.11.2.4 [time.zone.db.remote] p4.
Nonetheless, the editorial change seems to be applicable even without having this issue resolved, because
it doesn't actually change the normative state by itself.
[2024-10-03; Jonathan adds wording]
Proposed resolution:
This wording is relative to N4988.
Change 16.3.2.4 [structure.specifications] as indicated:
(3.6) — Postconditions: the conditions (sometimes termed observable results) established by the function when a call to it returns normally.
Section: 32.7.3 [re.regex.assign] Status: Open Submitter: Jonathan Wakely Opened: 2012-03-08 Last modified: 2024-10-03
Priority: 3
View all other issues in [re.regex.assign].
View all issues with Open status.
Discussion:
The post-conditions of basic_regex<>::assign
32.7.3 [re.regex.assign] p16 say:
If no exception is thrown,
flags()
returnsf
andmark_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(i)), 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(i). 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(i) is a paper providing the clause 17 wording that gives the guarantee for postcondition paragraphs, and then reviews clauses 18-30 to apply that guarantee consistently. We do not want to pick up these issues piecemeal, as we risk opening many issues in an ongoing process.
[2015-05-06 Lenexa: EricWF to write paper addressing 2136 and 2137]
[2024-10-03; Jonathan comments]
I could find no other cases in the entire standard where we say something like this in a Postconditions: element. 31.6.3.5.4 [streambuf.virt.pback] p2 says "Postconditions: On return, the constraints of [...]" which is probably redundant (postconditions are always "on return").
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 strings
, interpreted according the flags specified inf
. If an exception is thrown,*this
is unchanged. -16- Postconditions:If no exception is thrown,flags()
returnsf
andmark_count()
returns the number of marked sub-expressions within the expression.
Copy
/Move-Constructible
/Assignable
or Destructible
?Section: 16.4.4.2 [utility.arg.requirements] Status: Open Submitter: Nikolay Ivchenkov Opened: 2012-03-23 Last modified: 2024-03-15
Priority: 3
View all other issues in [utility.arg.requirements].
View all issues with Open status.
Discussion:
According to 16.4.4.2 [utility.arg.requirements] p1
The template definitions in the C++ standard library refer to various named requirements whose details are set out in tables 17-24. In these tables,
T
is an object or reference type to be supplied by a C++ program instantiating a template;a
,b
, andc
are values of type (possiblyconst
)T
;s
andt
are modifiable lvalues of typeT
;u
denotes an identifier;rv
is an rvalue of typeT
; andv
is an lvalue of type (possiblyconst
)T
or an rvalue of typeconst 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
?
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 ofstd::thread
:
template <class F, class ...Args> explicit thread(F&& f, Args&&... args);Requires:
F
and eachTi
inArgs
shall satisfy theMoveConstructible
requirements.
When the first argument of this constructor is an lvalue (e.g. a name of a global function), template argument for F
is deduced to be lvalue reference type. What should "MoveConstructible
" mean with regard to an lvalue reference
type? Maybe the wording should say that std::decay<F>::type
and each std::decay<Ti>::type
(where
Ti
is an arbitrary item in Args
) shall satisfy the MoveConstructible
requirements?
[2013-03-15 Issues Teleconference]
Moved to Open.
The questions raised by the issue are real, and should have a clear answer.
[2015-10, Kona Saturday afternoon]
STL: std::thread needs to be fixed, and anything behaving like it needs to be fixed, rather than reference types. std::bind gets this right. We need to survey this. GR: That doesn't sound small to me. STL: Seach for CopyConstructible etc. It may be a long change, but not a hard one.
MC: It seems that we don't have a PR. Does anyone have one? Is anyone interested in doing a survey?
[2016-03, Jacksonville]
Casey volunteers to make a survey
[2016-06, Oulu]
During an independent survey performed by Daniel as part of the analysis of LWG 2716(i), some overlap was found between these two issues. Daniel suggested to take responsibility for surveying LWG 2146(i) and opined that the P/R of LWG 2716(i) should restrict to forwarding references, where the deduction to lvalue references can happen without providing an explicit template argument just by providing an lvalue function argument.
[2018-06, Rapperwsil]
Jonathan says that this will be covered by his Omnibus requirements paper.
[2019 Cologne Wednesday night]
Daniel will start working on this again; Marshall to provide rationale why some of the examples are not well-formed.
[2020-10-02; Issue processing telecon: change from P2 to P3]
For the examples given in the original report, the for_each
case is now banned, because 27.2 [algorithms.requirements] p15
forbids explicit template argument lists. std::thread
's constructor
has also been fixed to describe the requirements on decay_t<T>
instead of T
.
We believe we're more careful these days about using remove_cvref
or decay
as needed, but there are still places where we incorrectly
state requirements in terms of types that might be references.
The swap
case still needs solving. Still need a survey.
[2024-03-15; LWG 4047(i) addresses the swap
part]
Proposed resolution:
Section: 16.4.4.3 [swappable.requirements], 24.2.2 [container.requirements.general] Status: LEWG Submitter: Robert Shearer Opened: 2012-04-13 Last modified: 2020-09-06
Priority: 3
View all other issues in [swappable.requirements].
View all issues with LEWG status.
Discussion:
Sub-clause 16.4.4.3 [swappable.requirements] defines two notions of swappability: a binary version defining when two objects are swappable with one another, and a unary notion defining whether an object is swappable (without qualification), with the latter definition requiring that the object satisfy the former with respect to all values of the same type.
LetT
be a container type based on a non-propagating allocator whose instances do not necessarily
compare equal. Then sub-clause 24.2.2 [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 22.2.2 [utility.swap] p4, 22.3.2 [pairs.pair] p31, 22.4.4.4 [tuple.swap] p2,
27.7.3 [alg.swap] p2, and 27.7.3 [alg.swap] p6, which use the binary definition). This renders
many of the mutating sequence algorithms of sub-clause 27.7 [alg.modifying.operations], for example,
inapplicable to sequences of standard container types, even where every element of the sequence is swappable
with every other.
Note that this concern extends beyond standard containers to all future allocator-based types.
Resolution proposal:
I see two distinct straightforward solutions:
I favor the latter solution, for reasons detailed in the following issue.
[ 2012-10 Portland: Move to Open ]
The issue is broader than containers with stateful allocotors, although they are the most obvious
example contained within the standard itself. The basic problem is that once you have a stateful
allocator, that does not propagate_on_swap
, then whether two objects of this type can be
swapped with well defined behavior is a run-time property (the allocators compare equal) rather
than a simple compile-time property that can be deduced from the type. Strictly speaking, any
type where the nature of swap is a runtime property does not meet the swappable
requirements of C++11, although typical sequences of such types are going to have elements that
are all swappable with
any other element in the sequence (using our other term of art
for specifying requirements) as the common case is a container of elements who all share the
same allocator.
The heart of the problem is that the swappable
requirments demand that any two objects
of the same type be swappable with
each other, so if any two such objects would not
be swappable with
each other, then the whole type is never swappable
. Many
algorithms in clause 25 are specified in terms of swappable
which is essentially an
overspecification as all they actually need is that any element in the sequence is swappable
with
any other element in the sequence.
At this point Howard joins the discussion and points out that the intent of introducing the
two swap-related terms was to support vector<bool>::reference
types, and we are
reading something into the wording that was never intended. Consuses is that regardless of
the intent, that is what the words today say.
There is some support to see a paper reviewing the whole of clause 25 for this issue, and other select clauses as may be necessary.
There was some consideration to introducing a note into the front of clause 25 to indicate
swappable
requirements in the clause should be interpreted to allow such awkward
types, but ultimately no real enthusiasm for introducing a swappable for clause 25
requirement term, especially if it confusingly had the same name as a term used with a
subtly different meaning through the rest of the standard.
There was no enthusiasm for the alternate resolution of requiring containers with unequal
allocators that do not propagate provide a well-defined swap behavior, as it is not
believed to be possible without giving swap
linear complexity for such values,
and even then would require adding the constraint that the container element types are
CopyConstructible.
Final conclusion: move to open pending a paper from a party with a strong interest in stateful allocators.
[2016-03 Jacksonville]
Alisdair says that his paper P0178 addresses this.
[2016-06 Oulu]
P0178 reviewed, and sent back to LEWG for confirmation.
Thursday Morning: A joint LWG/LEWG meeting declined to adopt P0178.
[2017-02 in Kona, LEWG responds]
Note in the issue that this is tracked here
[2017-06-02 Issues Telecon]
Leave as LEWG; priority 3
Proposed resolution:
Apply P0178.
swap
contractSection: 22.2.2 [utility.swap], 16.4.4.3 [swappable.requirements], 24.2.2 [container.requirements.general] Status: LEWG Submitter: Robert Shearer Opened: 2012-04-13 Last modified: 2020-10-02
Priority: 2
View all other issues in [utility.swap].
View all issues with LEWG status.
Discussion:
Sub-clause 22.2.2 [utility.swap] defines a non-member 'swap' function with defined behavior for
all MoveConstructible
and MoveAssignable
types. It does not guarantee
constant-time complexity or noexcept
in general, however this definition does
render all objects of MoveConstructible
and MoveAssignable
type swappable
(by the unary definition of sub-clause 16.4.4.3 [swappable.requirements]) in the absence of
specializations or overloads.
swap
function defined in Table 96, however,
defines semantics incompatible with the generic non-member swap
function,
since it is defined to call a member swap
function whose semantics are
undefined for some values of MoveConstructible
and MoveAssignable
types.
The obvious (perhaps naive) interpretation of sub-clause 16.4.4.3 [swappable.requirements] is as a guide to
the "right" semantics to provide for a non-member swap
function (called in
the context defined by 16.4.4.3 [swappable.requirements] p3) in order to provide interoperable
user-defined types for generic programming. The standard container types don't follow these guidelines.
More generally, the design in the standard represents a classic example of "contract narrowing". It
is entirely reasonable for the contract of a particular swap
overload to provide more
guarantees, such as constant-time execution and noexcept
, than are provided by the swap
that is provided for any MoveConstructible
and MoveAssignable
types, but it is not
reasonable for such an overload to fail to live up to the guarantees it provides for general types when
it is applied to more specific types. Such an overload or specialization in generic programming is akin
to an override of an inherited virtual function in OO programming: violating a superclass contract in a
subclass may be legal from the point of view of the language, but it is poor design and can easily lead
to errors. While we cannot prevent user code from providing overloads that violate the more general
swap
contract, we can avoid doing so within the library itself.
My proposed resolution is to draw a sharp distinction between member swap
functions, which provide
optimal performance but idiosyncratic contracts, and non-member swap
functions, which should always
fulfill at least the contract of 22.2.2 [utility.swap] and thus render objects swappable. The member
swap
for containers with non-propagating allocators, for example, would offer constant-time
guarantees and noexcept
but would only offer defined behavior for values with allocators that compare
equal; non-member swap
would test allocator equality and then dispatch to either member swap
or
std::swap
depending on the result, providing defined behavior for all values (and rendering the type
"swappable"), but offering neither the constant-time nor the noexcept
guarantees.
[2013-03-15 Issues Teleconference]
Moved to Open.
This topic deserves more attention than can be given in the telecon, and there is no proposed resolution.
[2016-03 Jacksonville]
Alisdair says that his paper P0178 addresses this.
[2016-08 Chicago]
Send to LEWG
[2016-06 Oulu]
P0178 reviewed, and sent back to LEWG for confirmation.
Thursday Morning: A joint LWG/LEWG meeting declined to adopt P0178.
[2020-10-02; remove P0178 as Proposed Resolution]
Proposed resolution:
std::array<T,0>
initialization work when T
is not default-constructible?Section: 24.3.8.5 [array.zero] Status: Open Submitter: Daryle Walker Opened: 2012-05-08 Last modified: 2021-03-14
Priority: 3
View all other issues in [array.zero].
View all issues with Open status.
Discussion:
Objects of std::array<T, N>
are supposed to be initialized with aggregate initialization (when
not the destination of a copy or move). This clearly works when N
is positive. What happens when N
is zero? To continue using an (inner) set of braces for initialization, a std::array<T, 0>
implementation
must have an array member of at least one element, and let default initialization take care of those secret elements.
This cannot work when T
has a set of constructors and the default constructor is deleted from that set.
Solution: Add a new paragraph in 24.3.8.5 [array.zero]:
The unspecified internal structure of array for this case shall allow initializations like:
array<T, 0> a = { };and said initializations must be valid even when
T
is not default-constructible.
[2012, Portland: Move to Open]
Some discussion to understand the issue, which is that implementations currently have freedom to implement
an empty array
by holding a dummy element, and so might not support value initialization, which is
surprising when trying to construct an empty container. However, this is not mandated, it is an unspecified
implementation detail.
Jeffrey points out that the implication of 24.3.8.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
.
[2015-10, Kona Saturday afternoon]
MC: How important is this? Can you not just use default construction for empty arrays?
TK: It needs to degenerate properly from a pack. STL agrees.
JW: Yes, this is important, and we have to make it work.
MC: I hate the words "initialization like".
JW: I'll reword this.
WEB: Can I ask that once JW has reworded this we move it to Review rather than Open?
MC: We'll try to review it in a telecon and hopefully get it to tentatively ready.
STL: Double braces must also work: array<T, 0> a = {{}};
.
Jonathan to reword.
[2018-03-14 Wednesday evening issues processing]
Jens suggested that we remove the requirement that begin() == end() ==
unique-value,
specifically the unique value part.
Previous resolution [SUPERSEDED]:
This wording is relative to N3376.
Add the following new paragraph between the current 24.3.8.5 [array.zero] p1 and p2:
-1-
-?- The unspecified internal structure ofarray
shall provide support for the special caseN == 0
.array
for this case shall allow initializations like:array<T, 0> a = { };and said initializations must be valid even when
-2- In the case thatT
is not default-constructible.N == 0
,begin() == end() ==
unique value. The return value ofdata()
is unspecified. -3- The effect of callingfront()
orback()
for a zero-sized array is undefined. -4- Member functionswap()
shall have a noexcept-specification which is equivalent tonoexcept(true)
.
[2018-06-14, Jonathan Wakely comments and provides revised wording]
The new wording does not address the 2018-03-14 suggestion from Jens to remove the unique value. It wasn't clear to me that there was consensus to make that change, and it would be a change in behaviour not just a clarification of the existing wording.
Previous resolution [SUPERSEDED]:
This wording is relative to N4750.
Modify 24.3.8.5 [array.zero] as indicated:
-1-
-?- A zero-sizedarray
shallprovides support for the special case of a zero-sizedarray
that is always empty, i.e.N == 0
, with the properties described in this subclause.array
type is an aggregate that meets theDefaultConstructible
(Table 22) andCopyConstructible
(Table 24) requirements. There is a single element of the aggregate, of an unspecifiedDefaultConstructible
type. [Note: This allows initialization of the formarray<T, 0> a = {{}};
. There is no requirement forT
to beDefaultConstructible
. — end note] -2-In the case thatN == 0
,begin() == end() ==
unique valuebegin()
andend()
return non-dereferenceable iterators such thatbegin() == end()
anda.begin() != b.begin()
wherea
andb
are distinct objects of the same zero-sizedarray
type. The return value ofdata()
is unspecified. -3- The effect of callingfront()
orback()
for a zero-sized array is undefined. -4- Member functionswap()
shall havehas constant complexity and a non-throwing exception specification.
[2018-08-30, Jonathan revises wording following feedback from Daniel Kruegler and Tim Song.]
Daniel noted that it's undefined to compare iterators from different containers,
so a.begin() != b.begin()
can't be used. That means whether the iterators
from different containers are unique is unobservable anyway.
We can say they don't share the same underlying sequence, which tells users they can't compare them
and tells implementors they can't return value-initialized iterators.
Tim noted that it's not sufficient to say the unspecified type in a zero-sized array is DefaultConstructible,
it also needs to be constructible from = {}
. Also, a zero-sized array should be CopyAssignable.
Previous resolution [SUPERSEDED]:
This wording is relative to N4762.
Modify 24.3.8.5 [array.zero] as indicated:
-1-
-?- A zero-sizedarray
shallprovides support for the special case of a zero-sizedarray
that is always empty, i.e.N == 0
, with the properties described in this subclause.array
type is an aggregate that meets the Cpp17DefaultConstructible (Table 24) and Cpp17CopyConstructible (Table 26) and Cpp17CopyAssignable (Table 28) requirements. There is a single element of the aggregate, of an unspecified Cpp17DefaultConstructible type that is copy-list-initializable from an empty list. [Note: This allows initialization of the formarray<T, 0> a = {{}};
. There is no requirement forT
to be Cpp17DefaultConstructible. — end note] -2-In the case thatN == 0
,begin() == end() ==
unique valuebegin()
andend()
return non-dereferenceable iterators such thatbegin() == end()
. Whena
andb
are distinct objects of the same zero-sizedarray
type,a.begin()
andb.begin()
are not iterators over the same underlying sequence. [Note: Thereforebegin()
does not return a value-initialized iterator — end note]. The return value ofdata()
is unspecified. -3- The effect of callingfront()
orback()
for a zero-sized array is undefined. -4- Member functionswap()
shall havehas constant complexity and a non-throwing exception specification.
[2021-03-14; Johel Ernesto Guerrero Peña comments and provides improved wording]
The currently proposed wording specifies:
There is a single element of the aggregate, of an unspecified Cpp17DefaultConstructible type that is copy-list-initializable from an empty list.
This doesn't specify which expressions involving zero-sized array specializations are constant expressions.
24.3.8.1 [array.overview] p4 specifies array<T, 0>
to be a structural type when T
is a structural type. This requires that its single element, let's call it single-element, be a
structural type. But that says nothing about which of the special member functions of single-element
are constant expressions. By being a structural type, single-element is permitted to be implemented
as a literal class type. To meet this requirement, single-element can be implemented to have one
constexpr constructor that is not a copy or move constructor (6.8.1 [basic.types.general] p10), so
its default constructor needn't be constexpr. This is unlike non-zero-sized array specializations, which
inherit these properties from T
. Furthermore, this permits an implementation of single-element
whose default constructor stores the result of std::source_location::current()
in a data member
(as exemplified in the specification for current
). Cpp17DefaultConstructible doesn't
require the default constructor to produce equal values. The simplest way to solve these issues and any other
that might arise from future changes and oversights would be to specify single-element as an empty
aggregate type. Then the wording from 24.3.8.2 [array.cons] p1 makes it clear that all the special
member functions are constant expressions. It would also mean that the default constructor produces
template-argument-equivalent values.
Proposed resolution:
This wording is relative to N4878.
Modify 24.3.8.5 [array.zero] as indicated:
-1-
-?- A zero-sizedarray
shallprovides support for the special case of a zero-sizedarray
that is always empty, i.e.N == 0
, with the properties described in this subclause.array
type is an aggregate that meets the Cpp17DefaultConstructible (Table 29 [tab:cpp17.defaultconstructible]) and Cpp17CopyConstructible (Table 31 [tab:cpp17.copyconstructible]) and Cpp17CopyAssignable (Table 33 [tab:cpp17.copyassignable]) requirements. There is a single element of the aggregate, of an unspecified empty aggregate type. [Note: This allows initialization of the formarray<T, 0> a = {{}};
. There is no requirement forT
to be Cpp17DefaultConstructible. — end note] -2-In the case thatN == 0
,begin() == end() ==
unique valuebegin()
andend()
return non-dereferenceable iterators such thatbegin() == end()
. Whena
andb
are distinct objects of the same zero-sizedarray
type,a.begin()
andb.begin()
are not iterators over the same underlying sequence. [Note: Thereforebegin()
does not return a value-initialized iterator — end note].. The return value ofdata()
is unspecified. -3- The effect of callingfront()
orback()
for a zero-sized array is undefined. -4- Member functionswap()
shall havehas constant complexity and a non-throwing exception specification.
std::vector
Section: 24.3.12.3 [vector.capacity] Status: Open Submitter: Nikolay Ivchenkov Opened: 2012-05-08 Last modified: 2022-11-06
Priority: 3
View other active issues in [vector.capacity].
View all other issues in [vector.capacity].
View all issues with Open status.
Discussion:
There are various operations on std::vector
that can cause elements of the vector to be
moved from one location to another. A move operation can use either rvalue or const lvalue as
argument; the choice depends on the value of !is_nothrow_move_constructible<T>::value &&
is_copy_constructible<T>::value
, where T
is the element type. Thus, some operations
on std::vector
(e.g. 'resize' with single parameter, 'reserve', 'emplace_back') should have
conditional requirements. For example, let's consider the requirement for 'reserve' in N3376 –
24.3.12.3 [vector.capacity]/2:
Requires:
T
shall beMoveInsertable
into*this
.
This requirement is not sufficient if an implementation is free to select copy constructor when
!is_nothrow_move_constructible<T>::value && is_copy_constructible<T>::value
evaluates to true. Unfortunately, is_copy_constructible
cannot reliably determine whether
T
is really copy-constructible. A class may contain public non-deleted copy constructor whose
definition does not exist or cannot be instantiated successfully (e.g.,
std::vector<std::unique_ptr<int>>
has copy constructor, but this type is not
copy-constructible). Thus, the actual requirements should be:
if !is_nothrow_move_constructible<T>::value && is_copy_constructible<T>::value
then T
shall be CopyInsertable
into *this
;
otherwise T
shall be MoveInsertable
into *this
.
Maybe it would be useful to introduce a new name for such conditional requirement (in addition to
"CopyInsertable
" and "MoveInsertable
").
[2016-08 Chicago]
The problem does not appear to be as severe as described. The MoveInsertable
requirements are consistently correct, but an issue may arise on the
exception-safety guarantees when we check for
is_copy_constructible_v<T>
. The problem, as described, is
typically for templates that appear to have a copy constructor, but one that
fails to compile once instantiated, and so gives a misleading result for the
trait.
In general, users should not provide such types, and the standard would not
serve users well by trying to address support for such types. However, the
standard should not be providing such types either, such as
vector<unique_ptr<T>>
. A possible resolution would be
to tighten the constraints in Table 80 — Container Requirements, so that if
the Requirements for the copy constructor/assingment operator of a container
are not satisfied, that operation shall be deleted.
A futher problem highlighted by this approach is that there are no constraints on
the copy-assignment operator, so that vector<unique_ptr<T>>
should be CopyAssignable
! However, we can lift the equivalent constraints from
the Allocator-aware container requirements.
[08-2016, Chicago]
Fri PM: Move to Open
[2017-11 Albuquerque Saturday issues processing]
There's a bunch of uses of "shall" here that are incorrect. Also, CopyInsertable contains some semantic requirements, which can't be checked at compile time, so 'ill-formed' is not possible for detecting that.
[2018-06 Rapperswil Wednesday issues processing]
Daniel to provide updated wording.
[2018-06-12, Daniel provides revised wording]
Previous resolution [SUPERSEDED]:
This wording is relative to N4606.
24.2.2 [container.requirements.general] Table 80 — Container requirements Expression Return type Operational semantics Assertion/note/pre-/post-condition Complexity X(a)
Requires: T
isCopyInsertable
intoX
(see below)., otherwise this expression shall be ill-formed.
post:a == X(a)
.linear X u(a)
X u = a;
Requires: T
isCopyInsertable
intoX
(see below)., otherwise this expression shall be ill-formed.
post:u == a
.linear ... ... ... ... ... r = a
X&
Requires: T
isCopyInsertable
intoX
andCopyAssignable
, otherwise this expression shall be ill-formed.
post:r == a
.linear
24.2.2 [container.requirements.general] Table 83 — Allocator-aware container requirements Expression Return type Operational semantics Assertion/note/pre-/post-condition Complexity a = t
X&
Requires: T
isCopyInsertable
intoX
andCopyAssignable
., otherwise this expression shall be ill-formed
post:r == a
.linear
[2018-08-23 Batavia Issues processing. Priority to 3]
Changed CopyInsertable
-> Cpp17CopyInsertable
in the resolution.
Tim says that the wording is not quite right — it imposes additional requirements.
[2022-11-06; Daniel comments]
This issue has considerable overlap with LWG 3758(i).
Proposed resolution:
This wording is relative to N4750.
The revised wording below uses the new Mandates: element introduced by adopting P0788R3 at the Rapperswil meeting 2018 and which will become a new term of art with Jonathan's omnibus paper throughout the Standard Library.
Expression | Return type | Operational semantics | Assertion/note/pre-/post-condition | Complexity |
X(a) |
Mandates: Syntactic requirements of T is Cpp17CopyInsertable into X (see below).Requires: T is Cpp17CopyInsertable into
X post: a == X(a) .
|
linear | ||
X u(a) X u = a; |
Mandates: Syntactic requirements of T is Cpp17CopyInsertable into X (see below).Requires: T is Cpp17CopyInsertable into
X post: u == a .
|
linear | ||
... | ... | ... | ... | ... |
r = a |
X& |
Mandates: Syntactic requirements of T is Cpp17CopyInsertable into X (see below) and
CopyAssignable .Requires: T is Cpp17CopyInsertable into X
and CopyAssignable .post: r == a . |
linear |
Expression | Return type | Operational semantics | Assertion/note/pre-/post-condition | Complexity |
a = t |
X& |
Mandates: Syntactic requirements of T isCpp17CopyInsertable into X and CopyAssignable .Requires: T is Cpp17CopyInsertable into X and
CopyAssignable .post: r == a . |
linear |
operator +
in the description of the algorithmsSection: 27 [algorithms] Status: Open Submitter: Nikolay Ivchenkov Opened: 2012-08-01 Last modified: 2018-06-12
Priority: 4
View other active issues in [algorithms].
View all other issues in [algorithms].
View all issues with Open status.
Discussion:
According to 27.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 ofa+n
is the same as that ofX 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 fromfirst
and proceeding tolast
. For each non-negative integern < (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.
[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 onn
. Unfortunately,
the corresponding function advance
is completely underspecified in this regard, so I couldn't borrow wording
from it. We cannot even assume here that n
is the difference type of the iterator, because for output iterators there is
no requirements for this associated type to be defined. The presented wording attempts to minimize assumptions, but still
can be considered as controversial.
[2018-06 Rapperswil Wednesday issues processing]
Status to Open
Proposed resolution:
This wording is relative to N4606.
Change 27.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 ofa+n
is the same as that ofX tmp = a; advance(tmp, n); return tmp;when
X
meets the input iterator requirements (25.3.5.3 [input.iterators]), otherwise it is the same as that ofX 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 ofb-a
is the same as ofreturn distance(a, b);
swap
breaks unordered containers' stateSection: 24.2.8.2 [unord.req.except] Status: Open Submitter: Alisdair Meredith Opened: 2012-09-23 Last modified: 2019-07-22
Priority: 3
View all issues with Open status.
Discussion:
The hash functor and key-comparison functor of unordered containers are allowed to throw on swap
.
24.2.8.2 [unord.req.except]p3 "For unordered associative containers, no swap
function throws
an exception unless that exception is thrown by the swap of the container's Hash or Pred object (if any)."
In such a case we must offer the basic exception safety guarantee, where both objects are left in valid
but unspecified states, and no resources are leaked. This yields a corrupt, un-usable container if the
first swap
succeeds, but the second fails by throwing, as the functors form a matched pair.
So our basic scenario is first, swap the allocators if the allocators propagate on swap, according to
allocator_traits
. Next we swap the pointers to our internal hash table data structures, so that
they match the allocators that allocated them. (Typically, this operation cannot throw). Now our containers
are back in a safely destructible state if an exception follows.
Next, let's say we swap the hash functor, and that throws. We have a corrupt data structure, in that the buckets are not correctly indexed by the correct functors, lookups will give unpredicatable results etc. We can safely restore a usable state by forcibly clearing each container - which does not leak resources and leaves us with two (empty but) usable containers.
Now let us assume that the hasher swap succeeds. Next we swap the equality comparator functor, and this too could throw. The important point to bear in mind is that these two functors form an important pairing - two objects that compare equal by the equality functor must also hash to the same value. If we swap one without the other, we most likely leave the container in an unusable state, even if we clear out all elements.
1. A colleague pointed out that the solution for this is to dynamically allocate the two functors, and then
we need only swap pointers, which is not a throwing operation. And if we don't want to allocate on default
construction (a common QoI request), we might consider moving to a dynamically allocated functors whenever
swap
is called, or on first insertion. Of course, allocating memory in swap
is a whole
new can of worms, but this does not really sound like the design we had intended.
2. The simplest option is to say that we do not support hasher or equality functors that throw on ADL
swap
. Note that the requirement is simply to not throw, rather than to be explicitly
marked as noexcept
. Throwing functors are allowed, so long as we never use values that
would actually manifest a throw when used in an unordered container.
Pablo went on to give me several more options, to be sure we have a full set to consider:
3. Disallow one or the other functor from throwing. In that case, the possibly-throwing functor must be swapped first, then the other functor, the allocator, and the data pointer(s) afterwards (in any order -- there was a TC that allocator assignment and swap may not throw if the corresponding propagation trait is true.). Of course, the question becomes: which functor is allowed to throw and which one is not?
4. Require that any successful functor swap
be reliably reversible.
This is very inventive. I know of no other place in the standard where
such a requirement is stated, though I have occasionally wanted such a
guarantee.
5. Allow a failed swap to leave the containers in a state where future insertions may fail for reasons other than is currently allowed. Specifically, if the hash and equality functors are out of sync, all insertions will fail. Presumably some "incompletely swapped" exception would be thrown. This is "slightly" inventive, although people have been discussing "radioactive" states for a while.
[2013-03-15 Issues Teleconference]
Moved to Open.
[2019 Cologne Wednesday night]
Billy to write resolution for option #2. This may require a paper.
Proposed resolution:
max_load_factor(z)
makes no strong guarantees, but bans useful behaviorSection: 24.2.8 [unord.req] Status: Open Submitter: Alisdair Meredith Opened: 2012-10-09 Last modified: 2016-12-10
Priority: 3
View other active issues in [unord.req].
View all other issues in [unord.req].
View all issues with Open status.
Discussion:
The user cannot specify a max_load_factor
for their unordered container
at construction, it must be supplied after the event, when the container is
potentially not empty. The contract for this method is deliberately vague, not
guaranteeing to use the value supplied by the user, and any value actually used
will be used as a ceiling that the container will attempt to respect.
The only guarantee we have is that, if user requests a max_load_factor
that is less than the current load_factor
, then the operation will take
constant time, thus outlawing an implementation that chooses to rehash and so
preserve as a class invariant that load_factor < max_load_factor
.
Reasonable options conforming to the standard include ignoring the user's request
if the requested value is too low, or deferring the rehash to the next insert
operation and allowing the container to have a strange state (wrt max_load_factor
)
until then - and there is still the question of rehashing if the next insert
is for a duplicate key in a unique container.
Given the deliberate vagueness of the current wording, to support a range of reasonable (but not perfect) behaviors, it is not clear why the equally reasonable rehash to restore the constraint should be outlawed. It is not thought that this is a performance critical operation, where users will be repeatedly setting low load factors on populated containers, in a tight or (less unlikely) an instant response scenario.
[2013-03-15 Issues Teleconference]
Moved to Open.
Alisdair to provide wording.
[2016-11-12, Issaquah]
Sat PM: Howard to provide wording
[2016-11-17 Howard provided wording.]
The provided wording is consistent with LWG discussion in Issaquah. An implementation of the proposed wording would be setting
max_load_factor()
tomax(z, load_factor())
. This preserves the container invariant:load_factor() <= max_load_factor()And it preserves the existing behavior that no rehash is done by this operation.
If it is desired to change the
max_load_factor()
to something smaller than the currentload_factor()
that can be done by first reducing the currentload_factor()
by either increasingbucket_count()
(viarehash
orreserve
), or decreasingsize()
(e.g.erase
), and then changingmax_load_factor()
.This resolution reaffirms that
load_factor() <= max_load_factor()
is a container invariant which can never be violated.
[2016-11-27, Nico comments]
Current implementations behave differently.
In regard to the sentence"The only guarantee we have is that, if user requests aNote that the current spec says that there is constant complexity without any precondition. So, rehashing to keep the invariant would violate the spec (which is probably not be the intention). This issue is related to LWG 2199(i).max_load_factor
that is less than the currentload_factor
, then the operation will take constant time, thus outlawing an implementation that chooses to rehash and so preserve as a class invariant thatload_factor < max_load_factor
."
Proposed resolution:
Modify Table 87 as follows:
Expression | Return type | Assertion/note pre-/post-condition | Complexity |
---|---|---|---|
a.max_load_factor(z)
|
void
|
Pre:
Post:
Note: |
Constant |
async
Section: 33.10.9 [futures.async] Status: Deferred Submitter: Detlef Vollmann Opened: 2012-10-19 Last modified: 2016-01-28
Priority: 4
View other active issues in [futures.async].
View all other issues in [futures.async].
Discussion:
promise
, packaged_task
, and async
are the only
places where a shared state is actually supposed to be allocated. Accordingly,
promise
and packaged_task
are "allocator-aware". But
function template async
provides no way to provide an allocator.
[2013-09 Chicago]
Matt: deprecate async
Nico: read my paper Alisdair: defer issues to wait for polymorphic allocators Alisdair: defer, active topic of research Deferred[2014-02-20 Re-open Deferred issues as Priority 4]
[2015-05 Lenexa, SG1 response]
We want whatever status approximates: "will not fix; we're working on a replacement facility and don't want to add features to a broken one"
Proposed resolution:
initializer_list
constructor requirementsSection: 24.2.4 [sequence.reqmts], 24.2.7 [associative.reqmts], 24.2.8 [unord.req], 28.5.3.2 [rand.req.seedseq] Status: Open Submitter: Jeffrey Yasskin Opened: 2012-10-21 Last modified: 2020-09-06
Priority: 3
View other active issues in [sequence.reqmts].
View all other issues in [sequence.reqmts].
View all issues with Open status.
Discussion:
In 24.2.4 [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 24.2.7 [associative.reqmts], 24.2.8 [unord.req], and
28.5.3.2 [rand.req.seedseq].
initializer_list<exact_type>
.
[2013-03-15 Issues Teleconference]
Moved to Open.
This is definitely not NAD
Should copy the suggested wording as the proposed resolution.
[2019-03-26; Daniel comments and provides wording]
The 2013-03-15 comment is confusing, since it recommends to "copy the suggested wording as the proposed resolution".
I couldn't find such wording in the issue nor in the associated wiki, so I provided that wording out of myself.
The tricky part is to define which kind of braced-init-list we want to allow. As Tim Song pointed out, we
still need the existing support for std::initializer_list<value_type>
as well, because otherwise
existing semantics based on expressions such as li.begin()
won't work anymore.
The below suggested wording restricts supported braced-init-lists to every initializer list that can be used
to copy-list-initialize an object of type std::initializer_list<value_type>
by saying:
"
bil
designates any braced-init-list suitable to copy-list-initialize an object of typeinitializer_list<value_type>
(9.4.5 [dcl.init.list])"
As a drive-by fix, the provided wording adds another initialization "expression" that makes the construction of the form
std::vector<int> v = {1, 2, 'a'};
valid (We just miss a copy-initialization case).
Proposed resolution:
This wording is relative to N4810.
[Drafting note: We need to special-case the "expression"
X u = bil;
below, because for empty braced-init-list the effects are those of calling the default constructor. — end drafting note]
Modify 24.2.4 [sequence.reqmts] as indicated:
-3- In Tables 66 and 67, […]
il
designates an objectvalue of typeinitializer_list<value_type>
,bil
designates any braced-init-list suitable to copy-list-initialize an object of typeinitializer_list<value_type>
(9.4.5 [dcl.init.list]), […]
Modify Table 66 — "Sequence container requirements (in addition to container)" as indicated:
Table 66 — Sequence container requirements (in addition to container) Expression Return type Assertion/note
pre-/post-condition[…]
X(il)
X u = il;
Equivalent to X(il.begin(), il.end())
orX u(il.begin(), il.end());
, respectivelyX(bil)
Equivalent to X(initializer_list<value_type>(bil))
X u = bil;
If bil
is empty, equivalent toX u;
, otherwise
equivalent toX u = initializer_list<value_type>(bil);
a = il
X&
[…] a = bil
X&
Equivalent to a = initializer_list<value_type>(bil)
[…]
a.insert(p, il)
iterator
[…] a.insert(p, bil)
iterator
Equivalent to a.insert(p, initializer_list<value_type>(bil))
[…]
a.assign(il)
void
[…] a.assign(bil)
void
Equivalent to a.assign(initializer_list<value_type>(bil))
[…]
Modify 24.2.7 [associative.reqmts] as indicated:
-8- In Table 69, […]
il
designates an objectvalue of typeinitializer_list<value_type>
,bil
designates any braced-init-list suitable to copy-list-initialize an object of typeinitializer_list<value_type>
(9.4.5 [dcl.init.list]), […]
Modify Table 69 — "Associative container requirements (in addition to container)" as indicated:
Table 69 — Associative container requirements (in addition to container) Expression Return type Assertion/note
pre-/post-conditionComplexity […]
X(il)
X u = il;
same as X(il.begin(), il.end())
orX u(il.begin(), il.end());
, respectivelysame as X(il.begin(), il.end())
orX u(il.begin(), il.end());
, respectivelyX(bil)
Equivalent to X(initializer_list<value_type>(bil))
X u = bil;
If bil
is empty, equivalent toX u;
, otherwise
equivalent toX u = initializer_list<value_type>(bil);
X(il,c)
same as X(il.begin(), il.end(), c)
same as X(il.begin(), il.end(), c)
X(bil, c)
Equivalent to X(initializer_list<value_type>(bil), c)
a = il
X&
[…] […] a = bil
X&
Equivalent to a = initializer_list<value_type>(bil)
[…]
a.insert(il)
void
equivalent to a.insert(il.begin(), il.end())
a.insert(bil)
void
Equivalent to a.insert(initializer_list<value_type>(bil))
[…]
a.assign(il)
void
[…] a.assign(bil)
void
Equivalent to a.assign(initializer_list<value_type>(bil))
[…]
Modify 24.2.8 [unord.req] p11's bullet list as indicated:
-11- In Table 70:
(11.1) — […]
[…]
(11.14) —
il
denotes a value of typeinitializer_list<value_type>
,(11.?) —
bil
denotes any braced-init-list suitable to copy-list-initialize an object of typeinitializer_list<value_type>
(9.4.5 [dcl.init.list]),[…]
Modify Table 70 — "Unordered associative container requirements (in addition to container)" as indicated:
[Drafting note: There is a preexisting issue with Table 70, that there is no symbol
u
specified ("u
denotes the name of a variable being declared"), so existing initialization forms with a named variable are currently always written as "X a[…]
" wherea
is defined as "a
denotes a value of typeX
", the wording below follows this existing practice but the author of this wording would like to kindly ask the Project Editor to introduce said symbolu
and apply it to all existing and new such named initialization forms instead. — end drafting note]
Table 70 — Unordered associative container requirements (in addition to container) Expression Return type Assertion/note
pre-/post-conditionComplexity […]
X(il)
X a = il;
X
Same as X(il.begin(), il.end())
orX a(il.begin(), il.end());
, respectivelySame as X(il.begin(), il.end())
orX a(il.begin(), il.end());
, respectivelyX(bil)
X
Equivalent to X(initializer_list<value_type>(bil))
X a = bil;
X
If bil
is empty, equivalent toX a;
, otherwise
equivalent toX a = initializer_list<value_type>(bil);
X(il, n)
X
Same as X(il.begin(), il.end(), n)
Same as X(il.begin(), il.end(), n)
X(bil, n)
X
Equivalent to X(initializer_list<value_type>(bil), n)
X(il, n, hf)
X
Same as X(il.begin(), il.end(), n, hf)
Same as X(il.begin(), il.end(), n, hf)
X(bil, n, hf)
X
Equivalent to X(initializer_list<value_type>(bil), n, hf)
X(il, n, hf, eq)
X
Same as X(il.begin(), il.end(), n, hf, eq)
Same as X(il.begin(), il.end(), n, hf, eq)
X(bil, n, hf, eq)
X
Equivalent to X(initializer_list<value_type>(bil), n, hf, eq)
[…]
a = il
X&
[…] […] a = bil
X&
Equivalent to a = initializer_list<value_type>(bil)
[…]
a.insert(il)
void
Same as a.insert(il.begin(), il.end())
.Same as a.insert(il.begin(), il.end())
.a.insert(bil)
void
Equivalent to a.insert(initializer_list<value_type>(bil))
[…]
Modify 28.5.3.2 [rand.req.seedseq] p2's bullet list as indicated:
-2- A class
S
satisfies the requirements of a seed sequence if the expressions shown in Table 82 are valid and have the indicated semantics, and […] In that Table and throughout this subclause:
(2.1) — […]
(2.?) —
u
denotes the name of a variable being declared,[…]
(2.6) —
il
is a value ofinitializer_list<T>
.;(2.?) —
bil
denotes any braced-init-list suitable to copy-list-initialize an object of typeinitializer_list<T>
(9.4.5 [dcl.init.list]).
Modify Table 82 — "Seed sequence requirements" as indicated:
Table 82 — Seed sequence requirements Expression Return type Pre/post-condition Complexity […]
S(il)
S u = il;
Same as S(il.begin(), il.end())
orS u(il.begin(), il.end());
, respectivelysame as S(il.begin(), il.end())
orS u(il.begin(), il.end());
, respectivelyS(bil)
Equivalent to S(initializer_list<T>(bil))
S u = bil;
If bil
is empty, equivalent toS u;
, otherwise
equivalent toS u = initializer_list<T>(bil);
[…]
basic_ios::init
call restrictionsSection: 31.5.4.2 [basic.ios.cons] Status: Open Submitter: Andrey Semashev Opened: 2012-11-09 Last modified: 2021-07-31
Priority: 4
View all other issues in [basic.ios.cons].
View all issues with Open status.
Discussion:
There is an ambiguity in how std::basic_ios::init
method (31.5.4.2 [basic.ios.cons])
can be used in the derived class. The Standard only specify the state of the basic_ios
object after the call completes. However, in basic_ios
default constructor description
(31.5.4.2 [basic.ios.cons]) there is this sentence:
Effects: Constructs an object of class
basic_ios
(31.5.2.8 [ios.base.cons]) leaving its member objects uninitialized. The object shall be initialized by callingbasic_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.
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
(31.5.2 [ios.base]), which
it derives from. This means that the implementation is allowed to use
non-POD data members with default constructors that initialize the
members with particular default values. For example, in the case of
Microsoft Visual C++ STL the leaked memory is an std::locale
instance
that is dynamically allocated during basic_ios::init
, a raw pointer to
which is stored within ios_base. It is possible to store e.g. an
unique_ptr
instead of a raw pointer as a member of ios_base
, the smart
pointer will default initialize the underlying raw pointer on default
construction and automatically destroy the allocated object upon being
reset or destroyed, which would eliminate the leak and allow
basic_ios::init
to be called multiple times. This leads to conclusion
that the default constructor of basic_ios
cannot leave "its member
objects uninitialized" but instead performs default initialization of
the member objects, which would mean the same thing in case of POD types.
However, I feel that restricting ios_base
and basic_ios
members to
non-POD types is not acceptable. Since multiple calls to basic_ios::init
are
not forbidden by the Standard, I propose to correct the basic_ios
default
constructor description so that it is allowed to destroy basic_ios
object
without calling basic_ios::init
. This would imply that any raw members of
basic_ios
and ios_base
should be initialized to values suitable for
destruction (essentially, this means only initializing raw pointers to NULL). The new
wording could look like this:
Effects: Constructs an object of class
basic_ios
(31.5.2.8 [ios.base.cons]) initializing its member objects to unspecified state, only suitable forbasic_ios
destruction. The object shall be initialized by callingbasic_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.
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 thatinit
must be called once and only once. Move then to review.
[2021-07-29 Tim comments]
The requirement that "init
must be called once and only once" conflicts
with the disposition of LWG 135(i).
Proposed resolution:
This wording is relative to N3485.
Edit 31.5.4.2 [basic.ios.cons] as indicated:
basic_ios();-2- Effects: Constructs an object of class
basic_ios
(31.5.2.8 [ios.base.cons])leaving its member objects uninitializedinitializing its member objects to unspecified state, only suitable forbasic_ios
destruction. The object shall be initialized by callingbasic_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.
CopyConstructible
Section: 24.2.7 [associative.reqmts], 24.2.8 [unord.req] Status: Open Submitter: Alisdair Meredith Opened: 2012-11-14 Last modified: 2015-10-22
Priority: 3
View other active issues in [associative.reqmts].
View all other issues in [associative.reqmts].
View all issues with Open status.
Discussion:
The requirements on the functors used to arrange elements in the various associative and unordered containers are given by a set of expressions in tables 102 — Associative container requirements, and 103 — Unordered associative container requirements. In keeping with Library convention these expressions make the minimal requirements necessary on their types. For example, we have the following 3 row extracts for the unordered containers:
Expression | Assertion/note pre-/post-condition |
|
Requires: hasher and key_equal are CopyConstructible .
|
|
Requires: hasher is CopyConstructible and
key_equal is DefaultConstructible .
|
|
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(i) addresses.
[2015-10-20, Daniel comments]
The revised resolution of LWG 2227(i) should resolve this issue as well. It follows the recommendations
of the submitter to require CopyConstructible
requirements for the function objects owned by containers,
but it does not impose any further fundamental requirements.
Proposed resolution:
See the resolution of LWG 2227(i).
regex_replace(basic_string)
allocator handlingSection: 32.10.4 [re.alg.replace] Status: New Submitter: Jeffrey Yasskin Opened: 2012-11-26 Last modified: 2016-01-28
Priority: 3
View all other issues in [re.alg.replace].
View all issues with New status.
Discussion:
template <class traits, class charT, class ST, class SA> basic_string<charT, ST, SA> regex_replace(const basic_string<charT, ST, SA>& s, const basic_regex<charT, traits>& e, const charT* fmt, regex_constants::match_flag_type flags = regex_constants::match_default);
and friends are documented as
Constructs an empty string result of type
basic_string<charT, ST, SA>
and callsregex_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:
operator==
for regex_token_iterator
Section: 32.11.2.3 [re.tokiter.comp] Status: Open Submitter: Pete Becker Opened: 2012-11-21 Last modified: 2024-10-03
Priority: 3
View all issues with Open status.
Discussion:
Consider the following example:
std::string str0("x"); std::regex rg0("a"); std::regex_token_iterator it0(str0.begin(), str0.end(), rg0, -1); // points at "x" in str0 std::string str1("x"); std::regex rg1("b"); std::regex_token_iterator it1(str1.begin(), str1.end(), rg1, -1); // points at "x" in str1
32.11.2.3 [re.tokiter.comp] p1 says that it0.operator==(it1)
returns true "if
*this
and right
are both suffix iterators and suffix == right.suffix
"; both
conditions are satisfied in this example. It does not say that they must both be iterators
into the same sequence, nor does it say (as general iterator requirements do) that they must
both be in the domain of ==
in order for the comparison to be meaningful. It's a
simple statement: they're equal if the strings they point at compare equal. Given this being
a valid comparison, the obtained result of "true" looks odd.
[2014-02-10]
Priority set to 2
[2018-08-20 Casey adds a proposed resolution]
Priority changed to 3.
Marshall notes that iterator comparisons typically require the iterators to denote elements of the same sequence.Previous resolution [SUPERSEDED]:
This wording is relative to N4762.
Modify 32.11.2.3 [re.tokiter.comp] as follows:
bool operator==(const regex_token_iterator& right) const;-?- Expects:
*this
andright
are both end-of-sequence iterators or both have the same underlying sequence.-1- Returns:
true
if*this
andright
are both end-of-sequence iterators, or if […]bool operator!=(const regex_token_iterator& right) const;-?- Expects:
*this
andright
are both end-of-sequence iterators or both have the same underlying sequence.-2- Returns:
!(*this == right)
.
[2018-08-23 Casey revises the P/R in response to LWG feedback]
Previous resolution [SUPERSEDED]:
This wording is relative to N4762.
Modify 32.11.2.3 [re.tokiter.comp] as follows:
bool operator==(const regex_token_iterator& right) const;-?- Expects: At least one of
*this
andright
is an end-of-sequence iterator, or both*this
andright
have the same underlying sequence.-1- Returns:
true
if*this
andright
are both end-of-sequence iterators, or if […]bool operator!=(const regex_token_iterator& right) const;-?- Expects: At least one of
*this
andright
is an end-of-sequence iterator, or both*this
andright
have the same underlying sequence.-2- Returns:
!(*this == right)
.
[2024-10-03; Jonathan rebases the wording on the latest WP]
Proposed resolution:
This wording is relative to N4988.
Modify 32.11.2.3 [re.tokiter.comp] as follows:
bool operator==(const regex_token_iterator& right) const;-?- Preconditions: At least one of
*this
andright
is an end-of-sequence iterator, or*this
andright
have the same underlying sequence.-1- Returns:
true
if*this
andright
are both end-of-sequence iterators, or if*this
andright
are both suffix iterators andsuffix == right.suffix
; otherwise returnsfalse
if*this
orright
is an end-of-sequence iterator or a suffix iterator. Otherwise returnstrue
ifposition == right.position
,N == right.N
, andsubs == right.subs
. Otherwise returnsfalse
.
Section: 24.2.7 [associative.reqmts] Status: Open Submitter: Juan Soulie Opened: 2012-12-19 Last modified: 2019-04-23
Priority: 3
View other active issues in [associative.reqmts].
View all other issues in [associative.reqmts].
View all issues with Open status.
Discussion:
Table 102 in 24.2.7 [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,
24.2.2 [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.
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
24.2.2 [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 24.2.2 [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()
andb.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 instd::map
assignments. unordered_map
is different, though.
[Note: Check what general container requirements say about container equality.]
DK will draft wording. The decision is to unambiguously make all {copy,move}-{construction,assignment} operations endow the
LHS with the exact state of the RHS, including all predicates and hash function states.
Conclusion: Update wording, revisit later.
[2015-05-06 Lenexa: Waiting for updated wording]
Previous resolution [SUPERSEDED]:
This wording is relative to N3485.
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()
andb.size()
…
a.key_comp()
X::key_compare
rReturnsthea
's comparison object
out of which a was constructed.constant
[2015-10-19 Daniel comments and provides alternative wording]
The current standard is especially unclear in regard to what effects move operations of unordered/associative containers should have. We have one example that is standardized exactly in this way by looking at 24.6.7.3 [priqueue.cons.alloc] p7:
template <class Alloc> priority_queue(priority_queue&& q, const Alloc& a);-7- Effects: Initializes
c
withstd::move(q.c)
as the first argument anda
as the second argument, and initializescomp
withstd::move(q.comp)
A similarly comparable example are the move-operations of std::unique_ptr
in regard to the deleter
(when this is no a reference), which also respect move-capabilities of that function object.
When an associative container is constructed by passing a comparison object the container shall not store a pointer or reference to the passed object, even if that object is passed by reference. When an associative container is copied, either through a copy constructor or an assignment operator, the target container shall then use the comparison object from the container being copied, as if that comparison object had been passed to the target container in its constructor.
The second sentence of this wording is problematic for several reasons:
It only talks about copy operations, not about move operations, except that the term "assignment" without leading "copy" is a bit ambigious (albeit it seems clear in the complete context).
It is not really clear how to interpret "as if that comparison object had been passed to the target container in its constructor" for an assignment operation. A possible but not conclusive interpretation could be that this is wording supporting a "copy-via-swap" idiom.
There does not exist similar wording for unordered containers, except that Table 102 provides entries for copy construction and copy assignment of the containers whose wording just talks of "copies" in either case.
Existing implementations differ already:
Visual Studio 2015 uses copy construction and copy assignment for the two copy operations but uses swap operations for the move operations.
GCC's libstdc++ performs copy construction and copy assignment for the two copy operations and for the two move operations, respectively
clang++'s libc++ performs copy/move construction and copy/move assignment for the corresponding four copy/move operations
The alternative wording provided below attempts to clarify that container copy/move operations perform the corresponding copy/move operations on the owned function objects.
In addition the wording also resolves LWG 2215(i): I believe that the current wording should require that container function objects should meet theCopyConstructible
requirements. Adding
this general requirement also fixes the underspecified requirements of the accessor functions key_comp()
and
value_comp()
.
I don't think that a general requirement for Swappable
is needed, only the member swap
function currently requires this.
Nonetheless the wording below does support stateful functors that are also moveable or move-assignable,
therefore the specified semantics in terms of move operations.
I should add the following warning, though: If this proposed wording would be accepted, there is a little chance of
code breakage, because the current wording can be read that in general there is no requirement that the
container functors are CopyConstructible
. The following code example is accepted by gcc + libstd++:
#include <map> #include <utility> #include <iostream> struct Cmp { Cmp() = default; Cmp(const Cmp&) = delete; Cmp(Cmp&&) = delete; Cmp& operator=(const Cmp&) = delete; Cmp& operator=(Cmp&&) = delete; template<class T> bool operator()(const T& x, const T& y) const { return x < y; } }; typedef std::map<int, int, Cmp> MyMap; int main() { MyMap m; std::cout << (m.find(12) == m.end()) << std::endl; }
Previous resolution [SUPERSEDED]:
This wording is relative to N4527.
Change 24.2.7 [associative.reqmts] p8 as indicated:
-8- In Table 101,
X
denotes an associative container class,a
denotes a value of typeX
,b
denotes a possiblyconst
value of typeX
,rv
denotes a non-const
rvalue of typeX
,u
denotes the name of a variable being declared, […]Change Table 101 as indicated:
Table 101 — Associative container requirements (in addition to container) Expression Return type Assertion/note pre-/post-condition Complexity …
X::key_compare
Compare
Requires: Compare
isCopyConstructible
.
defaults toless<key_type>
compile time X(c)
X u(c);
Requires:Effects: Constructs an empty container.key_compare
isCopyConstructible
.
Uses a copy ofc
as a comparison object.[…] …
X(i,j,c)
X u(i,j,c);
Requires: key_compare
isCopyConstructible
.value_type
isEmplaceConstructible
intoX
from*i
.
Effects: Constructs an empty container and inserts elements
from the range[i, j)
into it; usesc
as a comparison object.[…] …
X(il)
Same as X(il.begin(), il.end())
.same as X(il.begin(), il.end())
.X(b)
X a(b)
(In addition to the requirements of Table 95)
Effects: Copy constructs the comparison object ofa
from
the comparison object ofb
.Linear in b.size()
X(rv)
X a(rv)
(In addition to the requirements of Table 95 and Table 98)
Effects: Move constructs the comparison object ofa
from
the comparison object ofrv
.constant a = b
X&
(In addition to the requirements of Table 95 and Table 98)
Requires:key_compare
isCopyAssignable
.
Effects: Copy assigns the comparison object ofb
to the comparison object ofa
.Linear in a.size()
andb.size()
a = rv
X&
(In addition to the requirements of Table 95 and Table 98)
Requires:key_compare
isMoveAssignable
.
Effects: Move assigns from the comparison object ofrv
to the comparison object ofa
.Linear …
a.key_comp()
X::key_compare
rReturnsthea
's comparison object
out of which a was constructed.constant Change 24.2.7 [associative.reqmts] p12 as indicated:
-12- When an associative container is constructed by passing a comparison object the container shall not store a pointer or reference to the passed object, even if that object is passed by reference.
When an associative container is copied, either through a copy constructor or an assignment operator, the target container shall then use the comparison object from the container being copied, as if that comparison object had been passed to the target container in its constructor.Change 24.2.8 [unord.req] p11 as indicated:
-11- In Table 102:
X
denotes an unordered associative container class,a
denotes a value of typeX
,b
denotes a possiblyconst
value of typeX
,rv
denotes a non-const
rvalue of typeX
, […]Change Table 102 as indicated:
Table 102 — Unordered associative container requirements (in addition to container) Expression Return type Assertion/note pre-/post-condition Complexity …
X::hasher
Hash
Requires: Hash
isCopyConstructible
.
Hash
shall be a unary function object type
such that the expressionhf(k)
has typestd::size_t
.compile time X::key_equal
Pred
Requires: Pred
isCopyConstructible
.
Pred
shall be a binary predicate that takes
two arguments of typeKey
.
Pred
is an equivalence relation.compile time …
X(n, hf, eq)
X a(n, hf, eq)X
Requires:Effects: […]hasher
andkey_equal
areCopyConstructible
.[…] X(n, hf)
X a(n, hf)X
Requires: hasher
isCopyConstructible
andkey_equal
isDefaultConstructible
.
Effects: […][…] …
X(i, j, n, hf, eq)
X a(i, j, n, hf, eq)X
Requires: hasher
andkey_equal
areCopyConstructible
.value_type
isEmplaceConstructible
intoX
from*i
.
Effects: […][…] X(i, j, n, hf)
X a(i, j, n, hf)X
Requires: hasher
isCopyConstructible
andkey_equal
isDefaultConstructible
.
value_type
isEmplaceConstructible
intoX
from*i
.
Effects: […][…] …
X(b)
X a(b)X
Copy constructor. In addition(In addition to the requirements of Table 95)
to the requirements of Table 95,
copies the hash function,
predicate, and maximum load
factor.
Effects: Copy constructs the hash function, predicate, and maximum load factor
ofa
from the corresponding objects ofb
.Average case linear in
b.size()
,
worst case quadratic.X(rv)
X a(rv)X
(In addition to the requirements of Table 95 and Table 98)
Effects: Move constructs the hash function, predicate, and maximum load factor
ofa
from the corresponding objects ofrv
.constant a = b
X&
Copy assignment operator. In(In addition to the requirements of Table 95 and Table 98)
addition to the requirements of
Table 95, copies the hash
function, predicate, and
maximum load factor.
Requires:hasher
andkey_equal
areCopyAssignable
.
Effects: Copy assigns the hash function, predicate, and maximum load factor
ofb
to the corresponding objects ofa
.Average case linear in
b.size()
,
worst case quadratic.a = rv
X&
(In addition to the requirements of Table 95 and Table 98)
Requires:hasher
andkey_equal
areMoveAssignable
.
Effects: Move assigns the hash function, predicate, and maximum load factor
fromrv
to the corresponding objects ofa
.Linear …
[2016-08-07]
Daniel removes the previously proposed wording to work on revised wording.
[2019-04-22, Billy comments]
In addition to the Cpp17CopyConstructible discussion going on there, I think we need to require that
calling the comparison function when Compare
itself is const
needs to produce the same answer
as if Compare
is non-const
.
Proposed resolution:
kill_dependency
unconditionally noexceptSection: 33.5.2 [atomics.syn], 33.5.4 [atomics.order] Status: SG1 Submitter: Daniel Krügler Opened: 2013-01-19 Last modified: 2016-01-28
Priority: Not Prioritized
View other active issues in [atomics.syn].
View all other issues in [atomics.syn].
View all issues with SG1 status.
Discussion:
The "magic" kill_dependency
function is a function without any constraints on the template parameter T
and is specified as
template <class T> T kill_dependency(T y) noexcept;-14- Effects: The argument does not carry a dependency to the return value (1.10).
-15- Returns:y
.
I wonder whether the unconditional noexcept
is really intended here:
Assume we have some type U
that has a potentially throwing move
constructor (or it has a potentially throwing copy constructor and no
move constructor), for any "normal" function template with the same
signature and the same effects (modulo the dependency magic) this
would mean that it cannot safely be declared noexcept
because of the
return statement being part of the complete function call affected by
noexcept
(The by-value function argument is irrelevant in this
context). In other words it seems that a function call such as
struct S { ... S(const S& r) { if(some condition) throw Something(); } ... }; int main() { S s1 = ...; S s2 = std::kill_dependency(s1); }
would be required to call std::terminate
if the copy constructor of S
throws during the return
of std::kill_dependency
.
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:
<cuchar>
macrosSection: 23.5 [c.strings] Status: New Submitter: Jason Merrill Opened: 2013-01-29 Last modified: 2016-01-28
Priority: 4
View other active issues in [c.strings].
View all other issues in [c.strings].
View all issues with New status.
Discussion:
Apparently C1X changes __STDC_UTF_16__
and __STDC_UTF_32__
from macros
defined in uchar.h
(and reflected in C++ by Table 79) to be predefined by the compiler.
Do we want to do the same?
Proposed resolution:
Section: 23.5 [c.strings] Status: Open Submitter: Johannes Schaub Opened: 2013-02-02 Last modified: 2016-08-09
Priority: 3
View other active issues in [c.strings].
View all other issues in [c.strings].
View all issues with Open status.
Discussion:
The non-explicit nature of the iterator-pair constructor of containers, such a
template <class InputIterator> vector(InputIterator first, InputIterator last, const Allocator& = Allocator());
can be selected in unexpected situations, leading to a hard runtime error, as demonstrated by the following example:
#include <vector> void f(std::vector<char> v){ /* ... */} int main() { f({"A", "B"}); }
The actually intended initializer-list constructor isn't feasible here, so the best match is the constructor template
template <class InputIterator> vector(InputIterator first, InputIterator last, const Allocator& = Allocator());
This compiles, but will result in code running amok. The potential trap (that cannot be easily detected by the library implementation) could be reduced by making this constructor explicit. It would still have the effect to be selected here, but the code would be ill-formed, so the programmer gets a clear message here.
[2014-06 Rapperswil]
JW: can't fix this, don't want to touch this, Do The Right Thing clause has been a source of tricky issues. only really happens with string literals, that's the only way to create an array that isn't obviously an array
GR: want to see paper AM: is it only string literals, or also UDLs? STL: maybe, but we don't need to deal with that. This is only a problem in a very specific case Leave as Open.Proposed resolution:
numeric_limits::is_iec559
misnamedSection: 17.3.5 [numeric.limits] Status: New Submitter: Pete Becker Opened: 2013-03-08 Last modified: 2018-11-08
Priority: 4
View other active issues in [numeric.limits].
View all other issues in [numeric.limits].
View all issues with New status.
Discussion:
This member should probably be named "is_ieee754". Or at least the standard should explain that IEC-559 no longer exists, and that it's been superseded by IEEE-754.
[2016-06, Oulu]
The ISO version of the standard is ISO/IEC/IEEE 60559:2011,
which C11 Annex F refers to as IEC 60559
(although C still refers to it as IEC 559 in the __STDC_IEC_559__
macro).
Proposed resolution:
unique_ptr<T>::get_deleter()(p)
to be able to destroy the unique_ptr
Section: 20.3.1.3 [unique.ptr.single] Status: Open Submitter: Rob Desbois Opened: 2013-05-15 Last modified: 2017-03-21
Priority: 3
View other active issues in [unique.ptr.single].
View all other issues in [unique.ptr.single].
View all issues with Open status.
Discussion:
N3337 20.3.1.3.6 [unique.ptr.single.modifiers] contains 2 non-normative notes stating:
[para 4]: "The order of these operations is significant because the call to
get_deleter()
may destroy*this
."[para 5]: "The postcondition does not hold if the call to
get_deleter()
destroys*this
sincethis->get()
is no longer a valid expression."
It seems this wording was created to resolve 998(i) 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]
get_deleter()(old_p)
destroyed *this
, none. Otherwise,
get() == p
. get_deleter()
destroys *this
since this->get()
is no longer a valid expression. — end note]I expect it will also be necessary to amend the requirements for a deleter, so in addition:
20.3.1.3 [unique.ptr.single] [para 1]: The default type for the template parameter D
is default_delete
.
A client-supplied template argument D
shall be a function object type (20.10), lvalue-reference to function, or
lvalue-reference to function object type for which, given a value d
of type D
and a value ptr
of type
unique_ptr<T, D>::pointer
, the expression d(ptr)
is valid and has the effect of disposing of the pointer
as appropriate for that deleter. Where D
is not an lvalue reference type, d(ptr)
shall be valid if ptr
refers directly or indirectly to the invoking unique_ptr
object.
[2013-10-05, Stephan T. Lavavej comments and provides alternative wording]
In Chicago, we determined that the original proposed change to 20.3.1.3 [unique.ptr.single]/1 was insufficient, because
d
might be a reference to a deleter functor that's destroyed during self-destruction.
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.3.1.3.6 [unique.ptr.single.modifiers]/5 had to be changed. The current note is slightly
squirrely but it does not lead to confusion for implementers or users.
Previous resolution from Rob Desbois:
Edit 20.3.1.3 [unique.ptr.single] p1 as indicated:
The default type for the template parameter
D
isdefault_delete
. A client-supplied template argumentD
shall be a function object type (20.10), lvalue-reference to function, or lvalue-reference to function object type for which, given a valued
of typeD
and a valueptr
of typeunique_ptr<T, D>::pointer
, the expressiond(ptr)
is valid and has the effect of disposing of the pointer as appropriate for that deleter. WhereD
is not an lvalue reference type,d(ptr)
shall be valid ifptr
refers directly or indirectly to the invokingunique_ptr
object.Edit 20.3.1.3.6 [unique.ptr.single.modifiers] p4+5 as indicated:
void reset(pointer p = pointer()) noexcept;-3- Requires: The expression
-4- Effects: assignsget_deleter()(get())
shall be well formed, shall have well-defined behavior, and shall not throw exceptions.p
to the stored pointer, and then if the old value of the stored pointer,old_p
, was not equal tonullptr
, callsget_deleter()(old_p)
. No operation shall be performed after the call toget_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-5- Postconditions: If the callget_deleter()
may destroy*this
. — end note]get_deleter()(old_p)
destroyed*this
, none. Otherwise,get() == p
.[Note: The postcondition does not hold if the call toget_deleter()
destroys*this
sincethis->get()
is no longer a valid expression. — end note]
Previous resolution [SUPERSEDED]:
This wording is relative to N3691.
Edit 20.3.1.3 [unique.ptr.single] p1 as indicated:
The default type for the template parameter
D
isdefault_delete
. A client-supplied template argumentD
shall be a function object type (20.10), lvalue-reference to function, or lvalue-reference to function object type for which, given a valued
of typeD
and a valueptr
of typeunique_ptr<T, D>::pointer
, the expressiond(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 ofd
or (ifD
is an lvalue reference to function object type) the function object thatd
refers to.
[2015-05, Lenexa]
After some discussion in Lenexa there was some wavering on if the added sentence is necessary. Here is example code that
demonstrates why the extra sentence is necessary. In this example the call to d(ptr)
is valid, however the deleter
references *this
after destructing its element:
#include <cassert> #include <memory> #include <iostream> class Deleter { int state_ = 0; enum { destructed = -4, self_move_assigned = -3, move_assigned_from = -2, move_constructed_from = -1 }; public: ~Deleter() {state_ = destructed;} Deleter() = default; Deleter(Deleter const&) = default; Deleter& operator=(Deleter const&) = default; Deleter(Deleter&& a) noexcept : state_(a.state_) {a.state_ = move_constructed_from;} Deleter& operator=(Deleter&& a) noexcept { if (this == &a) state_ = self_move_assigned; else { state_ = a.state_; a.state_ = move_assigned_from; } return *this; } Deleter(int state) : state_(state) { assert(state >= 0); } template <class T> void operator()(T* t) const { std::cout << "Deleter beginning operator()(T*)\n"; std::cout << "The deleter = " << *this << '\n'; std::cout << "Deleter about to destruct the X.\n"; delete t; std::cout << "Deleter has destructed the X.\n"; std::cout << "The deleter = " << *this << '\n'; std::cout << "Deleter ending operator()(T*)\n"; } friend std::ostream& operator<<(std::ostream& os, const Deleter& a) { switch (a.state_) { case destructed: os << "**destructed**"; break; case self_move_assigned: os << "self_move_assigned"; break; case move_assigned_from: os << "move_assigned_from"; break; case move_constructed_from: os << "move_constructed_from"; break; default: os << a.state_; break; } return os; } }; struct X { Deleter deleter_{1}; }; int main() { auto xp = new X; { std::unique_ptr<X, Deleter&> p(xp, xp->deleter_); std::cout << "unique_ptr is constructed.\n"; std::cout << "The deleter = " << p.get_deleter() << '\n'; std::cout << "Destructing unique_ptr...\n"; } std::cout << "unique_ptr is destructed.\n"; }
Which outputs:
unique_ptr is constructed. The deleter = 1 Destructing unique_ptr... Deleter beginning operator()(T*) The deleter = 1 Deleter about to destruct the X. Deleter has destructed the X. The deleter = **destructed** Deleter ending operator()(T*) unique_ptr is destructed.
The line "The deleter = **destructed**
" represents the deleter referencing itself after it has been destructed by the
d(ptr)
expression, but prior to that call returning.
The expression
d(ptr)
shall not refer to the objectd
after it executesptr->~T()
.
[2015-07, Telecon]
Geoffrey: Deleter may or may not execute ~T().
Alisdair: After the destructor after the element has run. Say it in words instead of code.
Howard will provide updated wording. Perhaps need both normative and non-normative wording.
[2015-08-03, Howard updates P/R per telecon discussion.]
[2017-03-04, Kona]
This is related to 2751(i), which has been suggested NAD.
STL wants "Effects equivalent to" here - say it in code. Marshall to research.
Proposed resolution:
This wording is relative to N4431.
Edit 20.3.1.3 [unique.ptr.single] p1 as indicated:
The default type for the template parameter
D
isdefault_delete
. A client-supplied template argumentD
shall be a function object type (20.9), lvalue-reference to function, or lvalue-reference to function object type for which, given a valued
of typeD
and a valueptr
of typeunique_ptr<T, D>::pointer
, the expressiond(ptr)
is valid and has the effect of disposing of the pointer as appropriate for that deleter. The expressiond(ptr)
, if it destructs the object referred to byptr
, shall not refer to the objectd
after it destructs*ptr
. [Note: The object being destructed may control the lifetime ofd
. — end note]
Section: 33.5.4 [atomics.order] Status: Open Submitter: Brian Demsky Opened: 2013-06-17 Last modified: 2016-01-28
Priority: 4
View other active issues in [atomics.order].
View all other issues in [atomics.order].
View all issues with Open status.
Discussion:
I believe that the following variation on IRIW should admit executions in
which c1 = d1 = 5
and c2 = d2 = 0
. If this is allowed, then what is sequence of
program evaluations for 33.5.4 [atomics.order] p9 that justifies the store to z
? It seems that
33.5.4 [atomics.order] p9 should not allow this execution because one of the stores to x
or y
has
to appear earlier in the sequence, each of the fetch_adds
reads the previous load in the thread (and thus must
appear later in the sequence), and 33.5.4 [atomics.order] p9 states that each load must read from the last prior
assignment in the sequence.
atomic_int x; atomic_int y; atomic_int z; int c1, c2, d1, d2; static void a(void* obj) { atomic_store_explicit(&x, 5, memory_order_relaxed); } static void b(void* obj) { atomic_store_explicit(&y, 5, memory_order_relaxed); } static void c(void* obj) { c1 = atomic_load_explicit(&x, memory_order_relaxed); // this could also be an atomic load if the address depends on c1: c2 = atomic_fetch_add_explicit(&y, c1, memory_order_relaxed); } static void d(void* obj) { d1 = atomic_load_explicit(&y, memory_order_relaxed); d2 = atomic_fetch_add_explicit(&x, d1, memory_order_relaxed); } int user_main(int argc, char** argv) { thrd_t t1, t2, t3, t4; atomic_init(&x, 0); atomic_init(&y, 0); printf("Main thread: creating 4 threads\n"); thrd_create(&t1, (thrd_start_t)&a, NULL); thrd_create(&t2, (thrd_start_t)&b, NULL); thrd_create(&t3, (thrd_start_t)&c, NULL); thrd_create(&t4, (thrd_start_t)&d, NULL); thrd_join(t1); thrd_join(t2); thrd_join(t3); thrd_join(t4); printf("c1=%d c2=%d\n",c1,c2); printf("d1=%d d2=%d\n",d1,d2); // Can this store write 1000 (i.e., c1=d1=5, c2=d2=0)? atomic_store(&z, (c1+d1)*100+c2+d2); printf("Main thread is finished\n"); return 0; }
It seems that the easiest fix is to allow a load in 33.5.4 [atomics.order] p9 to read from any prior store in the evaluation order.
That said, I would personally advocate the following: It seems to me that C/C++ atomics are in a bit of different situation than Java because: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 edgex->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.
[2015-05 Lenexa, SG1 response]
This was partially addressed (weasel-worded) in C++14 (See N3786). The remainder is an open research problem. N3710 outlines a "solution" that doesn't have a consensus behind it because it costs performance. We have no better solution at the moment.
Proposed resolution:
partial_sort_copy
underspecified for ranges of two different typesSection: 27.8.2.4 [partial.sort.copy] Status: New Submitter: Matt Austern Opened: 2013-06-26 Last modified: 2016-01-28
Priority: 3
View all issues with New status.
Discussion:
The signature of this function is:
template<class InputIterator, class RandomAccessIterator> RandomAccessIterator partial_sort_copy(InputIterator first, InputIterator last, RandomAccessIterator result_first, RandomAccessIterator result_last);
(and the usual overload for an explicitly provided comparison function). The standard says nothing about requirements
in the case where the input type (iterator_traits<InputIterator>::value_type
) and the output type
(iterator_traits<RandomAccessIterator>::value_type
) are different.
Proposed resolution:
Section: 24.2.2 [container.requirements.general] Status: New Submitter: Matt Austern Opened: 2013-06-26 Last modified: 2016-01-28
Priority: 4
View other active issues in [container.requirements.general].
View all other issues in [container.requirements.general].
View all issues with New status.
Discussion:
Consider the following code snippet:
#include <vector> #include <algorithm> int main() { std::vector<int> v1(100, 3); std::vector<int> v2(100); copy(v1.begin(), v1.end(), v2.begin()); }
It compiles without error on my desktop. Is it required to? I can't find evidence from the standard that it is.
In my test std::copy
was found by argument-dependent lookup because the implementation I used made
std::vector<int>::iterator
a user-defined type defined in namespace std
. But the standard
only requires std::vector<int>::iterator
to be an implementation specified random access iterator
type. I can't find anything requiring it to be a user-defined type at all (and in fact there are reasonable implementation
where it isn't), let alone a user defined type defined in a specific namespace.
Since the defining namespace of container iterators is visible to users, should the standard say anything about what that namespace is?
Proposed resolution:
stringbuf::underflow()
underspecifiedSection: 31.8.2.5 [stringbuf.virtuals] Status: Open Submitter: Sergey Zubkov Opened: 2013-08-29 Last modified: 2018-06-12
Priority: 4
View other active issues in [stringbuf.virtuals].
View all other issues in [stringbuf.virtuals].
View all issues with Open status.
Discussion:
In 31.8.2.5 [stringbuf.virtuals]/1, basic_stringbuf::underflow()
is specified to unconditionally
return traits::eof()
when a read position is not available.
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
99 [depr.strstreambuf.virtuals]/15.
[2018-06-06, Billy argues for NAD]
The existing "Any character in the underlying buffer which has been initialized is considered to be part of the input sequence."
sentence already describes what the stringbuf
is supposed to do to the get area. The specific mechanism that the
stringbuf
uses to alter the get area is unspecified because the mechanism by which the stringbuf
remembers the "high water mark" is unspecified.
stringstream s; s << "Hello"; s.seekp(0); string x; s >> x;
Before this P/R, this will store Hello
in x
, because the characters Hello
are initialized.
After this P/R, the "written put area" is empty, so it will store the empty string in x
.
[2018-06 Rapperswil Wednesday issues processing]
Billy to provide rationale for closing as NAD.
Proposed resolution:
This wording is relative to N3691.
Change 31.8.2.5 [stringbuf.virtuals] as indicated:
int_type underflow();-1- Returns: If the input sequence has a read position available or the function makes a read position available (as described below), returns
-?- The function can make a read position available only iftraits::to_int_type(*gptr())
. Otherwise, returnstraits::eof()
. Any character in the underlying buffer which has been initialized is considered to be part of the input sequence.(mode & ios_base::in) != 0
and if the write next pointerpptr()
is not null and is greater than the current read end pointeregptr()
. To make a read position available, the function alters the read end pointeregptr()
to equalpptr()
.
constexpr
guarantees of defaulted functions still insufficientSection: 22.3.2 [pairs.pair], 22.4.4.2 [tuple.cnstr], 29.5 [time.duration] Status: Open Submitter: Daniel Krügler Opened: 2013-09-09 Last modified: 2020-06-13
Priority: 3
View other active issues in [pairs.pair].
View all other issues in [pairs.pair].
View all issues with Open status.
Discussion:
During the acceptance of N3471 and
some similar constexpr
papers, specific wording was added to pair
, tuple
, and other templates
that were intended to impose implementation constraints that ensure that the observable constexpr
"character"
of a defaulted function template is solely determined by the required expressions of the user-provided types when instantiated,
for example:
The defaulted move and copy constructor, respectively, of pair shall be a
constexpr
function if and only if all required element-wise initializations for copy and move, respectively, would satisfy the requirements for aconstexpr
function.
This wording doesn't require enough, especially since the core language via CWG 1358 does now support constexpr
function template instantiations, even if such function cannot appear in a constant expression (as specified in 7.7 [expr.const])
or as a constant initializer of that object (as specified in [basic.start.init]). The wording should be
improved and should require valid uses in constant expressions and as constant initializers instead.
[Lenexa 2015-05-05]
STL : notice order of move/copy and copy/move with "respectively".
General word-smithing; ask for updated wording
Are we happy with this with changes we are suggesting?
unanimous
[2016-12-14, Daniel comments]
LWG 2833(i) overlaps considerably and both should be resolved together.
Previous resolution from Daniel [SUPERSEDED]:This wording is relative to N3691.
Change 22.3.2 [pairs.pair] p2 as indicated:
-2-
The defaulted move and copy constructor, respectively, of pair shall be aAn invocation of the move or copy constructor ofconstexpr
function if and only if all required element-wise initializations for copy and move, respectively, would satisfy the requirements for aconstexpr
functionpair
shall be a constant expression (7.7 [expr.const]) if all required element-wise initializations would be constant expressions. An invocation of the move or copy constructor ofpair
shall be a constant initializer for thatpair
object ( [basic.start.init]) if all required element-wise initializations would be constant initializers for the respective subobjects.Change 22.4.4.2 [tuple.cnstr] p2 as indicated:
-2-
The defaulted move and copy constructor, respectively, ofAn invocation of the move or copy constructor oftuple
shall be aconstexpr
function if and only if all required element-wise initializations for copy and move, respectively, would satisfy the requirements for aconstexpr
function. The defaulted move and copy constructor oftuple<>
shall beconstexpr
functionstuple
shall be a constant expression (7.7 [expr.const]) if all required element-wise initializations would be constant expressions. An invocation of the move or copy constructor oftuple
shall be a constant initializer for thattuple
object ( [basic.start.init]) if all required element-wise initializations would be constant initializers for the respective subobjects. An invocation of the move or copy constructor oftuple<>
shall be a constant expression, or a constant initializer for thattuple<>
object, respectively, if the function argument would be constant expression.Change 29.5 [time.duration] p7 as indicated:
-7- Remarks:
The defaulted copy constructor of duration shall be aAn invocation of the copy constructor ofconstexpr
function if and only if the required initialization of the memberrep_
for copy and move, respectively, would satisfy the requirements for aconstexpr
function.duration
shall be a constant expression (7.7 [expr.const]) if the required initialization of the memberrep_
would be a constant expression. An invocation of the copy constructor ofduration
shall be a constant initializer for thatduration
object ( [basic.start.init]) if the required initialization of the memberrep_
would be constant initializers for this subobject.
[2020-06-08 Nina Dinka Ranns comments]
The revised wording provided by LWG 2833(i) should resolve this issue as well.
Proposed resolution:
Section: 21 [meta] Status: Open Submitter: Daniel Krügler Opened: 2013-09-02 Last modified: 2016-01-28
Priority: 3
View other active issues in [meta].
View all other issues in [meta].
View all issues with Open status.
Discussion:
The current library specification uses at several places wording that is intended to refer to core language template deduction failure at the top-level of expressions (aka "SFINAE"), for example:
The expression
declval<T>() = declval<U>()
is well-formed when treated as an unevaluated operand (Clause 5). Access checking is performed as if in a context unrelated toT
andU
. 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(i) and 1391(i) through
N3142.
[2014-05-19, Daniel suggests a descriptive term]
constrictedly well-formed expression:
An expression e depending on a set of typesA1
, ..., 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".
**Insertable
,
EmplaceConstructible
, and Erasable
definitions in 24.2.2 [container.requirements.general], but given that
these are not fully described in terms of the aforementioned wording yet, I would recommend to fix them by a separate issue
once the committee has agreed on following the suggestion presented by this issue.
[2015-05-05 Lenexa: Move to Open]
...
MC: I think we like the direction but it isn't quite right: it needs some work
JW: I'm prepared to volunteer to move that further, hopefully with the help of Daniel
Roger Orr: should this be Core wording because it doesn't really have anything to do with libraries - the term could then just be used here
AM: Core has nothing to deal with that, though
HT: it seems there is nothing to imply that allows dropping out with an error - maybe that's a separate issue
MC: I'm not getting what you are getting at: could you write an issue? - any objection to move to Open?
...
Proposed resolution:
This wording is relative to N3936.
Add the following new definition to [definitions] as indicated:
valid in a contrived argument deduction context [defns.valid.contr.context]
A program construct c depending on a set of typesA1
, ..., An
, and treated as
an unevaluated operand (Clause 5) when c is an expression, which is well-formed.
Access checking is performed as if in a context unrelated to A1
, ..., An
.
Only the validity of the immediate context (13.10.3 [temp.deduct]) of c is considered.
[Note: The compilation of c can result in side effects such as the instantiation of class template
specializations and function template specializations, the generation of implicitly-defined functions, and so on.
Such side effects are not in the "immediate context" and can result in the program being ill-formed. —
end note].
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>() =
is valid in a
declval<U>()
contrived argument deduction context
([defns.valid.contr.context]) for types
T
andU
.well-formed when treated
as an unevaluated operand
(Clause 5). Access
checking is performed as if
in a context unrelated toT
andU
. 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 21.3.5.4 [meta.unary.prop] p7 as indicated:
-7- Given the following function prototype:
template <class T> add_rvalue_reference_t<T> create() noexcept;the predicate condition for a template specialization
is_constructible<T, Args...>
shall be satisfied if and only if the following variable definitionwould be well-formedfor some invented variablet
would be valid in a contrived argument deduction context ([defns.valid.contr.context]) for typesT
andArgs...
: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 toT
and any of theArgs
. 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>(),
is
declval<ArgTypes>()...)
valid in a contrived argument deduction
context ([defns.valid.contr.context]) for types
Fn
andArgTypes...
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 toFn
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 21.3.7 [meta.rel] p4 as indicated:
-4- Given the following function prototype:
template <class T> add_rvalue_reference_t<T> create() noexcept;the predicate condition for a template specialization
is_convertible<From, To>
shall be satisfied if and only if the return expression in the following code would bewell-formedvalid in a contrived argument deduction context ([defns.valid.contr.context]) for typesTo
andFrom
, 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 toTo
andFrom
. 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]
std::vector<UserType>
broken?Section: 17.6.3.4 [new.delete.placement] Status: New Submitter: Daniel Krügler Opened: 2013-09-18 Last modified: 2016-01-28
Priority: 3
View all other issues in [new.delete.placement].
View all issues with New status.
Discussion:
The library gives explicit permission in 16.4.5.2.1 [namespace.std] p2 that user code may explicitly instantiate a library template provided that the instantiations depend on at least one user-defined type:
A program may explicitly instantiate a template defined in the standard library only if the declaration depends on the name of a user-defined type and the instantiation meets the standard library requirements for the original template.
But it seems that the C++11 library is not specified in a way that guarantees such an instantiation to be well-formed if the minimum requirements of the library is not satisfied.
For example, in general, the first template parameter ofstd::vector
is not required to be
DefaultConstructible
in general, but due to the split of the single C++03 member function
with default argument
void resize(size_type sz, T c = T());
into
void resize(size_type sz); void resize(size_type sz, const T& c);
the effect is now that for a type ND
that is not DefaultConstructible
, such as
struct NP { NP(int); };
the explicit instantiation of std::vector<ND>
is no longer well-formed, because the attempt to
instantiate the single-argument overload of resize
cannot not succeed, because this function imposes
the DefaultInsertable
requirements and given the default allocator this effectively requires
DefaultConstructible
.
But DefaultConstructible
is not the only point, what about CopyConstructible
versus
MoveConstructible
alone? It turns out that currently the second resize
overload
would fail during an explicit instantiation for a type like
struct MO { MO() = default; MO(MO&&) = default; };
because it imposes CopyInsertable
requirements that end up being equivalent to the CopyConstructible
requirements for the default allocator.
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 examplestd::list
, std::vector
, or std::deque
with
value types that are not DefaultConstructible
or only MoveConstructible
.
This issue is raised to clarify the current situation in regard to the actual requirements imposed on user-provided
types that are used to explicitly instantiate Library-provided templates. For example, the current Container requirements
impose very little requirements on the actual value type and it is unclear to which extend library implementations have
to respect that.
The minimum solution of this issue should be to at least realize that there is no fundamental requirement on
DefaultConstructible
for value types of library containers, because we have since C++03 the general
statement of 16.4.4.2 [utility.arg.requirements] ("In general, a default constructor is not required.").
It is unclear whether CopyConstructible
should be required for an explicit instantiation request, but
given the careful introduction of move operations in the library it would seem astonishing that a
MoveConstructible
type wouldn't suffice for value types of the container types.
In any case I can envision at least two approaches to solve this issue:
As indicated in LWG 2292(i), 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(i) could be resolved by a similar solution as indicated in this issue here.
Proposed resolution:
explicit
only when necessary?Section: 24 [containers] Status: LEWG Submitter: Zhihao Yuan Opened: 2013-09-26 Last modified: 2018-11-12
Priority: 2
View other active issues in [containers].
View all other issues in [containers].
View all issues with LEWG status.
Discussion:
LWG 2193(i) yields explicit
for default ctors to allow {}
, but not for
all cases of uniform initialization. For example:
explicit vector(size_type count, const Allocator& alloc = Allocator());
This prevents {n, alloc()}
. Although this use is relatively rare,
but the behavior is inconsistent with that of
vector(size_type count, const T& value, const Allocator& alloc = Allocator());
[Urbana 2014-11-07: Move to Open]
[2018-08 Batavia Monday issue discussion]
This really needs a paper; splitting a lot of constructors. Nevin to write paper.
[2018-11 San Diego Thursday night issue processing]
LEWG has rejected Nevin's paper, so they need to formulate a policy.
Proposed resolution:
Section: 24.2.2 [container.requirements.general] Status: Open Submitter: Stephan T. Lavavej Opened: 2013-09-21 Last modified: 2023-01-20
Priority: 3
View other active issues in [container.requirements.general].
View all other issues in [container.requirements.general].
View all issues with Open status.
Discussion:
24.2.2 [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.
[2015-06, Telecon]
Still waiting for updated wording
[2015-08 Chicago]
Still waiting for updated wording
[2018-08-23 Batavia Issues processing]
Priority to 3
[2023-01-20; std-proposals post]
Emile Cormier
observed
that the proposed resolution of this issue contradicts with changes made by
LWG 2839(i). Specifially, the current draft does not require
container elements to be preserved on self-move-assignment.
If this issue is accepted, it would either need to allow
iterator invalidation on self-move-assignment or remove the
"If a
and rv
do not refer to the same object"
changes added to the container requirements by LWG 2839(i).
Proposed resolution:
This wording is relative to N3691.
In 24.2.2 [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 forarray
) invalidates any references, pointers, or iterators referring to the elements of the source container. [Note: Theend()
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: Theend()
iterator does not refer to any element, so it may be invalidated. — end note]
regex_constants::collate
's effects are inaccurately summarizedSection: 32.4.2 [re.synopt] Status: Open Submitter: Stephan T. Lavavej Opened: 2013-09-21 Last modified: 2016-01-28
Priority: 3
View all other issues in [re.synopt].
View all issues with Open status.
Discussion:
The table in 32.4.2 [re.synopt]/1 says that regex_constants::collate
"Specifies that character ranges of the form
"[a-b]
" shall be locale sensitive.", but 32.12 [re.grammar]/14 says that it affects individual character comparisons
too.
[2012-02-12 Issaquah : recategorize as P3]
Marshall Clow: 28.13/14 only applies to ECMAScript
All: we're unsure
Jonathan Wakely: we should ask John Maddock
Move to P3
[2014-5-14, John Maddock response]
The original intention was the original wording: namely that collate
only made character ranges locale sensitive.
To be frank it's a feature that's probably hardly ever used (though I have no real hard data on that), and is a leftover
from early POSIX standards which required locale sensitive collation for character ranges, and then later changed
to implementation defined if I remember correctly (basically nobody implemented locale-dependent collation).
Z < a
in that locale."
ECMAScript doesn't include collation at all.
IMO, +1 to changing 28.13 instead of 28.5.1. It seems like we'd be on
fairly solid ground if we wanted to remove regex_constants::collate
entirely, in favor of named character classes, but of course that's
not for this issue.
Proposed resolution:
This wording is relative to N3691.
In 32.4.2 [re.synopt]/1, Table 138 — "syntax_option_type
effects", change as indicated:
Table 138 — syntax_option_type
effectsElement Effect(s) if set …
collate
Specifies that character ranges of the form "comparisons and character range comparisons shall be locale sensitive.[a-b]
"…
Section: 32.6 [re.traits], 30.3.1.2.2 [locale.facet] Status: Open Submitter: Sergey Zubkov Opened: 2013-10-15 Last modified: 2016-02-01
Priority: 3
View all other issues in [re.traits].
View all issues with Open status.
Discussion:
32.6 [re.traits]/7, begins with "if typeid(use_facet<collate<charT> >) == typeid(collate_byname<charT>)
",
which appears to be pseudocode with the intention to convey that the collate facet has not been replaced by the user. Cf. the wording in
N1429 "there is no portable way to implement
transform_primary
in terms of std::locale
, since even if the sort key format returned by
std::collate_byname<>::transform
is known and can be converted into a primary sort key, the user can still
install their own custom std::collate
implementation into the locale object used, and that can use any sort key
format they see fit.".
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 30.3.1.2.2 [locale.facet]/4, which is only
required to provide equivalent semantics, to the named locale's facet, not to actually be one.
[2015-05-06 Lenexa: Move to Open]
MC, RP: Consequence of failing to follow the rule is UB.
MC: Tightening of requirements.
RP: It should be this way, we just didn't impose it before.
MC: Second change is a bug fix, original code didn't work.
TK: Doesn't seem to make things worse.
Bring up in larger group tomorrow.
JW arrives.
JW: libstdc++ violates this due to two std::string ABIs.
JW: This prevents installing a type derived from Facet_byname, constrains the implementor from using a smarter derived class version.
JW: Can't look at facet id to detect replacement, because replacements have the same id.
RP: Can you give it multiple ids through multiple inheritance?
JW: No, the facet mechanism wouldn't like that.
JW: We should also ask Martin Sebor, he's implemented this stuff recently.
MC: Sounds like this resolution doesn't work, need a better solution.
JW: Write in words "if the facet has not been replaced by the user", the implementation knows how to detect that, but not like this.
RP: User RE traits need to detect this too.
JW: =(
Move to Open, JW will invite Martin Sebor to join LWG for discussion.
Later ...
JW: This is not needed for user specializations after all.
MC: Agree, [re.traits]/7 only applies to the stdlib traits.
NM: Effects: doesn't make sense.
JW, NM, Martin Sebor to come up with new wording.
Proposed resolution:
This wording is relative to N3691.
Modify 30.3.1.2.2 [locale.facet]/4 as indicated:
For some standard facets a standard "...
_byname
" class, derived from it, implements the virtual function semanticsequivalent toprovided by that facet of the locale constructed bylocale(const char*)
with the same name. Each such facet provides a constructor that takes aconst char*
argument, which names the locale, and arefs
argument, which is passed to the base class constructor. Each such facet also provides a constructor that takes a string argumentstr
and arefs
argument, which has the same effect as calling the first constructor with the two argumentsstr.c_str()
andrefs
. If there is no "..._byname
" version of a facet, the base class implements named locale semantics itself by reference to other facets. For any localeloc
constructed bylocale(const char*)
and facetFacet
that has a corresponding standardFacet_byname
class,typeid(use_facet<Facet>(loc)) == typeid(Facet_byname)
.
Modify 32.6 [re.traits]/7 as indicated:
template <class ForwardIterator> string_type transform_primary(ForwardIterator first, ForwardIterator last) const;-7- Effects: if
typeid(use_facet<collate<charT> >(getloc())) == typeid(collate_byname<charT>)
and the form of the sort key returned bycollate_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.
wchar_t const*
or to wchar_t
not invoked for operator<<
Section: 31.7.6.2 [ostream] Status: New Submitter: Alf P. Steinbach Opened: 2013-10-29 Last modified: 2016-01-28
Priority: 4
View all other issues in [ostream].
View all issues with New status.
Discussion:
For wide streams argument types wchar_t const*
and wchar_t
are supported only as template parameters.
User defined conversions are not considered for template parameter matching. Hence inappropriate overloads of
operator<<
are selected when an implicit conversion is required for the argument, which is inconsistent
with the behavior for char const*
and char
, is unexpected, and is a useless result.
#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 31.7.6.2 [ostream], class template basic_ostream
synopsis, as indicated:
namespace std { […] // 27.7.3.6.4 character inserters template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, charT); template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, char); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, char); template<class traits> basic_ostream<wchar_t,traits>& operator<<(basic_ostream<wchar_t,traits>&, wchar_t); […] template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*); template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const char*); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, const char*); template<class traits> basic_ostream<wchar_t,traits>& operator<<(basic_ostream<wchar_t,traits>&, const wchar_t*); […] }
Modify 31.7.6.3.4 [ostream.inserters.character] as indicated: [Drafting note:
The replacement of os
by out
in p1 and the insertion of "out.
" in p4
just fix two obvious typos — end drafting note]
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, charT c); template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, char c); // specialization template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, char c); template<class traits> basic_ostream<wchar_t,traits>& operator<<(basic_ostream<wchar_t,traits>& out, wchar_t c); // signed and unsigned template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, signed char c); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, unsigned char c);-1- Effects: Behaves as a formatted output function (31.7.6.3.1 [ostream.formatted.reqmts]) of
-2- Returns:out
. Constructs a character sequenceseq
. Ifc
has typechar
and the character type of the stream is notchar
, thenseq
consists ofout.widen(c)
; otherwiseseq
consists ofc
. Determines padding forseq
as described in 31.7.6.3.1 [ostream.formatted.reqmts]. Insertsseq
intoout
. Calls.
osout.width(0)out
.template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, const charT* s); template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, const char* s); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const char* s); template<class traits> basic_ostream<wchar_t,traits>& operator<<(basic_ostream<wchar_t,traits>& out, const wchar_t* s); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const signed char* s); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const unsigned char* s);-3- Requires:
-4- Effects: Behaves like a formatted inserter (as described in 31.7.6.3.1 [ostream.formatted.reqmts]) ofs
shall not be a null pointer.out
. Creates a character sequenceseq
ofn
characters starting ats
, each widened usingout.widen()
(27.5.5.3), wheren
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 typeconst charT*
,
and also for the overloadwhere the first argument is of typebasic_ostream<char, traits>&
and the second is of typeconst char*
,where the first argument is of type
basic_ostream<wchar_t, traits>&
and the second is of typeconst wchar_t*
,
std::char_traits<char>::length(s)
for the overload where the first argument is of typebasic_ostream<charT, traits>&
and the second is of typeconst char*
,
traits::length(reinterpret_cast<const char*>(s))
for the other two overloads.Determines padding for
-5- Returns:seq
as described in 31.7.6.3.1 [ostream.formatted.reqmts]. Insertsseq
intoout
. Callsout.width(0)
.out
.
charT('1')
is not the wide equivalent of '1'
Section: 22.9.2 [template.bitset], 31.7.9 [quoted.manip] Status: Open Submitter: Zhihao Yuan Opened: 2013-12-02 Last modified: 2016-01-28
Priority: 3
View all other issues in [template.bitset].
View all issues with Open status.
Discussion:
Example: char16_t('1') != u'1'
is possible.
char16_t
is defined to be Unicode
code point, which is same to the ASCII value and UTF-8 for
7-bit chars. However, char
is not guaranteed to have an
encoding which is compatible with ASCII. For example, '1'
in EBCDIC is 241.
I found three places in the standard casting narrow char
literals: bitset::bitset
, bitset::to_string
and quoted
.
PJ confirmed this issue and says he has a solution used
in their <filesystem>
implementation, and he may want to
propose it to the standard.
The solution in my mind, for now, is to make those default
arguments magical, where the "magic" can be implemented
with a C11 _Generic
selection (works in clang):
#define _G(T, literal) _Generic(T{}, \ char: literal, \ wchar_t: L ## literal, \ char16_t: u ## literal, \ char32_t: U ## literal) _G(char16_t, '1') == u'1'
[Lenexa 2015-05-05: Move to Open]
Ask for complete PR (need quoted, to string, et al.)
Will then take it up again
Expectation is that this is correct way to fix this
Proposed resolution:
This wording is relative to N3797.
[Drafting note: This is a sample wording fixing only one case; I'm just too lazy to copy-paste it before we discussed whether the solution is worth and sufficient (for example, should the othercharT
s like unsigned char
just don't compile without
supplying those arguments? I hope so). — end drafting note]
Modify 22.9.2 [template.bitset] p1, class template bitset
synopsis, as indicated:
namespace std { template <size_t N> class bitset { public: […] template<class charT, class traits, class Allocator> explicit bitset( const basic_string<charT,traits,Allocator>& str, typename basic_string<charT,traits,Allocator>::size_type pos = 0, typename basic_string<charT,traits,Allocator>::size_type n = basic_string<charT,traits,Allocator>::npos, charT zero =charT('0')see below, charT one =charT('1')see below); […] }; […] }
Modify 22.9.2.2 [bitset.cons] as indicated:
template<class charT, class traits, class Allocator> explicit bitset(const basic_string<charT, traits, Allocator>& str, typename basic_string<charT, traits, Allocator>::size_type pos = 0, typename basic_string<charT, traits, Allocator>::size_type n = basic_string<charT, traits, Allocator>::npos, charT zero =charT('0')see below, charT one =charT('1')see below);-?- The default values of
-3- Requires::zero
andone
compare equal to the character literals0
and1
of typecharT
, respectively.pos <= str.size()
. […]
is_empty
type traitSection: 21.3.5.4 [meta.unary.prop] Status: Open Submitter: Richard Smith Opened: 2014-02-01 Last modified: 2017-02-02
Priority: 3
View other active issues in [meta.unary.prop].
View all other issues in [meta.unary.prop].
View all issues with Open status.
Discussion:
The 'Condition' for std::is_empty
is listed as:
"
T
is a class type, but not a union type, with no non-static data members other than bit-fields of length 0, no virtual member functions, no virtual base classes, and no base classB
for whichis_empty<B>::value
is false."
This is incorrect: there is no such thing as a non-static data member that is a bit-field of length 0, since bit-fields of length 0 must be unnamed, and unnamed bit-fields are not members (see 11.4.10 [class.bit] p2).
It also means that classes such as:struct S { int : 3; };
are empty (because they have no non-static data members). There's implementation divergence on the value of
is_empty<S>::value
.
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 membersother than, no unnamed bit-fields of non-zero length0, no virtual member functions, no virtual base classes, and no base classB
for whichis_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 membersother than bit-fields of length 0, no virtual member functions, no virtual base classes, and no base classB
for whichis_empty<B>::value
is false."
[2016-08 Chicago]
Walter says: We want is_empty_v<S>
to produce false as a result. Therefore, we recommend adoption of the first of the issue's suggestions.
Tuesday AM: Moved to Tentatively Ready
Previous resolution [SUPERSEDED]:
[2016-10 by Marshall - this PR incorrectly highlighted changed portions]
Modify Table 38 — Type property predicates for
is_empty
as follows:
T
is a non-union class type with no non-static data membersother than, no unnamed bit-fields of non-zero length0, no virtual member functions, no virtual base classes, and no base classB
for whichis_empty_v<B>
is false.
[2016-10 Telecon]
Should probably point at section 1.8 for some of this. Status back to 'Open'
Proposed resolution:
Modify Table 38 — Type property predicates for is_empty
as follows:
T
is a class type, but not a union type,is a non-union class type with no non-static data membersother than, no unnamed bit-fields of non-zero length0, no virtual member functions, no virtual base classes, and no base classB
for whichis_empty_v<B>
is false.
emplace()
should not move/copy the mapped_type
constructor
arguments when no insertion happensSection: 24.2.7 [associative.reqmts], 24.2.8 [unord.req] Status: New Submitter: Jeffrey Yasskin Opened: 2014-02-15 Last modified: 2015-09-23
Priority: 3
View other active issues in [associative.reqmts].
View all other issues in [associative.reqmts].
View all issues with New status.
Discussion:
a_uniq.emplace(args)
is specified as:
Effects: Inserts a value_type object
t
constructed with
std::forward<Args>(args)...
if and only if there is no element in the
container with key equivalent to the key oft
. Thebool
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 oft
.
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).
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(i) 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:
istreambuf_iterator
end-of-stream equalitySection: 25.6.4 [istreambuf.iterator] Status: New Submitter: Hyman Rosen Opened: 2014-02-19 Last modified: 2023-04-13
Priority: 3
View other active issues in [istreambuf.iterator].
View all other issues in [istreambuf.iterator].
View all issues with New status.
Discussion:
Given the following code,
#include <sstream> std::stringbuf buf; std::istreambuf_iterator<char> begin(&buf); std::istreambuf_iterator<char> end;
it is not clear from the wording of the Standard whether begin.equal(end)
must be true. In at least one implementation it is not (CC: Sun C++ 5.10 SunOS_sparc Patch 128228-25 2013/02/20) and in at least
one implementation it is (gcc version 4.3.2 x86_64-unknown-linux-gnu).
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()
.
[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.
[2023-03-31; Jonathan Wakely comments]
I agree that they should compare equal, but that's in conflict with the
resolution of LWG 2544(i), which says that begin
must not be at end-of-stream because &buf
is not null.
[2023-04-12; Jonathan adds wording]
Proposed resolution:
This wording is relative to N4944.
Change 25.6.4.1 [istreambuf.iterator.general] as indicated:
constexpr istreambuf_iterator() noexcept; constexpr istreambuf_iterator(default_sentinel_t) noexcept; istreambuf_iterator(const istreambuf_iterator&) noexcept = default; ~istreambuf_iterator() = default; istreambuf_iterator(istream_type& s) noexcept
;: istreambuf_iterator(s.rdbuf()) { } istreambuf_iterator(streambuf_type* s) noexcept; istreambuf_iterator(const proxy& p) noexcept; … private: streambuf_type* sbuf_; // exposition only int_type c_{}; // exposition only }; }
Change 25.6.4.3 [istreambuf.iterator.cons] as indicated:
For each
istreambuf_iterator
constructor in this section, an end-of-stream iterator is constructed ifand only ifthe exposition-only membersbuf_
is initialized with a null pointer value or ifsbuf_->sgetc()
returnstraits_type::eof()
.constexpr istreambuf_iterator() noexcept; constexpr istreambuf_iterator(default_sentinel_t) noexcept;-1- Effects: Initializes
sbuf_
withnullptr
.istreambuf_iterator(istream_type& s) noexcept;
-2- Effects: Initializessbuf_
withs.rdbuf()
.istreambuf_iterator(streambuf_type* s) noexcept;[Drafting note:
sgetc()
can throw, but this function isnoexcept
. Should it swallow exceptions and create an end-of-stream iterator, to avoid weakening the exception spec of an existing function?]-3- Effects: Initializes
sbuf_
withs
. Ifs
is not null, initializesc_
withs->sgetc()
. Setssbuf_
to null ifsgetc
exits via an exception, or iftraits_type::eq_int_type(c_, traits_type::eof())
istrue
.istreambuf_iterator(const proxy& p) noexcept;-4- Effects: Initializes
sbuf_
withp.sbuf_
. Ifp.sbuf_
is not null, initializesc_
withp.keep_
.
Change 25.6.4.4 [istreambuf.iterator.ops] as indicated:
charT operator*() const;-?- Preconditions:
sbuf_
is not null.-1- Returns:
The character obtained via thestreambuf
membersbuf_->sgetc()
.traits_type::to_char_type(c_)
.-?- Throws: Nothing.
istreambuf_iterator& operator++();-?- Preconditions:
sbuf_
is not null.-2- Effects:
As if byPerformssbuf_->sbumpc()
.c_ = sbuf_->snextc()
, then setssbuf_
to null iftraits_type::eq_int_type(c_, traits_type::eof())
istrue
.-3- Returns:
*this
.proxy operator++(int);-4-
Returns:proxy(sbuf_->sbumpc(), sbuf_)
.
Effects: Equivalent to:proxy p(**this, sbuf_); ++*this; return p;
bool equal(const istreambuf_iterator& b) const;-5- Returns:
bool(sbuf_) == bool(b.sbuf_)
.[Note: This is
true
if and only if both iterators are at end-of-stream, or neither is at end-of-stream, regardless of what streambuf object they use. — end note]template<class charT, class traits> bool operator==(const istreambuf_iterator<charT, traits>& a, const istreambuf_iterator<charT, traits>& b);-6- Returns:
a.equal(b)
.bool equal(const istreambuf_iterator& i, default_sentinel_t s) const;-7- Returns:
.
i.equal(s)i.sbuf_ == nullptr
Section: 29.5.9 [time.duration.literals] Status: Open Submitter: Jonathan Wakely Opened: 2014-05-16 Last modified: 2014-11-08
Priority: 3
View all issues with Open status.
Discussion:
29.5.9 [time.duration.literals] p3 says:
If any of these suffixes are applied to an integer literal and the resulting
chrono::duration
value cannot be represented in the result type because of overflow, the program is ill-formed.
Ill-formed requires a diagnostic at compile-time, but there is no way
to detect the overflow from unsigned long long
to the signed
duration<>::rep
type.
[Urbana 2014-11-07: Move to Open]
Proposed resolution:
type_info
's destructor shouldn't be required to be virtualSection: 17.7.3 [type.info] Status: Open Submitter: Stephan T. Lavavej Opened: 2014-06-14 Last modified: 2016-08-06
Priority: 3
View all other issues in [type.info].
View all issues with Open status.
Discussion:
type_info
's destructor is depicted as being virtual
, which is nearly unobservable to users (since they can't construct
or copy this class, they can't usefully derive from it). However, it's technically observable (via is_polymorphic
and
has_virtual_destructor
). It also imposes real costs on implementations, requiring them to store one vptr per
type_info
object, when RTTI space consumption is a significant concern.
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.
[Lenexa 2015-05-05: Move to Open]
Marshall to poll LEWG for their opinion
[2016-06]
On the reflector, STL wrote:
We'll prototype this change and report back with data in the future.
[2016-08 Chicago]
No update from STL. Set priority to P3
Proposed resolution:
This wording is relative to N3936.
Change 17.7.3 [type.info] as indicated:
namespace std { class type_info { public:virtualsee below ~type_info(); […] }; }-1- The class
type_info
describes type information generated by the implementation. Objects of this class effectively store a pointer to a name for the type, and an encoded value suitable for comparing two types for equality or collating order. The names, encoding rule, and collating sequence for types are all unspecified and may differ between programs. Whether~type_info()
isvirtual
is implementation-defined.
Section: 16.4.6.9 [reentrancy] Status: Open Submitter: Stephan T. Lavavej Opened: 2014-07-01 Last modified: 2021-07-31
Priority: 3
View all other issues in [reentrancy].
View all issues with Open status.
Discussion:
N3936 16.4.6.9 [reentrancy]/1 talks about "functions", but that doesn't address the scenario of calling different member functions of a single object. Member functions often have to violate and then re-establish invariants. For example, vectors often have "holes" during insertion, and element constructors/destructors/etc. shouldn't be allowed to observe the vector while it's in this invariant-violating state. The [reentrancy] Standardese should be extended to cover member functions, so that implementers can either say that member function reentrancy is universally prohibited, or selectively allowed for very specific scenarios.
(For clarity, this issue has been split off from LWG 2382(i).)[2014-11-03 Urbana]
AJM confirmed with SG1 that they had no special concerns with this issue, and LWG should retain ownership.
AM: this is too overly broad as it also covers calling the exact same member function on a different objectMove to Open
[2015-07 Telecon Urbana]
Marshall to ping STL for updated wording.
[2016-05 email from STL]
I don't have any better suggestions than my original PR at the moment.
Previous resolution [SUPERSEDED]:
This wording is relative to N3936.
Change 16.4.6.9 [reentrancy] p1 as indicated:
-1- Except where explicitly specified in this standard, it is implementation-defined which functions (including different member functions called on a single object) in the Standard C++ library may be recursively reentered.
[2021-07-29 Tim suggests new wording]
The "this
pointer" restriction is modeled on 11.9.5 [class.cdtor] p2.
It allows us to continue to specify a member function f
as calling some other
member function g
, since any such call would use something obtained
from the first member function's this
pointer.
const
(or are treated as such for the
purposes of data race avoidance). Using "access" means that we also cover direct
access to the object representation, such as the following pathological example
from Arthur O'Dwyer,
which is now undefined:
std::string s = "hello world"; char *first = (char*)&s; char *last = (char*)(&s + 1); s.append(first, last);
Proposed resolution:
This wording is relative to N4892.
Add the following paragraph to 16.4.6.9 [reentrancy]:
-?- During the execution of a standard library non-static member function F on an object, if that object is accessed through a glvalue that is not obtained, directly or indirectly, from the
this
pointer of F, in a manner that can conflict (6.9.2.2 [intro.races]) with any access that F is permitted to perform (16.4.6.10 [res.on.data.races]), the behavior is undefined unless otherwise specified.
std::align
[ptr.align]Section: 20.2.5 [ptr.align] Status: New Submitter: Melissa Mears Opened: 2014-08-06 Last modified: 2014-11-03
Priority: 3
View all other issues in [ptr.align].
View all issues with New status.
Discussion:
The specification of std::align
does not appear to specify what happens when the value of the size
parameter is 0. (The question of what happens when alignment
is 0 is mentioned in another Defect Report, 2377(i);
it would change the behavior to be undefined rather than potentially implementation-defined.)
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:
slice_array
, gslice_array
, mask_array
, indirect_array
copy constructorSection: 28.6.5 [template.slice.array], 28.6.7 [template.gslice.array], 28.6.8 [template.mask.array], 28.6.9 [template.indirect.array] Status: New Submitter: Akira Takahashi Opened: 2014-08-12 Last modified: 2014-11-03
Priority: 4
View all other issues in [template.slice.array].
View all issues with New status.
Discussion:
I found a missing specification of the copy constructor of the following class templates:
slice_array
(28.6.5 [template.slice.array])
gslice_array
(28.6.7 [template.gslice.array])
mask_array
(28.6.8 [template.mask.array])
indirect_array
(28.6.9 [template.indirect.array])
Proposed resolution:
Before 28.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 28.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 28.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 28.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: 32.2 [re.req] Status: New Submitter: Jonathan Wakely Opened: 2014-09-30 Last modified: 2020-04-16
Priority: 3
View other active issues in [re.req].
View all other issues in [re.req].
View all issues with New status.
Discussion:
The requirements on the traits class in 32.2 [re.req] do not say whether a
regular expression traits class is required to be DefaultConstructible
,
CopyConstructible
, CopyAssignable
etc.
std::regex_traits
class appears to be all of the above, but can
basic_regex
assume that for user-defined traits classes?
Should the following statements all leave u
in equivalent states?
X u{v}; X u; u = v; X u; u.imbue(v.getloc();
Whether they are equivalent has implications for basic_regex
copy construction and
assignment.
[2020-04-16, Jonathan adds that 32.7.5 [re.regex.locale] requires the traits type to be default-initialized, despite no guarantee that the traits type is default constructible. ]
Proposed resolution:
is_constructible
, etc. and default argumentsSection: 21 [meta] Status: Core Submitter: Hubert Tong Opened: 2014-11-04 Last modified: 2015-10-21
Priority: 3
View other active issues in [meta].
View all other issues in [meta].
Discussion:
The BaseCharacteristic
for is_constructible
is defined in terms of the well-formedness
of a declaration for an invented variable. The well-formedness of the described declaration itself may
change for the same set of arguments because of the introduction of default arguments.
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:
<initializer_list>
Section: 17.10 [support.initlist], 25.7 [iterator.range] Status: New Submitter: Richard Smith Opened: 2014-11-11 Last modified: 2021-06-06
Priority: 3
View other active issues in [support.initlist].
View all other issues in [support.initlist].
View all issues with New status.
Discussion:
These sections define helper functions, some of which apply to initializer_list<T>
. And they're
available if you include one of a long list of header files, many of which include <initializer_list>
.
But they are not available if you include <initializer_list>
. This seems very odd.
#include <initializer_list> auto x = {1, 2, 3}; const int *p = data(x); // error, undeclared #include <vector> const int *q = data(x); // ok
Proposed resolution:
Section: 16.4.4.6 [allocator.requirements], 24.3.12.3 [vector.capacity], 24.3.12.5 [vector.modifiers] Status: New Submitter: dyp Opened: 2014-12-06 Last modified: 2015-06-10
Priority: 3
View other active issues in [allocator.requirements].
View all other issues in [allocator.requirements].
View all issues with New status.
Discussion:
When resizing a vector
, the accessibility and exception specification of the value type's
constructors determines whether the elements are copied or moved to the new buffer.
However, the copy/move is performed via the allocator's construct
member function, which is
assumed, but not required, to call the copy/move constructor and propagate only exceptions
from the value type's copy/move constructor. The issue might also affect other classes.
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
atc
::new ((void*)c) C(forward<Args>(args)...)
…
and from 16.4.4.6 [allocator.requirements] p9:
An allocator may constrain the types on which it can be instantiated and the arguments for which its
construct
member may be called. If a type cannot be used with a particular allocator, the allocator class or the call toconstruct
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 24.2.2 [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 24.3.12.5 [vector.modifiers] p1:
[…]
void push_back(const T& x); void push_back(T&& x);Remarks: Causes reallocation if the n