diff --git a/papers/n4829.html b/papers/n4829.html new file mode 100644 index 0000000000..6c821330f4 --- /dev/null +++ b/papers/n4829.html @@ -0,0 +1,1279 @@ +N4829 +

N4829 Editors' Report -- Programming Languages -- C++

+ +

2019-08-15
+Richard Smith (editor) (Google Inc)
+Thomas Köppe (co-editor) (Google DeepMind)
+Jens Maurer (co-editor)
+Dawn Perchik (co-editor) (Bright Side Computing, LLC)
+<cxxeditor@gmail.com>

+ +

Acknowledgements

+ +

Special thanks to several paper authors +for supplying the LaTeX sources for their papers.

+ +

Special thanks also to the Editing Committee -- +Daniel Krügler, Davis Herring, Nina Ranns, and Ville Voutilainen -- +for providing a careful review of the application of these motions +and the editorial changes described below +to ensure the correctness of the C++20 Committee Draft.

+ +

Thanks to all those who have submitted editorial +issues +and to those who have provided pull requests with fixes.

+ +

New papers

+ + + +

Note: +A working draft was circulated to the editing committee for review, +and was mistakenly published with paper number N4828. +N4828 is not the C++20 Committee Draft, +and does not contain the results of addressing feedback from +the editing committee.

+ +

Motions incorporated into working draft

+ +

Core working group motions

+ +

CWG motion 1: Core issue resolutions for 10 issues in "tentatively ready" status applied: (DR)

+ + + +

CWG motion 2: P1161R3 "Deprecate uses of the comma operator in subscripting expressions"

+ +

CWG motion 3: P1331R2 "Permitting trivial default initialization in constexpr contexts"

+ +

CWG motion 4: P0735R1 "Interaction of memory_order_consume with release sequences"

+ +

CWG motion 5: P0848R3 "Conditionally trivial special member functions"

+ +

CWG motion 6: P1186R3 "When do you actually use <=>?"

+ +

CWG motion 7: P1301R4 "[[nodiscard("should have a reason")]]"

+ +

CWG motion 8: P1099R5 "using enum"

+ +

CWG motion 9: P1630R1 "Spaceship needs a tune-up"

+ +

CWG motion 10: P1616R1 "Using unconstrained template template parameters with constrained templates"

+ +

CWG motion 11: P1816R0 "Class template argument deduction for aggregates"

+ +

CWG motion 12: P1668R1 "Enabling constexpr intrinsics by permitting unevaluated inline assembly in constexpr functions"

+ +

CWG motion 13: P1766R1 "Mitigating minor modules maladies" (DR)

+ +

CWG motion 14: P1811R0 "Relaxing redefinition restrictions for re-exportation robustness"

+ +

CWG motion 15: P0388R4 "Permit conversions to arrays of unknown bound"

+ +

CWG motion 16: P1823R0 "Remove contracts"

+ +

CWG motion 17: P1143R2 "Adding the constinit keyword"

+ +

CWG motion 18: P1452R2 "On the non-uniform semantics of return-type-requirements"

+ +

CWG motion 19: P1152R4 "Deprecating volatile"

+ +

CWG motion 20: P1771R1 "[[nodiscard]] for constructors" (DR)

+ +

CWG motion 21: P1814R0 "Class template argument deduction for alias templates"

+ +

CWG motion 22 was withdrawn

+ +

CWG motion 23: P1825R0 "Merged wording for P0527R1 and P1155R3" (DR)

+ + + +

CWG motion 24: P1703R1 "Recognizing header unit imports requires full preprocessing"

+ +

CWG motion 25: P0784R7 "More constexpr containers"

+ +

Library working group motions

+ +

LWG motion 1: Library issue resolutions for 17 issues in "Ready" and "Tentatively Ready" status applied: (DR)

+ + + +

LWG motion 2: P1355R2 "Exposing a narrow contract for ceil2"

+ +

LWG motion 3: P0553R4 "Bit operations"

+ +

LWG motion 4: P1424R1 "constexpr feature macro concerns"

+ +

LWG motion 5: P0645R10 "Text formatting"

+ +

LWG motion 6: P1361R2 "Integration of chrono with text formatting"

+ +

LWG motion 7: P1652R1 "Printf corner cases in std::format"

+ +

LWG motion 8: P0631R8 "Math constants"

+ +

LWG motion 9: Synchronization library:

+ + + +

LWG motion 10: P1466R3 "Miscellaneous minor fixes for chrono"

+ +

LWG motion 11: P1754R1 "Rename concepts to standard_case for C++20, while we still can"

+ +

LWG motion 12: P1614R2 "The mothership has landed"

+ +

LWG motion 13: P0325R4 "to_array from LFTS with updates"

+ +

LWG motion 14: P0408R7 "Efficient access to basic_stringbuf's buffer"

+ +

LWG motion 15: P1423R3 "char8_t backward compatibility remediation"

+ +

LWG motion 16: P1502R1 "Standard library header units"

+ +

LWG motion 17: P1612R1 "Relocate endian's specification"

+ +

LWG motion 18: P1661R1 "Remove dedicated precalculated hash lookup interface"

+ +

LWG motion 19: P1650R0 "Output std::chrono::days with d suffix"

+ +

LWG motion 20: P1651R0 "bind_front should not unwrap reference_wrapper"

+ +

LWG motion 21: P1065R2 "Constexpr invoke"

+ +

LWG motion 22: P1207R4 "Movability of single-pass iterators"

+ +

LWG motion 23: P1035R7 "Input range adaptors"

+ +

LWG motion 24: P1638R1 "basic_istream_view::iterator should not be copyable"

+ +

LWG motion 25: P1522R1 "Iterator difference type and integer overflow"

+ +

LWG motion 26: P1004R2 "Making std::vector constexpr"

+ +

LWG motion 27: P0980R1 "Making std::string constexpr"

+ +

LWG motion 28: P0660R10 "Stop token and joining thread"

+ +

LWG motion 29: P1474R1 "Helpful pointers for ContiguousIterator"

+ +

LWG motion 30: P1523R1 "Views and size types"

+ +

LWG motion 31: P0466R5 "Layout-compatibility and pointer-interconvertibility traits"

+ +

LWG motion 32: P1208R6 "source_location"

+ +

Notable editorial changes

+ +

CWG motion 21

+ +

The changes for this motion in [over.match.class.deduct] +described the matching of a simple-template-id against +the defining-type-id of an alias template +in imprecise terms +(quoting only part of the grammar to which the change intended to apply). +This has been made more precise by repeating the full grammar +previously specified in [dcl.type.simple] +in [over.match.class.deduct].

+ +

LWG motions 5-7

+ +

The new std::format library underwent substantial editorial rework +for clarity and precision. +Thanks to Tomasz Kamiński and +Johel Ernesto Guerrero Peña +for reviewing the resulting edits, +and to Victor Zverovich for responding to various questions about intent.

+ +

LWG motion 10

+ +

The operator<< added for hh_mm_ss was written in terms of +the old chrono formatting machinery that was replaced by +std::format-based machinery by LWG motion 6. +It has been rephrased in terms of std::format. +Thanks to Howard Hinnant for providing wording.

+ +

LWG motion 11

+ +

In addition to the requested renames, the following concepts were also renamed, +following the editorial instructions to rename all other concepts:

+ + + +

LWG motion 14

+ +

This motion requested that the same constructor be added to basic_stringbuf +twice. It was only added once.

+ +

LWG motion 23

+ +

The wording paper proposed making changes to the algorithms

+ + + +

However, these algorithms were never adopted into the C++ working draft from +the Ranges Technical Specification, so after consulting with the Library +Working Group, the requested changes to these algorithms were ignored.

+ +

LWG motion 26, 27

+ +

These motions would have added constexpr to +operator<, operator>, operator<=, operator>=, and operator!= functions +that LWG motion 12 removed. +Instead constexpr was added to the replacement operator<=>.

+ +

In addition, following the paper's request to add constexpr to any +std::basic_string functions that the wording missed, and after consulting +with the LWG chair as directed, the overloads of std::erase and +std::erase_if for std::basic_string were also marked contexpr.

+ +

Section label changes

+ +

Several section labels introduced by the motions papers have been modified +to match our style guide. In addition to the section labels affected by the +above motions, the following section labels have been renamed:

+ + + +

Feature test macros

+ +

Attention should be drawn to the fact that multiple papers updated feature test +macros to the same version:

+ + + +

Implementers should be aware that the new version of the feature test macro +advertises support for both papers in these cases (in addition to advertising +support for prior papers that gave smaller version numbers to the relevant +macro).

+ +

Minor editorial fixes

+ +

A log of editorial fixes made to the working draft since N4820 is below. +This list excludes changes +that do not affect the body text or only affect whitespace or typeface. For a +complete list including such changes (or for the actual deltas applied by these +changes), consult the draft sources on github.

+ +
commit 44ea29778d15cd5d9f2b5c706c6b3f4338548ec2
+Author: Casey Carter <Casey@Carter.net>
+Date:   Tue Jun 25 06:04:14 2019 -0700
+
+    [range.filter.sentinel] Correct typo in constructor Effects (#2937)
+
+commit 97b615a5a6ab0598b624ee05402c531d0421cff6
+Author: Casey Carter <Casey@Carter.net>
+Date:   Tue Jun 25 06:09:55 2019 -0700
+
+    [iterator.synopsis] Copy constraint for iterator_traits<T*> from [iterator.traits]/5 (#2943)
+
+commit da7eac5e621b5fab12c0b1992100c4bfd983ed8e
+Author: Saar Raz <saar@raz.email>
+Date:   Mon Jul 1 22:46:37 2019 +0300
+
+    [Concepts] Remove qualified-concept-name reference
+
+    Update 'qualified-concept-name' (the previous incarnation of 'type-constraint') reference to 'type-constraint' in [temp.over.link]p6.
+
+commit f54f306c3b9fad27e70766963840e3df14f20b28
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Jul 4 15:34:38 2019 +0200
+
+    [func.bind] Remove bogus 'shall's. (#2955)
+
+commit 72cc844ef44ae47aebb1ad346146138d3279be9e
+Author: Eelis <github.com@contacts.eelis.net>
+Date:   Fri Jul 5 16:16:58 2019 +0200
+
+    [expr.reinterpret.cast] Properly capitalize full-sentence bullets. (#2956)
+
+commit c635711cdd81346ad41c7861adb8035176fa236f
+Author: Eelis <github.com@contacts.eelis.net>
+Date:   Fri Jul 5 23:55:22 2019 +0200
+
+    [temp.constr.constr] Add missing period at end of sentence. (#2957)
+
+commit 4f9942cafadc17fb902610b4c67afb6fcf81ff64
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sun Jul 7 19:38:20 2019 +0200
+
+    [dcl.asm] Rename grammar term 'asm-definition' to 'asm-declaration'
+
+commit 51c5b01217799fdfa754179c20af888ec8c1889d
+Author: Casey Carter <Casey@Carter.net>
+Date:   Wed Jul 10 00:40:19 2019 -0700
+
+    [temp.constr.order] Remove extraneous "the". (#2964)
+
+commit 67db9422b6bc58f5399c7c019ec5ede28d8ac4f5
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Jun 28 17:01:54 2019 +0200
+
+    [expr.prim.req] Fix cross-reference for substituting into constraints.
+
+commit 98c2c56ab5e945452586270d72d2fb606b71cd94
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Mon Jul 22 02:24:42 2019 +0200
+
+    [class.prop] [special] Move definition of eligible special member
+    functions to the section on special member functions.
+
+commit 94a72b5c11a20cfd6c92a4faa5bd0df4b8ebc620
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Mon Jul 22 02:28:15 2019 +0200
+
+    [class.dtor] Reorder the introduction of an implicit prospective
+    destructor to before we describe the overload resolution to pick the
+    actual destructor.
+
+commit 6bd3daeae3a3e9ae6174c35ab020dbfe4504b75b
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Thu Aug 1 20:04:36 2019 -0700
+
+    [class.ctor], [class.dtor] Introduce actual definitions for
+    "constructor" and "prospective destructor".
+
+commit dc45e8c329eeb0076d074fa671c2be2fc605555a
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Mon Jul 22 03:18:33 2019 +0200
+
+    [class.spaceship] Remove incorrect note.
+
+commit d6a291776858bc647fc6826888767284f305c799
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Mon Jul 22 03:58:34 2019 +0200
+
+    [dcl.attr.nodiscard] Simplify note describing the string-literal in a
+    nodiscard attribute and make it less confusing.
+
+commit 46ba985402de963f50d364b26b594707be16c7c9
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Mon Jul 22 04:42:43 2019 +0200
+
+    [dcl.enum] Avoid hanging paragraphs by moving "Enumeration declarations"
+    down one level to a sibling of "The using enum declaration".
+
+    [namespace.udir] Rename section to "Using namespace directive" to
+    further distinguish this from a using enum declaration.
+
+commit 5d1bb1c7f8ed44016c38bfeb9797e363d52cfc51
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Thu Aug 1 20:42:13 2019 -0700
+
+    [over.match.oper] Replace "member, non-member, and built-in candidates"
+    with "non-rewritten candidates"
+
+    This simplifies the wording, implicitly explains why we're considering
+    only some candidates, and avoids overtly suggesting that we could ever
+    pick a reversed-parameter-order built-in candidate.
+
+commit 1fbc1c315008152770eea8bd383aa2a4fa47cfd5
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Jul 26 16:56:13 2019 +0200
+
+    [basic.def.odr] Turn long comma-separate list into bullets.
+
+commit c0c589881759871b2183105f315d4ddd0d2734be
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Aug 1 22:47:19 2019 +0200
+
+    [expr.const.cast] Clarify pairwise correspondence for P_i.
+    [over.ics.rank] Move cross-reference pointing to [conv.qual].
+
+commit 47539b965a84f69c548fe043a632af17db3cb315
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Fri Aug 2 15:49:39 2019 -0700
+
+    [conv.qual] Move note after the rule that implies it.
+
+commit f10e3751b39138746b601fa702c9ed9e67777c96
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Fri Aug 2 15:59:50 2019 -0700
+
+    [over.ics.rank] Reorder examples to match order of normative text.
+
+commit 813a4300a036f12d5ff6b82965b83a8e87b1ae8d
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Fri Aug 2 16:55:56 2019 -0700
+
+    [dcl.attr.nodiscard] Fix vexing-parse bug in example. Make sure the
+    missiles actually get launched, not merely redeclared.
+
+commit 6e845457bfd83f20c2f61bf4015afcd96cbd0cec
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Fri Aug 2 17:17:52 2019 -0700
+
+    [over.match.class.deduct] Fix failure to handle the case where a
+    deducible alias template's defining-type-id contains a
+    nested-name-specifier (or 'typename' or 'template' keywords).
+
+commit 7226ced32fe3cda28eb05f044985427684397128
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Fri Aug 2 17:26:53 2019 -0700
+
+    [over.match.class.deduct] Switch from imperative to passive, and clarify
+    what happens if the various 'if' conditions are not met.
+
+commit 6552c03d3793e7532793097d760edc3a93e150b1
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Fri Aug 2 17:32:40 2019 -0700
+
+    [over.match.class.deduct] Put all bullets describing the properties of
+    f' at the same depth, and guard them all by the condition that we're
+    actually adding an f' to the set of guides.
+
+commit b3b7d37c073051826c21c231bd386c10d64433dc
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Aug 2 22:09:14 2019 +0200
+
+    [class.copy.elision] Add cross-reference, fix example.
+
+commit 4a657ca3e26850a993c2015bbecd6287e817a615
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sat Aug 3 18:51:09 2019 -0700
+
+    [iterator.concept.sizedsentinel], [range.sized], [range.view]
+    Provide proper descriptions for disable_sized_sentinel,
+    disable_sized_range, and enable_view.
+
+commit 796c871f9b14a42fea634ec97a35032bfe3c422a
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Tue Jul 23 09:57:04 2019 +0200
+
+    [bit] Avoid std::numeric_limits<...>
+
+    Referring to numeric_limits (without std:: prefix) is sufficient.
+
+commit fb97956bc9eee5a50c10df9148d9422e260e352c
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Wed Jul 31 17:28:28 2019 -0700
+
+    [format.formatter] Add subclause heading to avoid hanging paragraphs.
+
+commit eae84a0a10b4409da01ae5c9e7c734e113973cdf
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Wed Jul 31 17:34:37 2019 -0700
+
+    [format.string] Clarify that "other characters" means "characters other
+    than { and }".
+
+commit b62dc39c0541a1968ac1717773574f4ef868934c
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Wed Jul 31 18:05:00 2019 -0700
+
+    [format.string] Change 'integer' grammar to be left-recursive and factor
+    out separate positive-integer and nonnegative-integer productions for
+    clarity.
+
+commit 2db4bd64f7f157266ae0f7c7c44c4fe7c68c6070
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Wed Jul 31 18:14:56 2019 -0700
+
+    [format.string] Fix wording that talks about omitting arg-ids but
+    presupposes that they are all present to instead specify what happens
+    when some or all are absent.
+
+commit 5a32fd1040b8a7c4c997ba8841c4f28a34a6c97d
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Wed Jul 31 18:26:41 2019 -0700
+
+    [format.string] Add missing grammar definition for custom-format-spec
+    rather than leaving it dangling.
+
+commit d529b96f3be22332d4a88de646f56cb636680f6c
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Wed Jul 31 18:33:05 2019 -0700
+
+    [format.string] Make tone of wording more formal and less tutorialesque.
+
+commit 3ced91d524f3c2a850243863440151735276b38a
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Wed Jul 31 18:41:56 2019 -0700
+
+    [format.context] Add specification of wformat_context analogous to that
+    of format_context, as discussed on lib reflector.
+
+commit ed00761315546c11b48441e1bcef6aa5927f76c8
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Thu Aug 1 18:17:10 2019 -0700
+
+    [format.string] Explicitly list all the possible formatting types for
+    bool and charT in their respective tables rather than requiring the
+    reader to infer how to merge the integer table into the bool and charT
+    tables.
+
+commit 46622695da52f8080f7280207eecd93bd950cc1a
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sat Aug 3 19:57:13 2019 -0700
+
+    [format.functions] Use clamp rather than min(max(a,b),c)
+
+    Co-Authored-By: Johel Ernesto Guerrero Peña <johelegp@gmail.com>
+
+commit a870403a2dc47924e7f607f7c69694291d43007c
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sat Aug 3 20:39:06 2019 -0700
+
+    [format.arg] Don't use placeholder name for private member char-type.
+
+commit d17fd4d5f10f6af87654fdc73bd6417313a295f2
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sun Aug 4 14:04:04 2019 -0700
+
+    [format.string] Avoid duplicating the specification of '#' for integers.
+
+    Fix the specification for '#' being different for octal integers in the
+    two places it's specified.
+
+commit e30b8a69d485b96ddacfa31b7eb411c5a64d83a5
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sun Aug 4 14:23:48 2019 -0700
+
+    [format.string] Separate out the general (type-independent) description
+    of formatting from the format specifiers for arithmetic and string
+    types, and make the presentation of the latter consistent with the
+    presentation for chrono types.
+
+commit f430bec8e7a4437b69d1ad31b2c1f4246e753770
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sun Aug 4 15:09:26 2019 -0700
+
+    [format.string.std] Convert normative duplication to a note to avoid
+    creating the impression that alignment is only applied to non-string
+    types.
+
+commit b6454e39ede7ab11ce0958fa2ee3b487c8983ae1
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sun Aug 4 15:32:02 2019 -0700
+
+    [format.string] Further clarify description of cases where formatting is
+    described in terms of a call to to_chars.
+
+commit 895f30bd225d050bcb2ab9f0a793af9865dcd513
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sun Aug 4 20:02:33 2019 -0700
+
+    [format.formatter] Reorder Formatter requirements before the
+    descriptions of specializations that meet those requirements.
+
+commit c7ada4d28ae7be82ef64104617e216fd738a4d0f
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Tue Jul 30 16:07:16 2019 +0200
+
+    [numbers] Use 'template<class T>', not 'typename'.
+
+commit 14aa4ed0d323c163f0559bd7c8555d77f2dc8093
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Tue Jul 30 16:12:59 2019 +0200
+
+    [math.constants] Expand 'math' to 'mathematical'.
+
+commit 3f761c76b5daf9f1a75695226514c323ba6619f0
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Aug 1 10:50:09 2019 +0200
+
+    [numbers.syn] Use 'namespace std::numbers'.
+
+commit dc61857d3779253c6cdeec572cdcb43077b0ce86
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sun Aug 4 20:51:47 2019 -0700
+
+    [atomics.lockfree] "are" -> "is"; "along with" is not a coordinating
+    conjunction.
+
+commit 3d3f16f99454d3ffffcfbf92a02b9bcaac9b375b
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sun Aug 4 21:50:27 2019 -0700
+
+    [thread.barrier.class] Rename constructor parameter from `phase_count`
+    to `expected`.
+
+    The parameter is not a phase count, and is referred to by other
+    normative wording as `expected`; also, `expected` is the name we use for
+    the same parameter in the constructor of `latch`.
+
+commit 2e82327045fb92d89dd1431cc7e771da63c982dc
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Aug 1 10:37:25 2019 +0200
+
+    [time.hms.members] Rephrased note.
+    [time.hms.overview] Removed redundant declaration of operator<<.
+    [time.hms.overview] Moved exposition-only data members to the bottom.
+
+commit 1a37c22bb6b621f14d01b4e16378c9cd08724183
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sun Aug 4 23:36:25 2019 -0700
+
+    [time.hms.nonmembers] Finish rebase on std::format: rewrite hh_mm_ss
+    operator<< in terms of format rather than using (removed) old formatting
+    terminology.
+
+commit 584a87ec1d48862b9e68a269d0a5eb7b05d6999d
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Mon Aug 5 13:57:50 2019 -0700
+
+    [time.hms.nonmembers] Fix editorial error in hh_mm_ss operator<< (only
+    stream to 'os' once). This formulation was proposed by Howard Hinnant
+    on the lib reflector.
+
+commit d243672db3269754d4ee91a5fbcdfb82ae6f2539
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Tue Jul 30 16:01:10 2019 +0200
+
+    Apply P1452R2 On the non-uniform semantics of return-type-requirements
+    to newly-introduced return type requirements.
+
+commit 90f64792ec7d5372a093d3bea69dffff2f7af28a
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Mon Aug 5 13:48:59 2019 -0700
+
+    Rename _s to -s in placeholder names per editorial guidelines.
+
+commit ad685c42b18103ace094b375a4fde1a7ec6aba02
+Author: Dawn Perchik <dperchik@embarcadero.com>
+Date:   Tue Jul 30 19:33:10 2019 -0700
+
+    [stringbuf] Name string parameters "s" instead of "str" for consistency and to avoid confusion with "str" methods.
+
+commit 26f7cd6d3b2d271c74e1d2022f972f833de940f6
+Author: Dawn Perchik <dperchik@embarcadero.com>
+Date:   Thu Aug 1 13:35:42 2019 -0700
+
+    [stringbuf.members] Minor fixes to P0408R7 wording.
+
+    "str()" should be "str"; we're talking about all str member functions here.
+    Add comma after "For efficiency reasons".
+    "i.e." -> "e.g." since we're describing an example case.
+
+commit b4a8b798e00bce697af9b477a214828b69e9e383
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Mon Aug 5 17:31:21 2019 -0700
+
+    [module.unit] Add "either" to clarify that we're talking about
+    module-names containing a reserved identifier, not module names starting
+    with an identifier that contains a reserved identifier.
+
+commit 906fd4d0519994e06659ce066c8252df186c23b9
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Mon Aug 5 17:57:35 2019 -0700
+
+    [func.require] Convert restrictive 'which' to 'that'.
+
+commit 7e862f0f238257b2cbb1f7296a593b4587029e39
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Mon Aug 5 18:46:55 2019 -0700
+
+    [range.transform.sentinel] Reinstate transform_view::sentinel::operator-
+    overloads, accidentally removed during application of P1614R2.
+
+commit e02aa79ca43de3fdf6e1887d4fd02bc58874e190
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Wed Jul 31 22:55:50 2019 +0200
+
+    [range.istream.view] Do not repeat declaration of function istream_view
+    [range.elements.iterator] Renamed from [range.elements_view.iterator]
+    [range.elements.iterator] Use local typedef difference_type
+    [range.elements.iterator] Use reference return type for compound assignment
+
+commit a0b5a70fade22203ebfbaeb4828e0c304b1f62ab
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Mon Aug 5 23:02:38 2019 -0700
+
+    [ranges] Fix 'constexpr friend' to our preferred order 'friend constexpr'.
+
+commit f0256ab73cd6a9fae611af95526d16fe59968d4c
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Mon Aug 5 23:08:59 2019 -0700
+
+    [range.drop.view] Fix typo "requirement" -> "required".
+
+commit 7698c3dc28251540b4a4733cc4a6b3f6942f13ed
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Tue Aug 6 00:40:47 2019 -0700
+
+    [range.iota.view] Rename IOTA_DIFF_T to the preferred IOTA-DIFF-T.
+
+commit cf1bc270c0e7d7b1670502c69268b0373bbf9799
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Tue Aug 6 01:35:47 2019 -0700
+
+    [thread] Update headings, comments, and line wrapping to match editorial
+    conventions.
+
+commit 7f4e95e3296b31c23bfb358f31294d384a955e3b
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Sat Aug 3 08:38:34 2019 +0200
+
+    [support.srcloc] Fix comments in example.
+
+commit 06ab7ebef8a763e36f87f504ed7765528aa25fc7
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Tue Aug 6 02:28:42 2019 -0700
+
+    [support.srcloc.cons] Use term "default member initialier" rather than
+    describing it indirectly.
+
+commit 7beed51f4388074f46fd55a7c5f559cd82b7c40c
+Author: Dawn Perchik <dperchik@embarcadero.com>
+Date:   Tue Jul 30 20:36:34 2019 -0700
+
+    [alg.is.permutation] Add parameters to \libconcept{sized_sentinel_for} as suggested in PR #3099.
+
+commit fbb0691134e39059adaa4a886e7d746b0e56c81c
+Author: Dawn Perchik <dperchik@embarcadero.com>
+Date:   Wed Jul 31 12:52:26 2019 -0700
+
+    [concepts] Renamed concepts' section names to remove trailing prepositions for consistency.
+
+    * concept.convertibleto => concept.convertible
+    * concept.derivedfrom => concept.derived
+    * concept.stricttotallyordered => concept.totallyordered
+
+commit e2a070f7a5484e272c10e4ab31359fede5ff24a1
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Tue Aug 6 13:51:24 2019 -0700
+
+    [diff.cpp17.library], [tab:headers.cpp] Add missing <coroutine> entry
+    to the list of headers, and add various missing entries to the list of
+    new-in-C++20 headers.
+
+    Fixes #3122.
+
+commit 54a87d7849e7d5283c2d0a34f8200ef6a67bb0da
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Tue Aug 6 23:17:24 2019 +0200
+
+    [conv.qual,expr.static.cast] Harmonize notes on cv-qualified function types.
+
+commit ee234abfbfa7deb5c585b67590205e1660df180f
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Aug 1 16:45:51 2019 +0200
+
+    [time.clock,bit.cast] Replace template<typename...> with template<class...>
+
+    as per library specification policy.
+
+commit a374c4f3664cf84a4440feb3c236076b25cfe736
+Author: languagelawyer <38548419+languagelawyer@users.noreply.github.com>
+Date:   Thu Jul 25 21:24:06 2019 +0200
+
+    [tuple] Use "objects" instead of "variables"
+    with "temporary" in the definition of `forward_as_tuple`
+
+commit 7e02aa3d7d3e5e9dfc2c66451e112d40f4491465
+Author: Jonathan Wakely <cxx@kayari.org>
+Date:   Mon Jul 22 23:27:57 2019 +0100
+
+    [is.sorted] Add missing "return" and semi-colon
+
+    This was lost when changing "Returns:" to "Effects:" for P0896R4. The
+    paper included this change, but it was lost when applying it.
+
+commit cc421307fb4ce393e7ab1dcf0d0f1298d163fbe0
+Author: Yehezkel Bernat <yehezkelshb@gmail.com>
+Date:   Sun Jul 21 22:16:23 2019 +0300
+
+    Delete irrelevant copy-paste from previous section
+
+commit d4c4cc0ac037c51ec10cf6f7c80d8c761b517cba
+Author: onihusube <44743040+onihusube@users.noreply.github.com>
+Date:   Wed Jul 17 22:46:24 2019 +0900
+
+    [basic.lookup.argdep]/5 add export to apply()
+
+    fix #2968
+
+commit 557cfa9dd706780fb672bfe9e5e2f0ef3b2f3d4a
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Jul 4 09:31:57 2019 +0200
+
+    [basic.life] Lifetime of class objects is treated uniformly
+    under CWG2256, regardless of triviality of the destructor.
+
+commit 4c3b9f50ecd230263974c81e1df2fb07b541c58d
+Author: onihusube <44743040+onihusube@users.noreply.github.com>
+Date:   Mon Jul 1 16:26:16 2019 +0900
+
+    [module.global] fix sample code comment
+
+commit 06bd4b02febcb43c014ffd46b7a07dab8d66aa4b
+Author: onihusube <44743040+onihusube@users.noreply.github.com>
+Date:   Mon Jul 1 16:41:33 2019 +0900
+
+    [cpp.module] fix sample code comment
+
+commit 1be069efaa41f4df376364290f8069ec030b13cc
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Jun 28 17:11:44 2019 +0200
+
+    [time.parse] Fix description of %Ex and %EX parse flags.
+
+    Also refer to the table number instead of 'the table below'.
+
+commit f038d86fb9112b62adaaebaf95dc70d786412cbd
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Fri Jun 28 16:50:03 2019 +0200
+
+    [res.on.functions] Properly capitalize full-sentence bullets.
+
+    Also add periods at the end of sentences.
+
+commit 43945886b4ff4481da3d29b3f624d55bc9b5d124
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Mon Jun 24 22:43:30 2019 +0200
+
+    [conv.qual] Fix example for cv-decomposition.
+
+    After CWG2051, a cv-decomposition can also be a no-op.
+
+commit 915031ddbf75f856efcea43928d9f459140834fd
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Tue Aug 6 09:31:52 2019 +0200
+
+    [meta.trans.other] Use hyphens, not underscores, for meta-functions.
+
+commit be443affbf06bfb14c2295311ed469896ae39d6c
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Wed Aug 7 17:59:27 2019 -0700
+
+    [range.drop.while.overview] Add missing space in example.
+
+commit 1e09011ff3627db60ae10fa8fee2e2f5ef7dc5c9
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sat Aug 10 18:13:55 2019 -0700
+
+    [format.string.general] indexes -> indices
+
+commit 71251ae592a49149faec1389ec85f22322aa0ba5
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sat Aug 10 18:23:43 2019 -0700
+
+    [format.string.std] Fix space collapse in example. Use commas rather
+    than spaces to separate fields to more clearly show where whitespace is
+    introduced by a field rather than between fields.
+
+commit ee719cb98574ade2c113a17a16e6af247913456b
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sat Aug 10 18:30:01 2019 -0700
+
+    [tab:format.type.float] Add "equivalent to" to remaining calls to
+    to_chars for consistency.
+
+commit add4ff3339153382b0e59d45e6bfeee4f923060a
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sat Aug 10 18:35:05 2019 -0700
+
+    [time.format] Fix some minor issues (comma rather than period, moving a
+    "Let" sentence out of a Remarks clause to a separate paragraph, using
+    'class' rather than 'typename').
+
+commit d4b47a09e9089bc661c4ad6bb882a46f4aae92b6
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sat Aug 10 18:38:26 2019 -0700
+
+    [time.syn] Fix specifier order in declarations to match library style.
+    Rename parameter 't' to 'hms' to make declaration and later description
+    match.
+
+commit 550553189899e1687629827dbb3fbf9c401f5d96
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sat Aug 10 18:40:49 2019 -0700
+
+    [range.istream.iterator] Fix 'parent_' to the obviously-intended 'parent'.
+
+commit 791a19a1d206c77b97e7725aa9a8ea779bf94d7a
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sat Aug 10 19:08:16 2019 -0700
+
+    [chrono], [iostreams], [support] Fix 'template <' and 'typename T' to
+    the conventional 'template<' and 'class T' throughout the library.
+
+commit ac72157b97d4b7b85ddb7ca412b5a4ee1806614d
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sat Aug 10 19:11:57 2019 -0700
+
+    [cmp.object] Add missing template-head to function description.
+
+commit b050fd474f11441942c88ef69b8622c8036656ac
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sat Aug 10 19:26:09 2019 -0700
+
+    [re.submatch.op] Fix inconsistency between declaration and description
+    of sub_match operator<=>: remove 'constexpr' from declaration, and
+    change return type in definition from 'bool' to 'auto'.
+
+commit 1335e42809151ecfdb671ea2aea1dab0c8d5db53
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sat Aug 10 19:33:48 2019 -0700
+
+    [iterator.concept.sizedsentinel] Avoid potential ambiguity between
+    inclusive and exclusive "or" by using "and/or".
+
+commit 1b2bfda98c20ecd71a35b7321662f8f976134793
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sat Aug 10 19:51:39 2019 -0700
+
+    [atomic] Remove invalid trailing 'const' from non-member function
+    atomic_flag_notify_all.
+
+commit afed449f0fa1324001260c9d658f6d05da90a9f9
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sat Aug 10 19:55:21 2019 -0700
+
+    [thread.sema.cnt] "Class" -> "Class template" in description of a class
+    template.
+
+commit 7445919de1bcf4780693b7870a245486839587ea
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sat Aug 10 19:58:05 2019 -0700
+
+    [thread.latch] Remove italics from non-definition of "latch".
+
+commit 224384ab43e4e9829eee5d97f09218850026d342
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Sat Aug 10 20:05:07 2019 -0700
+
+    [atomic] Consistently order atomic<...> and atomic_ref<...> definitions:
+    keep compare_exchange and fetch_* operations together because the latter
+    are a particular form of compare_exchange operation.
+
+commit 8644a2ce2faa6e979e224f069e4ca48238ea8570
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Mon Aug 12 16:47:06 2019 -0700
+
+    [atomics.syn], [atomics.flag] Clean up presentation around
+    ATOMIC_FLAG_INIT.
+
+     * Add some vertical whitespace in description of atomic_flag operations.
+     * Reorder ATOMIC_FLAG_INIT earlier in synopsis for consistency.
+     * Add proper item description for ATOMIC_FLAG_INIT.
+     * Remove repetition of declarations of atomic_flag non-member functions
+       and the ATOMIC_FLAG_INIT macro from [atomics.flag].
+
+commit 2c1ab9775cc53e848a1efff4f9976455538994d4
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Mon Aug 12 16:56:24 2019 -0700
+
+    [string.erasure] Following the guidance given by P0980R1, and after
+    consultation with LWG chair, mark the std::erase and std::erase_if
+    overloads for std::basic_string as constexpr in addition to those
+    explicitly called out by the wording paper.
+
+commit 009d46f9b057a635383dce8bbcad121c86f1d306
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Tue Aug 13 18:16:48 2019 -0700
+
+    [over.match.class.deduct] Replace "therefrom" with a more common
+    construction, and more directly talk about the class template for which
+    we are ultimately performing deduction.
+
+commit ac9189f351bf0407a31968199c22274ff41fe9e7
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Tue Aug 13 18:21:14 2019 -0700
+
+    [diff.cpp17.class] Remove redundant cross-reference.
+
+commit ba642aa699973f21613cbe3e6a0b6d9c1e0f2e6a
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Wed Aug 14 16:16:48 2019 -0700
+
+    [ostream] Add back the comments that P1423R3 requested, but now as a
+    note.
+
+commit 37ccff2c0e9be3a62fcd85b55e4d05c2b312335f
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Wed Aug 14 16:48:00 2019 -0700
+
+    [dcl.fct.def.default] Clarify that the rule concerning how the type of a
+    defaulted function can differ from the type of an implicitly-declared
+    function only applies to the functions that are implicitly declared.
+
+commit 42ee105f5804a74bb15960944ee7fe1cd4420e04
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Wed Aug 14 16:56:23 2019 -0700
+
+    [over.match.class.deduct] Clarify that an incomplete class type is never
+    treated as being an aggregate.
+
+commit fce4ac9764e10042bd8d0bb4152e83d697c8bdae
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Wed Aug 14 17:02:06 2019 -0700
+
+    [dcl.typedef] Split paragraph on typedef name for linkage into two parts
+    (how you know when you have one, and the restrictions on types that have
+    one).
+
+commit 90a29c08bc80091c093937a7d96ce28df5ceee44
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Wed Aug 14 17:21:15 2019 -0700
+
+    [conv.qual] Avoid bouncing back and forth between subscripts and regular
+    scripts for T1 and T2, and add missing definition for cv^j_i and P^j_i.
+
+commit 03bcd8d3e5ece969af846e23cd451549185fdac4
+Author: Jens Maurer <Jens.Maurer@gmx.net>
+Date:   Thu Aug 8 01:07:54 2019 +0200
+
+    [expr.ass] Remove mention of class types.
+
+commit 173905005c2c419548418239518db72bfda9dd9a
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Wed Aug 14 17:48:53 2019 -0700
+
+    [dcl.attr.nodiscard] Make the constructor case better parallel the
+    function case by duplicating the implied "through a reachable
+    declaration" wording.
+
+commit acbe5e429499d0eaf6c118f0bca4bbc26830bcaf
+Author: Davis Herring <herring@lanl.gov>
+Date:   Mon Aug 12 12:07:06 2019 -0600
+
+    [dcl.attr.nodiscard], [diff.cpp17.dcl.dcl] Fix grammar/usage
+
+commit 5aa019b19118973d99a2b2282d3f6264da81c9d8
+Author: Davis Herring <herring@lanl.gov>
+Date:   Mon Aug 12 12:13:20 2019 -0600
+
+    [basic.def.odr] Clean up new bullets
+
+commit eb443396ac48b4e2ac9c6be0d9ec6bf9dda107eb
+Author: Davis Herring <herring@lanl.gov>
+Date:   Mon Aug 12 12:27:41 2019 -0600
+
+    [module.reach], [over.ics.rank] Fix punctuation
+
+commit 37d2e59e8deb847f5ebdade20604bdf5c119649a
+Author: Davis Herring <herring@lanl.gov>
+Date:   Mon Aug 12 14:14:50 2019 -0600
+
+    [expr.ass] Improve preposition
+
+commit 4a0fd9aa43a0d63d6fe875b886cdea8ec24d7f9d
+Author: Davis Herring <herring@lanl.gov>
+Date:   Mon Aug 12 15:03:56 2019 -0600
+
+    [over.match.class.deduct] Supply missing word
+
+commit 05c786cc68bf14a828cc59f32d34fae2baf33794
+Author: Davis Herring <herring@lanl.gov>
+Date:   Tue Aug 13 00:49:41 2019 -0600
+
+    [expr.new] Use typical \iref
+
+commit fc1863291a3f62a684d9bffa51fdc2837e9edcd0
+Author: Davis Herring <herring@lanl.gov>
+Date:   Tue Aug 13 14:55:54 2019 -0600
+
+    [class.spaceship] Remove vacuous conversion
+
+    The synthesized three-way comparison always produces a value of type R
+
+commit 80f2c46251f07abf422cdd86a3f3d30c47fda587
+Author: Davis Herring <herring@lanl.gov>
+Date:   Tue Aug 13 14:59:46 2019 -0600
+
+    [over.match.class.deduct] Fix terminology
+
+    An element with a dependent type might not be a subaggregate
+    Add cross-reference
+
+commit bfa0e698359d44e8a2b0a056e13e908a8185e296
+Author: Davis Herring <herring@lanl.gov>
+Date:   Tue Aug 13 15:02:06 2019 -0600
+
+    [over.match.class.deduct] Use "deduces"
+
+    ...for consistency in example
+
+commit 174edca593a860440860f95c3ee61aa739e2afdc
+Author: Davis Herring <herring@lanl.gov>
+Date:   Tue Aug 13 23:41:02 2019 -0600
+
+    [over.match.class.deduct] Simplify example
+
+commit a9f901af95f16540444144a397fe3b598ae2961b
+Author: Richard Smith <richard@metafoo.co.uk>
+Date:   Wed Aug 14 17:51:44 2019 -0700
+
+    [class.dtor] "The defaulted destructor" -> "A defaulted destructor",
+    since the destructor for a class might not be defaulted.
+
diff --git a/papers/n4829.md b/papers/n4829.md new file mode 100644 index 0000000000..0fee37aa7b --- /dev/null +++ b/papers/n4829.md @@ -0,0 +1,1137 @@ +# N4829 Editors' Report -- Programming Languages -- C++ + +2019-08-15 +Richard Smith (editor) (Google Inc) +Thomas Köppe (co-editor) (Google DeepMind) +Jens Maurer (co-editor) +Dawn Perchik (co-editor) (Bright Side Computing, LLC) +`` + +## Acknowledgements + +Special thanks to several paper authors +for supplying the LaTeX sources for their papers. + +Special thanks also to the Editing Committee -- +Daniel Krügler, Davis Herring, Nina Ranns, and Ville Voutilainen -- +for providing a careful review of the application of these motions +and the editorial changes described below +to ensure the correctness of the C++20 Committee Draft. + +Thanks to all those who have [submitted editorial +issues](https://github.com/cplusplus/draft/wiki/How-to-submit-an-editorial-issue) +and to those who have provided pull requests with fixes. + +## New papers + + * [N4830](http://wg21.link/n4830) is the committee draft for C++20. It replaces [N4820](http://wg21.link/n4820). + * N4829 is this Editors' Report. + +**Note**: +A working draft was circulated to the editing committee for review, +and was mistakenly published with paper number N4828. +N4828 is not the C++20 Committee Draft, +and does not contain the results of addressing feedback from +the editing committee. + +## Motions incorporated into working draft + +### Core working group motions + +CWG motion 1: [Core issue resolutions](http://wg21.link/p1510r0) for 10 issues in "tentatively ready" status applied: **(DR)** + + * [682](http://wg21.link/cwg682) Missing description of lookup of template aliases + * [2207](http://wg21.link/cwg2207) Alignment of allocation function return value + * [2300](http://wg21.link/cwg2300) Lambdas in multiple definitions + * [2366](http://wg21.link/cwg2366) Can default initialization be constant initialization? + * [2376](http://wg21.link/cwg2376) Class template argument deduction with array declarator + * [2390](http://wg21.link/cwg2390) Is the argument of `__has_cpp_attribute` macro-expanded? + * [2400](http://wg21.link/cwg2400) Constexpr virtual functions and temporary objects + * [2404](http://wg21.link/cwg2404) `[[no_unique_address]]` and allocation order + * [2406](http://wg21.link/cwg2406) `[[fallthrough]]` attribute and iteration statements + * [2418](http://wg21.link/cwg2418) Missing cases in definition of "usable in constant expressions" + +CWG motion 2: [P1161R3 "Deprecate uses of the comma operator in subscripting expressions"](http://wg21.link/p1161r3) + +CWG motion 3: [P1331R2 "Permitting trivial default initialization in constexpr contexts"](http://wg21.link/p1331r2) + +CWG motion 4: [P0735R1 "Interaction of `memory_order_consume` with release sequences"](http://wg21.link/p0735r1) + +CWG motion 5: [P0848R3 "Conditionally trivial special member functions"](http://wg21.link/p0848r3) + +CWG motion 6: [P1186R3 "When do you actually use `<=>`?"](http://wg21.link/p1186r3) + +CWG motion 7: [P1301R4 "`[[nodiscard("should have a reason")]]`"](http://wg21.link/p1301r4) + +CWG motion 8: [P1099R5 "`using enum`"](http://wg21.link/p1099r5) + +CWG motion 9: [P1630R1 "Spaceship needs a tune-up"](http://wg21.link/p1630r1) + +CWG motion 10: [P1616R1 "Using unconstrained template template parameters with constrained templates"](http://wg21.link/p1616r1) + +CWG motion 11: [P1816R0 "Class template argument deduction for aggregates"](http://wg21.link/p1816r0) + +CWG motion 12: [P1668R1 "Enabling `constexpr` intrinsics by permitting unevaluated inline assembly in `constexpr` functions"](http://wg21.link/p1668r1) + +CWG motion 13: [P1766R1 "Mitigating minor modules maladies"](http://wg21.link/p1766r1) **(DR)** + +CWG motion 14: [P1811R0 "Relaxing redefinition restrictions for re-exportation robustness"](http://wg21.link/p1811r0) + +CWG motion 15: [P0388R4 "Permit conversions to arrays of unknown bound"](http://wg21.link/p0388r4) + +CWG motion 16: [P1823R0 "Remove contracts"](http://wg21.link/p1823r0) + +CWG motion 17: [P1143R2 "Adding the `constinit` keyword"](http://wg21.link/p1143r2) + +CWG motion 18: [P1452R2 "On the non-uniform semantics of *return-type-requirement*s"](http://wg21.link/p1452r2) + +CWG motion 19: [P1152R4 "Deprecating `volatile`"](http://wg21.link/p1152r4) + +CWG motion 20: [P1771R1 "`[[nodiscard]]` for constructors"](http://wg21.link/p1771r1) **(DR)** + +CWG motion 21: [P1814R0 "Class template argument deduction for alias templates"](http://wg21.link/p1814r0) + +CWG motion 22 was withdrawn + +CWG motion 23: [P1825R0 "Merged wording for P0527R1 and P1155R3"](http://wg21.link/p1825r0) **(DR)** + + * [P0527R1 "Implicitly move from rvalue references in return statements"](http://wg21.link/p0527r1) + * [P1155R3 "More implicit moves"](http://wg21.link/p1155r3) + +CWG motion 24: [P1703R1 "Recognizing header unit imports requires full preprocessing"](http://wg21.link/p1703r1) + +CWG motion 25: [P0784R7 "More `constexpr` containers"](http://wg21.link/p0784r7) + +### Library working group motions + +LWG motion 1: [Library issue resolutions](http://wg21.link/p1724r0) for 17 issues in "Ready" and "Tentatively Ready" status applied: **(DR)** + + * [3209](http://wg21.link/lwg3209) Expression in `year::ok()` returns clause is ill-formed + * [3208](http://wg21.link/lwg3208) `Boolean`'s expression requirements are ordered inconsistently + * [3206](http://wg21.link/lwg3206) `year_month_day` conversion to `sys_days` uses not-existing member function + * [3202](http://wg21.link/lwg3202) [P0318R1](http://wg21.link/p0318r1) was supposed to be revised + * [3199](http://wg21.link/lwg3199) `istream >> bitset<0>` fails + * [3198](http://wg21.link/lwg3198) Bad constraint on `std::span::span()` + * [3196](http://wg21.link/lwg3196) `std::optional` is ill-formed if `T` is an array + * [3191](http://wg21.link/lwg3191) `std::ranges::shuffle` synopsis does not match algorithm definition + * [3187](http://wg21.link/lwg3187) [P0591R4](http://wg21.link/p0591r4) reverted [DR 2586](http://wg21.link/lwg2586) fixes to `scoped_allocator_adaptor::construct()` + * [3186](http://wg21.link/lwg3186) Ranges `remove`, `partition`, and `partial_sort_copy` algorithms discard useful information + * [3185](http://wg21.link/lwg3185) Uses-allocator construction functions missing `constexpr` and `noexcept` + * [3184](http://wg21.link/lwg3184) Inconsistencies in `bind_front` wording + * [3183](http://wg21.link/lwg3183) Normative permission to specialize ranges variable templates + * [3169](http://wg21.link/lwg3169) Ranges permutation generators discard useful information + * [3158](http://wg21.link/lwg3158) `tuple(allocator_arg_t, const Alloc&)` should be conditionally explicit + * [3055](http://wg21.link/lwg3055) `path::operator+=(`single-character`)` misspecified + * [2899](http://wg21.link/lwg2899) `is_(nothrow_)move_constructible` and `tuple`, `optional` and `unique_ptr` + +LWG motion 2: [P1355R2 "Exposing a narrow contract for `ceil2`"](http://wg21.link/p1355r2) + +LWG motion 3: [P0553R4 "Bit operations"](http://wg21.link/p0553r4) + +LWG motion 4: [P1424R1 "`constexpr` feature macro concerns"](http://wg21.link/p1424r1) + +LWG motion 5: [P0645R10 "Text formatting"](http://wg21.link/p0645r10) + +LWG motion 6: [P1361R2 "Integration of chrono with text formatting"](http://wg21.link/p1361r2) + +LWG motion 7: [P1652R1 "Printf corner cases in `std::format`"](http://wg21.link/p1652r1) + +LWG motion 8: [P0631R8 "Math constants"](http://wg21.link/p0631r8) + +LWG motion 9: Synchronization library: + + * [P1135R6 "The C++20 synchronization library"](http://wg21.link/p1135r6) + * [P1643R1 "Add wait/notify to `atomic_ref`"](http://wg21.link/p1643r1) + * [P1644R0 "Add wait/notify to `atomic`"](http://wg21.link/p1644r0) + +LWG motion 10: [P1466R3 "Miscellaneous minor fixes for chrono"](http://wg21.link/p1466r3) + +LWG motion 11: [P1754R1 "Rename concepts to `standard_case` for C++20, while we still can"](http://wg21.link/p1754r1) + +LWG motion 12: [P1614R2 "The mothership has landed"](http://wg21.link/p1614r2) + +LWG motion 13: [P0325R4 "`to_array` from LFTS with updates"](http://wg21.link/p0325r4) + +LWG motion 14: [P0408R7 "Efficient access to `basic_stringbuf`'s buffer"](http://wg21.link/p0408r7) + +LWG motion 15: [P1423R3 "`char8_t` backward compatibility remediation"](http://wg21.link/p1423r3) + +LWG motion 16: [P1502R1 "Standard library header units"](http://wg21.link/p1502r1) + +LWG motion 17: [P1612R1 "Relocate `endian`'s specification"](http://wg21.link/p1612r1) + +LWG motion 18: [P1661R1 "Remove dedicated precalculated hash lookup interface"](http://wg21.link/p1661r1) + +LWG motion 19: [P1650R0 "Output `std::chrono::days` with `d` suffix"](http://wg21.link/p1650r0) + +LWG motion 20: [P1651R0 "`bind_front` should not unwrap `reference_wrapper`"](http://wg21.link/p1651r0) + +LWG motion 21: [P1065R2 "Constexpr `invoke`"](http://wg21.link/p1065r2) + +LWG motion 22: [P1207R4 "Movability of single-pass iterators"](http://wg21.link/p1207r4) + +LWG motion 23: [P1035R7 "Input range adaptors"](http://wg21.link/p1035r7) + +LWG motion 24: [P1638R1 "`basic_istream_view::iterator` should not be copyable"](http://wg21.link/p1638r1) + +LWG motion 25: [P1522R1 "Iterator difference type and integer overflow"](http://wg21.link/p1522r1) + +LWG motion 26: [P1004R2 "Making `std::vector` constexpr"](http://wg21.link/p1004r2) + +LWG motion 27: [P0980R1 "Making `std::string` constexpr"](http://wg21.link/p0980r1) + +LWG motion 28: [P0660R10 "Stop token and joining thread"](http://wg21.link/p0660r10) + +LWG motion 29: [P1474R1 "Helpful pointers for `ContiguousIterator`"](http://wg21.link/p1474r1) + +LWG motion 30: [P1523R1 "Views and size types"](http://wg21.link/p1523r1) + +LWG motion 31: [P0466R5 "Layout-compatibility and pointer-interconvertibility traits"](http://wg21.link/p0466r5) + +LWG motion 32: [P1208R6 "`source_location`"](http://wg21.link/p1208r6) + +## Notable editorial changes + +### CWG motion 21 + +The changes for this motion in [over.match.class.deduct] +described the matching of a *simple-template-id* against +the *defining-type-id* of an alias template +in imprecise terms +(quoting only part of the grammar to which the change intended to apply). +This has been made more precise by repeating the full grammar +previously specified in [dcl.type.simple] +in [over.match.class.deduct]. + +### LWG motions 5-7 + +The new `std::format` library underwent substantial editorial rework +for clarity and precision. +Thanks to Tomasz Kamiński and +Johel Ernesto Guerrero Peña +for reviewing the resulting edits, +and to Victor Zverovich for responding to various questions about intent. + +### LWG motion 10 + +The `operator<<` added for `hh_mm_ss` was written in terms of +the old chrono formatting machinery that was replaced by +`std::format`-based machinery by LWG motion 6. +It has been rephrased in terms of `std::format`. +Thanks to Howard Hinnant for providing wording. + +### LWG motion 11 + +In addition to the requested renames, the following concepts were also renamed, +following the editorial instructions to rename all other concepts: + + * `ThreeWayComparableWith` -> `three_way_comparable_with` + * `ThreeWayComparable` -> `three_way_comparable` + * `ForwardRange` -> `forward_range` + +### LWG motion 14 + +This motion requested that the same constructor be added to `basic_stringbuf` +twice. It was only added once. + +### LWG motion 23 + +The wording paper proposed making changes to the algorithms + + * `std::ranges::sample` + * `std::ranges::shift_left` + * `std::ranges::shift_right` + +However, these algorithms were never adopted into the C++ working draft from +the Ranges Technical Specification, so after consulting with the Library +Working Group, the requested changes to these algorithms were ignored. + +### LWG motion 26, 27 + +These motions would have added `constexpr` to +`operator<`, `operator>`, `operator<=`, `operator>=`, and `operator!=` functions +that LWG motion 12 removed. +Instead `constexpr` was added to the replacement `operator<=>`. + +In addition, following the paper's request to add `constexpr` to any +`std::basic_string` functions that the wording missed, and after consulting +with the LWG chair as directed, the overloads of `std::erase` and +`std::erase_if` for `std::basic_string` were also marked `contexpr`. + +### Section label changes + +Several section labels introduced by the motions papers have been modified +to match our style guide. In addition to the section labels affected by the +above motions, the following section labels have been renamed: + + * [concept.convertibleto] => [concept.convertible] + * [concept.derivedfrom] => [concept.derived] + * [concept.stricttotallyordered] => [concept.totallyordered] + +## Feature test macros + +Attention should be drawn to the fact that multiple papers updated feature test +macros to the same version: + + * `__cpp_constexpr` was updated to `201907L` by both + [P1331R2](http://wg21.link/p1331r2) (CWG motion 3) and + [P1668R1](http://wg21.link/p1668r1) (CWG motion 12). + * `__has_cpp_attribute(nodiscard)` was updated to `201907L` by both + [P1304R4](http://wg21.link/p1304r4) (CWG motion 7) and + [P1771R1](http://wg21.link/p1771r1) (CWG motion 20). + +Implementers should be aware that the new version of the feature test macro +advertises support for both papers in these cases (in addition to advertising +support for prior papers that gave smaller version numbers to the relevant +macro). + +## Minor editorial fixes + +A log of editorial fixes made to the working draft since N4820 is below. +This list excludes changes +that do not affect the body text or only affect whitespace or typeface. For a +complete list including such changes (or for the actual deltas applied by these +changes), consult the [draft sources on github](https://github.com/cplusplus/draft/compare/n4820...n4830). + + commit 44ea29778d15cd5d9f2b5c706c6b3f4338548ec2 + Author: Casey Carter + Date: Tue Jun 25 06:04:14 2019 -0700 + + [range.filter.sentinel] Correct typo in constructor Effects (#2937) + + commit 97b615a5a6ab0598b624ee05402c531d0421cff6 + Author: Casey Carter + Date: Tue Jun 25 06:09:55 2019 -0700 + + [iterator.synopsis] Copy constraint for iterator_traits from [iterator.traits]/5 (#2943) + + commit da7eac5e621b5fab12c0b1992100c4bfd983ed8e + Author: Saar Raz + Date: Mon Jul 1 22:46:37 2019 +0300 + + [Concepts] Remove qualified-concept-name reference + + Update 'qualified-concept-name' (the previous incarnation of 'type-constraint') reference to 'type-constraint' in [temp.over.link]p6. + + commit f54f306c3b9fad27e70766963840e3df14f20b28 + Author: Jens Maurer + Date: Thu Jul 4 15:34:38 2019 +0200 + + [func.bind] Remove bogus 'shall's. (#2955) + + commit 72cc844ef44ae47aebb1ad346146138d3279be9e + Author: Eelis + Date: Fri Jul 5 16:16:58 2019 +0200 + + [expr.reinterpret.cast] Properly capitalize full-sentence bullets. (#2956) + + commit c635711cdd81346ad41c7861adb8035176fa236f + Author: Eelis + Date: Fri Jul 5 23:55:22 2019 +0200 + + [temp.constr.constr] Add missing period at end of sentence. (#2957) + + commit 4f9942cafadc17fb902610b4c67afb6fcf81ff64 + Author: Jens Maurer + Date: Sun Jul 7 19:38:20 2019 +0200 + + [dcl.asm] Rename grammar term 'asm-definition' to 'asm-declaration' + + commit 51c5b01217799fdfa754179c20af888ec8c1889d + Author: Casey Carter + Date: Wed Jul 10 00:40:19 2019 -0700 + + [temp.constr.order] Remove extraneous "the". (#2964) + + commit 67db9422b6bc58f5399c7c019ec5ede28d8ac4f5 + Author: Jens Maurer + Date: Fri Jun 28 17:01:54 2019 +0200 + + [expr.prim.req] Fix cross-reference for substituting into constraints. + + commit 98c2c56ab5e945452586270d72d2fb606b71cd94 + Author: Richard Smith + Date: Mon Jul 22 02:24:42 2019 +0200 + + [class.prop] [special] Move definition of eligible special member + functions to the section on special member functions. + + commit 94a72b5c11a20cfd6c92a4faa5bd0df4b8ebc620 + Author: Richard Smith + Date: Mon Jul 22 02:28:15 2019 +0200 + + [class.dtor] Reorder the introduction of an implicit prospective + destructor to before we describe the overload resolution to pick the + actual destructor. + + commit 6bd3daeae3a3e9ae6174c35ab020dbfe4504b75b + Author: Richard Smith + Date: Thu Aug 1 20:04:36 2019 -0700 + + [class.ctor], [class.dtor] Introduce actual definitions for + "constructor" and "prospective destructor". + + commit dc45e8c329eeb0076d074fa671c2be2fc605555a + Author: Richard Smith + Date: Mon Jul 22 03:18:33 2019 +0200 + + [class.spaceship] Remove incorrect note. + + commit d6a291776858bc647fc6826888767284f305c799 + Author: Richard Smith + Date: Mon Jul 22 03:58:34 2019 +0200 + + [dcl.attr.nodiscard] Simplify note describing the string-literal in a + nodiscard attribute and make it less confusing. + + commit 46ba985402de963f50d364b26b594707be16c7c9 + Author: Richard Smith + Date: Mon Jul 22 04:42:43 2019 +0200 + + [dcl.enum] Avoid hanging paragraphs by moving "Enumeration declarations" + down one level to a sibling of "The using enum declaration". + + [namespace.udir] Rename section to "Using namespace directive" to + further distinguish this from a using enum declaration. + + commit 5d1bb1c7f8ed44016c38bfeb9797e363d52cfc51 + Author: Richard Smith + Date: Thu Aug 1 20:42:13 2019 -0700 + + [over.match.oper] Replace "member, non-member, and built-in candidates" + with "non-rewritten candidates" + + This simplifies the wording, implicitly explains why we're considering + only some candidates, and avoids overtly suggesting that we could ever + pick a reversed-parameter-order built-in candidate. + + commit 1fbc1c315008152770eea8bd383aa2a4fa47cfd5 + Author: Jens Maurer + Date: Fri Jul 26 16:56:13 2019 +0200 + + [basic.def.odr] Turn long comma-separate list into bullets. + + commit c0c589881759871b2183105f315d4ddd0d2734be + Author: Jens Maurer + Date: Thu Aug 1 22:47:19 2019 +0200 + + [expr.const.cast] Clarify pairwise correspondence for P_i. + [over.ics.rank] Move cross-reference pointing to [conv.qual]. + + commit 47539b965a84f69c548fe043a632af17db3cb315 + Author: Richard Smith + Date: Fri Aug 2 15:49:39 2019 -0700 + + [conv.qual] Move note after the rule that implies it. + + commit f10e3751b39138746b601fa702c9ed9e67777c96 + Author: Richard Smith + Date: Fri Aug 2 15:59:50 2019 -0700 + + [over.ics.rank] Reorder examples to match order of normative text. + + commit 813a4300a036f12d5ff6b82965b83a8e87b1ae8d + Author: Richard Smith + Date: Fri Aug 2 16:55:56 2019 -0700 + + [dcl.attr.nodiscard] Fix vexing-parse bug in example. Make sure the + missiles actually get launched, not merely redeclared. + + commit 6e845457bfd83f20c2f61bf4015afcd96cbd0cec + Author: Richard Smith + Date: Fri Aug 2 17:17:52 2019 -0700 + + [over.match.class.deduct] Fix failure to handle the case where a + deducible alias template's defining-type-id contains a + nested-name-specifier (or 'typename' or 'template' keywords). + + commit 7226ced32fe3cda28eb05f044985427684397128 + Author: Richard Smith + Date: Fri Aug 2 17:26:53 2019 -0700 + + [over.match.class.deduct] Switch from imperative to passive, and clarify + what happens if the various 'if' conditions are not met. + + commit 6552c03d3793e7532793097d760edc3a93e150b1 + Author: Richard Smith + Date: Fri Aug 2 17:32:40 2019 -0700 + + [over.match.class.deduct] Put all bullets describing the properties of + f' at the same depth, and guard them all by the condition that we're + actually adding an f' to the set of guides. + + commit b3b7d37c073051826c21c231bd386c10d64433dc + Author: Jens Maurer + Date: Fri Aug 2 22:09:14 2019 +0200 + + [class.copy.elision] Add cross-reference, fix example. + + commit 4a657ca3e26850a993c2015bbecd6287e817a615 + Author: Richard Smith + Date: Sat Aug 3 18:51:09 2019 -0700 + + [iterator.concept.sizedsentinel], [range.sized], [range.view] + Provide proper descriptions for disable_sized_sentinel, + disable_sized_range, and enable_view. + + commit 796c871f9b14a42fea634ec97a35032bfe3c422a + Author: Jens Maurer + Date: Tue Jul 23 09:57:04 2019 +0200 + + [bit] Avoid std::numeric_limits<...> + + Referring to numeric_limits (without std:: prefix) is sufficient. + + commit fb97956bc9eee5a50c10df9148d9422e260e352c + Author: Richard Smith + Date: Wed Jul 31 17:28:28 2019 -0700 + + [format.formatter] Add subclause heading to avoid hanging paragraphs. + + commit eae84a0a10b4409da01ae5c9e7c734e113973cdf + Author: Richard Smith + Date: Wed Jul 31 17:34:37 2019 -0700 + + [format.string] Clarify that "other characters" means "characters other + than { and }". + + commit b62dc39c0541a1968ac1717773574f4ef868934c + Author: Richard Smith + Date: Wed Jul 31 18:05:00 2019 -0700 + + [format.string] Change 'integer' grammar to be left-recursive and factor + out separate positive-integer and nonnegative-integer productions for + clarity. + + commit 2db4bd64f7f157266ae0f7c7c44c4fe7c68c6070 + Author: Richard Smith + Date: Wed Jul 31 18:14:56 2019 -0700 + + [format.string] Fix wording that talks about omitting arg-ids but + presupposes that they are all present to instead specify what happens + when some or all are absent. + + commit 5a32fd1040b8a7c4c997ba8841c4f28a34a6c97d + Author: Richard Smith + Date: Wed Jul 31 18:26:41 2019 -0700 + + [format.string] Add missing grammar definition for custom-format-spec + rather than leaving it dangling. + + commit d529b96f3be22332d4a88de646f56cb636680f6c + Author: Richard Smith + Date: Wed Jul 31 18:33:05 2019 -0700 + + [format.string] Make tone of wording more formal and less tutorialesque. + + commit 3ced91d524f3c2a850243863440151735276b38a + Author: Richard Smith + Date: Wed Jul 31 18:41:56 2019 -0700 + + [format.context] Add specification of wformat_context analogous to that + of format_context, as discussed on lib reflector. + + commit ed00761315546c11b48441e1bcef6aa5927f76c8 + Author: Richard Smith + Date: Thu Aug 1 18:17:10 2019 -0700 + + [format.string] Explicitly list all the possible formatting types for + bool and charT in their respective tables rather than requiring the + reader to infer how to merge the integer table into the bool and charT + tables. + + commit 46622695da52f8080f7280207eecd93bd950cc1a + Author: Richard Smith + Date: Sat Aug 3 19:57:13 2019 -0700 + + [format.functions] Use clamp rather than min(max(a,b),c) + + Co-Authored-By: Johel Ernesto Guerrero Peña + + commit a870403a2dc47924e7f607f7c69694291d43007c + Author: Richard Smith + Date: Sat Aug 3 20:39:06 2019 -0700 + + [format.arg] Don't use placeholder name for private member char-type. + + commit d17fd4d5f10f6af87654fdc73bd6417313a295f2 + Author: Richard Smith + Date: Sun Aug 4 14:04:04 2019 -0700 + + [format.string] Avoid duplicating the specification of '#' for integers. + + Fix the specification for '#' being different for octal integers in the + two places it's specified. + + commit e30b8a69d485b96ddacfa31b7eb411c5a64d83a5 + Author: Richard Smith + Date: Sun Aug 4 14:23:48 2019 -0700 + + [format.string] Separate out the general (type-independent) description + of formatting from the format specifiers for arithmetic and string + types, and make the presentation of the latter consistent with the + presentation for chrono types. + + commit f430bec8e7a4437b69d1ad31b2c1f4246e753770 + Author: Richard Smith + Date: Sun Aug 4 15:09:26 2019 -0700 + + [format.string.std] Convert normative duplication to a note to avoid + creating the impression that alignment is only applied to non-string + types. + + commit b6454e39ede7ab11ce0958fa2ee3b487c8983ae1 + Author: Richard Smith + Date: Sun Aug 4 15:32:02 2019 -0700 + + [format.string] Further clarify description of cases where formatting is + described in terms of a call to to_chars. + + commit 895f30bd225d050bcb2ab9f0a793af9865dcd513 + Author: Richard Smith + Date: Sun Aug 4 20:02:33 2019 -0700 + + [format.formatter] Reorder Formatter requirements before the + descriptions of specializations that meet those requirements. + + commit c7ada4d28ae7be82ef64104617e216fd738a4d0f + Author: Jens Maurer + Date: Tue Jul 30 16:07:16 2019 +0200 + + [numbers] Use 'template', not 'typename'. + + commit 14aa4ed0d323c163f0559bd7c8555d77f2dc8093 + Author: Jens Maurer + Date: Tue Jul 30 16:12:59 2019 +0200 + + [math.constants] Expand 'math' to 'mathematical'. + + commit 3f761c76b5daf9f1a75695226514c323ba6619f0 + Author: Jens Maurer + Date: Thu Aug 1 10:50:09 2019 +0200 + + [numbers.syn] Use 'namespace std::numbers'. + + commit dc61857d3779253c6cdeec572cdcb43077b0ce86 + Author: Richard Smith + Date: Sun Aug 4 20:51:47 2019 -0700 + + [atomics.lockfree] "are" -> "is"; "along with" is not a coordinating + conjunction. + + commit 3d3f16f99454d3ffffcfbf92a02b9bcaac9b375b + Author: Richard Smith + Date: Sun Aug 4 21:50:27 2019 -0700 + + [thread.barrier.class] Rename constructor parameter from `phase_count` + to `expected`. + + The parameter is not a phase count, and is referred to by other + normative wording as `expected`; also, `expected` is the name we use for + the same parameter in the constructor of `latch`. + + commit 2e82327045fb92d89dd1431cc7e771da63c982dc + Author: Jens Maurer + Date: Thu Aug 1 10:37:25 2019 +0200 + + [time.hms.members] Rephrased note. + [time.hms.overview] Removed redundant declaration of operator<<. + [time.hms.overview] Moved exposition-only data members to the bottom. + + commit 1a37c22bb6b621f14d01b4e16378c9cd08724183 + Author: Richard Smith + Date: Sun Aug 4 23:36:25 2019 -0700 + + [time.hms.nonmembers] Finish rebase on std::format: rewrite hh_mm_ss + operator<< in terms of format rather than using (removed) old formatting + terminology. + + commit 584a87ec1d48862b9e68a269d0a5eb7b05d6999d + Author: Richard Smith + Date: Mon Aug 5 13:57:50 2019 -0700 + + [time.hms.nonmembers] Fix editorial error in hh_mm_ss operator<< (only + stream to 'os' once). This formulation was proposed by Howard Hinnant + on the lib reflector. + + commit d243672db3269754d4ee91a5fbcdfb82ae6f2539 + Author: Jens Maurer + Date: Tue Jul 30 16:01:10 2019 +0200 + + Apply P1452R2 On the non-uniform semantics of return-type-requirements + to newly-introduced return type requirements. + + commit 90f64792ec7d5372a093d3bea69dffff2f7af28a + Author: Richard Smith + Date: Mon Aug 5 13:48:59 2019 -0700 + + Rename _s to -s in placeholder names per editorial guidelines. + + commit ad685c42b18103ace094b375a4fde1a7ec6aba02 + Author: Dawn Perchik + Date: Tue Jul 30 19:33:10 2019 -0700 + + [stringbuf] Name string parameters "s" instead of "str" for consistency and to avoid confusion with "str" methods. + + commit 26f7cd6d3b2d271c74e1d2022f972f833de940f6 + Author: Dawn Perchik + Date: Thu Aug 1 13:35:42 2019 -0700 + + [stringbuf.members] Minor fixes to P0408R7 wording. + + "str()" should be "str"; we're talking about all str member functions here. + Add comma after "For efficiency reasons". + "i.e." -> "e.g." since we're describing an example case. + + commit b4a8b798e00bce697af9b477a214828b69e9e383 + Author: Richard Smith + Date: Mon Aug 5 17:31:21 2019 -0700 + + [module.unit] Add "either" to clarify that we're talking about + module-names containing a reserved identifier, not module names starting + with an identifier that contains a reserved identifier. + + commit 906fd4d0519994e06659ce066c8252df186c23b9 + Author: Richard Smith + Date: Mon Aug 5 17:57:35 2019 -0700 + + [func.require] Convert restrictive 'which' to 'that'. + + commit 7e862f0f238257b2cbb1f7296a593b4587029e39 + Author: Richard Smith + Date: Mon Aug 5 18:46:55 2019 -0700 + + [range.transform.sentinel] Reinstate transform_view::sentinel::operator- + overloads, accidentally removed during application of P1614R2. + + commit e02aa79ca43de3fdf6e1887d4fd02bc58874e190 + Author: Jens Maurer + Date: Wed Jul 31 22:55:50 2019 +0200 + + [range.istream.view] Do not repeat declaration of function istream_view + [range.elements.iterator] Renamed from [range.elements_view.iterator] + [range.elements.iterator] Use local typedef difference_type + [range.elements.iterator] Use reference return type for compound assignment + + commit a0b5a70fade22203ebfbaeb4828e0c304b1f62ab + Author: Richard Smith + Date: Mon Aug 5 23:02:38 2019 -0700 + + [ranges] Fix 'constexpr friend' to our preferred order 'friend constexpr'. + + commit f0256ab73cd6a9fae611af95526d16fe59968d4c + Author: Richard Smith + Date: Mon Aug 5 23:08:59 2019 -0700 + + [range.drop.view] Fix typo "requirement" -> "required". + + commit 7698c3dc28251540b4a4733cc4a6b3f6942f13ed + Author: Richard Smith + Date: Tue Aug 6 00:40:47 2019 -0700 + + [range.iota.view] Rename IOTA_DIFF_T to the preferred IOTA-DIFF-T. + + commit cf1bc270c0e7d7b1670502c69268b0373bbf9799 + Author: Richard Smith + Date: Tue Aug 6 01:35:47 2019 -0700 + + [thread] Update headings, comments, and line wrapping to match editorial + conventions. + + commit 7f4e95e3296b31c23bfb358f31294d384a955e3b + Author: Jens Maurer + Date: Sat Aug 3 08:38:34 2019 +0200 + + [support.srcloc] Fix comments in example. + + commit 06ab7ebef8a763e36f87f504ed7765528aa25fc7 + Author: Richard Smith + Date: Tue Aug 6 02:28:42 2019 -0700 + + [support.srcloc.cons] Use term "default member initialier" rather than + describing it indirectly. + + commit 7beed51f4388074f46fd55a7c5f559cd82b7c40c + Author: Dawn Perchik + Date: Tue Jul 30 20:36:34 2019 -0700 + + [alg.is.permutation] Add parameters to \libconcept{sized_sentinel_for} as suggested in PR #3099. + + commit fbb0691134e39059adaa4a886e7d746b0e56c81c + Author: Dawn Perchik + Date: Wed Jul 31 12:52:26 2019 -0700 + + [concepts] Renamed concepts' section names to remove trailing prepositions for consistency. + + * concept.convertibleto => concept.convertible + * concept.derivedfrom => concept.derived + * concept.stricttotallyordered => concept.totallyordered + + commit e2a070f7a5484e272c10e4ab31359fede5ff24a1 + Author: Richard Smith + Date: Tue Aug 6 13:51:24 2019 -0700 + + [diff.cpp17.library], [tab:headers.cpp] Add missing entry + to the list of headers, and add various missing entries to the list of + new-in-C++20 headers. + + Fixes #3122. + + commit 54a87d7849e7d5283c2d0a34f8200ef6a67bb0da + Author: Jens Maurer + Date: Tue Aug 6 23:17:24 2019 +0200 + + [conv.qual,expr.static.cast] Harmonize notes on cv-qualified function types. + + commit ee234abfbfa7deb5c585b67590205e1660df180f + Author: Jens Maurer + Date: Thu Aug 1 16:45:51 2019 +0200 + + [time.clock,bit.cast] Replace template with template + + as per library specification policy. + + commit a374c4f3664cf84a4440feb3c236076b25cfe736 + Author: languagelawyer <38548419+languagelawyer@users.noreply.github.com> + Date: Thu Jul 25 21:24:06 2019 +0200 + + [tuple] Use "objects" instead of "variables" + with "temporary" in the definition of `forward_as_tuple` + + commit 7e02aa3d7d3e5e9dfc2c66451e112d40f4491465 + Author: Jonathan Wakely + Date: Mon Jul 22 23:27:57 2019 +0100 + + [is.sorted] Add missing "return" and semi-colon + + This was lost when changing "Returns:" to "Effects:" for P0896R4. The + paper included this change, but it was lost when applying it. + + commit cc421307fb4ce393e7ab1dcf0d0f1298d163fbe0 + Author: Yehezkel Bernat + Date: Sun Jul 21 22:16:23 2019 +0300 + + Delete irrelevant copy-paste from previous section + + commit d4c4cc0ac037c51ec10cf6f7c80d8c761b517cba + Author: onihusube <44743040+onihusube@users.noreply.github.com> + Date: Wed Jul 17 22:46:24 2019 +0900 + + [basic.lookup.argdep]/5 add export to apply() + + fix #2968 + + commit 557cfa9dd706780fb672bfe9e5e2f0ef3b2f3d4a + Author: Jens Maurer + Date: Thu Jul 4 09:31:57 2019 +0200 + + [basic.life] Lifetime of class objects is treated uniformly + under CWG2256, regardless of triviality of the destructor. + + commit 4c3b9f50ecd230263974c81e1df2fb07b541c58d + Author: onihusube <44743040+onihusube@users.noreply.github.com> + Date: Mon Jul 1 16:26:16 2019 +0900 + + [module.global] fix sample code comment + + commit 06bd4b02febcb43c014ffd46b7a07dab8d66aa4b + Author: onihusube <44743040+onihusube@users.noreply.github.com> + Date: Mon Jul 1 16:41:33 2019 +0900 + + [cpp.module] fix sample code comment + + commit 1be069efaa41f4df376364290f8069ec030b13cc + Author: Jens Maurer + Date: Fri Jun 28 17:11:44 2019 +0200 + + [time.parse] Fix description of %Ex and %EX parse flags. + + Also refer to the table number instead of 'the table below'. + + commit f038d86fb9112b62adaaebaf95dc70d786412cbd + Author: Jens Maurer + Date: Fri Jun 28 16:50:03 2019 +0200 + + [res.on.functions] Properly capitalize full-sentence bullets. + + Also add periods at the end of sentences. + + commit 43945886b4ff4481da3d29b3f624d55bc9b5d124 + Author: Jens Maurer + Date: Mon Jun 24 22:43:30 2019 +0200 + + [conv.qual] Fix example for cv-decomposition. + + After CWG2051, a cv-decomposition can also be a no-op. + + commit 915031ddbf75f856efcea43928d9f459140834fd + Author: Jens Maurer + Date: Tue Aug 6 09:31:52 2019 +0200 + + [meta.trans.other] Use hyphens, not underscores, for meta-functions. + + commit be443affbf06bfb14c2295311ed469896ae39d6c + Author: Richard Smith + Date: Wed Aug 7 17:59:27 2019 -0700 + + [range.drop.while.overview] Add missing space in example. + + commit 1e09011ff3627db60ae10fa8fee2e2f5ef7dc5c9 + Author: Richard Smith + Date: Sat Aug 10 18:13:55 2019 -0700 + + [format.string.general] indexes -> indices + + commit 71251ae592a49149faec1389ec85f22322aa0ba5 + Author: Richard Smith + Date: Sat Aug 10 18:23:43 2019 -0700 + + [format.string.std] Fix space collapse in example. Use commas rather + than spaces to separate fields to more clearly show where whitespace is + introduced by a field rather than between fields. + + commit ee719cb98574ade2c113a17a16e6af247913456b + Author: Richard Smith + Date: Sat Aug 10 18:30:01 2019 -0700 + + [tab:format.type.float] Add "equivalent to" to remaining calls to + to_chars for consistency. + + commit add4ff3339153382b0e59d45e6bfeee4f923060a + Author: Richard Smith + Date: Sat Aug 10 18:35:05 2019 -0700 + + [time.format] Fix some minor issues (comma rather than period, moving a + "Let" sentence out of a Remarks clause to a separate paragraph, using + 'class' rather than 'typename'). + + commit d4b47a09e9089bc661c4ad6bb882a46f4aae92b6 + Author: Richard Smith + Date: Sat Aug 10 18:38:26 2019 -0700 + + [time.syn] Fix specifier order in declarations to match library style. + Rename parameter 't' to 'hms' to make declaration and later description + match. + + commit 550553189899e1687629827dbb3fbf9c401f5d96 + Author: Richard Smith + Date: Sat Aug 10 18:40:49 2019 -0700 + + [range.istream.iterator] Fix 'parent_' to the obviously-intended 'parent'. + + commit 791a19a1d206c77b97e7725aa9a8ea779bf94d7a + Author: Richard Smith + Date: Sat Aug 10 19:08:16 2019 -0700 + + [chrono], [iostreams], [support] Fix 'template <' and 'typename T' to + the conventional 'template<' and 'class T' throughout the library. + + commit ac72157b97d4b7b85ddb7ca412b5a4ee1806614d + Author: Richard Smith + Date: Sat Aug 10 19:11:57 2019 -0700 + + [cmp.object] Add missing template-head to function description. + + commit b050fd474f11441942c88ef69b8622c8036656ac + Author: Richard Smith + Date: Sat Aug 10 19:26:09 2019 -0700 + + [re.submatch.op] Fix inconsistency between declaration and description + of sub_match operator<=>: remove 'constexpr' from declaration, and + change return type in definition from 'bool' to 'auto'. + + commit 1335e42809151ecfdb671ea2aea1dab0c8d5db53 + Author: Richard Smith + Date: Sat Aug 10 19:33:48 2019 -0700 + + [iterator.concept.sizedsentinel] Avoid potential ambiguity between + inclusive and exclusive "or" by using "and/or". + + commit 1b2bfda98c20ecd71a35b7321662f8f976134793 + Author: Richard Smith + Date: Sat Aug 10 19:51:39 2019 -0700 + + [atomic] Remove invalid trailing 'const' from non-member function + atomic_flag_notify_all. + + commit afed449f0fa1324001260c9d658f6d05da90a9f9 + Author: Richard Smith + Date: Sat Aug 10 19:55:21 2019 -0700 + + [thread.sema.cnt] "Class" -> "Class template" in description of a class + template. + + commit 7445919de1bcf4780693b7870a245486839587ea + Author: Richard Smith + Date: Sat Aug 10 19:58:05 2019 -0700 + + [thread.latch] Remove italics from non-definition of "latch". + + commit 224384ab43e4e9829eee5d97f09218850026d342 + Author: Richard Smith + Date: Sat Aug 10 20:05:07 2019 -0700 + + [atomic] Consistently order atomic<...> and atomic_ref<...> definitions: + keep compare_exchange and fetch_* operations together because the latter + are a particular form of compare_exchange operation. + + commit 8644a2ce2faa6e979e224f069e4ca48238ea8570 + Author: Richard Smith + Date: Mon Aug 12 16:47:06 2019 -0700 + + [atomics.syn], [atomics.flag] Clean up presentation around + ATOMIC_FLAG_INIT. + + * Add some vertical whitespace in description of atomic_flag operations. + * Reorder ATOMIC_FLAG_INIT earlier in synopsis for consistency. + * Add proper item description for ATOMIC_FLAG_INIT. + * Remove repetition of declarations of atomic_flag non-member functions + and the ATOMIC_FLAG_INIT macro from [atomics.flag]. + + commit 2c1ab9775cc53e848a1efff4f9976455538994d4 + Author: Richard Smith + Date: Mon Aug 12 16:56:24 2019 -0700 + + [string.erasure] Following the guidance given by P0980R1, and after + consultation with LWG chair, mark the std::erase and std::erase_if + overloads for std::basic_string as constexpr in addition to those + explicitly called out by the wording paper. + + commit 009d46f9b057a635383dce8bbcad121c86f1d306 + Author: Richard Smith + Date: Tue Aug 13 18:16:48 2019 -0700 + + [over.match.class.deduct] Replace "therefrom" with a more common + construction, and more directly talk about the class template for which + we are ultimately performing deduction. + + commit ac9189f351bf0407a31968199c22274ff41fe9e7 + Author: Richard Smith + Date: Tue Aug 13 18:21:14 2019 -0700 + + [diff.cpp17.class] Remove redundant cross-reference. + + commit ba642aa699973f21613cbe3e6a0b6d9c1e0f2e6a + Author: Richard Smith + Date: Wed Aug 14 16:16:48 2019 -0700 + + [ostream] Add back the comments that P1423R3 requested, but now as a + note. + + commit 37ccff2c0e9be3a62fcd85b55e4d05c2b312335f + Author: Richard Smith + Date: Wed Aug 14 16:48:00 2019 -0700 + + [dcl.fct.def.default] Clarify that the rule concerning how the type of a + defaulted function can differ from the type of an implicitly-declared + function only applies to the functions that are implicitly declared. + + commit 42ee105f5804a74bb15960944ee7fe1cd4420e04 + Author: Richard Smith + Date: Wed Aug 14 16:56:23 2019 -0700 + + [over.match.class.deduct] Clarify that an incomplete class type is never + treated as being an aggregate. + + commit fce4ac9764e10042bd8d0bb4152e83d697c8bdae + Author: Richard Smith + Date: Wed Aug 14 17:02:06 2019 -0700 + + [dcl.typedef] Split paragraph on typedef name for linkage into two parts + (how you know when you have one, and the restrictions on types that have + one). + + commit 90a29c08bc80091c093937a7d96ce28df5ceee44 + Author: Richard Smith + Date: Wed Aug 14 17:21:15 2019 -0700 + + [conv.qual] Avoid bouncing back and forth between subscripts and regular + scripts for T1 and T2, and add missing definition for cv^j_i and P^j_i. + + commit 03bcd8d3e5ece969af846e23cd451549185fdac4 + Author: Jens Maurer + Date: Thu Aug 8 01:07:54 2019 +0200 + + [expr.ass] Remove mention of class types. + + commit 173905005c2c419548418239518db72bfda9dd9a + Author: Richard Smith + Date: Wed Aug 14 17:48:53 2019 -0700 + + [dcl.attr.nodiscard] Make the constructor case better parallel the + function case by duplicating the implied "through a reachable + declaration" wording. + + commit acbe5e429499d0eaf6c118f0bca4bbc26830bcaf + Author: Davis Herring + Date: Mon Aug 12 12:07:06 2019 -0600 + + [dcl.attr.nodiscard], [diff.cpp17.dcl.dcl] Fix grammar/usage + + commit 5aa019b19118973d99a2b2282d3f6264da81c9d8 + Author: Davis Herring + Date: Mon Aug 12 12:13:20 2019 -0600 + + [basic.def.odr] Clean up new bullets + + commit eb443396ac48b4e2ac9c6be0d9ec6bf9dda107eb + Author: Davis Herring + Date: Mon Aug 12 12:27:41 2019 -0600 + + [module.reach], [over.ics.rank] Fix punctuation + + commit 37d2e59e8deb847f5ebdade20604bdf5c119649a + Author: Davis Herring + Date: Mon Aug 12 14:14:50 2019 -0600 + + [expr.ass] Improve preposition + + commit 4a0fd9aa43a0d63d6fe875b886cdea8ec24d7f9d + Author: Davis Herring + Date: Mon Aug 12 15:03:56 2019 -0600 + + [over.match.class.deduct] Supply missing word + + commit 05c786cc68bf14a828cc59f32d34fae2baf33794 + Author: Davis Herring + Date: Tue Aug 13 00:49:41 2019 -0600 + + [expr.new] Use typical \iref + + commit fc1863291a3f62a684d9bffa51fdc2837e9edcd0 + Author: Davis Herring + Date: Tue Aug 13 14:55:54 2019 -0600 + + [class.spaceship] Remove vacuous conversion + + The synthesized three-way comparison always produces a value of type R + + commit 80f2c46251f07abf422cdd86a3f3d30c47fda587 + Author: Davis Herring + Date: Tue Aug 13 14:59:46 2019 -0600 + + [over.match.class.deduct] Fix terminology + + An element with a dependent type might not be a subaggregate + Add cross-reference + + commit bfa0e698359d44e8a2b0a056e13e908a8185e296 + Author: Davis Herring + Date: Tue Aug 13 15:02:06 2019 -0600 + + [over.match.class.deduct] Use "deduces" + + ...for consistency in example + + commit 174edca593a860440860f95c3ee61aa739e2afdc + Author: Davis Herring + Date: Tue Aug 13 23:41:02 2019 -0600 + + [over.match.class.deduct] Simplify example + + commit a9f901af95f16540444144a397fe3b598ae2961b + Author: Richard Smith + Date: Wed Aug 14 17:51:44 2019 -0700 + + [class.dtor] "The defaulted destructor" -> "A defaulted destructor", + since the destructor for a class might not be defaulted. diff --git a/papers/n4830.pdf b/papers/n4830.pdf new file mode 100644 index 0000000000..9342aa6d06 Binary files /dev/null and b/papers/n4830.pdf differ diff --git a/source/algorithms.tex b/source/algorithms.tex index f68441ae72..c2518033ec 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -242,9 +242,9 @@ \tcode{ranges::next(i, s)}. \pnum -Overloads of algorithms that take \libconcept{Range} arguments\iref{range.range} +Overloads of algorithms that take \libconcept{range} arguments\iref{range.range} behave as if they are implemented by calling \tcode{ranges::begin} and -\tcode{ranges::end} on the \libconcept{Range}(s) and +\tcode{ranges::end} on the \libconcept{range}(s) and dispatching to the overload in namespace \tcode{ranges} that takes separate iterator and sentinel arguments. @@ -262,6 +262,7 @@ \tcode{for_each_result}, \tcode{minmax_result}, \tcode{mismatch_result}, +\tcode{next_permutation_result}, \tcode{copy_result}, and \tcode{partition_copy_result} have the template parameters, data members, and special members specified below. @@ -438,6 +439,7 @@ in a thread of execution implicitly created by the library to support parallel algorithm execution. If the threads of execution created by \tcode{thread}\iref{thread.thread.class} +or \tcode{jthread}\iref{thread.jthread.class} provide concurrent forward progress guarantees\iref{intro.progress}, then a thread of execution implicitly created by the library will provide parallel forward progress guarantees; @@ -617,11 +619,11 @@ ForwardIterator first, ForwardIterator last, Predicate pred); namespace ranges { - template S, class Proj = identity, - IndirectUnaryPredicate> Pred> + template S, class Proj = identity, + indirect_unary_predicate> Pred> constexpr bool all_of(I first, S last, Pred pred, Proj proj = {}); - template, Proj>> Pred> + template, Proj>> Pred> constexpr bool all_of(R&& r, Pred pred, Proj proj = {}); } @@ -633,11 +635,11 @@ ForwardIterator first, ForwardIterator last, Predicate pred); namespace ranges { - template S, class Proj = identity, - IndirectUnaryPredicate> Pred> + template S, class Proj = identity, + indirect_unary_predicate> Pred> constexpr bool any_of(I first, S last, Pred pred, Proj proj = {}); - template, Proj>> Pred> + template, Proj>> Pred> constexpr bool any_of(R&& r, Pred pred, Proj proj = {}); } @@ -649,11 +651,11 @@ ForwardIterator first, ForwardIterator last, Predicate pred); namespace ranges { - template S, class Proj = identity, - IndirectUnaryPredicate> Pred> + template S, class Proj = identity, + indirect_unary_predicate> Pred> constexpr bool none_of(I first, S last, Pred pred, Proj proj = {}); - template, Proj>> Pred> + template, Proj>> Pred> constexpr bool none_of(R&& r, Pred pred, Proj proj = {}); } @@ -671,24 +673,24 @@ [[no_unique_address]] F fun; template - requires ConvertibleTo && ConvertibleTo + requires convertible_to && convertible_to operator for_each_result() const & { return {in, fun}; } template - requires ConvertibleTo && ConvertibleTo + requires convertible_to && convertible_to operator for_each_result() && { return {std::move(in), std::move(fun)}; } }; - template S, class Proj = identity, - IndirectUnaryInvocable> Fun> + template S, class Proj = identity, + indirectly_unary_invocable> Fun> constexpr for_each_result for_each(I first, S last, Fun f, Proj proj = {}); - template, Proj>> Fun> + template, Proj>> Fun> constexpr for_each_result, Fun> for_each(R&& r, Fun f, Proj proj = {}); } @@ -723,25 +725,25 @@ Predicate pred); namespace ranges { - template S, class T, class Proj = identity> - requires IndirectRelation, const T*> + template S, class T, class Proj = identity> + requires indirect_relation, const T*> constexpr I find(I first, S last, const T& value, Proj proj = {}); - template - requires IndirectRelation, Proj>, const T*> + template + requires indirect_relation, Proj>, const T*> constexpr safe_iterator_t find(R&& r, const T& value, Proj proj = {}); - template S, class Proj = identity, - IndirectUnaryPredicate> Pred> + template S, class Proj = identity, + indirect_unary_predicate> Pred> constexpr I find_if(I first, S last, Pred pred, Proj proj = {}); - template, Proj>> Pred> + template, Proj>> Pred> constexpr safe_iterator_t find_if(R&& r, Pred pred, Proj proj = {}); - template S, class Proj = identity, - IndirectUnaryPredicate> Pred> + template S, class Proj = identity, + indirect_unary_predicate> Pred> constexpr I find_if_not(I first, S last, Pred pred, Proj proj = {}); - template, Proj>> Pred> + template, Proj>> Pred> constexpr safe_iterator_t find_if_not(R&& r, Pred pred, Proj proj = {}); } @@ -770,15 +772,15 @@ BinaryPredicate pred); namespace ranges { - template S1, ForwardIterator I2, Sentinel S2, + template S1, forward_iterator I2, sentinel_for S2, class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> - requires IndirectlyComparable + requires indirectly_comparable constexpr subrange find_end(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); - template - requires IndirectlyComparable, iterator_t, Pred, Proj1, Proj2> + requires indirectly_comparable, iterator_t, Pred, Proj1, Proj2> constexpr safe_subrange_t find_end(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -808,16 +810,16 @@ BinaryPredicate pred); namespace ranges { - template S1, ForwardIterator I2, Sentinel S2, + template S1, forward_iterator I2, sentinel_for S2, class Proj1 = identity, class Proj2 = identity, - IndirectRelation, - projected> Pred = ranges::equal_to> + indirect_relation, + projected> Pred = ranges::equal_to> constexpr I1 find_first_of(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); - template, Proj1>, - projected, Proj2>> Pred = ranges::equal_to> + template, Proj1>, + projected, Proj2>> Pred = ranges::equal_to> constexpr safe_iterator_t find_first_of(R1&& r1, R2&& r2, Pred pred = {}, @@ -843,12 +845,12 @@ BinaryPredicate pred); namespace ranges { - template S, class Proj = identity, - IndirectRelation> Pred = ranges::equal_to> + template S, class Proj = identity, + indirect_relation> Pred = ranges::equal_to> constexpr I adjacent_find(I first, S last, Pred pred = {}, Proj proj = {}); - template, Proj>> Pred = ranges::equal_to> + template, Proj>> Pred = ranges::equal_to> constexpr safe_iterator_t adjacent_find(R&& r, Pred pred = {}, Proj proj = {}); } @@ -870,21 +872,21 @@ ForwardIterator first, ForwardIterator last, Predicate pred); namespace ranges { - template S, class T, class Proj = identity> - requires IndirectRelation, const T*> + template S, class T, class Proj = identity> + requires indirect_relation, const T*> constexpr iter_difference_t count(I first, S last, const T& value, Proj proj = {}); - template - requires IndirectRelation, Proj>, const T*> - constexpr iter_difference_t> + template + requires indirect_relation, Proj>, const T*> + constexpr range_difference_t count(R&& r, const T& value, Proj proj = {}); - template S, class Proj = identity, - IndirectUnaryPredicate> Pred> + template S, class Proj = identity, + indirect_unary_predicate> Pred> constexpr iter_difference_t count_if(I first, S last, Pred pred, Proj proj = {}); - template, Proj>> Pred> - constexpr iter_difference_t> + template, Proj>> Pred> + constexpr range_difference_t count_if(R&& r, Pred pred, Proj proj = {}); } @@ -937,29 +939,29 @@ [[no_unique_address]] I2 in2; template - requires ConvertibleTo && ConvertibleTo + requires convertible_to && convertible_to operator mismatch_result() const & { return {in1, in2}; } template - requires ConvertibleTo && ConvertibleTo + requires convertible_to && convertible_to operator mismatch_result() && { return {std::move(in1), std::move(in2)}; } }; - template S1, InputIterator I2, Sentinel S2, + template S1, input_iterator I2, sentinel_for S2, class Proj1 = identity, class Proj2 = identity, - IndirectRelation, - projected> Pred = ranges::equal_to> + indirect_relation, + projected> Pred = ranges::equal_to> constexpr mismatch_result mismatch(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); - template, Proj1>, - projected, Proj2>> Pred = ranges::equal_to> + indirect_relation, Proj1>, + projected, Proj2>> Pred = ranges::equal_to> constexpr mismatch_result, safe_iterator_t> mismatch(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -1000,15 +1002,15 @@ BinaryPredicate pred); namespace ranges { - template S1, InputIterator I2, Sentinel S2, + template S1, input_iterator I2, sentinel_for S2, class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> - requires IndirectlyComparable + requires indirectly_comparable constexpr bool equal(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); - template - requires IndirectlyComparable, iterator_t, Pred, Proj1, Proj2> + requires indirectly_comparable, iterator_t, Pred, Proj1, Proj2> constexpr bool equal(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); } @@ -1029,16 +1031,16 @@ BinaryPredicate pred); namespace ranges { - template S1, ForwardIterator I2, - Sentinel S2, class Pred = ranges::equal_to, class Proj1 = identity, + template S1, forward_iterator I2, + sentinel_for S2, class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> - requires IndirectlyComparable + requires indirectly_comparable constexpr bool is_permutation(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); - template - requires IndirectlyComparable, iterator_t, Pred, Proj1, Proj2> + requires indirectly_comparable, iterator_t, Pred, Proj1, Proj2> constexpr bool is_permutation(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); } @@ -1067,16 +1069,16 @@ BinaryPredicate pred); namespace ranges { - template S1, ForwardIterator I2, - Sentinel S2, class Pred = ranges::equal_to, + template S1, forward_iterator I2, + sentinel_for S2, class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> - requires IndirectlyComparable + requires indirectly_comparable constexpr subrange search(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); - template - requires IndirectlyComparable, iterator_t, Pred, Proj1, Proj2> + requires indirectly_comparable, iterator_t, Pred, Proj1, Proj2> constexpr safe_subrange_t search(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -1105,17 +1107,17 @@ BinaryPredicate pred); namespace ranges { - template S, class T, + template S, class T, class Pred = ranges::equal_to, class Proj = identity> - requires IndirectlyComparable + requires indirectly_comparable constexpr subrange search_n(I first, S last, iter_difference_t count, const T& value, Pred pred = {}, Proj proj = {}); - template - requires IndirectlyComparable, const T*, Pred, Proj> + requires indirectly_comparable, const T*, Pred, Proj> constexpr safe_subrange_t - search_n(R&& r, iter_difference_t> count, + search_n(R&& r, range_difference_t count, const T& value, Pred pred = {}, Proj proj = {}); } @@ -1140,24 +1142,24 @@ [[no_unique_address]] O out; template - requires ConvertibleTo && ConvertibleTo + requires convertible_to && convertible_to operator copy_result() const & { return {in, out}; } template - requires ConvertibleTo && ConvertibleTo + requires convertible_to && convertible_to operator copy_result() && { return {std::move(in), std::move(out)}; } }; - template S, WeaklyIncrementable O> - requires IndirectlyCopyable + template S, weakly_incrementable O> + requires indirectly_copyable constexpr copy_result copy(I first, S last, O result); - template - requires IndirectlyCopyable, O> + template + requires indirectly_copyable, O> constexpr copy_result, O> copy(R&& r, O result); } @@ -1175,8 +1177,8 @@ template using copy_n_result = copy_result; - template - requires IndirectlyCopyable + template + requires indirectly_copyable constexpr copy_n_result copy_n(I first, iter_difference_t n, O result); } @@ -1194,14 +1196,14 @@ template using copy_if_result = copy_result; - template S, WeaklyIncrementable O, class Proj = identity, - IndirectUnaryPredicate> Pred> - requires IndirectlyCopyable + template S, weakly_incrementable O, class Proj = identity, + indirect_unary_predicate> Pred> + requires indirectly_copyable constexpr copy_if_result copy_if(I first, S last, O result, Pred pred, Proj proj = {}); - template, Proj>> Pred> - requires IndirectlyCopyable, O> + template, Proj>> Pred> + requires indirectly_copyable, O> constexpr copy_if_result, O> copy_if(R&& r, O result, Pred pred, Proj proj = {}); } @@ -1215,12 +1217,12 @@ template using copy_backward_result = copy_result; - template S1, BidirectionalIterator I2> - requires IndirectlyCopyable + template S1, bidirectional_iterator I2> + requires indirectly_copyable constexpr copy_backward_result copy_backward(I1 first, S1 last, I2 result); - template - requires IndirectlyCopyable, I> + template + requires indirectly_copyable, I> constexpr copy_backward_result, I> copy_backward(R&& r, I result); } @@ -1239,12 +1241,12 @@ template using move_result = copy_result; - template S, WeaklyIncrementable O> - requires IndirectlyMovable + template S, weakly_incrementable O> + requires indirectly_movable constexpr move_result move(I first, S last, O result); - template - requires IndirectlyMovable, O> + template + requires indirectly_movable, O> constexpr move_result, O> move(R&& r, O result); } @@ -1258,12 +1260,12 @@ template using move_backward_result = copy_result; - template S1, BidirectionalIterator I2> - requires IndirectlyMovable + template S1, bidirectional_iterator I2> + requires indirectly_movable constexpr move_backward_result move_backward(I1 first, S1 last, I2 result); - template - requires IndirectlyMovable, I> + template + requires indirectly_movable, I> constexpr move_backward_result, I> move_backward(R&& r, I result); } @@ -1281,12 +1283,12 @@ template using swap_ranges_result = mismatch_result; - template S1, InputIterator I2, Sentinel S2> - requires IndirectlySwappable + template S1, input_iterator I2, sentinel_for S2> + requires indirectly_swappable constexpr swap_ranges_result swap_ranges(I1 first1, S1 last1, I2 first2, S2 last2); - template - requires IndirectlySwappable, iterator_t> + template + requires indirectly_swappable, iterator_t> constexpr swap_ranges_result, safe_iterator_t> swap_ranges(R1&& r1, R2&& r2); } @@ -1323,14 +1325,14 @@ template using unary_transform_result = copy_result; - template S, WeaklyIncrementable O, - CopyConstructible F, class Proj = identity> - requires Writable>> + template S, weakly_incrementable O, + copy_constructible F, class Proj = identity> + requires writable>> constexpr unary_transform_result transform(I first1, S last1, O result, F op, Proj proj = {}); - template - requires Writable, Proj>>> + requires writable, Proj>>> constexpr unary_transform_result, O> transform(R&& r, O result, F op, Proj proj = {}); @@ -1341,31 +1343,31 @@ [[no_unique_address]] O out; template - requires ConvertibleTo && - ConvertibleTo && ConvertibleTo + requires convertible_to && + convertible_to && convertible_to operator binary_transform_result() const & { return {in1, in2, out}; } template - requires ConvertibleTo && - ConvertibleTo && ConvertibleTo + requires convertible_to && + convertible_to && convertible_to operator binary_transform_result() && { return {std::move(in1), std::move(in2), std::move(out)}; } }; - template S1, InputIterator I2, Sentinel S2, - WeaklyIncrementable O, CopyConstructible F, class Proj1 = identity, + template S1, input_iterator I2, sentinel_for S2, + weakly_incrementable O, copy_constructible F, class Proj1 = identity, class Proj2 = identity> - requires Writable, + requires writable, projected>> constexpr binary_transform_result transform(I1 first1, S1 last1, I2 first2, S2 last2, O result, F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {}); - template - requires Writable, Proj1>, + template + requires writable, Proj1>, projected, Proj2>>> constexpr binary_transform_result, safe_iterator_t, O> transform(R1&& r1, R2&& r2, O result, @@ -1389,23 +1391,23 @@ Predicate pred, const T& new_value); namespace ranges { - template S, class T1, class T2, class Proj = identity> - requires Writable && - IndirectRelation, const T1*> + template S, class T1, class T2, class Proj = identity> + requires writable && + indirect_relation, const T1*> constexpr I replace(I first, S last, const T1& old_value, const T2& new_value, Proj proj = {}); - template - requires Writable, const T2&> && - IndirectRelation, Proj>, const T1*> + template + requires writable, const T2&> && + indirect_relation, Proj>, const T1*> constexpr safe_iterator_t replace(R&& r, const T1& old_value, const T2& new_value, Proj proj = {}); - template S, class T, class Proj = identity, - IndirectUnaryPredicate> Pred> - requires Writable + template S, class T, class Proj = identity, + indirect_unary_predicate> Pred> + requires writable constexpr I replace_if(I first, S last, Pred pred, const T& new_value, Proj proj = {}); - template, Proj>> Pred> - requires Writable, const T&> + template, Proj>> Pred> + requires writable, const T&> constexpr safe_iterator_t replace_if(R&& r, Pred pred, const T& new_value, Proj proj = {}); } @@ -1434,17 +1436,17 @@ template using replace_copy_result = copy_result; - template S, class T1, class T2, OutputIterator O, - class Proj = identity> - requires IndirectlyCopyable && - IndirectRelation, const T1*> + template S, class T1, class T2, + output_iterator O, class Proj = identity> + requires indirectly_copyable && + indirect_relation, const T1*> constexpr replace_copy_result replace_copy(I first, S last, O result, const T1& old_value, const T2& new_value, Proj proj = {}); - template O, + template O, class Proj = identity> - requires IndirectlyCopyable, O> && - IndirectRelation, Proj>, const T1*> + requires indirectly_copyable, O> && + indirect_relation, Proj>, const T1*> constexpr replace_copy_result, O> replace_copy(R&& r, O result, const T1& old_value, const T2& new_value, Proj proj = {}); @@ -1452,15 +1454,15 @@ template using replace_copy_if_result = copy_result; - template S, class T, OutputIterator O, - class Proj = identity, IndirectUnaryPredicate> Pred> - requires IndirectlyCopyable + template S, class T, output_iterator O, + class Proj = identity, indirect_unary_predicate> Pred> + requires indirectly_copyable constexpr replace_copy_if_result replace_copy_if(I first, S last, O result, Pred pred, const T& new_value, Proj proj = {}); - template O, class Proj = identity, - IndirectUnaryPredicate, Proj>> Pred> - requires IndirectlyCopyable, O> + template O, class Proj = identity, + indirect_unary_predicate, Proj>> Pred> + requires indirectly_copyable, O> constexpr replace_copy_if_result, O> replace_copy_if(R&& r, O result, Pred pred, const T& new_value, Proj proj = {}); @@ -1480,11 +1482,11 @@ ForwardIterator first, Size n, const T& value); namespace ranges { - template O, Sentinel S> + template O, sentinel_for S> constexpr O fill(O first, S last, const T& value); - template R> + template R> constexpr safe_iterator_t fill(R&& r, const T& value); - template O> + template O> constexpr O fill_n(O first, iter_difference_t n, const T& value); } @@ -1503,14 +1505,14 @@ ForwardIterator first, Size n, Generator gen); namespace ranges { - template S, CopyConstructible F> - requires Invocable && Writable> + template S, copy_constructible F> + requires invocable && writable> constexpr O generate(O first, S last, F gen); - template - requires Invocable && OutputRange> + template + requires invocable && output_range> constexpr safe_iterator_t generate(R&& r, F gen); - template - requires Invocable && Writable> + template + requires invocable && writable> constexpr O generate_n(O first, iter_difference_t n, F gen); } @@ -1531,21 +1533,21 @@ Predicate pred); namespace ranges { - template S, class T, class Proj = identity> - requires IndirectRelation, const T*> - constexpr I remove(I first, S last, const T& value, Proj proj = {}); - template - requires Permutable> && - IndirectRelation, Proj>, const T*> - constexpr safe_iterator_t + template S, class T, class Proj = identity> + requires indirect_relation, const T*> + constexpr subrange remove(I first, S last, const T& value, Proj proj = {}); + template + requires permutable> && + indirect_relation, Proj>, const T*> + constexpr safe_subrange_t remove(R&& r, const T& value, Proj proj = {}); - template S, class Proj = identity, - IndirectUnaryPredicate> Pred> - constexpr I remove_if(I first, S last, Pred pred, Proj proj = {}); - template, Proj>> Pred> - requires Permutable> - constexpr safe_iterator_t + template S, class Proj = identity, + indirect_unary_predicate> Pred> + constexpr subrange remove_if(I first, S last, Pred pred, Proj proj = {}); + template, Proj>> Pred> + requires permutable> + constexpr safe_subrange_t remove_if(R&& r, Pred pred, Proj proj = {}); } @@ -1574,29 +1576,29 @@ template using remove_copy_result = copy_result; - template S, WeaklyIncrementable O, class T, + template S, weakly_incrementable O, class T, class Proj = identity> - requires IndirectlyCopyable && - IndirectRelation, const T*> + requires indirectly_copyable && + indirect_relation, const T*> constexpr remove_copy_result remove_copy(I first, S last, O result, const T& value, Proj proj = {}); - template - requires IndirectlyCopyable, O> && - IndirectRelation, Proj>, const T*> + template + requires indirectly_copyable, O> && + indirect_relation, Proj>, const T*> constexpr remove_copy_result, O> remove_copy(R&& r, O result, const T& value, Proj proj = {}); template using remove_copy_if_result = copy_result; - template S, WeaklyIncrementable O, - class Proj = identity, IndirectUnaryPredicate> Pred> - requires IndirectlyCopyable + template S, weakly_incrementable O, + class Proj = identity, indirect_unary_predicate> Pred> + requires indirectly_copyable constexpr remove_copy_if_result remove_copy_if(I first, S last, O result, Pred pred, Proj proj = {}); - template, Proj>> Pred> - requires IndirectlyCopyable, O> + template, Proj>> Pred> + requires indirectly_copyable, O> constexpr remove_copy_if_result, O> remove_copy_if(R&& r, O result, Pred pred, Proj proj = {}); } @@ -1616,13 +1618,13 @@ BinaryPredicate pred); namespace ranges { - template S, class Proj = identity, - IndirectRelation> C = ranges::equal_to> - constexpr I unique(I first, S last, C comp = {}, Proj proj = {}); - template, Proj>> C = ranges::equal_to> - requires Permutable> - constexpr safe_iterator_t + template S, class Proj = identity, + indirect_relation> C = ranges::equal_to> + constexpr subrange unique(I first, S last, C comp = {}, Proj proj = {}); + template, Proj>> C = ranges::equal_to> + requires permutable> + constexpr safe_subrange_t unique(R&& r, C comp = {}, Proj proj = {}); } @@ -1650,20 +1652,20 @@ template using unique_copy_result = copy_result; - template S, WeaklyIncrementable O, - class Proj = identity, IndirectRelation> C = ranges::equal_to> - requires IndirectlyCopyable && - (ForwardIterator || - (InputIterator && Same, iter_value_t>) || - IndirectlyCopyableStorable) + template S, weakly_incrementable O, + class Proj = identity, indirect_relation> C = ranges::equal_to> + requires indirectly_copyable && + (forward_iterator || + (input_iterator && same_as, iter_value_t>) || + indirectly_copyable_storable) constexpr unique_copy_result unique_copy(I first, S last, O result, C comp = {}, Proj proj = {}); - template, Proj>> C = ranges::equal_to> - requires IndirectlyCopyable, O> && - (ForwardIterator> || - (InputIterator && Same>, iter_value_t>) || - IndirectlyCopyableStorable, O>) + template, Proj>> C = ranges::equal_to> + requires indirectly_copyable, O> && + (forward_iterator> || + (input_iterator && same_as, iter_value_t>) || + indirectly_copyable_storable, O>) constexpr unique_copy_result, O> unique_copy(R&& r, O result, C comp = {}, Proj proj = {}); } @@ -1676,11 +1678,11 @@ BidirectionalIterator first, BidirectionalIterator last); namespace ranges { - template S> - requires Permutable + template S> + requires permutable constexpr I reverse(I first, S last); - template - requires Permutable> + template + requires permutable> constexpr safe_iterator_t reverse(R&& r); } @@ -1698,12 +1700,12 @@ template using reverse_copy_result = copy_result; - template S, WeaklyIncrementable O> - requires IndirectlyCopyable + template S, weakly_incrementable O> + requires indirectly_copyable constexpr reverse_copy_result reverse_copy(I first, S last, O result); - template - requires IndirectlyCopyable, O> + template + requires indirectly_copyable, O> constexpr reverse_copy_result, O> reverse_copy(R&& r, O result); } @@ -1720,10 +1722,10 @@ ForwardIterator last); namespace ranges { - template S> + template S> constexpr subrange rotate(I first, I middle, S last); - template - requires Permutable> + template + requires permutable> constexpr safe_subrange_t rotate(R&& r, iterator_t middle); } @@ -1741,12 +1743,12 @@ template using rotate_copy_result = copy_result; - template S, WeaklyIncrementable O> - requires IndirectlyCopyable + template S, weakly_incrementable O> + requires indirectly_copyable constexpr rotate_copy_result rotate_copy(I first, I middle, S last, O result); - template - requires IndirectlyCopyable, O> + template + requires indirectly_copyable, O> constexpr rotate_copy_result, O> rotate_copy(R&& r, iterator_t middle, O result); } @@ -1765,15 +1767,13 @@ UniformRandomBitGenerator&& g); namespace ranges { - template S, class Gen> - requires Permutable && - UniformRandomBitGenerator> && - ConvertibleTo, iter_difference_t> + template S, class Gen> + requires permutable && + uniform_random_bit_generator> I shuffle(I first, S last, Gen&& g); - template - requires Permutable> && - UniformRandomBitGenerator> && - ConvertibleTo, iter_difference_t>> + template + requires permutable> && + uniform_random_bit_generator> safe_iterator_t shuffle(R&& r, Gen&& g); } @@ -1813,13 +1813,13 @@ Compare comp); namespace ranges { - template S, class Comp = ranges::less, + template S, class Comp = ranges::less, class Proj = identity> - requires Sortable + requires sortable constexpr I sort(I first, S last, Comp comp = {}, Proj proj = {}); - template - requires Sortable, Comp, Proj> + template + requires sortable, Comp, Proj> constexpr safe_iterator_t sort(R&& r, Comp comp = {}, Proj proj = {}); } @@ -1838,12 +1838,12 @@ Compare comp); namespace ranges { - template S, class Comp = ranges::less, + template S, class Comp = ranges::less, class Proj = identity> - requires Sortable + requires sortable I stable_sort(I first, S last, Comp comp = {}, Proj proj = {}); - template - requires Sortable, Comp, Proj> + template + requires sortable, Comp, Proj> safe_iterator_t stable_sort(R&& r, Comp comp = {}, Proj proj = {}); } @@ -1868,13 +1868,13 @@ RandomAccessIterator last, Compare comp); namespace ranges { - template S, class Comp = ranges::less, + template S, class Comp = ranges::less, class Proj = identity> - requires Sortable + requires sortable constexpr I partial_sort(I first, I middle, S last, Comp comp = {}, Proj proj = {}); - template - requires Sortable, Comp, Proj> + template + requires sortable, Comp, Proj> constexpr safe_iterator_t partial_sort(R&& r, iterator_t middle, Comp comp = {}, Proj proj = {}); @@ -1907,20 +1907,23 @@ Compare comp); namespace ranges { - template S1, RandomAccessIterator I2, Sentinel S2, + template using partial_sort_copy_result = copy_result; + + template S1, + random_access_iterator I2, sentinel_for S2, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> - requires IndirectlyCopyable && Sortable && - IndirectStrictWeakOrder, projected> - constexpr I2 + requires indirectly_copyable && sortable && + indirect_strict_weak_order, projected> + constexpr partial_sort_copy_result partial_sort_copy(I1 first, S1 last, I2 result_first, S2 result_last, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); - template - requires IndirectlyCopyable, iterator_t> && - Sortable, Comp, Proj2> && - IndirectStrictWeakOrder, Proj1>, - projected, Proj2>> - constexpr safe_iterator_t + requires indirectly_copyable, iterator_t> && + sortable, Comp, Proj2> && + indirect_strict_weak_order, Proj1>, + projected, Proj2>> + constexpr partial_sort_copy_result, safe_iterator_t> partial_sort_copy(R1&& r, R2&& result_r, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); } @@ -1939,11 +1942,11 @@ Compare comp); namespace ranges { - template S, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> + template S, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr bool is_sorted(I first, S last, Comp comp = {}, Proj proj = {}); - template, Proj>> Comp = ranges::less> + template, Proj>> Comp = ranges::less> constexpr bool is_sorted(R&& r, Comp comp = {}, Proj proj = {}); } @@ -1965,11 +1968,11 @@ Compare comp); namespace ranges { - template S, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> + template S, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr I is_sorted_until(I first, S last, Comp comp = {}, Proj proj = {}); - template, Proj>> Comp = ranges::less> + template, Proj>> Comp = ranges::less> constexpr safe_iterator_t is_sorted_until(R&& r, Comp comp = {}, Proj proj = {}); } @@ -1991,13 +1994,13 @@ RandomAccessIterator last, Compare comp); namespace ranges { - template S, class Comp = ranges::less, + template S, class Comp = ranges::less, class Proj = identity> - requires Sortable + requires sortable constexpr I nth_element(I first, I nth, S last, Comp comp = {}, Proj proj = {}); - template - requires Sortable, Comp, Proj> + template + requires sortable, Comp, Proj> constexpr safe_iterator_t nth_element(R&& r, iterator_t nth, Comp comp = {}, Proj proj = {}); } @@ -2013,12 +2016,12 @@ const T& value, Compare comp); namespace ranges { - template S, class T, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> + template S, class T, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr I lower_bound(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); - template, Proj>> Comp = + template, Proj>> Comp = ranges::less> constexpr safe_iterator_t lower_bound(R&& r, const T& value, Comp comp = {}, Proj proj = {}); @@ -2034,11 +2037,11 @@ const T& value, Compare comp); namespace ranges { - template S, class T, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> + template S, class T, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr I upper_bound(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); - template, Proj>> Comp = + template, Proj>> Comp = ranges::less> constexpr safe_iterator_t upper_bound(R&& r, const T& value, Comp comp = {}, Proj proj = {}); @@ -2054,12 +2057,12 @@ const T& value, Compare comp); namespace ranges { - template S, class T, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> + template S, class T, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr subrange equal_range(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); - template, Proj>> Comp = + template, Proj>> Comp = ranges::less> constexpr safe_subrange_t equal_range(R&& r, const T& value, Comp comp = {}, Proj proj = {}); @@ -2075,12 +2078,12 @@ const T& value, Compare comp); namespace ranges { - template S, class T, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> + template S, class T, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr bool binary_search(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); - template, Proj>> Comp = + template, Proj>> Comp = ranges::less> constexpr bool binary_search(R&& r, const T& value, Comp comp = {}, Proj proj = {}); @@ -2094,11 +2097,11 @@ ForwardIterator first, ForwardIterator last, Predicate pred); namespace ranges { - template S, class Proj = identity, - IndirectUnaryPredicate> Pred> + template S, class Proj = identity, + indirect_unary_predicate> Pred> constexpr bool is_partitioned(I first, S last, Pred pred, Proj proj = {}); - template, Proj>> Pred> + template, Proj>> Pred> constexpr bool is_partitioned(R&& r, Pred pred, Proj proj = {}); } @@ -2113,14 +2116,14 @@ Predicate pred); namespace ranges { - template S, class Proj = identity, - IndirectUnaryPredicate> Pred> - constexpr I + template S, class Proj = identity, + indirect_unary_predicate> Pred> + constexpr subrange partition(I first, S last, Pred pred, Proj proj = {}); - template, Proj>> Pred> - requires Permutable> - constexpr safe_iterator_t + template, Proj>> Pred> + requires permutable> + constexpr safe_subrange_t partition(R&& r, Pred pred, Proj proj = {}); } @@ -2135,14 +2138,14 @@ Predicate pred); namespace ranges { - template S, class Proj = identity, - IndirectUnaryPredicate> Pred> - requires Permutable - I stable_partition(I first, S last, Pred pred, Proj proj = {}); - template, Proj>> Pred> - requires Permutable> - safe_iterator_t stable_partition(R&& r, Pred pred, Proj proj = {}); + template S, class Proj = identity, + indirect_unary_predicate> Pred> + requires permutable + subrange stable_partition(I first, S last, Pred pred, Proj proj = {}); + template, Proj>> Pred> + requires permutable> + safe_subrange_t stable_partition(R&& r, Pred pred, Proj proj = {}); } template - requires ConvertibleTo && - ConvertibleTo && ConvertibleTo + requires convertible_to && + convertible_to && convertible_to operator partition_copy_result() const & { return {in, out1, out2}; } template - requires ConvertibleTo && - ConvertibleTo && ConvertibleTo + requires convertible_to && + convertible_to && convertible_to operator partition_copy_result() && { return {std::move(in), std::move(out1), std::move(out2)}; } }; - template S, WeaklyIncrementable O1, WeaklyIncrementable O2, - class Proj = identity, IndirectUnaryPredicate> Pred> - requires IndirectlyCopyable && IndirectlyCopyable + template S, + weakly_incrementable O1, weakly_incrementable O2, + class Proj = identity, indirect_unary_predicate> Pred> + requires indirectly_copyable && indirectly_copyable constexpr partition_copy_result partition_copy(I first, S last, O1 out_true, O2 out_false, Pred pred, Proj proj = {}); - template, Proj>> Pred> - requires IndirectlyCopyable, O1> && - IndirectlyCopyable, O2> + indirect_unary_predicate, Proj>> Pred> + requires indirectly_copyable, O1> && + indirectly_copyable, O2> constexpr partition_copy_result, O1, O2> partition_copy(R&& r, O1 out_true, O2 out_false, Pred pred, Proj proj = {}); } @@ -2202,11 +2206,11 @@ Predicate pred); namespace ranges { - template S, class Proj = identity, - IndirectUnaryPredicate> Pred> + template S, class Proj = identity, + indirect_unary_predicate> Pred> constexpr I partition_point(I first, S last, Pred pred, Proj proj = {}); - template, Proj>> Pred> + template, Proj>> Pred> constexpr safe_iterator_t partition_point(R&& r, Pred pred, Proj proj = {}); } @@ -2242,16 +2246,16 @@ template using merge_result = binary_transform_result; - template S1, InputIterator I2, Sentinel S2, - WeaklyIncrementable O, class Comp = ranges::less, class Proj1 = identity, + template S1, input_iterator I2, sentinel_for S2, + weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> - requires Mergeable + requires mergeable constexpr merge_result merge(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); - template - requires Mergeable, iterator_t, O, Comp, Proj1, Proj2> + requires mergeable, iterator_t, O, Comp, Proj1, Proj2> constexpr merge_result, safe_iterator_t, O> merge(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -2277,12 +2281,12 @@ BidirectionalIterator last, Compare comp); namespace ranges { - template S, class Comp = ranges::less, + template S, class Comp = ranges::less, class Proj = identity> - requires Sortable + requires sortable I inplace_merge(I first, I middle, S last, Comp comp = {}, Proj proj = {}); - template - requires Sortable, Comp, Proj> + template + requires sortable, Comp, Proj> safe_iterator_t inplace_merge(R&& r, iterator_t middle, Comp comp = {}, Proj proj = {}); @@ -2308,16 +2312,16 @@ Compare comp); namespace ranges { - template S1, InputIterator I2, Sentinel S2, + template S1, input_iterator I2, sentinel_for S2, class Proj1 = identity, class Proj2 = identity, - IndirectStrictWeakOrder, projected> Comp = + indirect_strict_weak_order, projected> Comp = ranges::less> constexpr bool includes(I1 first1, S1 last1, I2 first2, S2 last2, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); - template, Proj1>, - projected, Proj2>> Comp = ranges::less> + indirect_strict_weak_order, Proj1>, + projected, Proj2>> Comp = ranges::less> constexpr bool includes(R1&& r1, R2&& r2, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); } @@ -2351,16 +2355,16 @@ template using set_union_result = binary_transform_result; - template S1, InputIterator I2, Sentinel S2, - WeaklyIncrementable O, class Comp = ranges::less, + template S1, input_iterator I2, sentinel_for S2, + weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> - requires Mergeable + requires mergeable constexpr set_union_result set_union(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); - template - requires Mergeable, iterator_t, O, Comp, Proj1, Proj2> + requires mergeable, iterator_t, O, Comp, Proj1, Proj2> constexpr set_union_result, safe_iterator_t, O> set_union(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -2395,16 +2399,16 @@ template using set_intersection_result = binary_transform_result; - template S1, InputIterator I2, Sentinel S2, - WeaklyIncrementable O, class Comp = ranges::less, + template S1, input_iterator I2, sentinel_for S2, + weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> - requires Mergeable + requires mergeable constexpr set_intersection_result set_intersection(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); - template - requires Mergeable, iterator_t, O, Comp, Proj1, Proj2> + requires mergeable, iterator_t, O, Comp, Proj1, Proj2> constexpr set_intersection_result, safe_iterator_t, O> set_intersection(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -2439,16 +2443,16 @@ template using set_difference_result = copy_result; - template S1, InputIterator I2, Sentinel S2, - WeaklyIncrementable O, class Comp = ranges::less, + template S1, input_iterator I2, sentinel_for S2, + weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> - requires Mergeable + requires mergeable constexpr set_difference_result set_difference(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); - template - requires Mergeable, iterator_t, O, Comp, Proj1, Proj2> + requires mergeable, iterator_t, O, Comp, Proj1, Proj2> constexpr set_difference_result, O> set_difference(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -2483,17 +2487,17 @@ template using set_symmetric_difference_result = binary_transform_result; - template S1, InputIterator I2, Sentinel S2, - WeaklyIncrementable O, class Comp = ranges::less, + template S1, input_iterator I2, sentinel_for S2, + weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> - requires Mergeable + requires mergeable constexpr set_symmetric_difference_result set_symmetric_difference(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); - template - requires Mergeable, iterator_t, O, Comp, Proj1, Proj2> + requires mergeable, iterator_t, O, Comp, Proj1, Proj2> constexpr set_symmetric_difference_result, safe_iterator_t, O> set_symmetric_difference(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -2507,13 +2511,13 @@ Compare comp); namespace ranges { - template S, class Comp = ranges::less, + template S, class Comp = ranges::less, class Proj = identity> - requires Sortable + requires sortable constexpr I push_heap(I first, S last, Comp comp = {}, Proj proj = {}); - template - requires Sortable, Comp, Proj> + template + requires sortable, Comp, Proj> constexpr safe_iterator_t push_heap(R&& r, Comp comp = {}, Proj proj = {}); } @@ -2525,13 +2529,13 @@ Compare comp); namespace ranges { - template S, class Comp = ranges::less, + template S, class Comp = ranges::less, class Proj = identity> - requires Sortable + requires sortable constexpr I pop_heap(I first, S last, Comp comp = {}, Proj proj = {}); - template - requires Sortable, Comp, Proj> + template + requires sortable, Comp, Proj> constexpr safe_iterator_t pop_heap(R&& r, Comp comp = {}, Proj proj = {}); } @@ -2543,13 +2547,13 @@ Compare comp); namespace ranges { - template S, class Comp = ranges::less, + template S, class Comp = ranges::less, class Proj = identity> - requires Sortable + requires sortable constexpr I make_heap(I first, S last, Comp comp = {}, Proj proj = {}); - template - requires Sortable, Comp, Proj> + template + requires sortable, Comp, Proj> constexpr safe_iterator_t make_heap(R&& r, Comp comp = {}, Proj proj = {}); } @@ -2561,13 +2565,13 @@ Compare comp); namespace ranges { - template S, class Comp = ranges::less, + template S, class Comp = ranges::less, class Proj = identity> - requires Sortable + requires sortable constexpr I sort_heap(I first, S last, Comp comp = {}, Proj proj = {}); - template - requires Sortable, Comp, Proj> + template + requires sortable, Comp, Proj> constexpr safe_iterator_t sort_heap(R&& r, Comp comp = {}, Proj proj = {}); } @@ -2586,11 +2590,11 @@ Compare comp); namespace ranges { - template S, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> + template S, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr bool is_heap(I first, S last, Comp comp = {}, Proj proj = {}); - template, Proj>> Comp = ranges::less> + template, Proj>> Comp = ranges::less> constexpr bool is_heap(R&& r, Comp comp = {}, Proj proj = {}); } @@ -2612,11 +2616,11 @@ Compare comp); namespace ranges { - template S, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> + template S, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr I is_heap_until(I first, S last, Comp comp = {}, Proj proj = {}); - template, Proj>> Comp = ranges::less> + template, Proj>> Comp = ranges::less> constexpr safe_iterator_t is_heap_until(R&& r, Comp comp = {}, Proj proj = {}); } @@ -2632,15 +2636,15 @@ namespace ranges { template> Comp = ranges::less> + indirect_strict_weak_order> Comp = ranges::less> constexpr const T& min(const T& a, const T& b, Comp comp = {}, Proj proj = {}); - template> Comp = ranges::less> + template> Comp = ranges::less> constexpr T min(initializer_list r, Comp comp = {}, Proj proj = {}); - template, Proj>> Comp = ranges::less> - requires IndirectlyCopyableStorable, iter_value_t>*> - constexpr iter_value_t> + template, Proj>> Comp = ranges::less> + requires indirectly_copyable_storable, range_value_t*> + constexpr range_value_t min(R&& r, Comp comp = {}, Proj proj = {}); } @@ -2654,15 +2658,15 @@ namespace ranges { template> Comp = ranges::less> + indirect_strict_weak_order> Comp = ranges::less> constexpr const T& max(const T& a, const T& b, Comp comp = {}, Proj proj = {}); - template> Comp = ranges::less> + template> Comp = ranges::less> constexpr T max(initializer_list r, Comp comp = {}, Proj proj = {}); - template, Proj>> Comp = ranges::less> - requires IndirectlyCopyableStorable, iter_value_t>*> - constexpr iter_value_t> + template, Proj>> Comp = ranges::less> + requires indirectly_copyable_storable, range_value_t*> + constexpr range_value_t max(R&& r, Comp comp = {}, Proj proj = {}); } @@ -2681,30 +2685,30 @@ [[no_unique_address]] T max; template - requires ConvertibleTo + requires convertible_to operator minmax_result() const & { return {min, max}; } template - requires ConvertibleTo + requires convertible_to operator minmax_result() && { return {std::move(min), std::move(max)}; } }; template> Comp = ranges::less> + indirect_strict_weak_order> Comp = ranges::less> constexpr minmax_result minmax(const T& a, const T& b, Comp comp = {}, Proj proj = {}); - template> Comp = ranges::less> + template> Comp = ranges::less> constexpr minmax_result minmax(initializer_list r, Comp comp = {}, Proj proj = {}); - template, Proj>> Comp = ranges::less> - requires IndirectlyCopyableStorable, iter_value_t>*> - constexpr minmax_result>> + template, Proj>> Comp = ranges::less> + requires indirectly_copyable_storable, range_value_t*> + constexpr minmax_result> minmax(R&& r, Comp comp = {}, Proj proj = {}); } @@ -2722,11 +2726,11 @@ Compare comp); namespace ranges { - template S, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> + template S, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr I min_element(I first, S last, Comp comp = {}, Proj proj = {}); - template, Proj>> Comp = ranges::less> + template, Proj>> Comp = ranges::less> constexpr safe_iterator_t min_element(R&& r, Comp comp = {}, Proj proj = {}); } @@ -2745,11 +2749,11 @@ Compare comp); namespace ranges { - template S, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> + template S, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr I max_element(I first, S last, Comp comp = {}, Proj proj = {}); - template, Proj>> Comp = ranges::less> + template, Proj>> Comp = ranges::less> constexpr safe_iterator_t max_element(R&& r, Comp comp = {}, Proj proj = {}); } @@ -2773,12 +2777,12 @@ template using minmax_element_result = minmax_result; - template S, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> + template S, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr minmax_element_result minmax_element(I first, S last, Comp comp = {}, Proj proj = {}); - template, Proj>> Comp = ranges::less> + template, Proj>> Comp = ranges::less> constexpr minmax_element_result> minmax_element(R&& r, Comp comp = {}, Proj proj = {}); } @@ -2813,35 +2817,33 @@ Compare comp); namespace ranges { - template S1, InputIterator I2, Sentinel S2, + template S1, input_iterator I2, sentinel_for S2, class Proj1 = identity, class Proj2 = identity, - IndirectStrictWeakOrder, projected> Comp = + indirect_strict_weak_order, projected> Comp = ranges::less> constexpr bool lexicographical_compare(I1 first1, S1 last1, I2 first2, S2 last2, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); - template, Proj1>, - projected, Proj2>> Comp = ranges::less> + indirect_strict_weak_order, Proj1>, + projected, Proj2>> Comp = ranges::less> constexpr bool lexicographical_compare(R1&& r1, R2&& r2, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); } - // \ref{alg.3way}, three-way comparison algorithms - template - constexpr auto compare_3way(const T& a, const U& b); + // \ref{alg.three.way}, three-way comparison algorithms template constexpr auto - lexicographical_compare_3way(InputIterator1 b1, InputIterator1 e1, - InputIterator2 b2, InputIterator2 e2, - Cmp comp) + lexicographical_compare_three_way(InputIterator1 b1, InputIterator1 e1, + InputIterator2 b2, InputIterator2 e2, + Cmp comp) -> common_comparison_category_t; template constexpr auto - lexicographical_compare_3way(InputIterator1 b1, InputIterator1 e1, - InputIterator2 b2, InputIterator2 e2); + lexicographical_compare_three_way(InputIterator1 b1, InputIterator1 e1, + InputIterator2 b2, InputIterator2 e2); // \ref{alg.permutation.generators}, permutations template @@ -2852,15 +2854,21 @@ BidirectionalIterator last, Compare comp); namespace ranges { - template S, class Comp = ranges::less, + template + struct next_permutation_result { + bool found; + I in; + }; + + template S, class Comp = ranges::less, class Proj = identity> - requires Sortable - constexpr bool + requires sortable + constexpr next_permutation_result next_permutation(I first, S last, Comp comp = {}, Proj proj = {}); - template - requires Sortable, Comp, Proj> - constexpr bool + requires sortable, Comp, Proj> + constexpr next_permutation_result> next_permutation(R&& r, Comp comp = {}, Proj proj = {}); } @@ -2872,15 +2880,18 @@ BidirectionalIterator last, Compare comp); namespace ranges { - template S, class Comp = ranges::less, + template + using prev_permutation_result = next_permutation_result; + + template S, class Comp = ranges::less, class Proj = identity> - requires Sortable - constexpr bool + requires sortable + constexpr prev_permutation_result prev_permutation(I first, S last, Comp comp = {}, Proj proj = {}); - template - requires Sortable, Comp, Proj> - constexpr bool + requires sortable, Comp, Proj> + constexpr prev_permutation_result> prev_permutation(R&& r, Comp comp = {}, Proj proj = {}); } } @@ -2898,11 +2909,11 @@ bool all_of(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, Predicate pred); -template S, class Proj = identity, - IndirectUnaryPredicate> Pred> +template S, class Proj = identity, + indirect_unary_predicate> Pred> constexpr bool ranges::all_of(I first, S last, Pred pred, Proj proj = {}); -template, Proj>> Pred> +template, Proj>> Pred> constexpr bool ranges::all_of(R&& r, Pred pred, Proj proj = {}); \end{itemdecl} @@ -2932,11 +2943,11 @@ bool any_of(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, Predicate pred); -template S, class Proj = identity, - IndirectUnaryPredicate> Pred> +template S, class Proj = identity, + indirect_unary_predicate> Pred> constexpr bool ranges::any_of(I first, S last, Pred pred, Proj proj = {}); -template, Proj>> Pred> +template, Proj>> Pred> constexpr bool ranges::any_of(R&& r, Pred pred, Proj proj = {}); \end{itemdecl} @@ -2965,11 +2976,11 @@ bool none_of(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, Predicate pred); -template S, class Proj = identity, - IndirectUnaryPredicate> Pred> +template S, class Proj = identity, + indirect_unary_predicate> Pred> constexpr bool ranges::none_of(I first, S last, Pred pred, Proj proj = {}); -template, Proj>> Pred> +template, Proj>> Pred> constexpr bool ranges::none_of(R&& r, Pred pred, Proj proj = {}); \end{itemdecl} @@ -3072,12 +3083,12 @@ \indexlibrary{\idxcode{for_each}}% \begin{itemdecl} -template S, class Proj = identity, - IndirectUnaryInvocable> Fun> +template S, class Proj = identity, + indirectly_unary_invocable> Fun> constexpr ranges::for_each_result ranges::for_each(I first, S last, Fun f, Proj proj = {}); -template, Proj>> Fun> +template, Proj>> Fun> constexpr ranges::for_each_result, Fun> ranges::for_each(R&& r, Fun f, Proj proj = {}); \end{itemdecl} @@ -3108,7 +3119,7 @@ \pnum \begin{note} The overloads in namespace \tcode{ranges} require -\tcode{Fun} to model \libconcept{CopyConstructible}. +\tcode{Fun} to model \libconcept{copy_constructible}. \end{note} \end{itemdescr} @@ -3214,25 +3225,25 @@ ForwardIterator first, ForwardIterator last, Predicate pred); -template S, class T, class Proj = identity> - requires IndirectRelation, const T*> +template S, class T, class Proj = identity> + requires indirect_relation, const T*> constexpr I ranges::find(I first, S last, const T& value, Proj proj = {}); -template - requires IndirectRelation, Proj>, const T*> +template + requires indirect_relation, Proj>, const T*> constexpr safe_iterator_t ranges::find(R&& r, const T& value, Proj proj = {}); -template S, class Proj = identity, - IndirectUnaryPredicate> Pred> +template S, class Proj = identity, + indirect_unary_predicate> Pred> constexpr I ranges::find_if(I first, S last, Pred pred, Proj proj = {}); -template, Proj>> Pred> +template, Proj>> Pred> constexpr safe_iterator_t ranges::find_if(R&& r, Pred pred, Proj proj = {}); -template S, class Proj = identity, - IndirectUnaryPredicate> Pred> +template S, class Proj = identity, + indirect_unary_predicate> Pred> constexpr I ranges::find_if_not(I first, S last, Pred pred, Proj proj = {}); -template, Proj>> Pred> +template, Proj>> Pred> constexpr safe_iterator_t ranges::find_if_not(R&& r, Pred pred, Proj proj = {}); \end{itemdecl} @@ -3289,18 +3300,18 @@ ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate pred); -template S1, ForwardIterator I2, Sentinel S2, +template S1, forward_iterator I2, sentinel_for S2, class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> - requires IndirectlyComparable + requires indirectly_comparable constexpr subrange ranges::find_end(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, - Proj1 proj1 = {}, Proj2 proj2 = {}); -template - requires IndirectlyComparable, iterator_t, Pred, Proj1, Proj2> + requires indirectly_comparable, iterator_t, Pred, Proj1, Proj2> constexpr safe_subrange_t ranges::find_end(R1&& r1, R2&& r2, Pred pred = {}, - Proj1 proj1 = {}, Proj2 proj2 = {}); + Proj1 proj1 = {}, Proj2 proj2 = {}); \end{itemdecl} \begin{itemdescr} @@ -3374,17 +3385,17 @@ ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate pred); -template S1, ForwardIterator I2, Sentinel S2, +template S1, forward_iterator I2, sentinel_for S2, class Proj1 = identity, class Proj2 = identity, - IndirectRelation, - projected> Pred = ranges::equal_to> + indirect_relation, + projected> Pred = ranges::equal_to> constexpr I1 ranges::find_first_of(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); -template, Proj1>, - projected, Proj2>> Pred = ranges::equal_to> + indirect_relation, Proj1>, + projected, Proj2>> Pred = ranges::equal_to> constexpr safe_iterator_t ranges::find_first_of(R1&& r1, R2&& r2, Pred pred = {}, @@ -3441,11 +3452,11 @@ ForwardIterator first, ForwardIterator last, BinaryPredicate pred); -template S, class Proj = identity, - IndirectRelation> Pred = ranges::equal_to> +template S, class Proj = identity, + indirect_relation> Pred = ranges::equal_to> constexpr I ranges::adjacent_find(I first, S last, Pred pred = {}, Proj proj = {}); -template, Proj>> Pred = ranges::equal_to> +template, Proj>> Pred = ranges::equal_to> constexpr safe_iterator_t ranges::adjacent_find(R&& r, Pred pred = {}, Proj proj = {}); \end{itemdecl} @@ -3498,21 +3509,21 @@ count_if(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, Predicate pred); -template S, class T, class Proj = identity> - requires IndirectRelation, const T*> +template S, class T, class Proj = identity> + requires indirect_relation, const T*> constexpr iter_difference_t ranges::count(I first, S last, const T& value, Proj proj = {}); -template - requires IndirectRelation, Proj>, const T*> - constexpr iter_difference_t> +template + requires indirect_relation, Proj>, const T*> + constexpr range_difference_t ranges::count(R&& r, const T& value, Proj proj = {}); -template S, class Proj = identity, - IndirectUnaryPredicate> Pred> +template S, class Proj = identity, + indirect_unary_predicate> Pred> constexpr iter_difference_t ranges::count_if(I first, S last, Pred pred, Proj proj = {}); -template, Proj>> Pred> - constexpr iter_difference_t> +template, Proj>> Pred> + constexpr range_difference_t ranges::count_if(R&& r, Pred pred, Proj proj = {}); \end{itemdecl} @@ -3595,17 +3606,17 @@ ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate pred); -template S1, InputIterator I2, Sentinel S2, +template S1, input_iterator I2, sentinel_for S2, class Proj1 = identity, class Proj2 = identity, - IndirectRelation, - projected> Pred = ranges::equal_to> + indirect_relation, + projected> Pred = ranges::equal_to> constexpr ranges::mismatch_result ranges::mismatch(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); -template, Proj1>, - projected, Proj2>> Pred = ranges::equal_to> + indirect_relation, Proj1>, + projected, Proj2>> Pred = ranges::equal_to> constexpr ranges::mismatch_result, safe_iterator_t> ranges::mismatch(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -3688,15 +3699,15 @@ ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate pred); -template S1, InputIterator I2, Sentinel S2, +template S1, input_iterator I2, sentinel_for S2, class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> - requires IndirectlyComparable + requires indirectly_comparable constexpr bool ranges::equal(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); -template - requires IndirectlyComparable, iterator_t, Pred, Proj1, Proj2> + requires indirectly_comparable, iterator_t, Pred, Proj1, Proj2> constexpr bool ranges::equal(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); \end{itemdecl} @@ -3740,7 +3751,7 @@ \oldconcept{RandomAccessIterator} requirements\iref{random.access.iterators} for the overloads in namespace \tcode{std}, or \item - pairwise model \tcode{SizedSentinel}\iref{iterator.concept.sizedsentinel} + pairwise model \libconcept{sized_sentinel_for}\iref{iterator.concept.sizedsentinel} for the overloads in namespace \tcode{ranges}, \end{itemize} and \tcode{last1 - first1 != last2 - first2}, @@ -3819,16 +3830,16 @@ \indexlibrary{\idxcode{is_permutation}}% \begin{itemdecl} -template S1, ForwardIterator I2, - Sentinel S2, class Pred = ranges::equal_to, class Proj1 = identity, +template S1, forward_iterator I2, + sentinel_for S2, class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> - requires IndirectlyComparable + requires indirectly_comparable constexpr bool ranges::is_permutation(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); -template - requires IndirectlyComparable, iterator_t, Pred, Proj1, Proj2> + requires indirectly_comparable, iterator_t, Pred, Proj1, Proj2> constexpr bool ranges::is_permutation(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); \end{itemdecl} @@ -3848,8 +3859,8 @@ \complexity No applications of the corresponding predicate and projections if: \begin{itemize} -\item \tcode{S1} and \tcode{I1} model \libconcept{SizedSentinel}, -\item \tcode{S2} and \tcode{I2} model \libconcept{SizedSentinel}, and +\item \tcode{S1} and \tcode{I1} model \tcode{\libconcept{sized_sentinel_for}}, +\item \tcode{S2} and \tcode{I2} model \tcode{\libconcept{sized_sentinel_for}}, and \item \tcode{last1 - first1 != last2 - first2}. \end{itemize} Otherwise, exactly \tcode{last1 - first1} applications @@ -3907,16 +3918,16 @@ \indexlibrary{\idxcode{search}}% \begin{itemdecl} -template S1, ForwardIterator I2, - Sentinel S2, class Pred = ranges::equal_to, +template S1, forward_iterator I2, + sentinel_for S2, class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> - requires IndirectlyComparable + requires indirectly_comparable constexpr subrange ranges::search(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); -template - requires IndirectlyComparable, iterator_t, Pred, Proj1, Proj2> + requires indirectly_comparable, iterator_t, Pred, Proj1, Proj2> constexpr safe_subrange_t ranges::search(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -3995,17 +4006,17 @@ \indexlibrary{\idxcode{search_n}}% \begin{itemdecl} -template S, class T, +template S, class T, class Pred = ranges::equal_to, class Proj = identity> - requires IndirectlyComparable + requires indirectly_comparable constexpr subrange ranges::search_n(I first, S last, iter_difference_t count, const T& value, Pred pred = {}, Proj proj = {}); -template - requires IndirectlyComparable, const T*, Pred, Proj> + requires indirectly_comparable, const T*, Pred, Proj> constexpr safe_subrange_t - ranges::search_n(R&& r, iter_difference_t> count, + ranges::search_n(R&& r, range_difference_t count, const T& value, Pred pred = {}, Proj proj = {}); \end{itemdecl} @@ -4052,11 +4063,11 @@ constexpr OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result); -template S, WeaklyIncrementable O> - requires IndirectlyCopyable +template S, weakly_incrementable O> + requires indirectly_copyable constexpr ranges::copy_result ranges::copy(I first, S last, O result); -template - requires IndirectlyCopyable, O> +template + requires indirectly_copyable, O> constexpr ranges::copy_result, O> ranges::copy(R&& r, O result); \end{itemdecl} @@ -4130,8 +4141,8 @@ ForwardIterator1 first, Size n, ForwardIterator2 result); -template - requires IndirectlyCopyable +template + requires indirectly_copyable constexpr ranges::copy_n_result ranges::copy_n(I first, iter_difference_t n, O result); \end{itemdecl} @@ -4172,14 +4183,14 @@ ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, Predicate pred); -template S, WeaklyIncrementable O, class Proj = identity, - IndirectUnaryPredicate> Pred> - requires IndirectlyCopyable +template S, weakly_incrementable O, class Proj = identity, + indirect_unary_predicate> Pred> + requires indirectly_copyable constexpr ranges::copy_if_result ranges::copy_if(I first, S last, O result, Pred pred, Proj proj = {}); -template, Proj>> Pred> - requires IndirectlyCopyable, O> +template, Proj>> Pred> + requires indirectly_copyable, O> constexpr ranges::copy_if_result, O> ranges::copy_if(R&& r, O result, Pred pred, Proj proj = {}); \end{itemdecl} @@ -4244,12 +4255,12 @@ BidirectionalIterator1 last, BidirectionalIterator2 result); -template S1, BidirectionalIterator I2> - requires IndirectlyCopyable +template S1, bidirectional_iterator I2> + requires indirectly_copyable constexpr ranges::copy_backward_result ranges::copy_backward(I1 first, S1 last, I2 result); -template - requires IndirectlyCopyable, I> +template + requires indirectly_copyable, I> constexpr ranges::copy_backward_result, I> ranges::copy_backward(R&& r, I result); \end{itemdecl} @@ -4296,12 +4307,12 @@ constexpr OutputIterator move(InputIterator first, InputIterator last, OutputIterator result); -template S, WeaklyIncrementable O> - requires IndirectlyMovable +template S, weakly_incrementable O> + requires indirectly_movable constexpr ranges::move_result ranges::move(I first, S last, O result); -template - requires IndirectlyMovable, O> +template + requires indirectly_movable, O> constexpr ranges::move_result, O> ranges::move(R&& r, O result); \end{itemdecl} @@ -4386,12 +4397,12 @@ move_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 result); -template S1, BidirectionalIterator I2> - requires IndirectlyMovable +template S1, bidirectional_iterator I2> + requires indirectly_movable constexpr ranges::move_backward_result ranges::move_backward(I1 first, S1 last, I2 result); -template - requires IndirectlyMovable, I> +template + requires indirectly_movable, I> constexpr ranges::move_backward_result, I> ranges::move_backward(R&& r, I result); \end{itemdecl} @@ -4453,12 +4464,12 @@ ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2); -template S1, InputIterator I2, Sentinel S2> - requires IndirectlySwappable +template S1, input_iterator I2, sentinel_for S2> + requires indirectly_swappable constexpr ranges::swap_ranges_result ranges::swap_ranges(I1 first1, S1 last1, I2 first2, S2 last2); -template - requires IndirectlySwappable, iterator_t> +template + requires indirectly_swappable, iterator_t> constexpr ranges::swap_ranges_result, safe_iterator_t> ranges::swap_ranges(R1&& r1, R2&& r2); \end{itemdecl} @@ -4556,27 +4567,27 @@ ForwardIterator2 first2, ForwardIterator result, BinaryOperation binary_op); -template S, WeaklyIncrementable O, - CopyConstructible F, class Proj = identity> - requires Writable>> +template S, weakly_incrementable O, + copy_constructible F, class Proj = identity> + requires writable>> constexpr ranges::unary_transform_result ranges::transform(I first1, S last1, O result, F op, Proj proj = {}); -template - requires Writable, Proj>>> + requires writable, Proj>>> constexpr ranges::unary_transform_result, O> ranges::transform(R&& r, O result, F op, Proj proj = {}); -template S1, InputIterator I2, Sentinel S2, - WeaklyIncrementable O, CopyConstructible F, class Proj1 = identity, +template S1, input_iterator I2, sentinel_for S2, + weakly_incrementable O, copy_constructible F, class Proj1 = identity, class Proj2 = identity> - requires Writable, + requires writable, projected>> constexpr ranges::binary_transform_result ranges::transform(I1 first1, S1 last1, I2 first2, S2 last2, O result, F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {}); -template - requires Writable, Proj1>, +template + requires writable, Proj1>, projected, Proj2>>> constexpr ranges::binary_transform_result, safe_iterator_t, O> ranges::transform(R1&& r1, R2&& r2, O result, @@ -4675,23 +4686,23 @@ ForwardIterator first, ForwardIterator last, Predicate pred, const T& new_value); -template S, class T1, class T2, class Proj = identity> - requires Writable && - IndirectRelation, const T1*> +template S, class T1, class T2, class Proj = identity> + requires writable && + indirect_relation, const T1*> constexpr I ranges::replace(I first, S last, const T1& old_value, const T2& new_value, Proj proj = {}); -template - requires Writable, const T2&> && - IndirectRelation, Proj>, const T1*> +template + requires writable, const T2&> && + indirect_relation, Proj>, const T1*> constexpr safe_iterator_t ranges::replace(R&& r, const T1& old_value, const T2& new_value, Proj proj = {}); -template S, class T, class Proj = identity, - IndirectUnaryPredicate> Pred> - requires Writable +template S, class T, class Proj = identity, + indirect_unary_predicate> Pred> + requires writable constexpr I ranges::replace_if(I first, S last, Pred pred, const T& new_value, Proj proj = {}); -template, Proj>> Pred> - requires Writable, const T&> +template, Proj>> Pred> + requires writable, const T&> constexpr safe_iterator_t ranges::replace_if(R&& r, Pred pred, const T& new_value, Proj proj = {}); \end{itemdecl} @@ -4754,30 +4765,30 @@ ForwardIterator2 result, Predicate pred, const T& new_value); -template S, class T1, class T2, OutputIterator O, +template S, class T1, class T2, output_iterator O, class Proj = identity> - requires IndirectlyCopyable && - IndirectRelation, const T1*> + requires indirectly_copyable && + indirect_relation, const T1*> constexpr ranges::replace_copy_result ranges::replace_copy(I first, S last, O result, const T1& old_value, const T2& new_value, Proj proj = {}); -template O, +template O, class Proj = identity> - requires IndirectlyCopyable, O> && - IndirectRelation, Proj>, const T1*> + requires indirectly_copyable, O> && + indirect_relation, Proj>, const T1*> constexpr ranges::replace_copy_result, O> ranges::replace_copy(R&& r, O result, const T1& old_value, const T2& new_value, Proj proj = {}); -template S, class T, OutputIterator O, - class Proj = identity, IndirectUnaryPredicate> Pred> - requires IndirectlyCopyable +template S, class T, output_iterator O, + class Proj = identity, indirect_unary_predicate> Pred> + requires indirectly_copyable constexpr ranges::replace_copy_if_result ranges::replace_copy_if(I first, S last, O result, Pred pred, const T& new_value, Proj proj = {}); -template O, class Proj = identity, - IndirectUnaryPredicate, Proj>> Pred> - requires IndirectlyCopyable, O> +template O, class Proj = identity, + indirect_unary_predicate, Proj>> Pred> + requires indirectly_copyable, O> constexpr ranges::replace_copy_if_result, O> ranges::replace_copy_if(R&& r, O result, Pred pred, const T& new_value, Proj proj = {}); @@ -4848,11 +4859,11 @@ ForwardIterator first, Size n, const T& value); -template O, Sentinel S> +template O, sentinel_for S> constexpr O ranges::fill(O first, S last, const T& value); -template R> +template R> constexpr safe_iterator_t ranges::fill(R&& r, const T& value); -template O> +template O> constexpr O ranges::fill_n(O first, iter_difference_t n, const T& value); \end{itemdecl} @@ -4901,14 +4912,14 @@ ForwardIterator generate_n(ExecutionPolicy&& exec, ForwardIterator first, Size n, Generator gen); -template S, CopyConstructible F> - requires Invocable && Writable> +template S, copy_constructible F> + requires invocable && writable> constexpr O ranges::generate(O first, S last, F gen); -template - requires Invocable && OutputRange> +template + requires invocable && output_range> constexpr safe_iterator_t ranges::generate(R&& r, F gen); -template - requires Invocable && Writable> +template + requires invocable && writable> constexpr O ranges::generate_n(O first, iter_difference_t n, F gen); \end{itemdecl} @@ -4957,21 +4968,21 @@ ForwardIterator first, ForwardIterator last, Predicate pred); -template S, class T, class Proj = identity> - requires IndirectRelation, const T*> - constexpr I ranges::remove(I first, S last, const T& value, Proj proj = {}); -template - requires Permutable> && - IndirectRelation, Proj>, const T*> - constexpr safe_iterator_t +template S, class T, class Proj = identity> + requires indirect_relation, const T*> + constexpr subrange ranges::remove(I first, S last, const T& value, Proj proj = {}); +template + requires permutable> && + indirect_relation, Proj>, const T*> + constexpr safe_subrange_t ranges::remove(R&& r, const T& value, Proj proj = {}); -template S, class Proj = identity, - IndirectUnaryPredicate> Pred> - constexpr I ranges::remove_if(I first, S last, Pred pred, Proj proj = {}); -template, Proj>> Pred> - requires Permutable> - constexpr safe_iterator_t +template S, class Proj = identity, + indirect_unary_predicate> Pred> + constexpr subrange ranges::remove_if(I first, S last, Pred pred, Proj proj = {}); +template, Proj>> Pred> + requires permutable> + constexpr safe_subrange_t ranges::remove_if(R&& r, Pred pred, Proj proj = {}); \end{itemdecl} @@ -4998,7 +5009,11 @@ \pnum \returns -The end of the resulting range. +Let $j$ be the end of the resulting range. Returns: +\begin{itemize} +\item $j$ for the overloads in namespace \tcode{std}, or +\item \tcode{\{$j$, last\}} for the overloads in namespace \tcode{ranges}. +\end{itemize} \pnum \remarks @@ -5044,25 +5059,25 @@ ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, Predicate pred); -template S, WeaklyIncrementable O, class T, +template S, weakly_incrementable O, class T, class Proj = identity> - requires IndirectlyCopyable && - IndirectRelation, const T*> + requires indirectly_copyable && + indirect_relation, const T*> constexpr ranges::remove_copy_result ranges::remove_copy(I first, S last, O result, const T& value, Proj proj = {}); -template - requires IndirectlyCopyable, O> && - IndirectRelation, Proj>, const T*> +template + requires indirectly_copyable, O> && + indirect_relation, Proj>, const T*> constexpr ranges::remove_copy_result, O> ranges::remove_copy(R&& r, O result, const T& value, Proj proj = {}); -template S, WeaklyIncrementable O, - class Proj = identity, IndirectUnaryPredicate> Pred> - requires IndirectlyCopyable +template S, weakly_incrementable O, + class Proj = identity, indirect_unary_predicate> Pred> + requires indirectly_copyable constexpr ranges::remove_copy_if_result ranges::remove_copy_if(I first, S last, O result, Pred pred, Proj proj = {}); -template, Proj>> Pred> - requires IndirectlyCopyable, O> +template, Proj>> Pred> + requires indirectly_copyable, O> constexpr ranges::remove_copy_if_result, O> ranges::remove_copy_if(R&& r, O result, Pred pred, Proj proj = {}); \end{itemdecl} @@ -5132,13 +5147,13 @@ ForwardIterator first, ForwardIterator last, BinaryPredicate pred); -template S, class Proj = identity, - IndirectRelation> C = ranges::equal_to> - constexpr I ranges::unique(I first, S last, C comp = {}, Proj proj = {}); -template, Proj>> C = ranges::equal_to> - requires Permutable> - constexpr safe_iterator_t +template S, class Proj = identity, + indirect_relation> C = ranges::equal_to> + constexpr subrange ranges::unique(I first, S last, C comp = {}, Proj proj = {}); +template, Proj>> C = ranges::equal_to> + requires permutable> + constexpr safe_subrange_t ranges::unique(R&& r, C comp = {}, Proj proj = {}); \end{itemdecl} @@ -5173,7 +5188,11 @@ \pnum \returns -The end of the resulting range. +Let $j$ be the end of the resulting range. Returns: +\begin{itemize} +\item $j$ for the overloads in namespace \tcode{std}, or +\item \tcode{\{$j$, last\}} for the overloads in namespace \tcode{ranges}. +\end{itemize} \pnum \complexity @@ -5206,20 +5225,20 @@ ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result, BinaryPredicate pred); -template S, WeaklyIncrementable O, - class Proj = identity, IndirectRelation> C = ranges::equal_to> - requires IndirectlyCopyable && - (ForwardIterator || - (InputIterator && Same, iter_value_t>) || - IndirectlyCopyableStorable) +template S, weakly_incrementable O, + class Proj = identity, indirect_relation> C = ranges::equal_to> + requires indirectly_copyable && + (forward_iterator || + (input_iterator && same_as, iter_value_t>) || + indirectly_copyable_storable) constexpr ranges::unique_copy_result ranges::unique_copy(I first, S last, O result, C comp = {}, Proj proj = {}); -template, Proj>> C = ranges::equal_to> - requires IndirectlyCopyable, O> && - (ForwardIterator> || - (InputIterator && Same>, iter_value_t>) || - IndirectlyCopyableStorable, O>) +template, Proj>> C = ranges::equal_to> + requires indirectly_copyable, O> && + (forward_iterator> || + (input_iterator && same_as, iter_value_t>) || + indirectly_copyable_storable, O>) constexpr ranges::unique_copy_result, O> ranges::unique_copy(R&& r, O result, C comp = {}, Proj proj = {}); \end{itemdecl} @@ -5305,11 +5324,11 @@ void reverse(ExecutionPolicy&& exec, BidirectionalIterator first, BidirectionalIterator last); -template S> - requires Permutable +template S> + requires permutable constexpr I ranges::reverse(I first, S last); -template - requires Permutable> +template + requires permutable> constexpr safe_iterator_t ranges::reverse(R&& r); \end{itemdecl} @@ -5348,12 +5367,12 @@ BidirectionalIterator first, BidirectionalIterator last, ForwardIterator result); -template S, WeaklyIncrementable O> - requires IndirectlyCopyable +template S, weakly_incrementable O> + requires indirectly_copyable constexpr ranges::reverse_copy_result ranges::reverse_copy(I first, S last, O result); -template - requires IndirectlyCopyable, O> +template + requires indirectly_copyable, O> constexpr ranges::reverse_copy_result, O> ranges::reverse_copy(R&& r, O result); \end{itemdecl} @@ -5400,7 +5419,7 @@ rotate(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator middle, ForwardIterator last); -template S> +template S> constexpr subrange ranges::rotate(I first, I middle, S last); \end{itemdecl} @@ -5441,8 +5460,8 @@ \end{itemdescr} \begin{itemdecl} -template - requires Permutable> +template + requires permutable> constexpr safe_subrange_t ranges::rotate(R&& r, iterator_t middle); \end{itemdecl} @@ -5465,8 +5484,8 @@ ForwardIterator1 first, ForwardIterator1 middle, ForwardIterator1 last, ForwardIterator2 result); - template S, WeaklyIncrementable O> - requires IndirectlyCopyable + template S, weakly_incrementable O> + requires indirectly_copyable constexpr ranges::rotate_copy_result ranges::rotate_copy(I first, I middle, S last, O result); \end{itemdecl} @@ -5503,8 +5522,8 @@ \end{itemdescr} \begin{itemdecl} -template - requires IndirectlyCopyable, O> +template + requires indirectly_copyable, O> constexpr ranges::rotate_copy_result, O> ranges::rotate_copy(R&& r, iterator_t middle, O result); \end{itemdecl} @@ -5596,13 +5615,13 @@ RandomAccessIterator last, UniformRandomBitGenerator&& g); -template S, class Gen> - requires Permutable && - UniformRandomBitGenerator> +template S, class Gen> + requires permutable && + uniform_random_bit_generator> I ranges::shuffle(I first, S last, Gen&& g); -template - requires Permutable> && - UniformRandomBitGenerator> +template + requires permutable> && + uniform_random_bit_generator> safe_iterator_t ranges::shuffle(R&& r, Gen&& g); \end{itemdecl} @@ -5827,13 +5846,13 @@ RandomAccessIterator first, RandomAccessIterator last, Compare comp); -template S, class Comp = ranges::less, +template S, class Comp = ranges::less, class Proj = identity> - requires Sortable + requires sortable constexpr I ranges::sort(I first, S last, Comp comp = {}, Proj proj = {}); -template - requires Sortable, Comp, Proj> +template + requires sortable, Comp, Proj> constexpr safe_iterator_t ranges::sort(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -5886,12 +5905,12 @@ RandomAccessIterator first, RandomAccessIterator last, Compare comp); -template S, class Comp = ranges::less, +template S, class Comp = ranges::less, class Proj = identity> - requires Sortable + requires sortable I ranges::stable_sort(I first, S last, Comp comp = {}, Proj proj = {}); -template - requires Sortable, Comp, Proj> +template + requires sortable, Comp, Proj> safe_iterator_t ranges::stable_sort(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -5958,9 +5977,9 @@ RandomAccessIterator last, Compare comp); -template S, class Comp = ranges::less, +template S, class Comp = ranges::less, class Proj = identity> - requires Sortable + requires sortable constexpr I ranges::partial_sort(I first, I middle, S last, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -6002,8 +6021,8 @@ \end{itemdescr} \begin{itemdecl} -template - requires Sortable, Comp, Proj> +template + requires sortable, Comp, Proj> constexpr safe_iterator_t ranges::partial_sort(R&& r, iterator_t middle, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -6049,20 +6068,20 @@ RandomAccessIterator result_last, Compare comp); -template S1, RandomAccessIterator I2, Sentinel S2, +template S1, random_access_iterator I2, sentinel_for S2, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> - requires IndirectlyCopyable && Sortable && - IndirectStrictWeakOrder, projected> - constexpr I2 + requires indirectly_copyable && sortable && + indirect_strict_weak_order, projected> + constexpr ranges::partial_sort_copy_result ranges::partial_sort_copy(I1 first, S1 last, I2 result_first, S2 result_last, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); -template - requires IndirectlyCopyable, iterator_t> && - Sortable, Comp, Proj2> && - IndirectStrictWeakOrder, Proj1>, - projected, Proj2>> - constexpr safe_iterator_t + requires indirectly_copyable, iterator_t> && + sortable, Comp, Proj2> && + indirect_strict_weak_order, Proj1>, + projected, Proj2>> + constexpr ranges::partial_sort_copy_result, safe_iterator_t> ranges::partial_sort_copy(R1&& r, R2&& result_r, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); \end{itemdecl} @@ -6110,7 +6129,13 @@ \pnum \returns -\tcode{result_first + $N$}. +\begin{itemize} +\item + \tcode{result_first + $N$} for the overloads in namespace \tcode{std}, or +\item + \tcode{\{last, result_first + $N$\}} for + the overloads in namespace \tcode{ranges}. +\end{itemize} \pnum \complexity @@ -6175,17 +6200,17 @@ \effects Equivalent to: \begin{codeblock} -is_sorted_until(std::forward(exec), first, last, comp) == last +return is_sorted_until(std::forward(exec), first, last, comp) == last; \end{codeblock} \end{itemdescr} \indexlibrary{\idxcode{is_sorted}}% \begin{itemdecl} -template S, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> +template S, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr bool ranges::is_sorted(I first, S last, Comp comp = {}, Proj proj = {}); -template, Proj>> Comp = ranges::less> +template, Proj>> Comp = ranges::less> constexpr bool ranges::is_sorted(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -6216,11 +6241,11 @@ ForwardIterator first, ForwardIterator last, Compare comp); -template S, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> +template S, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr I ranges::is_sorted_until(I first, S last, Comp comp = {}, Proj proj = {}); -template, Proj>> Comp = ranges::less> +template, Proj>> Comp = ranges::less> constexpr safe_iterator_t ranges::is_sorted_until(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -6262,9 +6287,9 @@ RandomAccessIterator first, RandomAccessIterator nth, RandomAccessIterator last, Compare comp); -template S, class Comp = ranges::less, +template S, class Comp = ranges::less, class Proj = identity> - requires Sortable + requires sortable constexpr I ranges::nth_element(I first, I nth, S last, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -6308,8 +6333,8 @@ \end{itemdescr} \begin{itemdecl} -template - requires Sortable, Comp, Proj> +template + requires sortable, Comp, Proj> constexpr safe_iterator_t ranges::nth_element(R&& r, iterator_t nth, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -6351,12 +6376,12 @@ lower_bound(ForwardIterator first, ForwardIterator last, const T& value, Compare comp); -template S, class T, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> +template S, class T, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr I ranges::lower_bound(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); -template, Proj>> Comp = +template, Proj>> Comp = ranges::less> constexpr safe_iterator_t ranges::lower_bound(R&& r, const T& value, Comp comp = {}, Proj proj = {}); @@ -6399,11 +6424,11 @@ upper_bound(ForwardIterator first, ForwardIterator last, const T& value, Compare comp); -template S, class T, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> +template S, class T, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr I ranges::upper_bound(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); -template, Proj>> Comp = +template, Proj>> Comp = ranges::less> constexpr safe_iterator_t ranges::upper_bound(R&& r, const T& value, Comp comp = {}, Proj proj = {}); @@ -6447,12 +6472,12 @@ ForwardIterator last, const T& value, Compare comp); -template S, class T, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> +template S, class T, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr subrange ranges::equal_range(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); -template, Proj>> Comp = +template, Proj>> Comp = ranges::less> constexpr safe_subrange_t ranges::equal_range(R&& r, const T& value, Comp comp = {}, Proj proj = {}); @@ -6511,12 +6536,12 @@ binary_search(ForwardIterator first, ForwardIterator last, const T& value, Compare comp); -template S, class T, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> +template S, class T, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr bool ranges::binary_search(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); -template, Proj>> Comp = +template, Proj>> Comp = ranges::less> constexpr bool ranges::binary_search(R&& r, const T& value, Comp comp = {}, Proj proj = {}); @@ -6561,11 +6586,11 @@ bool is_partitioned(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, Predicate pred); -template S, class Proj = identity, - IndirectUnaryPredicate> Pred> +template S, class Proj = identity, + indirect_unary_predicate> Pred> constexpr bool ranges::is_partitioned(I first, S last, Pred pred, Proj proj = {}); -template, Proj>> Pred> +template, Proj>> Pred> constexpr bool ranges::is_partitioned(R&& r, Pred pred, Proj proj = {}); \end{itemdecl} @@ -6596,14 +6621,14 @@ partition(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, Predicate pred); -template S, class Proj = identity, - IndirectUnaryPredicate> Pred> - constexpr I +template S, class Proj = identity, + indirect_unary_predicate> Pred> + constexpr subrange ranges::partition(I first, S last, Pred pred, Proj proj = {}); -template, Proj>> Pred> - requires Permutable> - constexpr safe_iterator_t +template, Proj>> Pred> + requires permutable> + constexpr safe_subrange_t ranges::partition(R&& r, Pred pred, Proj proj = {}); \end{itemdecl} @@ -6626,9 +6651,15 @@ \pnum \returns -An iterator \tcode{i} such that $E(\tcode{*j})$ is +Let \tcode{i} be an iterator such that $E(\tcode{*j})$ is \tcode{true} for every iterator \tcode{j} in \range{first}{i} and \tcode{false} for every iterator \tcode{j} in \range{i}{last}. +Returns: +\begin{itemize} +\item \tcode{i} for the overloads in namespace \tcode{std}, or +\item \tcode{\{i, last\}} for the overloads in namespace \tcode{ranges}. +\end{itemize} + \pnum \complexity Let $N = \tcode{last - first}$: @@ -6639,7 +6670,7 @@ At most $N / 2$ swaps if the type of \tcode{first} meets the \oldconcept{BidirectionalIterator} requirements for the overloads in namespace \tcode{std} or - models \libconcept{BidirectionalIterator} + models \libconcept{bidirectional_iterator} for the overloads in namespace \tcode{ranges}, and at most $N$ swaps otherwise. \item @@ -6659,14 +6690,14 @@ stable_partition(ExecutionPolicy&& exec, BidirectionalIterator first, BidirectionalIterator last, Predicate pred); -template S, class Proj = identity, - IndirectUnaryPredicate> Pred> - requires Permutable - I ranges::stable_partition(I first, S last, Pred pred, Proj proj = {}); -template, Proj>> Pred> - requires Permutable> - safe_iterator_t ranges::stable_partition(R&& r, Pred pred, Proj proj = {}); +template S, class Proj = identity, + indirect_unary_predicate> Pred> + requires permutable + subrange ranges::stable_partition(I first, S last, Pred pred, Proj proj = {}); +template, Proj>> Pred> + requires permutable> + safe_subrange_t ranges::stable_partition(R&& r, Pred pred, Proj proj = {}); \end{itemdecl} \begin{itemdescr} @@ -6691,11 +6722,17 @@ \pnum \returns -An iterator \tcode{i} +Let \tcode{i} be an iterator such that for every iterator \tcode{j} in \range{first}{i}, $E(\tcode{*j})$ is \tcode{true}, and for every iterator \tcode{j} in the range \range{i}{last}, -$E(\tcode{*j})$ is \tcode{false}, +$E(\tcode{*j})$ is \tcode{false}. +Returns: +\begin{itemize} +\item \tcode{i} for the overloads in namespace \tcode{std}, or +\item \tcode{\{i, last\}} for the overloads in namespace \tcode{ranges}. +\end{itemize} + \pnum \complexity @@ -6725,17 +6762,17 @@ ForwardIterator first, ForwardIterator last, ForwardIterator1 out_true, ForwardIterator2 out_false, Predicate pred); -template S, WeaklyIncrementable O1, WeaklyIncrementable O2, - class Proj = identity, IndirectUnaryPredicate> Pred> - requires IndirectlyCopyable && IndirectlyCopyable +template S, weakly_incrementable O1, weakly_incrementable O2, + class Proj = identity, indirect_unary_predicate> Pred> + requires indirectly_copyable && indirectly_copyable constexpr ranges::partition_copy_result ranges::partition_copy(I first, S last, O1 out_true, O2 out_false, Pred pred, - Proj proj = {}); -template, Proj>> Pred> - requires IndirectlyCopyable, O1> && - IndirectlyCopyable, O2> + indirect_unary_predicate, Proj>> Pred> + requires indirectly_copyable, O1> && + indirectly_copyable, O2> constexpr ranges::partition_copy_result, O1, O2> ranges::partition_copy(R&& r, O1 out_true, O2 out_false, Pred pred, Proj proj = {}); \end{itemdecl} @@ -6787,11 +6824,11 @@ constexpr ForwardIterator partition_point(ForwardIterator first, ForwardIterator last, Predicate pred); -template S, class Proj = identity, - IndirectUnaryPredicate> Pred> +template S, class Proj = identity, + indirect_unary_predicate> Pred> constexpr I ranges::partition_point(I first, S last, Pred pred, Proj proj = {}); -template, Proj>> Pred> +template, Proj>> Pred> constexpr safe_iterator_t ranges::partition_point(R&& r, Pred pred, Proj proj = {}); \end{itemdecl} @@ -6852,16 +6889,16 @@ ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result, Compare comp); -template S1, InputIterator I2, Sentinel S2, - WeaklyIncrementable O, class Comp = ranges::less, class Proj1 = identity, +template S1, input_iterator I2, sentinel_for S2, + weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> - requires Mergeable + requires mergeable constexpr ranges::merge_result ranges::merge(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); -template - requires Mergeable, iterator_t, O, Comp, Proj1, Proj2> + requires mergeable, iterator_t, O, Comp, Proj1, Proj2> constexpr ranges::merge_result, safe_iterator_t, O> ranges::merge(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -6943,9 +6980,9 @@ BidirectionalIterator middle, BidirectionalIterator last, Compare comp); -template S, class Comp = ranges::less, +template S, class Comp = ranges::less, class Proj = identity> - requires Sortable + requires sortable I ranges::inplace_merge(I first, I middle, S last, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -6995,8 +7032,8 @@ \end{itemdescr} \begin{itemdecl} -template - requires Sortable, Comp, Proj> +template + requires sortable, Comp, Proj> safe_iterator_t ranges::inplace_merge(R&& r, iterator_t middle, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -7043,16 +7080,16 @@ ForwardIterator2 first2, ForwardIterator2 last2, Compare comp); -template S1, InputIterator I2, Sentinel S2, +template S1, input_iterator I2, sentinel_for S2, class Proj1 = identity, class Proj2 = identity, - IndirectStrictWeakOrder, - projected> Comp = ranges::less> + indirect_strict_weak_order, + projected> Comp = ranges::less> constexpr bool ranges::includes(I1 first1, S1 last1, I2 first2, S2 last2, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); -template, Proj1>, - projected, Proj2>> Comp = ranges::less> + indirect_strict_weak_order, Proj1>, + projected, Proj2>> Comp = ranges::less> constexpr bool ranges::includes(R1&& r1, R2&& r2, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); \end{itemdecl} @@ -7117,16 +7154,16 @@ ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result, Compare comp); -template S1, InputIterator I2, Sentinel S2, - WeaklyIncrementable O, class Comp = ranges::less, +template S1, input_iterator I2, sentinel_for S2, + weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> - requires Mergeable + requires mergeable constexpr ranges::set_union_result ranges::set_union(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); -template - requires Mergeable, iterator_t, O, Comp, Proj1, Proj2> + requires mergeable, iterator_t, O, Comp, Proj1, Proj2> constexpr ranges::set_union_result, safe_iterator_t, O> ranges::set_union(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -7212,16 +7249,16 @@ ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result, Compare comp); -template S1, InputIterator I2, Sentinel S2, - WeaklyIncrementable O, class Comp = ranges::less, +template S1, input_iterator I2, sentinel_for S2, + weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> - requires Mergeable + requires mergeable constexpr ranges::set_intersection_result ranges::set_intersection(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); -template - requires Mergeable, iterator_t, O, Comp, Proj1, Proj2> + requires mergeable, iterator_t, O, Comp, Proj1, Proj2> constexpr ranges::set_intersection_result, safe_iterator_t, O> ranges::set_intersection(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -7305,16 +7342,16 @@ ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result, Compare comp); -template S1, InputIterator I2, Sentinel S2, - WeaklyIncrementable O, class Comp = ranges::less, +template S1, input_iterator I2, sentinel_for S2, + weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> - requires Mergeable + requires mergeable constexpr ranges::set_difference_result ranges::set_difference(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); -template - requires Mergeable, iterator_t, O, Comp, Proj1, Proj2> + requires mergeable, iterator_t, O, Comp, Proj1, Proj2> constexpr ranges::set_difference_result, O> ranges::set_difference(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -7399,17 +7436,17 @@ ForwardIterator2 first2, ForwardIterator2 last2, ForwardIterator result, Compare comp); -template S1, InputIterator I2, Sentinel S2, - WeaklyIncrementable O, class Comp = ranges::less, +template S1, input_iterator I2, sentinel_for S2, + weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> - requires Mergeable + requires mergeable constexpr ranges::set_symmetric_difference_result ranges::set_symmetric_difference(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); -template - requires Mergeable, iterator_t, O, Comp, Proj1, Proj2> + requires mergeable, iterator_t, O, Comp, Proj1, Proj2> constexpr ranges::set_symmetric_difference_result, safe_iterator_t, O> ranges::set_symmetric_difference(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -7506,13 +7543,13 @@ constexpr void push_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp); -template S, class Comp = ranges::less, +template S, class Comp = ranges::less, class Proj = identity> - requires Sortable + requires sortable constexpr I ranges::push_heap(I first, S last, Comp comp = {}, Proj proj = {}); -template - requires Sortable, Comp, Proj> +template + requires sortable, Comp, Proj> constexpr safe_iterator_t ranges::push_heap(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -7557,13 +7594,13 @@ constexpr void pop_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp); -template S, class Comp = ranges::less, +template S, class Comp = ranges::less, class Proj = identity> - requires Sortable + requires sortable constexpr I ranges::pop_heap(I first, S last, Comp comp = {}, Proj proj = {}); -template - requires Sortable, Comp, Proj> +template + requires sortable, Comp, Proj> constexpr safe_iterator_t ranges::pop_heap(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -7615,13 +7652,13 @@ constexpr void make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp); -template S, class Comp = ranges::less, +template S, class Comp = ranges::less, class Proj = identity> - requires Sortable + requires sortable constexpr I ranges::make_heap(I first, S last, Comp comp = {}, Proj proj = {}); -template - requires Sortable, Comp, Proj> +template + requires sortable, Comp, Proj> constexpr safe_iterator_t ranges::make_heap(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -7664,13 +7701,13 @@ constexpr void sort_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp); -template S, class Comp = ranges::less, +template S, class Comp = ranges::less, class Proj = identity> - requires Sortable + requires sortable constexpr I ranges::sort_heap(I first, S last, Comp comp = {}, Proj proj = {}); -template - requires Sortable, Comp, Proj> +template + requires sortable, Comp, Proj> constexpr safe_iterator_t ranges::sort_heap(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -7769,11 +7806,11 @@ \indexlibrary{\idxcode{is_heap}}% \begin{itemdecl} -template S, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> +template S, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr bool ranges::is_heap(I first, S last, Comp comp = {}, Proj proj = {}); -template, Proj>> Comp = ranges::less> +template, Proj>> Comp = ranges::less> constexpr bool ranges::is_heap(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -7804,11 +7841,11 @@ RandomAccessIterator first, RandomAccessIterator last, Compare comp); -template S, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> +template S, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr I ranges::is_heap_until(I first, S last, Comp comp = {}, Proj proj = {}); -template, Proj>> Comp = ranges::less> +template, Proj>> Comp = ranges::less> constexpr safe_iterator_t ranges::is_heap_until(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -7841,7 +7878,7 @@ constexpr const T& min(const T& a, const T& b, Compare comp); template> Comp = ranges::less> + indirect_strict_weak_order> Comp = ranges::less> constexpr const T& ranges::min(const T& a, const T& b, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -7874,13 +7911,13 @@ template constexpr T min(initializer_list r, Compare comp); -template> Comp = ranges::less> +template> Comp = ranges::less> constexpr T ranges::min(initializer_list r, Comp comp = {}, Proj proj = {}); -template, Proj>> Comp = ranges::less> - requires IndirectlyCopyableStorable, iter_value_t>*> - constexpr iter_value_t> +template, Proj>> Comp = ranges::less> + requires indirectly_copyable_storable, range_value_t*> + constexpr range_value_t ranges::min(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -7918,7 +7955,7 @@ constexpr const T& max(const T& a, const T& b, Compare comp); template> Comp = ranges::less> + indirect_strict_weak_order> Comp = ranges::less> constexpr const T& ranges::max(const T& a, const T& b, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -7951,13 +7988,13 @@ template constexpr T max(initializer_list r, Compare comp); -template> Comp = ranges::less> +template> Comp = ranges::less> constexpr T ranges::max(initializer_list r, Comp comp = {}, Proj proj = {}); -template, Proj>> Comp = ranges::less> - requires IndirectlyCopyableStorable, iter_value_t>*> - constexpr iter_value_t> +template, Proj>> Comp = ranges::less> + requires indirectly_copyable_storable, range_value_t*> + constexpr range_value_t ranges::max(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -7995,7 +8032,7 @@ constexpr pair minmax(const T& a, const T& b, Compare comp); template> Comp = ranges::less> + indirect_strict_weak_order> Comp = ranges::less> constexpr ranges::minmax_result ranges::minmax(const T& a, const T& b, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -8030,14 +8067,14 @@ template constexpr pair minmax(initializer_list t, Compare comp); -template> Comp = ranges::less> +template> Comp = ranges::less> constexpr ranges::minmax_result ranges::minmax(initializer_list r, Comp comp = {}, Proj proj = {}); -template, Proj>> Comp = ranges::less> - requires IndirectlyCopyableStorable, iter_value_t>*> - constexpr ranges::minmax_result>> +template, Proj>> Comp = ranges::less> + requires indirectly_copyable_storable, range_value_t*> + constexpr ranges::minmax_result> ranges::minmax(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -8087,11 +8124,11 @@ ForwardIterator first, ForwardIterator last, Compare comp); -template S, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> +template S, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr I ranges::min_element(I first, S last, Comp comp = {}, Proj proj = {}); -template, Proj>> Comp = ranges::less> +template, Proj>> Comp = ranges::less> constexpr safe_iterator_t ranges::min_element(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -8134,11 +8171,11 @@ ForwardIterator first, ForwardIterator last, Compare comp); -template S, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> +template S, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr I ranges::max_element(I first, S last, Comp comp = {}, Proj proj = {}); -template, Proj>> Comp = ranges::less> +template, Proj>> Comp = ranges::less> constexpr safe_iterator_t ranges::max_element(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -8183,12 +8220,12 @@ minmax_element(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, Compare comp); -template S, class Proj = identity, - IndirectStrictWeakOrder> Comp = ranges::less> +template S, class Proj = identity, + indirect_strict_weak_order> Comp = ranges::less> constexpr ranges::minmax_result ranges::minmax_element(I first, S last, Comp comp = {}, Proj proj = {}); -template, Proj>> Comp = ranges::less> +template, Proj>> Comp = ranges::less> constexpr ranges::minmax_result> ranges::minmax_element(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -8271,17 +8308,17 @@ ForwardIterator2 first2, ForwardIterator2 last2, Compare comp); -template S1, InputIterator I2, Sentinel S2, +template S1, input_iterator I2, sentinel_for S2, class Proj1 = identity, class Proj2 = identity, - IndirectStrictWeakOrder, - projected> Comp = ranges::less> + indirect_strict_weak_order, + projected> Comp = ranges::less> constexpr bool ranges::lexicographical_compare(I1 first1, S1 last1, I2 first2, S2 last2, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); -template, Proj1>, - projected, Proj2>> Comp = ranges::less> + indirect_strict_weak_order, Proj1>, + projected, Proj2>> Comp = ranges::less> constexpr bool ranges::lexicographical_compare(R1&& r1, R2&& r2, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -8331,46 +8368,15 @@ \end{note} \end{itemdescr} -\rSec2[alg.3way]{Three-way comparison algorithms} - -\indexlibrary{\idxcode{compare_3way}}% -\begin{itemdecl} -template constexpr auto compare_3way(const T& a, const U& b); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Compares two values and produces a result -of the strongest applicable comparison category type: -\begin{itemize} -\item - Returns \tcode{a <=> b} if that expression is well-formed. -\item - Otherwise, if the expressions \tcode{a == b} and \tcode{a < b} - are each well-formed and convertible to \tcode{bool}, - returns \tcode{strong_ordering::equal} - when \tcode{a == b} is \tcode{true}, - otherwise returns \tcode{strong_ordering::less} - when \tcode{a < b} is \tcode{true}, - and otherwise returns \tcode{strong_ordering::greater}. -\item - Otherwise, if the expression \tcode{a == b} - is well-formed and convertible to \tcode{bool}, - returns \tcode{strong_equality::equal} when \tcode{a == b} is \tcode{true}, - and otherwise returns \tcode{strong_equality::nonequal}. -\item - Otherwise, the function is defined as deleted. -\end{itemize} -\end{itemdescr} +\rSec2[alg.three.way]{Three-way comparison algorithms} -\indexlibrary{\idxcode{lexicographical_compare_3way}}% +\indexlibrary{\idxcode{lexicographical_compare_three_way}}% \begin{itemdecl} template constexpr auto - lexicographical_compare_3way(InputIterator1 b1, InputIterator1 e1, - InputIterator2 b2, InputIterator2 e2, - Cmp comp) + lexicographical_compare_three_way(InputIterator1 b1, InputIterator1 e1, + InputIterator2 b2, InputIterator2 e2, + Cmp comp) -> common_comparison_category_t; \end{itemdecl} @@ -8395,12 +8401,12 @@ \end{codeblock} \end{itemdescr} -\indexlibrary{\idxcode{lexicographical_compare_3way}}% +\indexlibrary{\idxcode{lexicographical_compare_three_way}}% \begin{itemdecl} template constexpr auto - lexicographical_compare_3way(InputIterator1 b1, InputIterator1 e1, - InputIterator2 b2, InputIterator2 e2); + lexicographical_compare_three_way(InputIterator1 b1, InputIterator1 e1, + InputIterator2 b2, InputIterator2 e2); \end{itemdecl} \begin{itemdescr} @@ -8408,10 +8414,7 @@ \effects Equivalent to: \begin{codeblock} -return lexicographical_compare_3way(b1, e1, b2, e2, - [](const auto& t, const auto& u) { - return compare_3way(t, u); - }); +return lexicographical_compare_three_way(b1, e1, b2, e2, compare_three_way()); \end{codeblock} \end{itemdescr} @@ -8427,15 +8430,15 @@ constexpr bool next_permutation(BidirectionalIterator first, BidirectionalIterator last, Compare comp); -template S, class Comp = ranges::less, +template S, class Comp = ranges::less, class Proj = identity> - requires Sortable - constexpr bool + requires sortable + constexpr ranges::next_permutation_result ranges::next_permutation(I first, S last, Comp comp = {}, Proj proj = {}); -template - requires Sortable, Comp, Proj> - constexpr bool + requires sortable, Comp, Proj> + constexpr ranges::next_permutation_result> ranges::next_permutation(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -8463,7 +8466,13 @@ \pnum \returns -\tcode{true} if and only if a next permutation was found. +Let \tcode{B} be \tcode{true} if a next permutation was found and +otherwise \tcode{false}. +Returns: +\begin{itemize} +\item \tcode{B} for the overloads in namespace \tcode{std}, or +\item \tcode{\{ B, last \}} for the overloads in namespace \tcode{ranges}. +\end{itemize} \pnum \complexity @@ -8480,15 +8489,15 @@ constexpr bool prev_permutation(BidirectionalIterator first, BidirectionalIterator last, Compare comp); -template S, class Comp = ranges::less, +template S, class Comp = ranges::less, class Proj = identity> - requires Sortable - constexpr bool + requires sortable + constexpr ranges::prev_permutation_result ranges::prev_permutation(I first, S last, Comp comp = {}, Proj proj = {}); -template - requires Sortable, Comp, Proj> - constexpr bool + requires sortable, Comp, Proj> + constexpr ranges::prev_permutation_result> ranges::prev_permutation(R&& r, Comp comp = {}, Proj proj = {}); \end{itemdecl} @@ -8516,7 +8525,13 @@ \pnum \returns -\tcode{true} if and only if a previous permutation was found. +Let \tcode{B} be \tcode{true} if a previous permutation was found and +otherwise \tcode{false}. +Returns: +\begin{itemize} +\item \tcode{B} for the overloads in namespace \tcode{std}, or +\item \tcode{\{ B, last \}} for the overloads in namespace \tcode{ranges}. +\end{itemize} \pnum \complexity diff --git a/source/atomics.tex b/source/atomics.tex index dd0a8aba40..101a09b4e6 100644 --- a/source/atomics.tex +++ b/source/atomics.tex @@ -15,6 +15,7 @@ \ref{atomics.alias} & Type aliases & \tcode{} \\ \ref{atomics.order} & Order and consistency & \\ \ref{atomics.lockfree} & Lock-free property & \\ +\ref{atomics.wait} & Waiting and notifying & \\ \ref{atomics.ref.generic} & Class template \tcode{atomic_ref} & \\ \ref{atomics.types.generic} & Class template \tcode{atomic} & \\ \ref{atomics.nonmembers} & Non-member functions & \\ @@ -55,6 +56,9 @@ // \ref{atomics.types.pointer}, partial specialization for pointers template struct atomic; + // \ref{atomics.types.operations}, initialization + #define ATOMIC_VAR_INIT(value) @\seebelow@ + // \ref{atomics.nonmembers}, non-member functions template bool atomic_is_lock_free(const volatile atomic*) noexcept; @@ -180,8 +184,24 @@ T atomic_fetch_xor_explicit(atomic*, typename atomic::value_type, memory_order) noexcept; - // \ref{atomics.types.operations}, initialization - #define ATOMIC_VAR_INIT(value) @\seebelow@ + template + void atomic_wait(const volatile atomic*, typename atomic::value_type); + template + void atomic_wait(const atomic*, typename atomic::value_type); + template + void atomic_wait_explicit(const volatile atomic*, typename atomic::value_type, + memory_order); + template + void atomic_wait_explicit(const atomic*, typename atomic::value_type, + memory_order); + template + void atomic_notify_one(volatile atomic*); + template + void atomic_notify_one(atomic*); + template + void atomic_notify_all(volatile atomic*); + template + void atomic_notify_all(atomic*); // \ref{atomics.alias}, type aliases using atomic_bool = atomic; @@ -235,8 +255,18 @@ using atomic_intmax_t = atomic; using atomic_uintmax_t = atomic; + using atomic_signed_lock_free = @\seebelow@; + using atomic_unsigned_lock_free = @\seebelow@; + // \ref{atomics.flag}, flag type and operations struct atomic_flag; + + #define ATOMIC_FLAG_INIT @\seebelow@ + + bool atomic_flag_test(const volatile atomic_flag*) noexcept; + bool atomic_flag_test(const atomic_flag*) noexcept; + bool atomic_flag_test_explicit(const volatile atomic_flag*, memory_order) noexcept; + bool atomic_flag_test_explicit(const atomic_flag*, memory_order) noexcept; bool atomic_flag_test_and_set(volatile atomic_flag*) noexcept; bool atomic_flag_test_and_set(atomic_flag*) noexcept; bool atomic_flag_test_and_set_explicit(volatile atomic_flag*, memory_order) noexcept; @@ -245,7 +275,17 @@ void atomic_flag_clear(atomic_flag*) noexcept; void atomic_flag_clear_explicit(volatile atomic_flag*, memory_order) noexcept; void atomic_flag_clear_explicit(atomic_flag*, memory_order) noexcept; - #define ATOMIC_FLAG_INIT @\seebelow@ + + void atomic_flag_wait(const volatile atomic_flag*, bool) noexcept; + void atomic_flag_wait(const atomic_flag*, bool) noexcept; + void atomic_flag_wait_explicit(const volatile atomic_flag*, + bool, memory_order) noexcept; + void atomic_flag_wait_explicit(const atomic_flag*, + bool, memory_order) noexcept; + void atomic_flag_notify_one(volatile atomic_flag*) noexcept; + void atomic_flag_notify_one(atomic_flag*) noexcept; + void atomic_flag_notify_all(volatile atomic_flag*) noexcept; + void atomic_flag_notify_all(atomic_flag*) noexcept; // \ref{atomics.fences}, fences extern "C" void atomic_thread_fence(memory_order) noexcept; @@ -308,6 +348,22 @@ \tcode{intptr_t}, and \tcode{uintptr_t} are defined, respectively. +\pnum +\indexlibrary{\idxcode{atomic_signed_lock_free}}% +\indexlibrary{\idxcode{atomic_unsigned_lock_free}}% +The type aliases +\tcode{atomic_signed_lock_free} and \tcode{atomic_unsigned_lock_free} +name specializations of \tcode{atomic} +whose template arguments are integral types, respectively signed and unsigned, +and whose \tcode{is_always_lock_free} property is \tcode{true}. +\begin{note} +These aliases are optional in freestanding implementations\iref{compliance}. +\end{note} +Implementations should choose for these aliases +the integral specializations of \tcode{atomic} +for which the atomic waiting and notifying operations\iref{atomics.wait} +are most efficient. + \rSec1[atomics.order]{Order and consistency} \indexlibrary{\idxcode{memory_order}}% \indexlibrarymember{relaxed}{memory_order}% @@ -562,6 +618,15 @@ lock-free. A value of 1 indicates that the types are sometimes lock-free. A value of 2 indicates that the types are always lock-free. +\pnum +At least one signed integral specialization of the \tcode{atomic} template, +along with the specialization +for the corresponding unsigned type\iref{basic.fundamental}, +is always lock-free. +\begin{note} +This requirement is optional in freestanding implementations\iref{compliance}. +\end{note} + \pnum The function \tcode{atomic_is_lock_free}\iref{atomics.types.operations} indicates whether the object is lock-free. In any given program execution, the @@ -580,6 +645,56 @@ mapped into a process more than once and by memory that is shared between two processes. \end{note} +\rSec1[atomics.wait]{Waiting and notifying} + +\pnum +\defnx{Atomic waiting operations}{atomic waiting operation} +and \defnx{atomic notifying operations}{atomic notifying operation} +provide a mechanism to wait for the value of an atomic object to change +more efficiently than can be achieved with polling. +An atomic waiting operation may block until it is unblocked +by an atomic notifying operation, according to each function's effects. +\begin{note} +Programs are not guaranteed to observe transient atomic values, +an issue known as the A-B-A problem, +resulting in continued blocking if a condition is only temporarily met. +\end{note} + +\pnum +\begin{note} +The following functions are atomic waiting operations: +\begin{itemize} +\item \tcode{atomic::wait}, +\item \tcode{atomic_flag::wait}, +\item \tcode{atomic_wait} and \tcode{atomic_wait_explicit}, +\item \tcode{atomic_flag_wait} and \tcode{atomic_flag_wait_explicit}, and +\item \tcode{atomic_ref::wait}. +\end{itemize} +\end{note} + +\pnum +\begin{note} +The following functions are atomic notifying operations: +\begin{itemize} +\item \tcode{atomic::notify_one} and \tcode{atomic::notify_all}, +\item \tcode{atomic_flag::notify_one} and \tcode{atomic_flag::notify_all}, +\item \tcode{atomic_notify_one} and \tcode{atomic_notify_all}, +\item \tcode{atomic_flag_notify_one} and \tcode{atomic_flag_notify_all}, and +\item \tcode{atomic_ref::notify_one} and \tcode{atomic_ref::notify_all}. +\end{itemize} +\end{note} + +\pnum +A call to an atomic waiting operation on an atomic object \tcode{M} +is \defn{eligible to be unblocked} +by a call to an atomic notifying operation on \tcode{M} +if there exist side effects \tcode{X} and \tcode{Y} on \tcode{M} such that: +\begin{itemize} +\item the atomic waiting operation has blocked after observing the result of \tcode{X}, +\item \tcode{X} precedes \tcode{Y} in the modification order of \tcode{M}, and +\item \tcode{Y} happens before the call to the atomic notifying operation. +\end{itemize} + \rSec1[atomics.ref.generic]{Class template \tcode{atomic_ref}} \indexlibrary{\idxcode{atomic_ref}}% @@ -614,6 +729,9 @@ memory_order = memory_order_seq_cst) const noexcept; bool compare_exchange_strong(T&, T, memory_order = memory_order_seq_cst) const noexcept; + void wait(T, memory_order = memory_order::seq_cst) const noexcept; + void notify_one() noexcept; + void notify_all() noexcept; }; } \end{codeblock} @@ -907,6 +1025,72 @@ \end{note} \end{itemdescr} +\indexlibrarymember{wait}{atomic_ref}% +\begin{itemdecl} +void wait(T old, memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{order} is +neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Repeatedly performs the following steps, in order: +\begin{itemize} +\item + Evaluates \tcode{load(order)} and + compares its value representation for equality against that of \tcode{old}. +\item + If they compare unequal, returns. +\item + Blocks until it + is unblocked by an atomic notifying operation or is unblocked spuriously. +\end{itemize} + +\pnum +\remarks +This function is an atomic waiting operation\iref{atomics.wait} +on atomic object \tcode{*ptr}. +\end{itemdescr} + +\indexlibrarymember{notify_one}{atomic_ref}% +\begin{itemdecl} +void notify_one() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +Unblocks the execution of at least one atomic waiting operation on \tcode{*ptr} +that is eligible to be unblocked\iref{atomics.wait} by this call, +if any such atomic waiting operations exist. + +\pnum +\remarks +This function is an atomic notifying operation\iref{atomics.wait} +on atomic object \tcode{*ptr}. +\end{itemdescr} + +\indexlibrarymember{notify_all}{atomic_ref}% +\begin{itemdecl} +void notify_all() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +Unblocks the execution of all atomic waiting operations on \tcode{*ptr} +that are eligible to be unblocked\iref{atomics.wait} by this call. + +\pnum +\remarks + This function is an atomic notifying operation\iref{atomics.wait} + on atomic object \tcode{*ptr}. +\end{itemdescr} + \rSec2[atomics.ref.int]{Specializations for integral types} \pnum @@ -980,6 +1164,10 @@ @\placeholdernc{integral}@ fetch_xor(@\placeholdernc{integral}@, memory_order = memory_order_seq_cst) const noexcept; + void wait(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) const noexcept; + void notify_one() noexcept; + void notify_all() noexcept; + @\placeholdernc{integral}@ operator++(int) const noexcept; @\placeholdernc{integral}@ operator--(int) const noexcept; @\placeholdernc{integral}@ operator++() const noexcept; @@ -1083,24 +1271,28 @@ operator @\placeholdernc{floating-point}@() const noexcept; bool is_lock_free() const noexcept; - void store(@\placeholder{floating-point}@, memory_order = memory_order_seq_cst) const noexcept; + void store(@\placeholdernc{floating-point}@, memory_order = memory_order_seq_cst) const noexcept; @\placeholder{floating-point}@ load(memory_order = memory_order_seq_cst) const noexcept; - @\placeholder{floating-point}@ exchange(@\placeholder{floating-point}@, + @\placeholder{floating-point}@ exchange(@\placeholdernc{floating-point}@, memory_order = memory_order_seq_cst) const noexcept; - bool compare_exchange_weak(@\placeholder{floating-point}@&, @\placeholder{floating-point}@, + bool compare_exchange_weak(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, memory_order, memory_order) const noexcept; - bool compare_exchange_strong(@\placeholder{floating-point}@&, @\placeholder{floating-point}@, + bool compare_exchange_strong(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, memory_order, memory_order) const noexcept; - bool compare_exchange_weak(@\placeholder{floating-point}@&, @\placeholder{floating-point}@, + bool compare_exchange_weak(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, memory_order = memory_order_seq_cst) const noexcept; - bool compare_exchange_strong(@\placeholder{floating-point}@&, @\placeholder{floating-point}@, + bool compare_exchange_strong(@\placeholder{floating-point}@&, @\placeholdernc{floating-point}@, memory_order = memory_order_seq_cst) const noexcept; - @\placeholder{floating-point}@ fetch_add(@\placeholder{floating-point}@, + @\placeholder{floating-point}@ fetch_add(@\placeholdernc{floating-point}@, memory_order = memory_order_seq_cst) const noexcept; - @\placeholder{floating-point}@ fetch_sub(@\placeholder{floating-point}@, + @\placeholder{floating-point}@ fetch_sub(@\placeholdernc{floating-point}@, memory_order = memory_order_seq_cst) const noexcept; + void wait(@\placeholdernc{floating-point}@, memory_order = memory_order::seq_cst) const noexcept; + void notify_one() noexcept; + void notify_all() noexcept; + @\placeholder{floating-point}@ operator+=(@\placeholder{floating-point}@) const noexcept; @\placeholder{floating-point}@ operator-=(@\placeholder{floating-point}@) const noexcept; }; @@ -1196,6 +1388,10 @@ T* fetch_add(difference_type, memory_order = memory_order_seq_cst) const noexcept; T* fetch_sub(difference_type, memory_order = memory_order_seq_cst) const noexcept; + void wait(T*, memory_order = memory_order::seq_cst) const noexcept; + void notify_one() noexcept; + void notify_all() noexcept; + T* operator++(int) const noexcept; T* operator--(int) const noexcept; T* operator++() const noexcept; @@ -1329,6 +1525,13 @@ bool compare_exchange_strong(T&, T, memory_order = memory_order::seq_cst) volatile noexcept; bool compare_exchange_strong(T&, T, memory_order = memory_order::seq_cst) noexcept; + void wait(T, memory_order = memory_order::seq_cst) const volatile noexcept; + void wait(T, memory_order = memory_order::seq_cst) const noexcept; + void notify_one() volatile noexcept; + void notify_one() noexcept; + void notify_all() volatile noexcept; + void notify_all() noexcept; + atomic() noexcept = default; constexpr atomic(T) noexcept; atomic(const atomic&) = delete; @@ -1735,6 +1938,80 @@ \end{note} \end{itemdescr} +\indexlibrarymember{wait}{atomic}% +\indexlibrarymember{wait}{atomic}% +\indexlibrarymember{wait}{atomic<\placeholder{integral}>}% +\indexlibrarymember{wait}{atomic<\placeholder{floating-point}>}% +\begin{itemdecl} +void wait(T old, memory_order order = memory_order::seq_cst) const volatile noexcept; +void wait(T old, memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{order} is neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Repeatedly performs the following steps, in order: +\begin{itemize} +\item + Evaluates \tcode{load(order)} and + compares its value representation for equality against that of \tcode{old}. +\item + If they compare unequal, returns. +\item + Blocks until it + is unblocked by an atomic notifying operation or is unblocked spuriously. +\end{itemize} + +\pnum +\remarks +This function is an atomic waiting operation\iref{atomics.wait}. +\end{itemdescr} + +\indexlibrarymember{notify_one}{atomic}% +\indexlibrarymember{notify_one}{atomic}% +\indexlibrarymember{notify_one}{atomic<\placeholder{integral}>}% +\indexlibrarymember{notify_one}{atomic<\placeholder{floating-point}>}% +\begin{itemdecl} +void notify_one() volatile noexcept; +void notify_one() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Unblocks the execution of at least one atomic waiting operation +that is eligible to be unblocked\iref{atomics.wait} by this call, +if any such atomic waiting operations exist. + +\pnum +\remarks +This function is an atomic notifying operation\iref{atomics.wait}. +\end{itemdescr} + +\indexlibrarymember{notify_all}{atomic}% +\indexlibrarymember{notify_all}{atomic}% +\indexlibrarymember{notify_all}{atomic<\placeholder{integral}>}% +\indexlibrarymember{notify_all}{atomic<\placeholder{floating-point}>}% +\begin{itemdecl} +void notify_all() volatile noexcept; +void notify_all() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Unblocks the execution of all atomic waiting operations +that are eligible to be unblocked\iref{atomics.wait} by this call. + +\pnum +\remarks +This function is an atomic notifying operation\iref{atomics.wait}. +\end{itemdescr} + \rSec2[atomics.types.int]{Specializations for integers} \indexlibrary{\idxcode{atomic<\placeholder{integral}>}}% @@ -1806,6 +2083,13 @@ @\placeholdernc{integral}@ fetch_xor(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) volatile noexcept; @\placeholdernc{integral}@ fetch_xor(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) noexcept; + void wait(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) const volatile noexcept; + void wait(@\placeholdernc{integral}@, memory_order = memory_order::seq_cst) const noexcept; + void notify_one() volatile noexcept; + void notify_one() noexcept; + void notify_all() volatile noexcept; + void notify_all() noexcept; + atomic() noexcept = default; constexpr atomic(@\placeholdernc{integral}@) noexcept; atomic(const atomic&) = delete; @@ -1992,6 +2276,13 @@ @\placeholdernc{floating-point}@ fetch_sub(@\placeholdernc{floating-point}@, memory_order = memory_order_seq_cst) noexcept; + void wait(@\placeholdernc{floating-point}@, memory_order = memory_order::seq_cst) const volatile noexcept; + void wait(@\placeholdernc{floating-point}@, memory_order = memory_order::seq_cst) const noexcept; + void notify_one() volatile noexcept; + void notify_one() noexcept; + void notify_all() volatile noexcept; + void notify_all() noexcept; + atomic() noexcept = default; constexpr atomic(@\placeholder{floating-point}@) noexcept; atomic(const atomic&) = delete; @@ -2115,11 +2406,19 @@ memory_order = memory_order::seq_cst) volatile noexcept; bool compare_exchange_strong(T*&, T*, memory_order = memory_order::seq_cst) noexcept; + T* fetch_add(ptrdiff_t, memory_order = memory_order::seq_cst) volatile noexcept; T* fetch_add(ptrdiff_t, memory_order = memory_order::seq_cst) noexcept; T* fetch_sub(ptrdiff_t, memory_order = memory_order::seq_cst) volatile noexcept; T* fetch_sub(ptrdiff_t, memory_order = memory_order::seq_cst) noexcept; + void wait(T*, memory_order = memory_order::seq_cst) const volatile noexcept; + void wait(T*, memory_order = memory_order::seq_cst) const noexcept; + void notify_one() volatile noexcept; + void notify_one() noexcept; + void notify_all() volatile noexcept; + void notify_all() noexcept; + atomic() noexcept = default; constexpr atomic(T*) noexcept; atomic(const atomic&) = delete; @@ -2313,27 +2612,25 @@ \begin{codeblock} namespace std { struct atomic_flag { + bool test(memory_order = memory_order::seq_cst) const volatile noexcept; + bool test(memory_order = memory_order::seq_cst) const noexcept; bool test_and_set(memory_order = memory_order::seq_cst) volatile noexcept; bool test_and_set(memory_order = memory_order::seq_cst) noexcept; void clear(memory_order = memory_order::seq_cst) volatile noexcept; void clear(memory_order = memory_order::seq_cst) noexcept; + void wait(bool, memory_order = memory_order::seq_cst) const volatile noexcept; + void wait(bool, memory_order = memory_order::seq_cst) const noexcept; + void notify_one() volatile noexcept; + void notify_one() noexcept; + void notify_all() volatile noexcept; + void notify_all() noexcept; + atomic_flag() noexcept = default; atomic_flag(const atomic_flag&) = delete; atomic_flag& operator=(const atomic_flag&) = delete; atomic_flag& operator=(const atomic_flag&) volatile = delete; }; - - bool atomic_flag_test_and_set(volatile atomic_flag*) noexcept; - bool atomic_flag_test_and_set(atomic_flag*) noexcept; - bool atomic_flag_test_and_set_explicit(volatile atomic_flag*, memory_order) noexcept; - bool atomic_flag_test_and_set_explicit(atomic_flag*, memory_order) noexcept; - void atomic_flag_clear(volatile atomic_flag*) noexcept; - void atomic_flag_clear(atomic_flag*) noexcept; - void atomic_flag_clear_explicit(volatile atomic_flag*, memory_order) noexcept; - void atomic_flag_clear_explicit(atomic_flag*, memory_order) noexcept; - - #define ATOMIC_FLAG_INIT @\seebelow@ } \end{codeblock} @@ -2348,7 +2645,14 @@ The \tcode{atomic_flag} type is a standard-layout struct. It has a trivial default constructor and a trivial destructor. +\indexlibrary{\idxcode{ATOMIC_FLAG_INIT}}% +\begin{itemdecl} +#define ATOMIC_FLAG_INIT @\seebelow@ +\end{itemdecl} + +\begin{itemdescr} \pnum +\remarks The macro \tcode{ATOMIC_FLAG_INIT} shall be defined in such a way that it can be used to initialize an object of type \tcode{atomic_flag} to the clear state. The macro can be used in the form: \begin{codeblock} @@ -2358,6 +2662,39 @@ For a complete static-duration object, that initialization shall be static. Unless initialized with \tcode{ATOMIC_FLAG_INIT}, it is unspecified whether an \tcode{atomic_flag} object has an initial state of set or clear. +\end{itemdescr} + +\indexlibrary{\idxcode{atomic_flag_test}}% +\indexlibrary{\idxcode{atomic_flag_test_explicit}}% +\indexlibrarymember{test}{atomic_flag}% +\begin{itemdecl} +bool atomic_flag_test(const volatile atomic_flag* object) noexcept; +bool atomic_flag_test(const atomic_flag* object) noexcept; +bool atomic_flag_test_explicit(const volatile atomic_flag* object, + memory_order order) noexcept; +bool atomic_flag_test_explicit(const atomic_flag* object, + memory_order order) noexcept; +bool atomic_flag::test(memory_order order = memory_order::seq_cst) const volatile noexcept; +bool atomic_flag::test(memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +For \tcode{atomic_flag_test}, let \tcode{order} be \tcode{memory_order::seq_cst}. + +\pnum +\expects +\tcode{order} is +neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Memory is affected according to the value of \tcode{order}. + +\pnum +\returns +Atomically returns the value pointed to by \tcode{object} or \tcode{this}. +\end{itemdescr} \indexlibrary{\idxcode{atomic_flag_test_and_set}}% \indexlibrary{\idxcode{atomic_flag_test_and_set_explicit}}% @@ -2402,6 +2739,89 @@ \tcode{false}. Memory is affected according to the value of \tcode{order}. \end{itemdescr} +\indexlibrary{\idxcode{atomic_flag_wait}}% +\indexlibrary{\idxcode{atomic_flag_wait_explicit}}% +\indexlibrarymember{wait}{atomic_flag}% +\begin{itemdecl} +void atomic_flag_wait(const volatile atomic_flag* object, bool old) noexcept; +void atomic_flag_wait(const atomic_flag* object, bool old) noexcept; +void atomic_flag_wait_explicit(const volatile atomic_flag* object, + bool old, memory_order order) noexcept; +void atomic_flag_wait_explicit(const atomic_flag* object, + bool old, memory_order order) noexcept; +void atomic_flag::wait(bool old, memory_order order = + memory_order::seq_cst) const volatile noexcept; +void atomic_flag::wait(bool old, memory_order order = + memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +For \tcode{atomic_flag_wait}, +let \tcode{order} be \tcode{memory_order::seq_cst}. +Let \tcode{flag} be \tcode{object} for the non-member functions and +\tcode{this} for the member functions. + +\pnum +\expects +\tcode{order} is +neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Repeatedly performs the following steps, in order: +\begin{itemize} +\item + Evaluates \tcode{flag->test(order) != old}. +\item + If the result of that evaluation is \tcode{true}, returns. +\item + Blocks until it + is unblocked by an atomic notifying operation or is unblocked spuriously. +\end{itemize} + +\pnum +\remarks +This function is an atomic waiting operation\iref{atomics.wait}. +\end{itemdescr} + +\begin{itemdecl} +void atomic_flag_notify_one(volatile atomic_flag* object) noexcept; +void atomic_flag_notify_one(atomic_flag* object) noexcept; +void atomic_flag::notify_one() volatile noexcept; +void atomic_flag::notify_one() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Unblocks the execution of at least one atomic waiting operation +that is eligible to be unblocked\iref{atomics.wait} by this call, +if any such atomic waiting operations exist. + +\pnum +\remarks +This function is an atomic notifying operation\iref{atomics.wait}. +\end{itemdescr} + +\begin{itemdecl} +void atomic_flag_notify_all(volatile atomic_flag* object) noexcept; +void atomic_flag_notify_all(atomic_flag* object) noexcept; +void atomic_flag::notify_all() volatile noexcept; +void atomic_flag::notify_all() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Unblocks the execution of all atomic waiting operations +that are eligible to be unblocked\iref{atomics.wait} by this call. + +\pnum +\remarks +This function is an atomic notifying operation\iref{atomics.wait}. +\end{itemdescr} + \rSec1[atomics.fences]{Fences} \pnum diff --git a/source/basic.tex b/source/basic.tex index dac414469e..553516a7b2 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -176,6 +176,8 @@ \item it is a \grammarterm{using-directive}\iref{namespace.udir}, \item it is +a \grammarterm{using-enum-declaration}\iref{enum.udecl}, +\item it is an explicit instantiation declaration\iref{temp.explicit}, or \item it is an explicit specialization\iref{temp.expl.spec} whose @@ -274,9 +276,10 @@ \rSec1[basic.def.odr]{One-definition rule} \pnum -A variable, function, class type, enumeration type, or template -shall not be defined where a prior definition is necessarily reachable\iref{module.reach}; -no diagnostic is required if the prior declaration is in another translation unit. +No translation unit shall contain more than one definition of any +variable, function, class type, enumeration type, template, +default argument for a parameter (for a function in a given scope), or +default template argument. \pnum \indextext{expression!potentially evaluated}% @@ -539,19 +542,24 @@ \end{note} \pnum -There can be more than one definition of a class type\iref{class}, -enumeration type\iref{dcl.enum}, inline function -with external linkage\iref{dcl.inline}, inline variable with external -linkage\iref{dcl.inline}, class template\iref{temp}, -non-static function template\iref{temp.fct}, -concept\iref{temp.concept}, -static data member of a class template\iref{temp.static}, member -function of a class template\iref{temp.mem.func}, or template -specialization for which some template parameters are not -specified~(\ref{temp.spec}, \ref{temp.class.spec}) in a program -provided that -no prior definition is necessarily reachable\iref{module.reach} -at the point where a definition appears, and +There can be more than one definition of a +\begin{itemize} +\item class type\iref{class}, +\item enumeration type\iref{dcl.enum}, +\item inline function or variable\iref{dcl.inline} with external linkage, +\item class template\iref{temp}, +\item non-static function template\iref{temp.fct}, +\item concept\iref{temp.concept}, +\item static data member of a class template\iref{temp.static}, +\item member function of a class template\iref{temp.mem.func}, +\item template specialization for which some template parameters are not +specified~(\ref{temp.spec}, \ref{temp.class.spec}), +\item default argument for a parameter (for a function in a given scope)% +\iref{dcl.fct.default}, or +\item default template argument\iref{temp.param} +\end{itemize} +in a program provided that +each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. There shall not be more than one definition of an entity @@ -562,11 +570,13 @@ an entity named \tcode{D} defined in more than one translation unit, then \begin{itemize} -\item each definition of \tcode{D} shall consist of the same sequence of -tokens; and +\item each definition of \tcode{D} shall consist of +the same sequence of tokens, +for which the definition of a closure type +is considered to consist of the sequence of tokens of +the corresponding \grammarterm{lambda-expression}; and \item in each definition of \tcode{D}, corresponding names, looked up -according to~\ref{basic.lookup}, shall refer to an entity defined within -the definition of \tcode{D}, or shall refer to the same entity, after +according to~\ref{basic.lookup}, shall refer to the same entity, after overload resolution\iref{over.match} and after matching of partial template specialization\iref{temp.over}, except that a name can refer to \begin{itemize} @@ -586,30 +596,27 @@ \end{itemize} and +\item in each definition of \tcode{D}, except within +the default arguments and default template arguments of \tcode{D}, +corresponding \grammarterm{lambda-expression}{s} shall have +the same closure type (see below); and + \item in each definition of \tcode{D}, corresponding entities shall have the same language linkage; and \item in each definition of \tcode{D}, the overloaded operators referred to, the implicit calls to conversion functions, constructors, operator new functions and operator delete functions, shall refer to the same -function, or to a function defined within the definition of \tcode{D}; -and +function; and -\item in each definition of \tcode{D}, a default argument used by an -(implicit or explicit) function call is treated as if its token sequence -were present in the definition of \tcode{D}; that is, the default -argument is subject to the requirements described in this paragraph (and, if -the default argument has subexpressions with default arguments, this -requirement applies recursively)\footnote{\ref{dcl.fct.default} -describes how default argument names are looked up.}; and - -\item if \tcode{D} invokes a function with a precondition, -or is a function -that contains an assertion or has a contract condition\iref{dcl.attr.contract}, -it is \impldef{consistency of build level and violation continuation mode} -under which conditions all definitions of \tcode{D} -shall be translated using the same build level -and violation continuation mode; and +\item in each definition of \tcode{D}, +a default argument used by an (implicit or explicit) function call or +a default template argument used by an (implicit or explicit) +\grammarterm{template-id} or \grammarterm{simple-template-id} +is treated as if its token sequence +were present in the definition of \tcode{D}; +that is, the default argument or default template argument +is subject to the requirements described in this paragraph (recursively); and \item if \tcode{D} is a class with an implicitly-declared constructor (\ref{class.default.ctor}, \ref{class.copy.ctor}), @@ -644,25 +651,69 @@ // \tcode{D()}'s implicit definition violates the ODR \end{codeblock} \end{example} + +\item if \tcode{D} is a class with +a defaulted three-way comparison operator function\iref{class.spaceship}, +it is as if the operator was +implicitly defined in every translation unit where it is odr-used, and the +implicit definition in every translation unit shall call the same +comparison operators for each subobject of \tcode{D}. \end{itemize} If \tcode{D} is a template and is defined in more than one translation unit, then the preceding requirements shall apply both to names from the template's enclosing scope used in the template definition\iref{temp.nondep}, and also to dependent names at -the point of instantiation\iref{temp.dep}. If the definitions of -\tcode{D} satisfy all these requirements, then the behavior is -as if there were a single definition of \tcode{D}. +the point of instantiation\iref{temp.dep}. +These requirements also apply to corresponding entities +defined within each definition of \tcode{D} +(including the closure types of \grammarterm{lambda-expression}{s}, +but excluding entities defined within default arguments or +default template arguments of either \tcode{D} or +an entity not defined within \tcode{D}). +For each such entity and for \tcode{D} itself, +the behavior is as if there is a single entity with a single definition, +including in the application of these requirements to other entities. \begin{note} The entity is still declared in multiple translation units, and \ref{basic.link} still applies to these declarations. In particular, \grammarterm{lambda-expression}{s}\iref{expr.prim.lambda} appearing in the type of \tcode{D} may result -in the different declarations having distinct types. +in the different declarations having distinct types, and +\grammarterm{lambda-expression}{s} appearing in a default argument of \tcode{D} +may still denote different types in different translation units. \end{note} If the definitions of -\tcode{D} do not satisfy these requirements, then the behavior is -undefined.% +\tcode{D} do not satisfy these requirements, then +the program is ill-formed, no diagnostic required.% \indextext{one-definition rule|)} +\begin{example} +\begin{codeblock} +inline void f(bool cond, void (*p)()) { + if (cond) f(false, []{}); +} +inline void g(bool cond, void (*p)() = []{}) { + if (cond) g(false); +} +struct X { + void h(bool cond, void (*p)() = []{}) { + if (cond) h(false); + } +}; +\end{codeblock} + +If the definition of \tcode{f} appears in multiple translation units, +the behavior of the program is as if +there is only one definition of \tcode{f}. +If the definition of \tcode{g} appears in multiple translation units, +the program is ill-formed (no diagnostic required) because +each such definition uses a default argument that +refers to a distinct \grammarterm{lambda-expression} closure type. +The definition of \tcode{X} can appear +in multiple translation units of a valid program; +the \grammarterm{lambda-expression}{s} defined within +the default argument of \tcode{X::h} within the definition of \tcode{X} +denote the same closure type in each translation unit. +\end{example} \rSec1[basic.scope]{Scope}% \indextext{scope|(} @@ -764,9 +815,12 @@ \rSec2[basic.scope.pdecl]{Point of declaration} +\indextext{declaration!point of|(}% + \pnum -\indextext{name!point of declaration}% -The \defn{point of declaration} for a name is immediately after its +\indextext{name!point of declaration|see{declaration, point of}}% +\indextext{point of!declaration|see{declaration, point of}}% +The \defnx{point of declaration}{declaration!point of} for a name is immediately after its complete declarator\iref{dcl.decl} and before its \grammarterm{initializer} (if any), except as noted below. \begin{example} @@ -912,9 +966,11 @@ \end{note} \pnum -\begin{note} For point of instantiation of a template, -see~\ref{temp.point}.\end{note}% -\indextext{scope!declarations and|)} +\begin{note} +For point of instantiation of a template, see~\ref{temp.point}. +\end{note}% +\indextext{scope!declarations and|)}% +\indextext{declaration!point of|)} \rSec2[basic.scope.block]{Block scope} @@ -1858,7 +1914,7 @@ import M; export R::X make(); namespace R { static int g(X); } -template void apply(T t, U u) { +export template void apply(T t, U u) { f(t, u); g(t); } @@ -2399,7 +2455,8 @@ looked up in the class of the object expression\iref{class.member.lookup}. If the identifier is not found, it is then looked up in the context of the entire -\grammarterm{postfix-expression} and shall name a class template. +\grammarterm{postfix-expression} and shall name a template +whose specializations are types. \pnum If the \grammarterm{id-expression} in a class member @@ -2538,8 +2595,7 @@ \pnum A token sequence beginning with -\opt{\tcode{export}} \tcode{module} or -\opt{\tcode{export}} \tcode{import} +\opt{\tcode{export}} \tcode{module} and not immediately followed by \tcode{::} is never interpreted as the \grammarterm{declaration} of a \grammarterm{top-level-declaration}. @@ -3137,12 +3193,12 @@ \pnum A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the destructor for an -object of a class type with a non-trivial destructor. For an object of a -class type with a non-trivial destructor, the program is not required to +object of a class type. +For an object of a class type, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a \grammarterm{delete-expression}\iref{expr.delete} -is not used to release the storage, the destructor shall not be +is not used to release the storage, the destructor is not implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior. @@ -3620,14 +3676,7 @@ The order, contiguity, and initial value of storage allocated by successive calls to an allocation function are unspecified. -For an allocation function other than -a reserved placement allocation function\iref{new.delete.placement}, -the pointer returned is -suitably aligned so that it can be converted to a pointer to any -suitable complete object type\iref{new.delete.single} -and then used to access the object or array in the -storage allocated (until the storage is explicitly deallocated by a call -to a corresponding deallocation function). Even if the size of the space +Even if the size of the space requested is zero, the request can fail. If the request succeeds, the value returned by a replaceable allocation function is a non-null pointer value\iref{conv.ptr} @@ -3645,6 +3694,27 @@ substantially the same. \Cpp{} differs from C in requiring a zero request to return a non-null pointer.} +\pnum +For an allocation function other than +a reserved placement allocation function\iref{new.delete.placement}, +the pointer returned on a successful call +shall represent the address of storage that is aligned as follows: +\begin{itemize} +\item + If the allocation function takes an argument + of type \tcode{std::align_val_t}, + the storage will have the alignment specified + by the value of this argument. +\item + Otherwise, if the allocation function is named \tcode{operator new[]}, + the storage is aligned for any object that + does not have new-extended alignment\iref{basic.align} and + is no larger than the requested size. +\item + Otherwise, the storage is aligned for any object that + does not have new-extended alignment and is of the requested size. +\end{itemize} + \pnum An allocation function that fails to allocate storage can invoke the currently installed new-handler function\iref{new.handler}, if any. @@ -4030,10 +4100,9 @@ \pnum When an object of class type \tcode{X} is passed to or returned from a function, -if each copy constructor, move constructor, and destructor of \tcode{X} -is either trivial or deleted, -and \tcode{X} -has at least one non-deleted copy or move constructor, +if \tcode{X} has at least one eligible copy or move constructor\iref{special}, +each such constructor is trivial, +and the destructor of \tcode{X} is either trivial or deleted, implementations are permitted to create a temporary object to hold the function parameter or result object. @@ -4041,7 +4110,7 @@ from the function argument or return value, respectively, and the function's parameter or return object is initialized as if by -using the non-deleted trivial constructor to copy the temporary +using the eligible trivial constructor to copy the temporary (even if that constructor is inaccessible or would not be selected by overload resolution to perform a copy or move of the object). @@ -4471,7 +4540,7 @@ \item a possibly cv-qualified class type\iref{class} that has all of the following properties: \begin{itemize} -\item it has a trivial destructor, +\item it has a constexpr destructor\iref{dcl.constexpr}, \item it is either a closure type\iref{expr.prim.lambda.closure}, an aggregate type\iref{dcl.init.aggr}, or has at least one constexpr constructor or constructor template @@ -5503,10 +5572,8 @@ \begin{itemize} \item \placeholder{A} performs a release operation on an atomic object \placeholder{M}, and, in -another thread, \placeholder{B} performs a consume operation on \placeholder{M} and reads a -value written by any -\indextext{side effects}% -side effect in the release sequence headed by \placeholder{A}, or +another thread, \placeholder{B} performs a consume operation on \placeholder{M} and reads +the value written by \placeholder{A}, or \item for some evaluation \placeholder{X}, \placeholder{A} is dependency-ordered before \placeholder{X} and @@ -5856,11 +5923,12 @@ \pnum It is \impldef{whether the thread that executes \tcode{main} and the threads created -by \tcode{std::thread} provide concurrent forward progress guarantees} whether the +by \tcode{std::thread} or \tcode{std::jthread} provide concurrent forward progress guarantees} whether the implementation-created thread of execution that executes \tcode{main}\iref{basic.start.main} and the threads of execution created by -\tcode{std::thread}\iref{thread.thread.class} provide concurrent forward progress -guarantees. +\tcode{std::thread}\iref{thread.thread.class} +or \tcode{std::jthread}\iref{thread.jthread.class} +provide concurrent forward progress guarantees. \begin{note} General-purpose implementations should provide these guarantees. \end{note} @@ -6069,7 +6137,7 @@ \indextext{initialization!constant}% \defnx{Constant initialization}{constant initialization} is performed if a variable or temporary object with static or thread storage duration -is initialized by a constant initializer\iref{expr.const} for the entity. +is constant-initialized\iref{expr.const}. \indextext{initialization!zero-initialization}% If constant initialization is not performed, a variable with static storage duration\iref{basic.stc.static} or thread storage diff --git a/source/classes.tex b/source/classes.tex index 0b9e26bccf..7c14167ec5 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -146,19 +146,19 @@ A \defnadj{trivially copyable}{class} is a class: \begin{itemize} -\item where each copy constructor, move constructor, copy assignment operator, -and move assignment operator~(\ref{class.copy.ctor}, \ref{class.copy.assign}) -is either deleted or trivial, -\item that has at least one non-deleted copy constructor, move constructor, -copy assignment operator, or move assignment operator, and +\item that has at least one eligible +copy constructor, move constructor, +copy assignment operator, or +move assignment operator~(\ref{special}, \ref{class.copy.ctor}, \ref{class.copy.assign}), +\item where each eligible copy constructor, move constructor, copy assignment operator, +and move assignment operator is trivial, and \item that has a trivial, non-deleted destructor\iref{class.dtor}. \end{itemize} \pnum A \defnadj{trivial}{class} is a class that is trivially copyable and -has one or more default constructors\iref{class.default.ctor}, -all of which are either trivial or deleted and -at least one of which is not deleted. +has one or more eligible default constructors\iref{class.default.ctor}, +all of which are trivial. \begin{note} In particular, a trivially copyable or trivial class does not have virtual functions or virtual base classes.\end{note} @@ -440,6 +440,7 @@ \opt{attribute-specifier-seq} \opt{decl-specifier-seq} \opt{member-declarator-list} \terminal{;}\br function-definition\br using-declaration\br + using-enum-declaration\br static_assert-declaration\br template-declaration\br deduction-guide\br @@ -561,8 +562,7 @@ \begin{itemize} \item function body\iref{dcl.fct.def.general}, \item default argument\iref{dcl.fct.default}, -\item \grammarterm{noexcept-specifier}\iref{except.spec}, -\item contract condition\iref{dcl.attr.contract}, or +\item \grammarterm{noexcept-specifier}\iref{except.spec}, or \item default member initializer \end{itemize} within the \grammarterm{member-specification} of the class. @@ -713,19 +713,22 @@ \end{example} \pnum +\begin{note} \indextext{layout!class object}% Non-static data members of a (non-union) class -with the same access control\iref{class.access} +with the same access control\iref{class.access} and +non-zero size\iref{intro.object} are allocated so that later members have higher addresses within a class object. \indextext{allocation!unspecified}% The order of allocation of non-static data members with different access control -is unspecified\iref{class.access}. +is unspecified. Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions\iref{class.virtual} and virtual base classes\iref{class.mi}. +\end{note} \pnum If \tcode{T} is the name of a class, then each of the following shall @@ -1144,10 +1147,10 @@ \indextext{constructor!move}% \indextext{assignment operator!copy}% \indextext{assignment operator!move}% -The default constructor\iref{class.default.ctor}, -copy constructor, move constructor\iref{class.copy.ctor}, -copy assignment operator, move assignment operator\iref{class.copy.assign}, -and destructor\iref{class.dtor} are +Default constructors\iref{class.default.ctor}, +copy constructors, move constructors\iref{class.copy.ctor}, +copy assignment operators, move assignment operators\iref{class.copy.assign}, +and prospective destructors\iref{class.dtor} are \term{special member functions}. \begin{note} The implementation will implicitly declare these member functions for some class types when the program does not explicitly declare them. @@ -1192,6 +1195,25 @@ ensures that only derived classes and friends can create objects using it. \end{example} +\pnum +Two special member functions are of the same kind if: +\begin{itemize} +\item they are both default constructors, +\item they are both copy or move constructors +with the same first parameter type, or +\item they are both copy or move assignment operators +with the same first parameter type +and the same \grammarterm{cv-qualifier}s and \grammarterm{ref-qualifier}, if any. +\end{itemize} + +\pnum +An \defnadj{eligible}{special member function} is a special member function for which: +\begin{itemize} +\item the function is not deleted, +\item the associated constraints\iref{temp.constr}, if any, are satisfied, and +\item no special member function of the same kind is more constrained\iref{temp.constr.order}. +\end{itemize} + \pnum For a class, its non-static data members, its non-virtual direct base classes, and, if the class is not abstract\iref{class.abstract}, its virtual base @@ -1202,8 +1224,8 @@ \indextext{special member function|see{constructor}}% \pnum -Constructors do not have names. -In a declaration of a constructor, the \grammarterm{declarator} is a +A \defn{constructor} is introduced by a declaration +whose \grammarterm{declarator} is a function declarator\iref{dcl.fct} of the form \begin{ncbnf} @@ -1228,7 +1250,7 @@ \grammarterm{id-expression} is a \grammarterm{qualified-id} that names a constructor\iref{class.qual}. \end{itemize} - +Constructors do not have names. In a constructor declaration, each \grammarterm{decl-specifier} in the optional \grammarterm{decl-specifier-seq} shall be \tcode{friend}, \tcode{inline}, \tcode{constexpr}, or an \grammarterm{explicit-specifier}. @@ -2090,7 +2112,8 @@ \indextext{special member function|see{destructor}}% \pnum -In a declaration of a destructor, the \grammarterm{declarator} is a +A \defnadj{prospective}{destructor} is introduced by a declaration +whose \grammarterm{declarator} is a function declarator\iref{dcl.fct} of the form \begin{ncbnf} @@ -2118,10 +2141,46 @@ same class as the \grammarterm{nested-name-specifier}. \end{itemize} -A destructor shall take no arguments\iref{dcl.fct}. +A prospective destructor shall take no arguments\iref{dcl.fct}. Each \grammarterm{decl-specifier} of the \grammarterm{decl-specifier-seq} -of a destructor declaration (if any) shall be \tcode{friend}, \tcode{inline}, or -\tcode{virtual}. +of a prospective destructor declaration (if any) +shall be +\tcode{friend}, +\tcode{inline}, +\tcode{virtual}, +\tcode{constexpr}, or +\tcode{consteval}. + +\pnum +\indextext{generated destructor|see{destructor, default}}% +\indextext{destructor!default}% +If a class has no user-declared +prospective destructor, +a prospective destructor is implicitly +declared as defaulted\iref{dcl.fct.def}. +An implicitly-declared prospective destructor is an +inline public member of its class. + +\pnum +An implicitly-declared prospective destructor for a class \tcode{X} will have the form +\begin{codeblock} +~X() +\end{codeblock} + +\pnum +At the end of the definition of a class, +overload resolution is performed +among the prospective destructors declared in that class +with an empty argument list +to select the \defn{destructor} for the class, +also known as the \defnadj{selected}{destructor}. +The program is ill-formed if overload resolution fails. +Destructor selection does not constitute +a reference to, +or odr-use\iref{basic.def.odr} of, +the selected destructor, +and in particular, +the selected destructor may be deleted\iref{dcl.fct.def.delete}. \pnum \indextext{restriction!destructor}% @@ -2148,15 +2207,6 @@ has the same exception specification as if it had been implicitly declared\iref{except.spec}. \end{note} -\pnum -\indextext{generated destructor|see{destructor, default}}% -\indextext{destructor!default}% -If a class has no user-declared -destructor, a destructor is implicitly -declared as defaulted\iref{dcl.fct.def}. -An implicitly-declared destructor is an -inline public member of its class. - \pnum A defaulted destructor for a class \tcode{X} is defined as deleted if: @@ -2189,6 +2239,13 @@ Otherwise, the destructor is \defnx{non-trivial}{destructor!non-trivial}. +\pnum +A defaulted destructor is a constexpr destructor +if it satisfies the requirements for a constexpr destructor\iref{dcl.constexpr}. +\begin{note} +In particular, a trivial destructor is a constexpr destructor. +\end{note} + \pnum A destructor that is defaulted and not defined as deleted @@ -2198,7 +2255,7 @@ or when it is explicitly defaulted after its first declaration. \pnum -Before the +Before a defaulted destructor for a class is implicitly defined, all the non-user-provided destructors for its base classes and its non-static data members shall have been implicitly defined. @@ -2238,11 +2295,12 @@ \pnum \indextext{destructor!virtual}% \indextext{destructor!pure virtual}% -A destructor can be declared +A prospective destructor can be declared \tcode{virtual}\iref{class.virtual} or pure -\tcode{virtual}\iref{class.abstract}; -if any objects of that class or any derived class are created in the program, +\tcode{virtual}\iref{class.abstract}. +If the destructor of a class is virtual and +any objects of that class or any derived class are created in the program, the destructor shall be defined. If a class has a base class with a virtual destructor, its destructor (whether user- or implicitly-declared) is virtual. @@ -4058,45 +4116,6 @@ A \tcode{consteval} virtual function shall not be overridden by a virtual function that is not \tcode{consteval}. -\pnum -If an overriding function specifies contract conditions\iref{dcl.attr.contract}, -it shall specify the same list of contract conditions as -its overridden functions; -no diagnostic is required -if corresponding conditions will always evaluate to the same value. -Otherwise, it is considered to have -the list of contract conditions from one of its overridden functions; -the names in the contract conditions are bound, -and the semantic constraints are checked, -at the point where the contract conditions appear. -Given a virtual function \tcode{f} -with a contract condition that odr-uses \tcode{*this}\iref{basic.def.odr}, -the class of which \tcode{f} is a direct member -shall be be an unambiguous and accessible base class of any class -in which \tcode{f} is overridden. -If a function overrides more than one function, -all of the overridden functions shall have -the same list of contract conditions\iref{dcl.attr.contract}; -no diagnostic is required -if corresponding conditions will always evaluate to the same value. -\begin{example} -\begin{codeblock} -struct A { - virtual void g() [[expects: x == 0]]; - int x = 42; -}; - -int x = 42; -struct B { - virtual void g() [[expects: x == 0]]; -} - -struct C : A, B { - virtual void g(); // error: preconditions of overridden functions are not the same -}; -\end{codeblock} -\end{example} - \rSec2[class.abstract]{Abstract classes}% \pnum @@ -6581,35 +6600,40 @@ \end{example} \pnum +An \defnadj{implicitly movable}{entity} is +a variable of automatic storage duration +that is either a non-volatile object or +an rvalue reference to a non-volatile object type. In the following copy-initialization contexts, a move operation might be used instead of a copy operation: \begin{itemize} -\item If the \grammarterm{expression} in a \tcode{return} or \tcode{co_return} statement\iref{stmt.return} +\item If the \grammarterm{expression} in a \tcode{return}\iref{stmt.return} or +\tcode{co_return}\iref{stmt.return.coroutine} statement is a (possibly parenthesized) \grammarterm{id-expression} -that names an object with automatic storage duration declared in the body +that names an implicitly movable entity declared in the body or \grammarterm{parameter-declaration-clause} of the innermost enclosing function or \grammarterm{lambda-expression}, or \item if the operand of a \grammarterm{throw-expression}\iref{expr.throw} -is the name of a non-volatile automatic object -(other than a function or catch-clause parameter) -whose scope does not extend beyond the end of the innermost enclosing -\grammarterm{try-block} (if there is one), +is a (possibly parenthesized) \grammarterm{id-expression} +that names an implicitly movable entity +whose scope does not extend beyond the \grammarterm{compound-statement} +of the innermost \grammarterm{try-block} or \grammarterm{function-try-block} +(if any) +whose \grammarterm{compound-statement} or \grammarterm{ctor-initializer} +encloses the \grammarterm{throw-expression}, \end{itemize} overload resolution to select the constructor for the copy or the \tcode{return_value} overload to call -is first performed as if the object were designated by an -rvalue. +is first performed as if the expression or operand were an rvalue. If the first overload resolution fails or was not performed, -or if the type of the first parameter of the selected -constructor or the \tcode{return_value} overload -is not an rvalue reference to the object's type (possibly cv-qualified), -overload resolution is performed again, considering the object as an lvalue. +overload resolution is performed again, +considering the expression or operand as an lvalue. \begin{note} This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor or the \tcode{return_value} overload to be called if elision is not performed, and the selected constructor -or the \tcode{return_value} overload must be accessible even if +or \tcode{return_value} overload must be accessible even if the call is elided. \end{note} @@ -6646,6 +6670,30 @@ \end{codeblock} \end{example} +\pnum +\begin{example} +\begin{codeblock} +template void g(const T&); + +template void f() { + T x; + try { + T y; + try { g(x); } + catch (...) { + if (/*...*/) + throw x; // does not move + throw y; // moves + } + g(y); + } catch(...) { + g(x); + g(y); // error: \tcode{y} is not in scope + } +} +\end{codeblock} +\end{example} + \rSec1[class.compare]{Comparisons}% \rSec2[class.compare.default]{Defaulted comparison operator functions}% @@ -6661,6 +6709,12 @@ \item a friend of \tcode{C} having two parameters of type \tcode{const C\&}. \end{itemize} +\pnum +A defaulted comparison operator function for class \tcode{C} +is defined as deleted if +any non-static data member of \tcode{C} is of reference type or +\tcode{C} is a union-like class\iref{class.union.anon}. + \pnum If the class definition does not explicitly declare an \tcode{==} operator function, @@ -6697,15 +6751,22 @@ given a glvalue \tcode{x} of type \tcode{const C}, either: \begin{itemize} \item - \tcode{C} is a non-class type and \tcode{x <=> x} is a valid expression - of type \tcode{std::strong_ordering} or \tcode{std::strong_equality}, or +\tcode{C} is a non-class type and +\tcode{x <=> x} is a valid expression +of type \tcode{std::strong_ordering} or \tcode{std::strong_equality}, or + \item - \tcode{C} is a class type with an \tcode{==} operator - defined as defaulted in the definition of \tcode{C}, - \tcode{x == x} is well-formed when contextually converted to \tcode{bool}, - all of \tcode{C}'s base class subobjects and non-static data members - have strong structural equality, and - \tcode{C} has no \tcode{mutable} or \tcode{volatile} subobjects. +\tcode{C} is a class type +where all of the following hold: +\begin{itemize} +\item All of \tcode{C}'s base class subobjects and non-static data members +have strong structural equality. +\item \tcode{C} has no mutable or volatile non-static data members. +\item At the end of the definition of \tcode{C}, +overload resolution performed for the expression \tcode{x == x} succeeds and +finds either a friend or public member \tcode{==} operator +that is defined as defaulted in the definition of \tcode{C}. +\end{itemize} \end{itemize} \pnum @@ -6760,15 +6821,12 @@ with parameters \tcode{x} and \tcode{y} is defined as deleted if \begin{itemize} \item - overload resolution\iref{over.match}, as applied to \tcode{x == y} - (also considering synthesized candidates - with reversed order of parameters\iref{over.match.oper}), - results in an ambiguity or a function - that is deleted or inaccessible from the operator function, or + overload resolution\iref{over.match}, as applied to \tcode{x == y}, + does not result in a usable function, or \item - \tcode{x == y} cannot be contextually converted to \tcode{bool}. + \tcode{x == y} is not a prvalue of type \tcode{bool}. \end{itemize} -Otherwise, the operator function yields \tcode{(x == y) ?\ false :\ true}. +Otherwise, the operator function yields \tcode{!(x == y)}. \pnum \begin{example} @@ -6777,7 +6835,7 @@ int i; friend bool operator==(const D& x, const D& y) = default; // OK, returns \tcode{x.i == y.i} - bool operator!=(const D& z) const = default; // OK, returns \tcode{(*this == z) ?\ false :\ true} + bool operator!=(const D& z) const = default; // OK, returns \tcode{!(*this == z)} }; \end{codeblock} \end{example} @@ -6785,24 +6843,92 @@ \rSec2[class.spaceship]{Three-way comparison} \indextext{operator!three-way comparison!defaulted}% +\pnum +The \defnadj{synthesized}{three-way comparison} +for comparison category type \tcode{R}\iref{cmp.categories} +of glvalues \tcode{a} and \tcode{b} of the same type +is defined as follows: + +\begin{itemize} +\item +If overload resolution for \tcode{a <=> b} +finds a usable function\iref{over.match}, +\tcode{static_cast(a <=> b)}. + +\item +Otherwise, if overload resolution for \tcode{a <=> b} +finds at least one viable candidate, +the synthesized three-way comparison is not defined. + +\item +Otherwise, if \tcode{R} is \tcode{strong_ordering}, then +\begin{codeblock} +a == b ? strong_ordering::equal : +a < b ? strong_ordering::less : + strong_ordering::greater +\end{codeblock} + +\item +Otherwise, if \tcode{R} is \tcode{weak_ordering}, then +\begin{codeblock} +a == b ? weak_ordering::equal : +a < b ? weak_ordering::less : + weak_ordering::greater +\end{codeblock} + +\item +Otherwise, if \tcode{R} is \tcode{partial_ordering}, then +\begin{codeblock} +a == b ? partial_ordering::equivalent : +a < b ? partial_ordering::less : +b < a ? partial_ordering::greater : + partial_ordering::unordered +\end{codeblock} + +\item +Otherwise, if \tcode{R} is \tcode{strong_equality}, then +\begin{codeblock} +a == b ? strong_equality::equal : strong_equality::nonequal +\end{codeblock} + +\item +Otherwise, if \tcode{R} is \tcode{weak_equality}, then +\begin{codeblock} +a == b ? weak_equality::equivalent : weak_equality::nonequivalent +\end{codeblock} + +\item +Otherwise, the synthesized three-way comparison is not defined. +\end{itemize} +\begin{note} +A synthesized three-way comparison may be ill-formed +if overload resolution finds usable functions +that do not otherwise meet the requirements implied by the defined expression. +\end{note} + \pnum Given an expanded list of subobjects for an object \tcode{x} of type \tcode{C}, the type of the expression $\tcode{x}_i$ \tcode{<=>} $\tcode{x}_i$ is denoted by $\tcode{R}_i$. +If overload resolution as applied to $\tcode{x}_i$ \tcode{<=>} $\tcode{x}_i$ +does not find a usable function, +then $\tcode{R}_i$ is \tcode{void}. If the declared return type of a defaulted three-way comparison operator function is \tcode{auto}, then the return type is deduced as the common comparison type (see below) of $\tcode{R}_0$, $\tcode{R}_1$, $\dotsc$, $\tcode{R}_{n-1}$. -\begin{note} -Otherwise, -the program will be ill-formed -if the expression $\tcode{x}_i$ \tcode{<=>} $\tcode{x}_i$ -is not implicitly convertible to the declared return type for any $i$. -\end{note} If the return type is deduced as \tcode{void}, the operator function is defined as deleted. +If the declared return type of +a defaulted three-way comparison operator function +is \tcode{R} +and the synthesized three-way comparison +for comparison category type \tcode{R} +between any objects $\tcode{x}_i$ and $\tcode{x}_i$ +is not defined or would be ill-formed, +the operator function is defined as deleted. \pnum The return value \tcode{V} of type \tcode{R} @@ -6812,11 +6938,12 @@ $\tcode{x}_i$ and $\tcode{y}_i$ in the expanded lists of subobjects for \tcode{x} and \tcode{y} (in increasing index order) -until the first index $i$ -where $\tcode{x}_i$ \tcode{<=>} $\tcode{y}_i$ +until the first index $i$ where +the synthesized three-way comparison for comparison category type \tcode{R} +between $\tcode{x}_i$ and $\tcode{y}_i$ yields a result value $\tcode{v}_i$ where $\tcode{v}_i \mathrel{\tcode{!=}} 0$, contextually converted to \tcode{bool}, yields \tcode{true}; -\tcode{V} is $\tcode{v}_i$ converted to \tcode{R}. +\tcode{V} is $\tcode{v}_i$. If no such index exists, \tcode{V} is \tcode{std::strong_ordering::equal} converted to \tcode{R}. @@ -6874,10 +7001,8 @@ \begin{itemize} \item overload resolution\iref{over.match}, -as applied to \tcode{x <=> y} -results in an ambiguity -or a function that is deleted or inaccessible from the operator function, -or +as applied to \tcode{x <=> y}, +does not result in a usable function, or \item the operator \tcode{@} diff --git a/source/compatibility.tex b/source/compatibility.tex index bdcd591c17..69ab2d722c 100644 --- a/source/compatibility.tex +++ b/source/compatibility.tex @@ -1819,6 +1819,9 @@ The \tcode{consteval} keyword is added to declare immediate functions\iref{dcl.constexpr}. \item +The \keyword{constinit} keyword is added to +prevent unintended dynamic initialization\iref{dcl.constinit}. +\item The \tcode{co_await}, \tcode{co_yield}, and \tcode{co_return} keywords are added to enable the definition of coroutines \iref{dcl.fct.def.coroutine}. \item @@ -1922,6 +1925,34 @@ \rSec2[diff.cpp17.dcl.dcl]{\ref{dcl.dcl}: declarations} +\diffref{dcl.typedef} +\change Unnamed classes with a typedef name for linkage purposes +can contain only C-compatible constructs. +\rationale Necessary for implementability. +\effect Valid C++ 2017 code may be ill-formed in this International Standard. +\begin{codeblock} +typedef struct { + void f() {} // ill-formed; previously well-formed +} S; +\end{codeblock} + +\diffref{dcl.fct.default} +\change A function cannot have different default arguments +in different translation units. +\rationale Required for modules support. +\effect Valid C++ 2017 code may be ill-formed in this International Standard, +with no diagnostic required. +\begin{codeblock} +// Translation unit 1 +int f(int a = 42); +int g() { return f(); } + +// Translation unit 2 +int f(int a = 76) { return a; } // ill-formed (no diagnostic required); previously well-formed +int g(); +int main() { return g(); } // used to return 42 +\end{codeblock} + \diffref{dcl.init.aggr} \change A class that has user-declared constructors is never an aggregate. \rationale Remove potentially error-prone aggregate initialization @@ -1999,11 +2030,87 @@ template struct A { A(); // error: \grammarterm{simple-template-id} not allowed for constructor - A(int); // OK, \grammarterm{injected-class-name} used + A(int); // OK, injected-class-name used ~A(); // error: \grammarterm{simple-template-id} not allowed for destructor }; \end{codeblock} +\diffref{class.copy.elision} +\change +A function returning an implicitly movable entity +may invoke a constructor taking an rvalue reference to a type +different from that of the returned expression. +Function and catch-clause parameters can be thrown using move constructors. +\rationale +Side effect of making it easier to write +more efficient code that takes advantage of moves. +\effect +Valid \CppXVII{} code may fail to compile or have different semantics +in this International Standard. +For example: +\begin{codeblock} +struct base { + base(); + base(base const &); +private: + base(base &&); +}; + +struct derived : base {}; + +base f(base b) { + throw b; // error: \tcode{base(base \&\&)} is private + derived d; + return d; // error: \tcode{base(base \&\&)} is private +} + +struct S { + S(const char *s) : m(s) { } + S(const S&) = default; + S(S&& other) : m(other.m) { other.m = nullptr; } + const char * m; +}; + +S consume(S&& s) { return s; } + +void g() { + S s("text"); + consume(static_cast(s)); + char c = *s.m; // undefined behavior; previously ok +} +\end{codeblock} + +\rSec2[diff.cpp17.over]{\ref{over}: overloading} + +\diffref{over.match.oper} +\change +Equality and inequality expressions can now find +reversed and rewritten candidates. +\rationale +Improve consistency of equality with three-way comparison +and make it easier to write the full complement of equality operations. +\effect +Equality and inequality expressions between two objects of different types, +where one is convertible to the other, +could invoke a different operator. +Equality and inequality expressions between two objects of the same type +could become ambiguous. +\begin{codeblock} +struct A { + operator int() const; +}; + +bool operator==(A, int); // \#1 +// \#2 is built-in candidate: \tcode{bool operator==(int, int);} +// \#3 is built-in candidate: \tcode{bool operator!=(int, int);} + +int check(A x, A y) { + return (x == y) + // ill-formed; previously well-formed + (10 == x) + // calls \#1, previously selected \#2 + (10 != x); // calls \#1, previously selected \#3 +} +\end{codeblock} + \rSec2[diff.cpp17.temp]{\ref{temp}: templates} \diffref{temp.names} @@ -2062,13 +2169,20 @@ \rationale New functionality. \effect The following \Cpp{} headers are new: +\tcode{}, \tcode{}, +\tcode{}, \tcode{}, \tcode{}, -\tcode{}, \tcode{}, +\tcode{}, +\tcode{}, +\tcode{}, \tcode{}, +\tcode{}, +\tcode{}, \tcode{}, +\tcode{}, \tcode{}, and \tcode{}. Valid \CppXVII{} code that \tcode{\#include}{s} headers with these names may be @@ -2149,14 +2263,33 @@ \rationale Required for new features. \effect -Valid ISO \CppXVII{} code that passes UTF-8 literals -to \tcode{basic_ostream::\brk{}operator<<} -no longer calls character-related overloads. +Valid ISO \CppXVII{} code that passes UTF-8 literals to +\tcode{basic_ostream::operator<<} or +\tcode{basic_ostream::operator<<} is now ill-formed. \begin{codeblock} std::cout << u8"text"; // previously called \tcode{operator<<(const char*)} and printed a string; - // now calls \tcode{operator<<(const void*)} and prints a pointer value + // now ill-formed std::cout << u8'X'; // previously called \tcode{operator<<(char)} and printed a character; - // now calls \tcode{operator<<(int)} and prints an integer value + // now ill-formed +\end{codeblock} + +\diffref{ostream.inserters.character} +\change +Overload resolution for ostream inserters +used with \tcode{wchar_t}, \tcode{char16_t}, or \tcode{char32_t} types. +\rationale +Removal of surprising behavior. +\effect +Valid ISO \CppXVII{} code that passes +\tcode{wchar_t}, \tcode{char16_t}, or \tcode{char32_t} characters or strings +to \tcode{basic_ostream::operator<<} or +that passes \tcode{char16_t} or \tcode{char32_t} characters or strings +to \tcode{basic_ostream::operator<<} is now ill-formed. +\begin{codeblock} +std::cout << u"text"; // previously formatted the string as a pointer value; + // now ill-formed +std::cout << u'X'; // previously formatted the character as an integer value; + // now ill-formed \end{codeblock} \diffref{fs.class.path} diff --git a/source/concepts.tex b/source/concepts.tex index a2969a1163..b94f4cce6f 100644 --- a/source/concepts.tex +++ b/source/concepts.tex @@ -147,116 +147,118 @@ \begin{codeblock} namespace std { // \ref{concepts.lang}, language-related concepts - // \ref{concept.same}, concept \libconcept{Same} + // \ref{concept.same}, concept \libconcept{same_as} template - concept Same = @\seebelow@; + concept same_as = @\seebelow@; - // \ref{concept.derivedfrom}, concept \libconcept{DerivedFrom} + // \ref{concept.derived}, concept \libconcept{derived_from} template - concept DerivedFrom = @\seebelow@; + concept derived_from = @\seebelow@; - // \ref{concept.convertibleto}, concept \libconcept{ConvertibleTo} + // \ref{concept.convertible}, concept \libconcept{convertible_to} template - concept ConvertibleTo = @\seebelow@; + concept convertible_to = @\seebelow@; - // \ref{concept.commonref}, concept \libconcept{CommonReference} + // \ref{concept.commonref}, concept \libconcept{common_reference_with} template - concept CommonReference = @\seebelow@; + concept common_reference_with = @\seebelow@; - // \ref{concept.common}, concept \libconcept{Common} + // \ref{concept.common}, concept \libconcept{common_with} template - concept Common = @\seebelow@; + concept common_with = @\seebelow@; - // \ref{concepts.integral}, integral concepts + // \ref{concepts.arithmetic}, arithmetic concepts template - concept Integral = @\seebelow@; + concept integral = @\seebelow@; template - concept SignedIntegral = @\seebelow@; + concept signed_integral = @\seebelow@; template - concept UnsignedIntegral = @\seebelow@; + concept unsigned_integral = @\seebelow@; + template + concept floating_point = @\seebelow@; - // \ref{concept.assignable}, concept \libconcept{Assignable} + // \ref{concept.assignable}, concept \libconcept{assignable_from} template - concept Assignable = @\seebelow@; + concept assignable_from = @\seebelow@; - // \ref{concept.swappable}, concept \libconcept{Swappable} + // \ref{concept.swappable}, concept \libconcept{swappable} namespace ranges { inline namespace @\unspec@ { inline constexpr @\unspec@ swap = @\unspec@; } } template - concept Swappable = @\seebelow@; + concept swappable = @\seebelow@; template - concept SwappableWith = @\seebelow@; + concept swappable_with = @\seebelow@; - // \ref{concept.destructible}, concept \libconcept{Destructible} + // \ref{concept.destructible}, concept \libconcept{destructible} template - concept Destructible = @\seebelow@; + concept destructible = @\seebelow@; - // \ref{concept.constructible}, concept \libconcept{Constructible} + // \ref{concept.constructible}, concept \libconcept{constructible_from} template - concept Constructible = @\seebelow@; + concept constructible_from = @\seebelow@; - // \ref{concept.defaultconstructible}, concept \libconcept{DefaultConstructible} + // \ref{concept.defaultconstructible}, concept \libconcept{default_constructible} template - concept DefaultConstructible = @\seebelow@; + concept default_constructible = @\seebelow@; - // \ref{concept.moveconstructible}, concept \libconcept{MoveConstructible} + // \ref{concept.moveconstructible}, concept \libconcept{move_constructible} template - concept MoveConstructible = @\seebelow@; + concept move_constructible = @\seebelow@; - // \ref{concept.copyconstructible}, concept \libconcept{CopyConstructible} + // \ref{concept.copyconstructible}, concept \libconcept{copy_constructible} template - concept CopyConstructible = @\seebelow@; + concept copy_constructible = @\seebelow@; // \ref{concepts.compare}, comparison concepts - // \ref{concept.boolean}, concept \libconcept{Boolean} + // \ref{concept.boolean}, concept \libconcept{boolean} template - concept Boolean = @\seebelow@; + concept boolean = @\seebelow@; - // \ref{concept.equalitycomparable}, concept \libconcept{EqualityComparable} + // \ref{concept.equalitycomparable}, concept \libconcept{equality_comparable} template - concept EqualityComparable = @\seebelow@; + concept equality_comparable = @\seebelow@; template - concept EqualityComparableWith = @\seebelow@; + concept equality_comparable_with = @\seebelow@; - // \ref{concept.stricttotallyordered}, concept \libconcept{StrictTotallyOrdered} + // \ref{concept.totallyordered}, concept \libconcept{totally_ordered} template - concept StrictTotallyOrdered = @\seebelow@; + concept totally_ordered = @\seebelow@; template - concept StrictTotallyOrderedWith = @\seebelow@; + concept totally_ordered_with = @\seebelow@; // \ref{concepts.object}, object concepts template - concept Movable = @\seebelow@; + concept movable = @\seebelow@; template - concept Copyable = @\seebelow@; + concept copyable = @\seebelow@; template - concept Semiregular = @\seebelow@; + concept semiregular = @\seebelow@; template - concept Regular = @\seebelow@; + concept regular = @\seebelow@; // \ref{concepts.callable}, callable concepts - // \ref{concept.invocable}, concept \libconcept{Invocable} + // \ref{concept.invocable}, concept \libconcept{invocable} template - concept Invocable = @\seebelow@; + concept invocable = @\seebelow@; - // \ref{concept.regularinvocable}, concept \libconcept{RegularInvocable} + // \ref{concept.regularinvocable}, concept \libconcept{regular_invocable} template - concept RegularInvocable = @\seebelow@; + concept regular_invocable = @\seebelow@; - // \ref{concept.predicate}, concept \libconcept{Predicate} + // \ref{concept.predicate}, concept \libconcept{predicate} template - concept Predicate = @\seebelow@; + concept predicate = @\seebelow@; - // \ref{concept.relation}, concept \libconcept{Relation} + // \ref{concept.relation}, concept \libconcept{relation} template - concept Relation = @\seebelow@; + concept relation = @\seebelow@; - // \ref{concept.strictweakorder}, concept \libconcept{StrictWeakOrder} + // \ref{concept.strictweakorder}, concept \libconcept{strict_weak_order} template - concept StrictWeakOrder = @\seebelow@; + concept strict_weak_order = @\seebelow@; } \end{codeblock} @@ -269,31 +271,31 @@ features. These concepts express relationships between types, type classifications, and fundamental type properties. -\rSec2[concept.same]{Concept \libconcept{Same}} +\rSec2[concept.same]{Concept \libconcept{same_as}} -\indexlibrary{\idxcode{Same}}% +\indexlibrary{\idxcode{same_as}}% \begin{itemdecl} template - concept @\placeholdernc{same-impl}@ = is_same_v; // \expos + concept @\placeholdernc{same-as-impl}@ = is_same_v; // \expos template - concept Same = @\placeholdernc{same-impl}@ && @\placeholdernc{same-impl}@; + concept same_as = @\placeholdernc{same-as-impl}@ && @\placeholdernc{same-as-impl}@; \end{itemdecl} \begin{itemdescr} \pnum \begin{note} -\tcode{\libconcept{Same}} subsumes \tcode{\libconcept{Same}} and +\tcode{\libconcept{same_as}} subsumes \tcode{\libconcept{same_as}} and vice versa. \end{note} \end{itemdescr} -\rSec2[concept.derivedfrom]{Concept \libconcept{DerivedFrom}} +\rSec2[concept.derived]{Concept \libconcept{derived_from}} -\indexlibrary{\idxcode{DerivedFrom}}% +\indexlibrary{\idxcode{derived_from}}% \begin{itemdecl} template - concept DerivedFrom = + concept derived_from = is_base_of_v && is_convertible_v; \end{itemdecl} @@ -301,24 +303,24 @@ \begin{itemdescr} \pnum \begin{note} -\tcode{\libconcept{DerivedFrom}} is satisfied if and only if +\tcode{\libconcept{derived_from}} is satisfied if and only if \tcode{Derived} is publicly and unambiguously derived from \tcode{Base}, or \tcode{Derived} and \tcode{Base} are the same class type ignoring cv-qualifiers. \end{note} \end{itemdescr} -\rSec2[concept.convertibleto]{Concept \libconcept{ConvertibleTo}} +\rSec2[concept.convertible]{Concept \libconcept{convertible_to}} \pnum -The \libconcept{ConvertibleTo} concept requires an expression of a particular +The \libconcept{convertible_to} concept requires an expression of a particular type and value category to be both implicitly and explicitly convertible to some other type. The implicit and explicit conversions are required to produce equal results. -\indexlibrary{\idxcode{ConvertibleTo}}% +\indexlibrary{\idxcode{convertible_to}}% \begin{itemdecl} template - concept ConvertibleTo = + concept convertible_to = is_convertible_v && requires(From (&f)()) { static_cast(f()); @@ -336,7 +338,7 @@ for some types \tcode{From} and \tcode{To}, and let \tcode{f} be a function with no arguments and return type \tcode{From} such that \tcode{f()} is equality-preserving. -\tcode{From} and \tcode{To} model \tcode{\libconcept{ConvertibleTo}} +\tcode{From} and \tcode{To} model \tcode{\libconcept{convertible_to}} only if: \begin{itemize} @@ -361,14 +363,14 @@ \end{itemdescr} -\rSec2[concept.commonref]{Concept \libconcept{CommonReference}} +\rSec2[concept.commonref]{Concept \libconcept{common_reference_with}} \pnum For two types \tcode{T} and \tcode{U}, if \tcode{common_reference_t} is well-formed and denotes a type \tcode{C} such that both -\tcode{\libconcept{ConvertibleTo}} +\tcode{\libconcept{convertible_to}} and -\tcode{\libconcept{ConvertibleTo}} +\tcode{\libconcept{convertible_to}} are modeled, then \tcode{T} and \tcode{U} share a \term{common reference type}, \tcode{C}. \begin{note} @@ -376,13 +378,13 @@ different type. \tcode{C} may be a reference type. \end{note} -\indexlibrary{\idxcode{CommonReference}}% +\indexlibrary{\idxcode{common_reference_with}}% \begin{itemdecl} template - concept CommonReference = - Same, common_reference_t> && - ConvertibleTo> && - ConvertibleTo>; + concept common_reference_with = + same_as, common_reference_t> && + convertible_to> && + convertible_to>; \end{itemdecl} \begin{itemdescr} @@ -393,7 +395,7 @@ \tcode{decltype((t1))} and \tcode{decltype((t2))} are each \tcode{T}, and let \tcode{u1} and \tcode{u2} be equality-preserving expressions such that \tcode{decltype((u1))} and \tcode{decltype((u2))} are each \tcode{U}. -\tcode{T} and \tcode{U} model \tcode{\libconcept{CommonReference}} +\tcode{T} and \tcode{U} model \tcode{\libconcept{common_reference_with}} only if: \begin{itemize} \item \tcode{C(t1)} equals \tcode{C(t2)} if and only if @@ -404,12 +406,12 @@ \pnum \begin{note} -Users can customize the behavior of \libconcept{CommonReference} by specializing +Users can customize the behavior of \libconcept{common_reference_with} by specializing the \tcode{basic_common_reference} class template\iref{meta.trans.other}. \end{note} \end{itemdescr} -\rSec2[concept.common]{Concept \libconcept{Common}} +\rSec2[concept.common]{Concept \libconcept{common_with}} \pnum If \tcode{T} and \tcode{U} can both be explicitly converted to some third type, @@ -420,19 +422,19 @@ different type. \tcode{C} might not be unique. \end{note} -\indexlibrary{\idxcode{Common}}% +\indexlibrary{\idxcode{common_with}}% \begin{itemdecl} template - concept Common = - Same, common_type_t> && + concept common_with = + same_as, common_type_t> && requires { static_cast>(declval()); static_cast>(declval()); } && - CommonReference< + common_reference_with< add_lvalue_reference_t, add_lvalue_reference_t> && - CommonReference< + common_reference_with< add_lvalue_reference_t>, common_reference_t< add_lvalue_reference_t, @@ -447,7 +449,7 @@ \tcode{decltype((t1))} and \tcode{decltype((t2))} are each \tcode{T}, and let \tcode{u1} and \tcode{u2} be equality-preserving expressions such that \tcode{decltype((u1))} and \tcode{decltype((u2))} are each \tcode{U}. -\tcode{T} and \tcode{U} model \tcode{\libconcept{Common}} +\tcode{T} and \tcode{U} model \tcode{\libconcept{common_with}} only if: \begin{itemize} \item \tcode{C(t1)} equals \tcode{C(t2)} if and only if @@ -458,50 +460,52 @@ \pnum \begin{note} -Users can customize the behavior of \libconcept{Common} by specializing the +Users can customize the behavior of \libconcept{common_with} by specializing the \tcode{common_type} class template\iref{meta.trans.other}. \end{note} \end{itemdescr} -\rSec2[concepts.integral]{Integral concepts} +\rSec2[concepts.arithmetic]{Arithmetic concepts} -\indexlibrary{\idxcode{Integral}}% -\indexlibrary{\idxcode{SignedIntegral}}% -\indexlibrary{\idxcode{UnsignedIntegral}}% +\indexlibrary{\idxcode{integral}}% +\indexlibrary{\idxcode{signed_integral}}% +\indexlibrary{\idxcode{unsigned_integral}}% \begin{itemdecl} template - concept Integral = is_integral_v; + concept integral = is_integral_v; +template + concept signed_integral = integral && is_signed_v; template - concept SignedIntegral = Integral && is_signed_v; + concept unsigned_integral = integral && !signed_integral; template - concept UnsignedIntegral = Integral && !SignedIntegral; + concept floating_point = is_floating_point_v; \end{itemdecl} \begin{itemdescr} \pnum \begin{note} -\libconcept{SignedIntegral} can be modeled even by types that are +\libconcept{signed_integral} can be modeled even by types that are not signed integral types\iref{basic.fundamental}; for example, \tcode{char}. \end{note} \pnum \begin{note} -\libconcept{UnsignedIntegral} can be modeled even by types that are +\libconcept{unsigned_integral} can be modeled even by types that are not unsigned integral types\iref{basic.fundamental}; for example, \tcode{bool}. \end{note} \end{itemdescr} -\rSec2[concept.assignable]{Concept \libconcept{Assignable}} +\rSec2[concept.assignable]{Concept \libconcept{assignable_from}} -\indexlibrary{\idxcode{Assignable}}% +\indexlibrary{\idxcode{assignable_from}}% \begin{itemdecl} template - concept Assignable = + concept assignable_from = is_lvalue_reference_v && - CommonReference&, const remove_reference_t&> && + common_reference_with&, const remove_reference_t&> && requires(LHS lhs, RHS&& rhs) { - { lhs = std::forward(rhs) } -> Same; + { lhs = std::forward(rhs) } -> same_as; }; \end{itemdecl} @@ -516,7 +520,7 @@ \item \tcode{rcopy} be a distinct object that is equal to \tcode{rhs}. \end{itemize} \tcode{LHS} and \tcode{RHS} model -\tcode{\libconcept{Assignable}} only if +\tcode{\libconcept{assignable_from}} only if \begin{itemize} \item \tcode{addressof(lhs = rhs) == addressof(lcopy)}. @@ -544,7 +548,7 @@ \end{note} \end{itemdescr} -\rSec2[concept.swappable]{Concept \libconcept{Swappable}} +\rSec2[concept.swappable]{Concept \libconcept{swappable}} \pnum Let \tcode{t1} and \tcode{t2} be equality-preserving expressions that denote @@ -561,7 +565,7 @@ is that \tcode{t1} equals \tcode{u2} and \tcode{u1} equals \tcode{t2}. \item If \tcode{T} and \tcode{U} are different types that model - \libconcept{CommonReference}, + \tcode{\libconcept{common_reference_with}}, the result of the operation is that \tcode{C(t1)} equals \tcode{C(u2)} and @@ -605,8 +609,8 @@ \item Otherwise, if \tcode{E1} and \tcode{E2} are lvalues of the - same type \tcode{T} that models \libconcept{MoveConstructible} and - \libconcept{Assignable}, + same type \tcode{T} that models \tcode{\libconcept{move_constructible}} and + \tcode{\libconcept{assignable_from}}, \tcode{S} is an expression that exchanges the denoted values. \tcode{S} is a constant expression if \begin{itemize} @@ -639,17 +643,17 @@ \tcode{E1} and \tcode{E2} and has type \tcode{void}. \end{note} -\indexlibrary{\idxcode{Swappable}}% +\indexlibrary{\idxcode{swappable}}% \begin{itemdecl} template - concept Swappable = requires(T& a, T& b) { ranges::swap(a, b); }; + concept swappable = requires(T& a, T& b) { ranges::swap(a, b); }; \end{itemdecl} -\indexlibrary{\idxcode{SwappableWith}}% +\indexlibrary{\idxcode{swappable_with}}% \begin{itemdecl} template - concept SwappableWith = - CommonReference&, const remove_reference_t&> && + concept swappable_with = + common_reference_with&, const remove_reference_t&> && requires(T&& t, U&& u) { ranges::swap(std::forward(t), std::forward(t)); ranges::swap(std::forward(u), std::forward(u)); @@ -660,7 +664,7 @@ \pnum \begin{note} -The semantics of the \libconcept{Swappable} and \libconcept{SwappableWith} +The semantics of the \libconcept{swappable} and \libconcept{swappable_with} concepts are fully defined by the \tcode{ranges::swap} customization point. \end{note} @@ -675,12 +679,12 @@ namespace ranges = std::ranges; -template U> +template U> void value_swap(T&& t, U&& u) { ranges::swap(std::forward(t), std::forward(u)); } -template +template void lv_swap(T& t1, T& t2) { ranges::swap(t1, t2); } @@ -708,17 +712,17 @@ \end{codeblock} \end{example} -\rSec2[concept.destructible]{Concept \libconcept{Destructible}} +\rSec2[concept.destructible]{Concept \libconcept{destructible}} \pnum -The \libconcept{Destructible} concept specifies properties of all types, +The \libconcept{destructible} concept specifies properties of all types, instances of which can be destroyed at the end of their lifetime, or reference types. -\indexlibrary{\idxcode{Destructible}}% +\indexlibrary{\idxcode{destructible}}% \begin{itemdecl} template - concept Destructible = is_nothrow_destructible_v; + concept destructible = is_nothrow_destructible_v; \end{itemdecl} \begin{itemdescr} @@ -730,39 +734,39 @@ \end{note} \end{itemdescr} -\rSec2[concept.constructible]{Concept \libconcept{Constructible}} +\rSec2[concept.constructible]{Concept \libconcept{constructible_from}} \pnum -The \libconcept{Constructible} concept constrains the initialization of a +The \libconcept{constructible_from} concept constrains the initialization of a variable of a given type with a particular set of argument types. -\indexlibrary{\idxcode{Constructible}}% +\indexlibrary{\idxcode{constructible_from}}% \begin{itemdecl} template - concept Constructible = Destructible && is_constructible_v; + concept constructible_from = destructible && is_constructible_v; \end{itemdecl} -\rSec2[concept.defaultconstructible]{Concept \libconcept{DefaultConstructible}} +\rSec2[concept.defaultconstructible]{Concept \libconcept{default_constructible}} -\indexlibrary{\idxcode{DefaultConstructible}}% +\indexlibrary{\idxcode{default_constructible}}% \begin{itemdecl} template - concept DefaultConstructible = Constructible; + concept default_constructible = constructible_from; \end{itemdecl} -\rSec2[concept.moveconstructible]{Concept \libconcept{MoveConstructible}} +\rSec2[concept.moveconstructible]{Concept \libconcept{move_constructible}} -\indexlibrary{\idxcode{MoveConstructible}}% +\indexlibrary{\idxcode{move_constructible}}% \begin{itemdecl} template - concept MoveConstructible = Constructible && ConvertibleTo; + concept move_constructible = constructible_from && convertible_to; \end{itemdecl} \begin{itemdescr} \pnum If \tcode{T} is an object type, then let \tcode{rv} be an rvalue of type \tcode{T} and \tcode{u2} a distinct object of type \tcode{T} equal to -\tcode{rv}. \tcode{T} models \libconcept{MoveConstructible} only if +\tcode{rv}. \tcode{T} models \libconcept{move_constructible} only if \begin{itemize} \item After the definition \tcode{T u = rv;}, \tcode{u} is equal to \tcode{u2}. @@ -774,23 +778,23 @@ \end{itemize} \end{itemdescr} -\rSec2[concept.copyconstructible]{Concept \libconcept{CopyConstructible}} +\rSec2[concept.copyconstructible]{Concept \libconcept{copy_constructible}} -\indexlibrary{\idxcode{CopyConstructible}}% +\indexlibrary{\idxcode{copy_constructible}}% \begin{itemdecl} template - concept CopyConstructible = - MoveConstructible && - Constructible && ConvertibleTo && - Constructible && ConvertibleTo && - Constructible && ConvertibleTo; + concept copy_constructible = + move_constructible && + constructible_from && convertible_to && + constructible_from && convertible_to && + constructible_from && convertible_to; \end{itemdecl} \begin{itemdescr} \pnum If \tcode{T} is an object type, then let \tcode{v} be an lvalue of type (possibly \tcode{const}) \tcode{T} or an rvalue of type \tcode{const T}. -\tcode{T} models \libconcept{CopyConstructible} only if +\tcode{T} models \libconcept{copy_constructible} only if \begin{itemize} \item After the definition \tcode{T u = v;}, \tcode{u} is equal to \tcode{v}. @@ -808,40 +812,40 @@ This subclause describes concepts that establish relationships and orderings on values of possibly differing object types. -\rSec2[concept.boolean]{Concept \libconcept{Boolean}} +\rSec2[concept.boolean]{Concept \libconcept{boolean}} \pnum -The \libconcept{Boolean} concept specifies the requirements on a type that is +The \libconcept{boolean} concept specifies the requirements on a type that is usable in Boolean contexts. -\indexlibrary{\idxcode{Boolean}}% +\indexlibrary{\idxcode{boolean}}% \begin{itemdecl} template - concept Boolean = - Movable> && // (see \ref{concepts.object}) + concept boolean = + movable> && // (see \ref{concepts.object}) requires(const remove_reference_t& b1, const remove_reference_t& b2, const bool a) { - { b1 } -> ConvertibleTo; - { !b1 } -> ConvertibleTo; - { b1 && a } -> Same; - { b1 || a } -> Same; - { b1 && b2 } -> Same; - { a && b2 } -> Same; - { b1 || b2 } -> Same; - { a || b2 } -> Same; - { b1 == b2 } -> ConvertibleTo; - { b1 == a } -> ConvertibleTo; - { a == b2 } -> ConvertibleTo; - { b1 != b2 } -> ConvertibleTo; - { b1 != a } -> ConvertibleTo; - { a != b2 } -> ConvertibleTo; + { b1 } -> convertible_to; + { !b1 } -> convertible_to; + { b1 && b2 } -> same_as; + { b1 && a } -> same_as; + { a && b2 } -> same_as; + { b1 || b2 } -> same_as; + { b1 || a } -> same_as; + { a || b2 } -> same_as; + { b1 == b2 } -> convertible_to; + { b1 == a } -> convertible_to; + { a == b2 } -> convertible_to; + { b1 != b2 } -> convertible_to; + { b1 != a } -> convertible_to; + { a != b2 } -> convertible_to; }; \end{itemdecl} \pnum For some type \tcode{B}, let \tcode{b1} and \tcode{b2} be lvalues of type \tcode{const remove_reference_t}. -\tcode{B} models \libconcept{Boolean} only if +\tcode{B} models \libconcept{boolean} only if \begin{itemize} \item \tcode{bool(b1) == !bool(!b1)}. @@ -864,22 +868,22 @@ \pnum \begin{example} The types \tcode{bool}, \tcode{true_type}\iref{meta.type.synop}, and -\tcode{bitset<$N$>::reference}\iref{template.bitset} are \libconcept{Boolean} +\tcode{bitset<$N$>::reference}\iref{template.bitset} are \libconcept{boolean} types. Pointers, smart pointers, and types with only explicit conversions to -\tcode{bool} are not \libconcept{Boolean} types. +\tcode{bool} are not \libconcept{boolean} types. \end{example} -\rSec2[concept.equalitycomparable]{Concept \libconcept{EqualityComparable}} +\rSec2[concept.equalitycomparable]{Concept \libconcept{equality_comparable}} \begin{itemdecl} template concept @\placeholder{weakly-equality-comparable-with}@ = // \expos requires(const remove_reference_t& t, const remove_reference_t& u) { - { t == u } -> Boolean; - { t != u } -> Boolean; - { u == t } -> Boolean; - { u != t } -> Boolean; + { t == u } -> boolean; + { t != u } -> boolean; + { u == t } -> boolean; + { u != t } -> boolean; }; \end{itemdecl} @@ -900,16 +904,16 @@ \end{itemize} \end{itemdescr} -\indexlibrary{\idxcode{EqualityComparable}}% +\indexlibrary{\idxcode{equality_comparable}}% \begin{itemdecl} template - concept EqualityComparable = @\placeholder{weakly-equality-comparable-with}@; + concept equality_comparable = @\placeholder{weakly-equality-comparable-with}@; \end{itemdecl} \begin{itemdescr} \pnum Let \tcode{a} and \tcode{b} be objects of type \tcode{T}. -\tcode{T} models \libconcept{EqualityComparable} only if +\tcode{T} models \libconcept{equality_comparable} only if \tcode{bool(a == b)} is \tcode{true} when \tcode{a} is equal to \tcode{b}\iref{concepts.equality}, and \tcode{false} otherwise. @@ -920,13 +924,13 @@ \end{note} \end{itemdescr} -\indexlibrary{\idxcode{EqualityComparableWith}}% +\indexlibrary{\idxcode{equality_comparable_with}}% \begin{itemdecl} template - concept EqualityComparableWith = - EqualityComparable && EqualityComparable && - CommonReference&, const remove_reference_t&> && - EqualityComparable< + concept equality_comparable_with = + equality_comparable && equality_comparable && + common_reference_with&, const remove_reference_t&> && + equality_comparable< common_reference_t< const remove_reference_t&, const remove_reference_t&>> && @@ -943,23 +947,23 @@ common_reference_t&, const remove_reference_t&> \end{codeblock} \tcode{T} and \tcode{U} model -\tcode{\libconcept{EqualityComparableWith}} only if +\tcode{\libconcept{equality_comparable_with}} only if \tcode{bool(t == u) == bool(C(t) == C(u))}. \end{itemdescr} -\rSec2[concept.stricttotallyordered]{Concept \libconcept{StrictTotallyOrdered}} +\rSec2[concept.totallyordered]{Concept \libconcept{totally_ordered}} -\indexlibrary{\idxcode{StrictTotallyOrdered}}% +\indexlibrary{\idxcode{totally_ordered}}% \begin{itemdecl} template - concept StrictTotallyOrdered = - EqualityComparable && + concept totally_ordered = + equality_comparable && requires(const remove_reference_t& a, const remove_reference_t& b) { - { a < b } -> Boolean; - { a > b } -> Boolean; - { a <= b } -> Boolean; - { a >= b } -> Boolean; + { a < b } -> boolean; + { a > b } -> boolean; + { a <= b } -> boolean; + { a >= b } -> boolean; }; \end{itemdecl} @@ -967,7 +971,7 @@ \pnum For some type \tcode{T}, let \tcode{a}, \tcode{b}, and \tcode{c} be lvalues of type \tcode{const remove_reference_t}. -\tcode{T} models \libconcept{StrictTotallyOrdered} only if +\tcode{T} models \libconcept{totally_ordered} only if \begin{itemize} \item Exactly one of \tcode{bool(a < b)}, \tcode{bool(a > b)}, or @@ -983,24 +987,24 @@ \begin{itemdecl} template - concept StrictTotallyOrderedWith = - StrictTotallyOrdered && StrictTotallyOrdered && - CommonReference&, const remove_reference_t&> && - StrictTotallyOrdered< + concept totally_ordered_with = + totally_ordered && totally_ordered && + common_reference_with&, const remove_reference_t&> && + totally_ordered< common_reference_t< const remove_reference_t&, const remove_reference_t&>> && - EqualityComparableWith && + equality_comparable_with && requires(const remove_reference_t& t, const remove_reference_t& u) { - { t < u } -> Boolean; - { t > u } -> Boolean; - { t <= u } -> Boolean; - { t >= u } -> Boolean; - { u < t } -> Boolean; - { u > t } -> Boolean; - { u <= t } -> Boolean; - { u >= t } -> Boolean; + { t < u } -> boolean; + { t > u } -> boolean; + { t <= u } -> boolean; + { t >= u } -> boolean; + { u < t } -> boolean; + { u > t } -> boolean; + { u <= t } -> boolean; + { u >= t } -> boolean; }; \end{itemdecl} @@ -1014,7 +1018,7 @@ common_reference_t&, const remove_reference_t&> \end{codeblock} \tcode{T} and \tcode{U} model -\tcode{\libconcept{StrictTotallyOrderedWith}} only if +\tcode{\libconcept{totally_ordered_with}} only if \begin{itemize} \item \tcode{bool(t < u) == bool(C(t) < C(u)).} @@ -1034,32 +1038,33 @@ This subclause describes concepts that specify the basis of the value-oriented programming style on which the library is based. -\indexlibrary{\idxcode{Movable}}% -\indexlibrary{\idxcode{Copyable}}% -\indexlibrary{\idxcode{Semiregular}}% -\indexlibrary{\idxcode{Regular}}% +\indexlibrary{\idxcode{movable}}% +\indexlibrary{\idxcode{copyable}}% +\indexlibrary{\idxcode{semiregular}}% +\indexlibrary{\idxcode{regular}}% \begin{itemdecl} template - concept Movable = is_object_v && MoveConstructible && Assignable && Swappable; + concept movable = is_object_v && move_constructible && + assignable_from && swappable; template - concept Copyable = CopyConstructible && Movable && Assignable; + concept copyable = copy_constructible && movable && assignable_from; template - concept Semiregular = Copyable && DefaultConstructible; + concept semiregular = copyable && default_constructible; template - concept Regular = Semiregular && EqualityComparable; + concept regular = semiregular && equality_comparable; \end{itemdecl} \begin{itemdescr} \pnum \begin{note} -The \libconcept{Semiregular} concept is modeled by types that behave similarly +The \libconcept{semiregular} concept is modeled by types that behave similarly to built-in types like \tcode{int}, except that they might not be comparable with \tcode{==}. \end{note} \pnum \begin{note} -The \libconcept{Regular} concept is modeled by types that behave similarly to +The \libconcept{regular} concept is modeled by types that behave similarly to built-in types like \tcode{int} and that are comparable with \tcode{==}. \end{note} @@ -1073,17 +1078,17 @@ The concepts in this subclause describe the requirements on function objects\iref{function.objects} and their arguments. -\rSec2[concept.invocable]{Concept \libconcept{Invocable}} +\rSec2[concept.invocable]{Concept \libconcept{invocable}} \pnum -The \libconcept{Invocable} concept specifies a relationship between a callable +The \libconcept{invocable} concept specifies a relationship between a callable type\iref{func.def} \tcode{F} and a set of argument types \tcode{Args...} which can be evaluated by the library function \tcode{invoke}\iref{func.invoke}. -\indexlibrary{\idxcode{Invocable}}% +\indexlibrary{\idxcode{invocable}}% \begin{itemdecl} template - concept Invocable = requires(F&& f, Args&&... args) { + concept invocable = requires(F&& f, Args&&... args) { invoke(std::forward(f), std::forward(args)...); // not required to be equality-preserving }; \end{itemdecl} @@ -1091,18 +1096,18 @@ \begin{itemdescr} \pnum \begin{example} -A function that generates random numbers can model \libconcept{Invocable}, +A function that generates random numbers can model \libconcept{invocable}, since the \tcode{invoke} function call expression is not required to be equality-preserving\iref{concepts.equality}. \end{example} \end{itemdescr} -\rSec2[concept.regularinvocable]{Concept \libconcept{RegularInvocable}} +\rSec2[concept.regularinvocable]{Concept \libconcept{regular_invocable}} -\indexlibrary{\idxcode{RegularInvocable}}% +\indexlibrary{\idxcode{regular_invocable}}% \begin{itemdecl} template - concept RegularInvocable = Invocable; + concept regular_invocable = invocable; \end{itemdecl} \begin{itemdescr} @@ -1112,50 +1117,50 @@ arguments\iref{concepts.equality}. \begin{note} This requirement supersedes the annotation in the definition of -\libconcept{Invocable}. +\libconcept{invocable}. \end{note} \pnum \begin{example} -A random number generator does not model \libconcept{RegularInvocable}. +A random number generator does not model \libconcept{regular_invocable}. \end{example} \pnum \begin{note} -The distinction between \libconcept{Invocable} and \libconcept{RegularInvocable} +The distinction between \libconcept{invocable} and \libconcept{regular_invocable} is purely semantic. \end{note} \end{itemdescr} -\rSec2[concept.predicate]{Concept \libconcept{Predicate}} +\rSec2[concept.predicate]{Concept \libconcept{predicate}} -\indexlibrary{\idxcode{Predicate}}% +\indexlibrary{\idxcode{predicate}}% \begin{itemdecl} template - concept Predicate = RegularInvocable && Boolean>; + concept predicate = regular_invocable && boolean>; \end{itemdecl} -\rSec2[concept.relation]{Concept \libconcept{Relation}} +\rSec2[concept.relation]{Concept \libconcept{relation}} -\indexlibrary{\idxcode{Relation}}% +\indexlibrary{\idxcode{relation}}% \begin{itemdecl} template - concept Relation = - Predicate && Predicate && - Predicate && Predicate; + concept relation = + predicate && predicate && + predicate && predicate; \end{itemdecl} -\rSec2[concept.strictweakorder]{Concept \libconcept{StrictWeakOrder}} +\rSec2[concept.strictweakorder]{Concept \libconcept{strict_weak_order}} -\indexlibrary{\idxcode{Relation}}% +\indexlibrary{\idxcode{strict_weak_order}}% \begin{itemdecl} template - concept StrictWeakOrder = Relation; + concept strict_weak_order = relation; \end{itemdecl} \begin{itemdescr} \pnum -A \libconcept{Relation} models \libconcept{StrictWeakOrder} only if +A \libconcept{relation} models \libconcept{strict_weak_order} only if it imposes a \term{strict weak ordering} on its arguments. \pnum diff --git a/source/config.tex b/source/config.tex index 75dc7ebf33..6e6488607d 100644 --- a/source/config.tex +++ b/source/config.tex @@ -1,8 +1,8 @@ %!TEX root = std.tex %%-------------------------------------------------- %% Version numbers -\newcommand{\docno}{N4820} -\newcommand{\prevdocno}{N4810} +\newcommand{\docno}{N4830} +\newcommand{\prevdocno}{N4820} \newcommand{\cppver}{201703L} %% Release date diff --git a/source/containers.tex b/source/containers.tex index df227bfcd6..24b4216aaf 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -71,12 +71,12 @@ In Tables~\ref{tab:container.req}, \ref{tab:container.rev.req}, and \ref{tab:container.opt} -\tcode{X} denotes a container class containing objects of type -\tcode{T}, \tcode{a} and \tcode{b} -denote values of type \tcode{X}, \tcode{u} -denotes an identifier, \tcode{r} denotes -a non-const value of type \tcode{X}, and \tcode{rv} -denotes a non-const rvalue of type \tcode{X}. +\tcode{X} denotes a container class containing objects of type \tcode{T}, +\tcode{a} and \tcode{b} denote values of type \tcode{X}, +\tcode{i} and \tcode{j} denote values of type (possibly const) \tcode{X::iterator}, +\tcode{u} denotes an identifier, +\tcode{r} denotes a non-const value of type \tcode{X}, and +\tcode{rv} denotes a non-const rvalue of type \tcode{X}. \begin{libreqtab5} {Container requirements} @@ -211,6 +211,14 @@ & constant \\ \rowsep +\tcode{i <=> j} & + \tcode{strong_ordering} + if \tcode{X::iterator} meets the random access iterator requirements, + otherwise \tcode{strong_equality} & + & + & + constant \\ \rowsep + \tcode{a == b} & convertible to \tcode{bool} & \tcode{==} is an equivalence relation. @@ -293,6 +301,7 @@ i <= j i >= j i > j +i <=> j i - j \end{codeblock} where \tcode{i} and \tcode{j} denote objects of a container's \tcode{iterator} @@ -456,14 +465,14 @@ whose member types \tcode{iterator} and \tcode{const_iterator} meet the \oldconcept{RandomAccessIterator} requirements\iref{random.access.iterators} and -model \libconcept{ContiguousIterator}\iref{iterator.concept.contiguous}. +model \libconcept{contiguous_iterator}\iref{iterator.concept.contiguous}. \pnum \tref{container.opt} lists operations that are provided for some types of containers but not others. Those containers for which the listed operations are provided shall implement the semantics described in \tref{container.opt} unless otherwise stated. -If the iterators passed to \tcode{lexicographical_compare} +If the iterators passed to \tcode{lexicographical_compare_three_way} meet the constexpr iterator requirements\iref{iterator.requirements.general} then the operations described in \tref{container.opt} are implemented by constexpr functions. @@ -483,33 +492,20 @@ & & \chdr{semantics} & \chdr{pre-/post-condition} & \\ \capsep \endhead -\tcode{a < b} & - convertible to \tcode{bool} & - \tcode{lexicographical_compare( a.begin(), a.end(), b.begin(), b.end())} & - \expects \tcode{<} is defined for values of type (possibly \tcode{const}) \tcode{T}. \tcode{<} is a total ordering relationship. & - linear \\ \rowsep - -\tcode{a > b} & - convertible to \tcode{bool} & - \tcode{b < a} & - & - linear \\ \rowsep - -\tcode{a <= b} & - convertible to \tcode{bool} & - \tcode{!(a > b)} & - & - linear \\ \rowsep - -\tcode{a >= b} & - convertible to \tcode{bool} & - \tcode{!(a < b)} & - & +\tcode{a <=> b} & + \tcode{\placeholdernc{synth-three-\brk{}way-result}\brk{}} & + \tcode{lexicographical_compare_three_way(a.begin(), a.end(), + b.begin(), b.end(), \placeholdernc{synth-three-way})} & + \expects + Either \tcode{<=>} is defined for values of type (possibly const) \tcode{T}, + or \tcode{<} is defined for values of type (possibly const) \tcode{T} and + \tcode{<} is a total ordering relationship. & linear \\ \end{libreqtab5} \begin{note} -The algorithm \tcode{lexicographical_compare()} is defined in \ref{algorithms}. +The algorithm \tcode{lexicographical_compare_three_way} +is defined in \ref{algorithms}. \end{note} \pnum @@ -2296,9 +2292,8 @@ \end{itemize} where \tcode{r1} and \tcode{r2} are keys of elements in \tcode{a_tran}, \item \tcode{n} denotes a value of type \tcode{size_type}, -\item \tcode{z} denotes a value of type \tcode{float}, -\item \tcode{nh} denotes a non-const rvalue of type \tcode{X::node_type}, and -\item \tcode{hk} and \tcode{hke} denote values of type \tcode{size_t}. +\item \tcode{z} denotes a value of type \tcode{float}, and +\item \tcode{nh} denotes a non-const rvalue of type \tcode{X::node_type}. \end{itemize} % Local command to index names as members of all unordered containers. @@ -2752,14 +2747,6 @@ & Average case \bigoh{1}, worst case \bigoh{\tcode{b.size()}}. \\ \rowsep % -\tcode{b.find(k, hk)} -& \tcode{iterator}; \br \tcode{const_iterator} for const \tcode{b}. -& \expects \tcode{b.hash_function()(k)} equals \tcode{hk}.\br - \returns An iterator pointing to an element with key equivalent to - \tcode{k}, or \tcode{b.end()} if no such element exists. -& Average case \bigoh{1}, worst case \bigoh{\tcode{b.size()}}. -\\ \rowsep -% \tcode{a_tran.find(ke)} & \tcode{iterator}; \br \tcode{const_iterator} for const \tcode{a_tran}. & \returns An iterator pointing to an element with key equivalent to @@ -2768,15 +2755,6 @@ worst case \bigoh{\tcode{a_tran.}\br{}\tcode{size()}}. % avoid overfull \\ \rowsep % -\tcode{a_tran.find(ke, hke)} -& \tcode{iterator}; \br \tcode{const_iterator} for const \tcode{a_tran}. -& \expects \tcode{a_tran.hash_function()(ke)} equals \tcode{hke}.\br - \returns An iterator pointing to an element with key equivalent to - \tcode{ke}, or \tcode{a_tran.end()} if no such element exists.% -& Average case \bigoh{1}, - worst case \bigoh{\tcode{a_tran.}\br{}\tcode{size()}}. % avoid overfull -\\ \rowsep -% \indexunordmem{count}% \tcode{b.count(k)} & \tcode{size_type} @@ -2784,13 +2762,6 @@ & Average case \bigoh{\tcode{b.count(k)}}, worst case \bigoh{\tcode{b.size()}}. \\ \rowsep % -\tcode{b.count(k, hk)} -& \tcode{size_type} -& \expects \tcode{b.hash_function()(k)} equals \tcode{hk}.\br - \returns The number of elements with key equivalent to \tcode{k}.% -& Average case \bigoh{\tcode{b.count(k)}}, worst case \bigoh{\tcode{b.size()}}. -\\ \rowsep -% \tcode{a_tran.count(ke)} & \tcode{size_type} & \returns The number of elements with key equivalent to \tcode{ke}.% @@ -2799,15 +2770,6 @@ worst case \bigoh{\tcode{a_tran.}\br{}\tcode{size()}}. % avoid overfull \\ \rowsep % -\tcode{a_tran.count(ke, hke)} -& \tcode{size_type} -& \expects \tcode{b.hash_function()(ke)} equals \tcode{hke}.\br - \returns The number of elements with key equivalent to \tcode{ke}.% -& Average case - \bigoh{\tcode{a_tran.}\br{}\tcode{count(ke)}}, % avoid overfull - worst case \bigoh{\tcode{a_tran.}\br{}\tcode{size()}}. % avoid overfull -\\ \rowsep -% \indexunordmem{contains}% \tcode{b.contains(k)} & \tcode{bool} @@ -2815,13 +2777,6 @@ & Average case \bigoh{1}, worst case \bigoh{\tcode{b.size()}}. \\ \rowsep % -\tcode{b.contains(k, hk)} -& \tcode{bool} -& \expects \tcode{b.hash_function()(ke)} equals \tcode{hke}.\br - \effects Equivalent to \tcode{b.find(k) != b.end()}% -& Average case \bigoh{1}, worst case \bigoh{\tcode{b.size()}}. -\\ \rowsep -% \tcode{a_tran.contains(ke)} & \tcode{bool} & \effects Equivalent to \tcode{a_tran.find(ke) != a_tran.end()}% @@ -2829,14 +2784,6 @@ worst case \bigoh{\tcode{a_tran.}\br{}\tcode{size()}}. % avoid overfull \\ \rowsep % -\tcode{a_tran.contains(ke, hke)} -& \tcode{bool} -& \expects \tcode{a_tran.hash_function()(ke)} equals \tcode{hke}.\br - \effects Equivalent to \tcode{a_tran.find(ke, hke) != a_tran.end()}% -& Average case \bigoh{1}, - worst case \bigoh{\tcode{a_tran.}\br{}\tcode{size()}}. % avoid overfull -\\ \rowsep -% \indexunordmem{equal_range}% \tcode{b.equal_range(k)} & \tcode{pair}; \br @@ -2848,17 +2795,6 @@ \bigoh{\tcode{b.size()}}. \\ \rowsep % -\tcode{b.equal_range(k, hk)} -& \tcode{pair}; \br - \tcode{pair} for const \tcode{b}. -& \expects \tcode{b.hash_function()(k)} equals \tcode{hk}.\br - \returns A range containing all elements with keys equivalent to - \tcode{k}. Returns \tcode{make_pair(b.end(), b.end())} if - no such elements exist.% -& Average case \bigoh{\tcode{b.count(k)}}, worst case - \bigoh{\tcode{b.size()}}. -\\ \rowsep -% \tcode{a_tran.equal_range(ke)} & \tcode{pair}; \br \tcode{pair} for const \tcode{a_tran}. @@ -2870,17 +2806,6 @@ worst case \bigoh{\tcode{a_tran.}\br{}\tcode{size()}}. % avoid overfull \\ \rowsep % -\tcode{a_tran.equal_range(ke, hke)} -& \tcode{pair}; \br - \tcode{pair} for const \tcode{a_tran}. -& \expects \tcode{a_tran.hash_function()(ke)} equals \tcode{hke}.\br - \returns A range containing all elements with keys equivalent to - \tcode{ke}. Returns \tcode{make_pair(a_tran.end(), a_tran.end())} if - no such elements exist.% -& Average case - \bigoh{\tcode{a_tran.}\br{}\tcode{count(ke)}}, % avoid overfull - worst case \bigoh{\tcode{a_tran.}\br{}\tcode{size()}}. % avoid overfull -\\ \rowsep \indexunordmem{bucket_count}% \tcode{b.bucket_count()} & \tcode{size_type} @@ -3150,21 +3075,15 @@ template struct array; template - constexpr bool operator==(const array& x, const array& y); - template - constexpr bool operator!=(const array& x, const array& y); - template - constexpr bool operator< (const array& x, const array& y); - template - constexpr bool operator> (const array& x, const array& y); - template - constexpr bool operator<=(const array& x, const array& y); + constexpr void swap(array& x, array& y) noexcept(noexcept(x.swap(y))); + + // \ref{array.creation}, array creation functions template - constexpr bool operator>=(const array& x, const array& y); + constexpr array, N> to_array(T (&a)[N]); template - constexpr void swap(array& x, array& y) noexcept(noexcept(x.swap(y))); + constexpr array, N> to_array(T (&&a)[N]); - // \ref{array.tuple}, tuple interface to class template \tcode{array} + // \ref{array.tuple}, tuple interface template struct tuple_size; template struct tuple_element; template @@ -3196,15 +3115,8 @@ template bool operator==(const deque& x, const deque& y); template - bool operator!=(const deque& x, const deque& y); - template - bool operator< (const deque& x, const deque& y); - template - bool operator> (const deque& x, const deque& y); - template - bool operator<=(const deque& x, const deque& y); - template - bool operator>=(const deque& x, const deque& y); + @\placeholder{synth-three-way-result}@ operator<=>(const deque& x, + @\itcorr@ const deque& y); template void swap(deque& x, deque& y) @@ -3236,15 +3148,8 @@ template bool operator==(const forward_list& x, const forward_list& y); template - bool operator!=(const forward_list& x, const forward_list& y); - template - bool operator< (const forward_list& x, const forward_list& y); - template - bool operator> (const forward_list& x, const forward_list& y); - template - bool operator<=(const forward_list& x, const forward_list& y); - template - bool operator>=(const forward_list& x, const forward_list& y); + @\placeholder{synth-three-way-result}@ operator<=>(const forward_list& x, + @\itcorr@ const forward_list& y); template void swap(forward_list& x, forward_list& y) @@ -3276,15 +3181,8 @@ template bool operator==(const list& x, const list& y); template - bool operator!=(const list& x, const list& y); - template - bool operator< (const list& x, const list& y); - template - bool operator> (const list& x, const list& y); - template - bool operator<=(const list& x, const list& y); - template - bool operator>=(const list& x, const list& y); + @\placeholder{synth-three-way-result}@ operator<=>(const list& x, + @\itcorr@ const list& y); template void swap(list& x, list& y) @@ -3314,26 +3212,19 @@ template> class vector; template - bool operator==(const vector& x, const vector& y); - template - bool operator!=(const vector& x, const vector& y); - template - bool operator< (const vector& x, const vector& y); + constexpr bool operator==(const vector& x, const vector& y); template - bool operator> (const vector& x, const vector& y); - template - bool operator<=(const vector& x, const vector& y); - template - bool operator>=(const vector& x, const vector& y); + constexpr @\placeholder{synth-three-way-result}@ operator<=>(const vector& x, + @\itcorr@ const vector& y); template - void swap(vector& x, vector& y) + constexpr void swap(vector& x, vector& y) noexcept(noexcept(x.swap(y))); template - void erase(vector& c, const U& value); + constexpr void erase(vector& c, const U& value); template - void erase_if(vector& c, Predicate pred); + constexpr void erase_if(vector& c, Predicate pred); // \ref{vector.bool}, class \tcode{vector} template class vector; @@ -3445,6 +3336,10 @@ constexpr T * data() noexcept; constexpr const T * data() const noexcept; + + friend constexpr bool operator==(const array&, const array&) = default; + friend constexpr @\placeholder{synth-three-way-result}@ + operator<=>(const array&, const array&); }; template @@ -3560,6 +3455,49 @@ Member function \tcode{swap()} shall have a non-throwing exception specification. +\rSec3[array.creation]{Array creation functions} +\indextext{\idxcode{array}!creation}% + +\indexlibrary{\idxcode{to_array}}% +\begin{itemdecl} +template + constexpr array, N> to_array(T (&a)[N]); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{is_array_v} is \tcode{false} and +\tcode{is_constructible_v} is \tcode{true}. + +\pnum +\expects +\tcode{T} meets the \oldconcept{CopyConstructible} requirements. + +\pnum +\returns \tcode{\{\{ a[0], $\dotsc$, a[N - 1] \}\}}. +\end{itemdescr} + +\indexlibrary{\idxcode{to_array}}% +\begin{itemdecl} +template + constexpr array, N> to_array(T (&&a)[N]); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{is_array_v} is \tcode{false} and +\tcode{is_move_constructible_v} is \tcode{true}. + +\pnum +\expects +\tcode{T} meets the \oldconcept{MoveConstructible} requirements. + +\pnum +\returns \tcode{\{\{ std::move(a[0]), $\dotsc$, std::move(a[N - 1]) \}\}}. +\end{itemdescr} + \rSec3[array.tuple]{Tuple interface} \indexlibrary{\idxcode{array}}% \indexlibrary{\idxcode{tuple}}% @@ -5433,6 +5371,10 @@ that are not described in one of these tables or for operations where there is additional semantic information. +\pnum +The types \tcode{iterator} and \tcode{const_iterator} meet +the constexpr iterator requirements\iref{iterator.requirements.general}. + \begin{codeblock} namespace std { template> @@ -5453,87 +5395,88 @@ using const_reverse_iterator = std::reverse_iterator; // \ref{vector.cons}, construct/copy/destroy - vector() noexcept(noexcept(Allocator())) : vector(Allocator()) { } - explicit vector(const Allocator&) noexcept; - explicit vector(size_type n, const Allocator& = Allocator()); - vector(size_type n, const T& value, const Allocator& = Allocator()); + constexpr vector() noexcept(noexcept(Allocator())) : vector(Allocator()) { } + constexpr explicit vector(const Allocator&) noexcept; + constexpr explicit vector(size_type n, const Allocator& = Allocator()); + constexpr vector(size_type n, const T& value, const Allocator& = Allocator()); template - vector(InputIterator first, InputIterator last, const Allocator& = Allocator()); - vector(const vector& x); - vector(vector&&) noexcept; - vector(const vector&, const Allocator&); - vector(vector&&, const Allocator&); - vector(initializer_list, const Allocator& = Allocator()); - ~vector(); - vector& operator=(const vector& x); - vector& operator=(vector&& x) + constexpr vector(InputIterator first, InputIterator last, const Allocator& = Allocator()); + constexpr vector(const vector& x); + constexpr vector(vector&&) noexcept; + constexpr vector(const vector&, const Allocator&); + constexpr vector(vector&&, const Allocator&); + constexpr vector(initializer_list, const Allocator& = Allocator()); + constexpr ~vector(); + constexpr vector& operator=(const vector& x); + constexpr vector& operator=(vector&& x) noexcept(allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value); - vector& operator=(initializer_list); + constexpr vector& operator=(initializer_list); template - void assign(InputIterator first, InputIterator last); - void assign(size_type n, const T& u); - void assign(initializer_list); - allocator_type get_allocator() const noexcept; + constexpr void assign(InputIterator first, InputIterator last); + constexpr void assign(size_type n, const T& u); + constexpr void assign(initializer_list); + constexpr allocator_type get_allocator() const noexcept; // iterators - iterator begin() noexcept; - const_iterator begin() const noexcept; - iterator end() noexcept; - const_iterator end() const noexcept; - reverse_iterator rbegin() noexcept; - const_reverse_iterator rbegin() const noexcept; - reverse_iterator rend() noexcept; - const_reverse_iterator rend() const noexcept; + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; + constexpr reverse_iterator rbegin() noexcept; + constexpr const_reverse_iterator rbegin() const noexcept; + constexpr reverse_iterator rend() noexcept; + constexpr const_reverse_iterator rend() const noexcept; - const_iterator cbegin() const noexcept; - const_iterator cend() const noexcept; - const_reverse_iterator crbegin() const noexcept; - const_reverse_iterator crend() const noexcept; + constexpr const_iterator cbegin() const noexcept; + constexpr const_iterator cend() const noexcept; + constexpr const_reverse_iterator crbegin() const noexcept; + constexpr const_reverse_iterator crend() const noexcept; // \ref{vector.capacity}, capacity - [[nodiscard]] bool empty() const noexcept; - size_type size() const noexcept; - size_type max_size() const noexcept; - size_type capacity() const noexcept; - void resize(size_type sz); - void resize(size_type sz, const T& c); - void reserve(size_type n); - void shrink_to_fit(); + [[nodiscard]] constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; + constexpr size_type capacity() const noexcept; + constexpr void resize(size_type sz); + constexpr void resize(size_type sz, const T& c); + constexpr void reserve(size_type n); + constexpr void shrink_to_fit(); // element access - reference operator[](size_type n); - const_reference operator[](size_type n) const; - const_reference at(size_type n) const; - reference at(size_type n); - reference front(); - const_reference front() const; - reference back(); - const_reference back() const; + constexpr reference operator[](size_type n); + constexpr const_reference operator[](size_type n) const; + constexpr const_reference at(size_type n) const; + constexpr reference at(size_type n); + constexpr reference front(); + constexpr const_reference front() const; + constexpr reference back(); + constexpr const_reference back() const; // \ref{vector.data}, data access - T* data() noexcept; - const T* data() const noexcept; + constexpr T* data() noexcept; + constexpr const T* data() const noexcept; // \ref{vector.modifiers}, modifiers - template reference emplace_back(Args&&... args); - void push_back(const T& x); - void push_back(T&& x); - void pop_back(); - - template iterator emplace(const_iterator position, Args&&... args); - iterator insert(const_iterator position, const T& x); - iterator insert(const_iterator position, T&& x); - iterator insert(const_iterator position, size_type n, const T& x); + template constexpr reference emplace_back(Args&&... args); + constexpr void push_back(const T& x); + constexpr void push_back(T&& x); + constexpr void pop_back(); + + template constexpr iterator emplace(const_iterator position, Args&&... args); + constexpr iterator insert(const_iterator position, const T& x); + constexpr iterator insert(const_iterator position, T&& x); + constexpr iterator insert(const_iterator position, size_type n, const T& x); template - iterator insert(const_iterator position, InputIterator first, InputIterator last); - iterator insert(const_iterator position, initializer_list il); - iterator erase(const_iterator position); - iterator erase(const_iterator first, const_iterator last); - void swap(vector&) + constexpr iterator insert(const_iterator position, + InputIterator first, InputIterator last); + constexpr iterator insert(const_iterator position, initializer_list il); + constexpr iterator erase(const_iterator position); + constexpr iterator erase(const_iterator first, const_iterator last); + constexpr void swap(vector&) noexcept(allocator_traits::propagate_on_container_swap::value || allocator_traits::is_always_equal::value); - void clear() noexcept; + constexpr void clear() noexcept; }; template>> @@ -5542,7 +5485,7 @@ // swap template - void swap(vector& x, vector& y) + constexpr void swap(vector& x, vector& y) noexcept(noexcept(x.swap(y))); } \end{codeblock}% @@ -5560,7 +5503,7 @@ \indexlibrary{\idxcode{vector}!constructor} \begin{itemdecl} -explicit vector(const Allocator&) noexcept; +constexpr explicit vector(const Allocator&) noexcept; \end{itemdecl} \begin{itemdescr} @@ -5574,7 +5517,7 @@ \indexlibrary{\idxcode{vector}!constructor} \begin{itemdecl} -explicit vector(size_type n, const Allocator& = Allocator()); +constexpr explicit vector(size_type n, const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -5591,8 +5534,8 @@ \indexlibrary{\idxcode{vector}!constructor} \begin{itemdecl} -vector(size_type n, const T& value, - const Allocator& = Allocator()); +constexpr vector(size_type n, const T& value, + const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -5611,8 +5554,8 @@ \indexlibrary{\idxcode{vector}!constructor} \begin{itemdecl} template - vector(InputIterator first, InputIterator last, - const Allocator& = Allocator()); + constexpr vector(InputIterator first, InputIterator last, + const Allocator& = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -5645,7 +5588,7 @@ \indexlibrary{\idxcode{capacity}!\idxcode{vector}}% \begin{itemdecl} -size_type capacity() const noexcept; +constexpr size_type capacity() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -5660,7 +5603,7 @@ \indexlibrary{\idxcode{reserve}!\idxcode{vector}}% \begin{itemdecl} -void reserve(size_type n); +constexpr void reserve(size_type n); \end{itemdecl} \begin{itemdescr} @@ -5712,7 +5655,7 @@ \indexlibrary{\idxcode{shrink_to_fit}!\idxcode{vector}}% \begin{itemdecl} -void shrink_to_fit(); +constexpr void shrink_to_fit(); \end{itemdecl} \begin{itemdescr} @@ -5744,7 +5687,7 @@ \indexlibrary{\idxcode{swap}!\idxcode{vector}}% \begin{itemdecl} -void swap(vector& x) +constexpr void swap(vector& x) noexcept(allocator_traits::propagate_on_container_swap::value || allocator_traits::is_always_equal::value); \end{itemdecl} @@ -5765,7 +5708,7 @@ \indexlibrary{\idxcode{resize}!\idxcode{vector}}% \begin{itemdecl} -void resize(size_type sz); +constexpr void resize(size_type sz); \end{itemdecl} \begin{itemdescr} @@ -5785,7 +5728,7 @@ \indexlibrary{\idxcode{resize}!\idxcode{vector}}% \begin{itemdecl} -void resize(size_type sz, const T& c); +constexpr void resize(size_type sz, const T& c); \end{itemdecl} \begin{itemdescr} @@ -5806,8 +5749,8 @@ \indexlibrary{\idxcode{data}!\idxcode{vector}}% \begin{itemdecl} -T* data() noexcept; -const T* data() const noexcept; +constexpr T* data() noexcept; +constexpr const T* data() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -5825,17 +5768,17 @@ \indexlibrary{\idxcode{insert}!\idxcode{vector}}% \begin{itemdecl} -iterator insert(const_iterator position, const T& x); -iterator insert(const_iterator position, T&& x); -iterator insert(const_iterator position, size_type n, const T& x); +constexpr iterator insert(const_iterator position, const T& x); +constexpr iterator insert(const_iterator position, T&& x); +constexpr iterator insert(const_iterator position, size_type n, const T& x); template - iterator insert(const_iterator position, InputIterator first, InputIterator last); -iterator insert(const_iterator position, initializer_list); + constexpr iterator insert(const_iterator position, InputIterator first, InputIterator last); +constexpr iterator insert(const_iterator position, initializer_list); -template reference emplace_back(Args&&... args); -template iterator emplace(const_iterator position, Args&&... args); -void push_back(const T& x); -void push_back(T&& x); +template constexpr reference emplace_back(Args&&... args); +template constexpr iterator emplace(const_iterator position, Args&&... args); +constexpr void push_back(const T& x); +constexpr void push_back(T&& x); \end{itemdecl} \begin{itemdescr} @@ -5872,9 +5815,9 @@ \indexlibrary{\idxcode{erase}!\idxcode{vector}}% \begin{itemdecl} -iterator erase(const_iterator position); -iterator erase(const_iterator first, const_iterator last); -void pop_back(); +constexpr iterator erase(const_iterator position); +constexpr iterator erase(const_iterator first, const_iterator last); +constexpr void pop_back(); \end{itemdecl} \begin{itemdescr} @@ -5901,7 +5844,7 @@ \indexlibrary{\idxcode{erase}!\idxcode{vector}}% \begin{itemdecl} template - void erase(vector& c, const U& value); + constexpr void erase(vector& c, const U& value); \end{itemdecl} \begin{itemdescr} @@ -5913,7 +5856,7 @@ \indexlibrary{\idxcode{erase_if}!\idxcode{vector}}% \begin{itemdecl} template - void erase_if(vector& c, Predicate pred); + constexpr void erase_if(vector& c, Predicate pred); \end{itemdecl} \begin{itemdescr} @@ -5951,89 +5894,90 @@ // bit reference class reference { friend class vector; - reference() noexcept; + constexpr reference() noexcept; public: - reference(const reference&) = default; - ~reference(); - operator bool() const noexcept; - reference& operator=(const bool x) noexcept; - reference& operator=(const reference& x) noexcept; - void flip() noexcept; // flips the bit + constexpr reference(const reference&) = default; + constexpr ~reference(); + constexpr operator bool() const noexcept; + constexpr reference& operator=(const bool x) noexcept; + constexpr reference& operator=(const reference& x) noexcept; + constexpr void flip() noexcept; // flips the bit }; // construct/copy/destroy - vector() : vector(Allocator()) { } - explicit vector(const Allocator&); - explicit vector(size_type n, const Allocator& = Allocator()); - vector(size_type n, const bool& value, const Allocator& = Allocator()); + constexpr vector() : vector(Allocator()) { } + constexpr explicit vector(const Allocator&); + constexpr explicit vector(size_type n, const Allocator& = Allocator()); + constexpr vector(size_type n, const bool& value, const Allocator& = Allocator()); template - vector(InputIterator first, InputIterator last, const Allocator& = Allocator()); - vector(const vector& x); - vector(vector&& x); - vector(const vector&, const Allocator&); - vector(vector&&, const Allocator&); - vector(initializer_list, const Allocator& = Allocator())); - ~vector(); - vector& operator=(const vector& x); - vector& operator=(vector&& x); - vector& operator=(initializer_list); + constexpr vector(InputIterator first, InputIterator last, const Allocator& = Allocator()); + constexpr vector(const vector& x); + constexpr vector(vector&& x); + constexpr vector(const vector&, const Allocator&); + constexpr vector(vector&&, const Allocator&); + constexpr vector(initializer_list, const Allocator& = Allocator())); + constexpr ~vector(); + constexpr vector& operator=(const vector& x); + constexpr vector& operator=(vector&& x); + constexpr vector& operator=(initializer_list); template - void assign(InputIterator first, InputIterator last); - void assign(size_type n, const bool& t); - void assign(initializer_list); - allocator_type get_allocator() const noexcept; + constexpr void assign(InputIterator first, InputIterator last); + constexpr void assign(size_type n, const bool& t); + constexpr void assign(initializer_list); + constexpr allocator_type get_allocator() const noexcept; // iterators - iterator begin() noexcept; - const_iterator begin() const noexcept; - iterator end() noexcept; - const_iterator end() const noexcept; - reverse_iterator rbegin() noexcept; - const_reverse_iterator rbegin() const noexcept; - reverse_iterator rend() noexcept; - const_reverse_iterator rend() const noexcept; + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; + constexpr reverse_iterator rbegin() noexcept; + constexpr const_reverse_iterator rbegin() const noexcept; + constexpr reverse_iterator rend() noexcept; + constexpr const_reverse_iterator rend() const noexcept; - const_iterator cbegin() const noexcept; - const_iterator cend() const noexcept; - const_reverse_iterator crbegin() const noexcept; - const_reverse_iterator crend() const noexcept; + constexpr const_iterator cbegin() const noexcept; + constexpr const_iterator cend() const noexcept; + constexpr const_reverse_iterator crbegin() const noexcept; + constexpr const_reverse_iterator crend() const noexcept; // capacity - [[nodiscard]] bool empty() const noexcept; - size_type size() const noexcept; - size_type max_size() const noexcept; - size_type capacity() const noexcept; - void resize(size_type sz, bool c = false); - void reserve(size_type n); - void shrink_to_fit(); + [[nodiscard]] constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; + constexpr size_type capacity() const noexcept; + constexpr void resize(size_type sz, bool c = false); + constexpr void reserve(size_type n); + constexpr void shrink_to_fit(); // element access - reference operator[](size_type n); - const_reference operator[](size_type n) const; - const_reference at(size_type n) const; - reference at(size_type n); - reference front(); - const_reference front() const; - reference back(); - const_reference back() const; + constexpr reference operator[](size_type n); + constexpr const_reference operator[](size_type n) const; + constexpr const_reference at(size_type n) const; + constexpr reference at(size_type n); + constexpr reference front(); + constexpr const_reference front() const; + constexpr reference back(); + constexpr const_reference back() const; // modifiers - template reference emplace_back(Args&&... args); - void push_back(const bool& x); - void pop_back(); - template iterator emplace(const_iterator position, Args&&... args); - iterator insert(const_iterator position, const bool& x); - iterator insert(const_iterator position, size_type n, const bool& x); + template constexpr reference emplace_back(Args&&... args); + constexpr void push_back(const bool& x); + constexpr void pop_back(); + template constexpr iterator emplace(const_iterator position, Args&&... args); + constexpr iterator insert(const_iterator position, const bool& x); + constexpr iterator insert(const_iterator position, size_type n, const bool& x); template - iterator insert(const_iterator position, InputIterator first, InputIterator last); - iterator insert(const_iterator position, initializer_list il); - - iterator erase(const_iterator position); - iterator erase(const_iterator first, const_iterator last); - void swap(vector&); - static void swap(reference x, reference y) noexcept; - void flip() noexcept; // flips all bits - void clear() noexcept; + constexpr iterator insert(const_iterator position, + InputIterator first, InputIterator last); + constexpr iterator insert(const_iterator position, initializer_list il); + + constexpr iterator erase(const_iterator position); + constexpr iterator erase(const_iterator first, const_iterator last); + constexpr void swap(vector&); + constexpr static void swap(reference x, reference y) noexcept; + constexpr void flip() noexcept; // flips all bits + constexpr void clear() noexcept; }; } \end{codeblock}% @@ -6061,7 +6005,7 @@ \indexlibrarymember{flip}{vector}% \begin{itemdecl} -void flip() noexcept; +constexpr void flip() noexcept; \end{itemdecl} \begin{itemdescr} @@ -6071,7 +6015,7 @@ \indexlibrarymember{swap}{vector}% \begin{itemdecl} -static void swap(reference x, reference y) noexcept; +constexpr static void swap(reference x, reference y) noexcept; \end{itemdecl} \begin{itemdescr} @@ -6138,20 +6082,9 @@ bool operator==(const map& x, const map& y); template - bool operator!=(const map& x, - const map& y); - template - bool operator< (const map& x, - const map& y); - template - bool operator> (const map& x, - const map& y); - template - bool operator<=(const map& x, - const map& y); - template - bool operator>=(const map& x, - const map& y); + @\placeholder{synth-three-way-result}@> + operator<=>(const map& x, + const map& y); template void swap(map& x, @@ -6170,20 +6103,9 @@ bool operator==(const multimap& x, const multimap& y); template - bool operator!=(const multimap& x, - const multimap& y); - template - bool operator< (const multimap& x, - const multimap& y); - template - bool operator> (const multimap& x, - const multimap& y); - template - bool operator<=(const multimap& x, - const multimap& y); - template - bool operator>=(const multimap& x, - const multimap& y); + @\placeholder{synth-three-way-result}@> + operator<=>(const multimap& x, + const multimap& y); template void swap(multimap& x, @@ -6221,20 +6143,8 @@ bool operator==(const set& x, const set& y); template - bool operator!=(const set& x, - const set& y); - template - bool operator< (const set& x, - const set& y); - template - bool operator> (const set& x, - const set& y); - template - bool operator<=(const set& x, - const set& y); - template - bool operator>=(const set& x, - const set& y); + @\placeholder{synth-three-way-result}@ operator<=>(const set& x, + @\itcorr@ const set& y); template void swap(set& x, @@ -6252,20 +6162,8 @@ bool operator==(const multiset& x, const multiset& y); template - bool operator!=(const multiset& x, - const multiset& y); - template - bool operator< (const multiset& x, - const multiset& y); - template - bool operator> (const multiset& x, - const multiset& y); - template - bool operator<=(const multiset& x, - const multiset& y); - template - bool operator>=(const multiset& x, - const multiset& y); + @\placeholder{synth-three-way-result}@ operator<=>(const multiset& x, + @\itcorr@ const multiset& y); template void swap(multiset& x, @@ -7749,16 +7647,10 @@ template bool operator==(const unordered_map& a, const unordered_map& b); - template - bool operator!=(const unordered_map& a, - const unordered_map& b); template bool operator==(const unordered_multimap& a, const unordered_multimap& b); - template - bool operator!=(const unordered_multimap& a, - const unordered_multimap& b); template void swap(unordered_map& x, @@ -7821,16 +7713,10 @@ template bool operator==(const unordered_set& a, const unordered_set& b); - template - bool operator!=(const unordered_set& a, - const unordered_set& b); template bool operator==(const unordered_multiset& a, const unordered_multiset& b); - template - bool operator!=(const unordered_multiset& a, - const unordered_multiset& b); template void swap(unordered_set& x, @@ -8038,40 +7924,23 @@ // map operations iterator find(const key_type& k); const_iterator find(const key_type& k) const; - iterator find(const key_type& k, size_t hash); - const_iterator find(const key_type& k, size_t hash) const; template iterator find(const K& k); template const_iterator find(const K& k) const; template - iterator find(const K& k, size_t hash); - template - const_iterator find(const K& k, size_t hash) const; size_type count(const key_type& k) const; - size_type count(const key_type& k, size_t hash) const; template size_type count(const K& k) const; - template - size_type count(const K& k, size_t hash) const; bool contains(const key_type& k) const; - bool contains(const key_type& k, size_t hash) const; template bool contains(const K& k) const; - template - bool contains(const K& k, size_t hash) const; pair equal_range(const key_type& k); pair equal_range(const key_type& k) const; - pair equal_range(const key_type& k, size_t hash); - pair equal_range(const key_type& k, size_t hash) const; template pair equal_range(const K& k); template pair equal_range(const K& k) const; - template - pair equal_range(const K& k, size_t hash); - template - pair equal_range(const K& k, size_t hash) const; // \ref{unord.map.elem}, element access mapped_type& operator[](const key_type& k); @@ -8626,40 +8495,22 @@ // map operations iterator find(const key_type& k); const_iterator find(const key_type& k) const; - iterator find(const key_type& k, size_t hash); - const_iterator find(const key_type& k, size_t hash) const; template iterator find(const K& k); template const_iterator find(const K& k) const; - template - iterator find(const K& k, size_t hash); - template - const_iterator find(const K& k, size_t hash) const; size_type count(const key_type& k) const; - size_type count(const key_type& k, size_t hash) const; template size_type count(const K& k) const; - template - size_type count(const K& k, size_t hash) const; bool contains(const key_type& k) const; - bool contains(const key_type& k, size_t hash) const; template bool contains(const K& k) const; - template - bool contains(const K& k, size_t hash) const; pair equal_range(const key_type& k); pair equal_range(const key_type& k) const; - pair equal_range(const key_type& k, size_t hash); - pair equal_range(const key_type& k, size_t hash) const; template pair equal_range(const K& k); template pair equal_range(const K& k) const; - template - pair equal_range(const K& k, size_t hash); - template - pair equal_range(const K& k, size_t hash) const; // bucket interface size_type bucket_count() const noexcept; @@ -9006,40 +8857,22 @@ // set operations iterator find(const key_type& k); const_iterator find(const key_type& k) const; - iterator find(const key_type& k, size_t hash); - const_iterator find(const key_type& k, size_t hash) const; template iterator find(const K& k); template const_iterator find(const K& k) const; - template - iterator find(const K& k, size_t hash); - template - const_iterator find(const K& k, size_t hash) const; size_type count(const key_type& k) const; - size_type count(const key_type& k, size_t hash) const; template size_type count(const K& k) const; - template - size_type count(const K& k, size_t hash) const; bool contains(const key_type& k) const; - bool contains(const key_type& k, size_t hash) const; template bool contains(const K& k) const; - template - bool contains(const K& k, size_t hash) const; pair equal_range(const key_type& k); pair equal_range(const key_type& k) const; - pair equal_range(const key_type& k, size_t hash); - pair equal_range(const key_type& k, size_t hash) const; template pair equal_range(const K& k); template pair equal_range(const K& k) const; - template - pair equal_range(const K& k, size_t hash); - template - pair equal_range(const K& k, size_t hash) const; // bucket interface size_type bucket_count() const noexcept; @@ -9348,40 +9181,22 @@ // set operations iterator find(const key_type& k); const_iterator find(const key_type& k) const; - iterator find(const key_type& k, size_t hash); - const_iterator find(const key_type& k, size_t hash) const; template iterator find(const K& k); template const_iterator find(const K& k) const; - template - iterator find(const K& k, size_t hash); - template - const_iterator find(const K& k, size_t hash) const; size_type count(const key_type& k) const; - size_type count(const key_type& k, size_t hash) const; template size_type count(const K& k) const; - template - size_type count(const K& k, size_t hash) const; bool contains(const key_type& k) const; - bool contains(const key_type& k, size_t hash) const; template bool contains(const K& k) const; - template - bool contains(const K& k, size_t hash) const; pair equal_range(const key_type& k); pair equal_range(const key_type& k) const; - pair equal_range(const key_type& k, size_t hash); - pair equal_range(const key_type& k, size_t hash) const; template pair equal_range(const K& k); template pair equal_range(const K& k) const; - template - pair equal_range(const K& k, size_t hash); - template - pair equal_range(const K& k, size_t hash) const; // bucket interface size_type bucket_count() const noexcept; @@ -9583,6 +9398,9 @@ bool operator<=(const queue& x, const queue& y); template bool operator>=(const queue& x, const queue& y); + template + compare_three_way_result_t + operator<=>(const queue& x, const queue& y); template void swap(queue& x, queue& y) noexcept(noexcept(x.swap(y))); @@ -9622,6 +9440,9 @@ bool operator<=(const stack& x, const stack& y); template bool operator>=(const stack& x, const stack& y); + template + compare_three_way_result_t + operator<=>(const stack& x, const stack& y); template void swap(stack& x, stack& y) noexcept(noexcept(x.swap(y))); @@ -9855,6 +9676,19 @@ \tcode{x.c >= y.c}. \end{itemdescr} +\indexlibrary{\idxcode{operator<=>}!\idxcode{queue}}% +\begin{itemdecl} +template + compare_three_way_result_t + operator<=>(const queue& x, const queue& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{x.c <=> y.c}. +\end{itemdescr} + \rSec3[queue.special]{Specialized algorithms} \indexlibrarymember{swap}{queue}% @@ -10402,6 +10236,19 @@ \tcode{x.c >= y.c}. \end{itemdescr} +\indexlibrary{\idxcode{operator<=>}!\idxcode{stack}}% +\begin{itemdecl} +template + compare_three_way_result_t + operator<=>(const stack& x, const stack& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{x.c <=> y.c}. +\end{itemdescr} + \rSec3[stack.special]{Specialized algorithms} \indexlibrarymember{swap}{stack}% @@ -10585,7 +10432,7 @@ \begin{itemdescr} \pnum \constraints -\tcode{Extent <= 0} is \tcode{true}. +\tcode{Extent == dynamic_extent || Extent == 0} is \tcode{true}. \pnum \ensures @@ -10967,7 +10814,7 @@ \begin{itemdescr} \pnum The types -model \libconcept{ContiguousIterator}\iref{iterator.concept.contiguous}, +model \libconcept{contiguous_iterator}\iref{iterator.concept.contiguous}, meet the \oldconcept{RandomAccessIterator} requirements\iref{random.access.iterators}, and diff --git a/source/declarations.tex b/source/declarations.tex index 8e45d5243f..56eae8421a 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -35,9 +35,10 @@ \begin{bnf} \nontermdef{block-declaration}\br simple-declaration\br - asm-definition\br + asm-declaration\br namespace-alias-definition\br using-declaration\br + using-enum-declaration\br using-directive\br static_assert-declaration\br alias-declaration\br @@ -78,7 +79,7 @@ \end{bnf} \begin{note} -\grammarterm{asm-definition}{s} are described in~\ref{dcl.asm}, and +\grammarterm{asm-declaration}{s} are described in~\ref{dcl.asm}, and \grammarterm{linkage-specification}{s} are described in~\ref{dcl.link}; \grammarterm{function-definition}{s} are described in~\ref{dcl.fct.def} and \grammarterm{template-declaration}{s} and @@ -256,6 +257,7 @@ \keyword{typedef}\br \keyword{constexpr}\br \keyword{consteval}\br + \keyword{constinit}\br \keyword{inline} \end{bnf} @@ -275,8 +277,9 @@ Each \grammarterm{decl-specifier} shall appear at most once in a complete \grammarterm{decl-specifier-seq}, except that \tcode{long} may appear twice. -The \tcode{constexpr} and \tcode{consteval} \grammarterm{decl-specifier}{s} -shall not both appear in a \grammarterm{decl-specifier-seq}. +At most one of +the \keyword{constexpr}, \keyword{consteval}, and \keyword{constinit} keywords +shall appear in a \grammarterm{decl-specifier-seq}. \pnum \indextext{ambiguity!declaration type}% @@ -736,6 +739,26 @@ \end{codeblock} \end{example} +\pnum +An unnamed class with a typedef name for linkage purposes shall not +\begin{itemize} +\item + declare any members + other than non-static data members, member enumerations, or member classes, +\item + have any base classes or default member initializers, or +\item + contain a \grammarterm{lambda-expression}, +\end{itemize} +and all member classes shall also satisfy these requirements (recursively). +\begin{example} +\begin{codeblock} +typedef struct { + int f() {} +} X; // error: struct with typedef name for linkage has member functions +\end{codeblock} +\end{example} + \rSec2[dcl.friend]{The \tcode{friend} specifier}% \indextext{specifier!\idxcode{friend}} @@ -793,12 +816,9 @@ \pnum A \tcode{constexpr} or \tcode{consteval} specifier -used in the declaration of a function that is not a constructor +used in the declaration of a function declares that function to be a \defnx{constexpr function}{specifier!\idxcode{constexpr}!function}. -Similarly, a \tcode{constexpr} or \tcode{consteval} specifier used in -a constructor declaration declares that constructor to be -a \defnx{constexpr constructor}{specifier!\idxcode{constexpr}!constructor}. A function or constructor declared with the \tcode{consteval} specifier is called an \defn{immediate function}. A destructor, an allocation function, or a deallocation function @@ -812,7 +832,7 @@ \begin{itemize} \item -its return type shall be a literal type; +its return type (if any) shall be a literal type; \item each of its parameter types shall be a literal type; @@ -820,16 +840,18 @@ \item it shall not be a coroutine\iref{dcl.fct.def.coroutine}; +\item +if the function is a constructor or destructor, +its class shall not have any virtual base classes; + \item its \grammarterm{function-body} shall not enclose\iref{stmt.stmt} \begin{itemize} -\item an \grammarterm{asm-definition}, \item a \tcode{goto} statement, \item an identifier label\iref{stmt.label}, \item a definition of a variable of non-literal type or -of static or thread storage duration or -for which no initialization is performed. +of static or thread storage duration. \end{itemize} \begin{note} A \grammarterm{function-body} that is \tcode{= delete} or \tcode{= default} @@ -853,8 +875,8 @@ return value; } constexpr int uninit() { - int a; // error: variable is uninitialized - return a; + struct { int a; } s; + return s.a; // error: uninitialized read of \tcode{s.a} } constexpr int prev(int x) { return --x; } // OK @@ -868,28 +890,10 @@ \pnum \indextext{specifier!\idxcode{constexpr}!constructor}% -The definition of a constexpr constructor shall satisfy the -following requirements: +The definition of a constexpr constructor +whose \grammarterm{function-body} is not \tcode{= delete} +shall additionally satisfy the following requirements: \begin{itemize} -\item -the class shall not have any virtual base classes; - -\item -each of the parameter types shall be a literal type. -\end{itemize} - -In addition, either its \grammarterm{function-body} shall be -\tcode{= delete}, or it shall satisfy the following requirements: -\begin{itemize} -\item -either its \grammarterm{function-body} shall be \tcode{= default}, or the \grammarterm{compound-statement} of its \grammarterm{function-body} -shall satisfy the requirements for a \grammarterm{function-body} of a -constexpr function; - -\item -every non-variant non-static data member and base class subobject -shall be initialized\iref{class.base.init}; - \item if the class is a union having variant members\iref{class.union}, exactly one of them shall be initialized; @@ -917,13 +921,25 @@ \end{codeblock} \end{example} +\pnum +The definition of a constexpr destructor +whose \grammarterm{function-body} is not \tcode{= delete} +shall additionally satisfy the following requirement: +\begin{itemize} +\item + for every subobject of class type or + (possibly multi-dimensional) array thereof, + that class type shall have a constexpr destructor. +\end{itemize} + \pnum For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression\iref{expr.const}, or, -for a constructor, a constant initializer for some object\iref{basic.start.static}, +for a constructor, an evaluated subexpression of +the initialization full-expression of some constant-initialized object\iref{basic.start.static}, the program is ill-formed, no diagnostic required. \begin{example} \begin{codeblock} @@ -950,12 +966,12 @@ template or member function of a class template would fail to satisfy the requirements for a constexpr -function or constexpr constructor, -that specialization is still a constexpr function or constexpr -constructor, even though a call to such a function cannot appear in a constant +function, +that specialization is still a constexpr function, +even though a call to such a function cannot appear in a constant expression. If no specialization of the template would satisfy the -requirements for a constexpr function or constexpr constructor -when considered as a non-template function or constructor, the template is +requirements for a constexpr function +when considered as a non-template function, the template is ill-formed, no diagnostic required. \pnum @@ -971,7 +987,7 @@ \pnum The \tcode{constexpr} and \tcode{consteval} specifiers have no -effect on the type of a constexpr function or a constexpr constructor. +effect on the type of a constexpr function. \begin{example} \begin{codeblock} constexpr int bar(int x, int y) // OK @@ -991,6 +1007,7 @@ In any \tcode{constexpr} variable declaration, the full-expression of the initialization shall be a constant expression\iref{expr.const}. +A \tcode{constexpr} variable shall have constant destruction. \begin{example} \begin{codeblock} struct pixel { @@ -1001,6 +1018,35 @@ \end{codeblock} \end{example} +\rSec2[dcl.constinit]{The \tcode{constinit} specifier} +\indextext{specifier!\idxcode{constinit}} + +\pnum +The \keyword{constinit} specifier shall be applied only +to a declaration of a variable with static or thread storage duration. +If the specifier is applied to any declaration of a variable, +it shall be applied to the initializing declaration. +No diagnostic is required if no \keyword{constinit} declaration +is reachable at the point of the initializing declaration. + +\pnum +If a variable declared with the \keyword{constinit} specifier has +dynamic initialization\iref{basic.start.dynamic}, the program is ill-formed. +\begin{note} +The \keyword{constinit} specifier ensures that the variable +is initialized during static initialization\iref{basic.start.static}. +\end{note} + +\pnum +\begin{example} +\begin{codeblock} +const char * g() { return "dynamic initialization"; } +constexpr const char * f(bool p) { return p ? "constant initializer" : g(); } +constinit const char * c = f(true); // OK +constinit const char * d = f(false); // ill-formed +\end{codeblock} +\end{example} + \rSec2[dcl.inline]{The \tcode{inline} specifier}% \indextext{specifier!\idxcode{inline}} @@ -1339,7 +1385,16 @@ \opt{\tcode{typename}} \opt{\grammarterm{nested-name-specifier}} \grammarterm{template-name} is a placeholder for a deduced class type\iref{dcl.type.class.deduct}. -The \grammarterm{template-name} shall name a class template. +The \grammarterm{nested-name-specifier}, if any, shall be non-dependent and +the \grammarterm{template-name} shall name a deducible template. +A \defnadj{deducible}{template} is either a class template or +is an alias template whose \grammarterm{defining-type-id} is of the form +\begin{ncsimplebnf} +\opt{\keyword{typename}} \opt{nested-name-specifier} \opt{\keyword{template}} simple-template-id +\end{ncsimplebnf} +where the \grammarterm{nested-name-specifier} (if any) is non-dependent and +the \grammarterm{template-name} of the \grammarterm{simple-template-id} +names a deducible template. \begin{note} An injected-class-name is never interpreted as a \grammarterm{template-name} in contexts where class template argument deduction would be performed\iref{temp.local}. @@ -1422,6 +1477,11 @@ class-key \opt{attribute-specifier-seq} \opt{nested-name-specifier} identifier\br class-key simple-template-id\br class-key nested-name-specifier \opt{\keyword{template}} simple-template-id\br + elaborated-enum-specifier +\end{bnf} + +\begin{bnf} +\nontermdef{elaborated-enum-specifier}\br \keyword{enum} \opt{nested-name-specifier} identifier \end{bnf} @@ -1971,7 +2031,18 @@ appears as a \grammarterm{decl-specifier} in the \grammarterm{decl-specifier-seq} of an initializing declaration\iref{dcl.init} of a variable, -the placeholder is replaced by the return type +the declared type of the variable shall be \cv{}~\tcode{T}, +where \tcode{T} is the placeholder. +\begin{example} +\begin{codeblock} +template struct A { + A(T...) {} +}; +A x[29]{}; // error: no declarator operators allowed +const A& y{}; // error: no declarator operators allowed +\end{codeblock} +\end{example} +The placeholder is replaced by the return type of the function selected by overload resolution for class template deduction\iref{over.match.class.deduct}. If the \grammarterm{decl-specifier-seq} @@ -3289,6 +3360,8 @@ \indextext{parameter!\idxcode{void}}% Except for this special case, a parameter shall not have type \term{cv} \tcode{void}. +A parameter with \tcode{volatile}-qualified type is deprecated; +see~\ref{depr.volatile.type}. If the \grammarterm{parameter-declaration-clause} \indextext{argument type!unknown}% @@ -3448,6 +3521,10 @@ There shall be no arrays of functions, although there can be arrays of pointers to functions. +\pnum +A \tcode{volatile}-qualified return type is deprecated; +see~\ref{depr.volatile.type}. + \pnum Types shall not be defined in return or parameter types. @@ -3765,11 +3842,12 @@ supplied in this or a previous declaration, unless the parameter was expanded from a parameter pack, or shall be a function parameter pack. +\begin{note} A default argument -shall not be redefined by a later declaration (not even to the -same value). +cannot be redefined by a later declaration +(not even to the same value)\iref{basic.def.odr}. +\end{note} \begin{example} - \begin{codeblock} void g(int = 0, ...); // OK, ellipsis is not a parameter so it can follow // a parameter with a default argument @@ -3797,8 +3875,7 @@ \end{example} For a given inline function defined in different translation units, the accumulated sets of default arguments at the end of the -translation units shall be the same; -see~\ref{basic.def.odr}. +translation units shall be the same; no diagnostic is required. If a friend declaration specifies a default argument expression, that declaration shall be a definition and shall be the only declaration of the function or function template in the translation unit. @@ -5653,10 +5730,14 @@ \end{codeblock} \end{example} -\item Otherwise, if \tcode{T} is a reference type, a prvalue of the type -referenced by \tcode{T} is generated. +\item Otherwise, if \tcode{T} is a reference type, a prvalue is generated. The prvalue initializes its result object by copy-list-initialization. The prvalue is then used to direct-initialize the reference. +The type of the temporary is the type referenced by \tcode{T}, +unless \tcode{T} is ``reference to array of unknown bound of \tcode{U}'', +in which case the type of the temporary is +the type of \tcode{x} in the declaration \tcode{U x[] $H$}, +where $H$ is the initializer list. \begin{note} As usual, the binding will fail and the program is ill-formed if the reference type is an lvalue reference to a non-const type. \end{note} @@ -5988,9 +6069,8 @@ \item not have default arguments. \end{itemize} -% FIXME: there's no such thing as an implicit declaration of a comparison operator \pnum -The type \tcode{T}$_1$ of an explicitly defaulted function \tcode{F} +The type \tcode{T}$_1$ of an explicitly defaulted special member function \tcode{F} is allowed to differ from the type \tcode{T}$_2$ it would have had if it were implicitly declared, as follows: \begin{itemize} @@ -6060,6 +6140,12 @@ for them~(\ref{class.ctor}, \ref{class.dtor}, \ref{class.copy.ctor}, \ref{class.copy.assign}), which might mean defining them as deleted. +A defaulted prospective destructor\iref{class.dtor} +that is not a destructor is defined as deleted. +A defaulted special member function +that is neither a prospective destructor nor +an eligible special member function\iref{special} +is defined as deleted. A function is \defn{user-provided} if it is user-declared and not explicitly defaulted or deleted on its first declaration. A user-provided explicitly-defaulted function @@ -6450,6 +6536,8 @@ the \grammarterm{decl-specifier-seq} and \placeholder{S} consist of the \grammarterm{storage-class-specifier}{s} of the \grammarterm{decl-specifier-seq} (if any). +A \cv{} that includes \tcode{volatile} is deprecated; +see~\ref{depr.volatile.type}. First, a variable with a unique name \exposid{e} is introduced. If the \grammarterm{assignment-expression} in the \grammarterm{initializer} has array type \tcode{A} and no \grammarterm{ref-qualifier} is present, @@ -6571,7 +6659,9 @@ the type of the \grammarterm{id-expression} \tcode{y} is ``\tcode{const volatile double}''. \end{example} -\rSec1[dcl.enum]{Enumeration declarations}% +\rSec1[enum]{Enumerations}% + +\rSec2[dcl.enum]{Enumeration declarations}% \indextext{enumeration}% \indextext{\idxcode{\{\}}!enum declaration@\tcode{enum} declaration}% \indextext{\idxcode{enum}!type of} @@ -6891,6 +6981,60 @@ \end{codeblock} \end{example} +\rSec2[enum.udecl]{The \tcode{using enum} declaration}% +\indextext{enumeration!using declaration}% + +\begin{bnf} +\nontermdef{using-enum-declaration}\br + \terminal{using} elaborated-enum-specifier \terminal{;} +\end{bnf} + +\pnum +The \grammarterm{elaborated-enum-specifier} +shall not name a dependent type +and the type shall have a reachable \grammarterm{enum-specifier}. + +\pnum +A \grammarterm{using-enum-declaration} +introduces the enumerator names of the named enumeration +as if by a \grammarterm{using-declaration} for each enumerator. + +\pnum +\begin{note} +A \grammarterm{using-enum-declaration} in class scope +adds the enumerators of the named enumeration as members to the scope. +This means they are accessible for member lookup. +\begin{example} +\begin{codeblock} +enum class fruit { orange, apple }; +struct S { + using enum fruit; // OK, introduces \tcode{orange} and \tcode{apple} into \tcode{S} +}; +void f() { + S s; + s.orange; // OK, names \tcode{fruit::orange} + S::orange; // OK, names \tcode{fruit::orange} +} +\end{codeblock} +\end{example} +\end{note} + +\pnum +\begin{note} +Two \grammarterm{using-enum-declaration}s +that introduce two enumerators of the same name conflict. +\begin{example} +\begin{codeblock} +enum class fruit { orange, apple }; +enum class color { red, orange }; +void f() { + using enum fruit; // OK + using enum color; // ill-formed: \tcode{color::orange} and \tcode{fruit::orange} conflict +} +\end{codeblock} +\end{example} +\end{note} + \rSec1[basic.namespace]{Namespaces}% \indextext{namespaces|(} @@ -7306,7 +7450,7 @@ \end{codeblock} \end{example} -\rSec2[namespace.udir]{Using directive}% +\rSec2[namespace.udir]{Using namespace directive}% \indextext{using-directive|(} \begin{bnf} @@ -7586,8 +7730,20 @@ \pnum In a \grammarterm{using-declaration} used as a \grammarterm{member-declaration}, -each \grammarterm{using-declarator}{'s} \grammarterm{nested-name-specifier} -shall name a base class of the class being defined. If a +each \grammarterm{using-declarator} +shall either name an enumerator +or have a \grammarterm{nested-name-specifier} +naming a base class of the class being defined. +\begin{example} +\begin{codeblock} +enum class button { up, down }; +struct S { + using button::up; + button b = up; // OK +}; +\end{codeblock} +\end{example} +If a \grammarterm{using-declarator} names a constructor, its \grammarterm{nested-name-specifier} shall name a direct base class of the class being defined. @@ -7654,10 +7810,9 @@ A \grammarterm{using-declaration} shall not name a namespace. \pnum -A \grammarterm{using-declaration} shall not name a scoped enumerator. - -\pnum -A \grammarterm{using-declaration} that names a class member shall be a +A \grammarterm{using-declaration} that names a class member +other than an enumerator +shall be a \grammarterm{member-declaration}. \begin{example} \begin{codeblock} @@ -8015,14 +8170,14 @@ An \tcode{asm} declaration has the form \begin{bnf} -\nontermdef{asm-definition}\br +\nontermdef{asm-declaration}\br \opt{attribute-specifier-seq} \keyword{asm} \terminal{(} string-literal \terminal{)} \terminal{;} \end{bnf} The \tcode{asm} declaration is conditionally-supported; its meaning is \impldef{meaning of \tcode{asm} declaration}. The optional \grammarterm{attribute-specifier-seq} in -an \grammarterm{asm-definition} appertains to the \tcode{asm} declaration. +an \grammarterm{asm-declaration} appertains to the \tcode{asm} declaration. \begin{note} Typically it is used to pass information through the implementation to an assembler. @@ -8281,7 +8436,6 @@ \begin{bnf} \nontermdef{attribute-specifier}\br \terminal{[} \terminal{[} \opt{attribute-using-prefix} attribute-list \terminal{]} \terminal{]}\br - contract-attribute-specifier\br alignment-specifier \end{bnf} @@ -8615,393 +8769,6 @@ \indextext{attribute|)}% \indextext{declaration|)} -\rSec2[dcl.attr.contract]{Contract attributes}% -\indextext{attribute!contracts|(} - -\rSec3[dcl.attr.contract.syn]{Syntax} - -\pnum -Contract attributes are used to specify -preconditions, postconditions, and assertions for functions. - -\begin{bnf} -\nontermdef{contract-attribute-specifier}\br - \terminal{[} \terminal{[} \keyword{expects} \opt{contract-level} \terminal{:} conditional-expression \terminal{]} \terminal{]}\br - \terminal{[} \terminal{[} \keyword{ensures} \opt{contract-level} \opt{identifier} \terminal{:} conditional-expression \terminal{]} \terminal{]}\br - \terminal{[} \terminal{[} \keyword{assert} \opt{contract-level} \terminal{:} conditional-expression \terminal{]} \terminal{]} -\end{bnf} - -\begin{bnf} -\nontermdef{contract-level}\br - \keyword{default}\br - \keyword{audit}\br - \keyword{axiom} -\end{bnf} - - -An ambiguity between -a \grammarterm{contract-level} and an \grammarterm{identifier} -is resolved in favor of \grammarterm{contract-level}. - -\pnum -A \grammarterm{contract-attribute-specifier} using \tcode{expects} -is a \defn{precondition}. -It expresses a function's expectation on its arguments and/or -the state of other objects using a predicate -that is intended to hold upon entry into the function. -The attribute may be applied to the function type of a function declaration. - -\pnum -A \grammarterm{contract-attribute-specifier} using \tcode{ensures} -is a \defn{postcondition}. -It expresses a condition that a function should ensure -for the return value and/or the state of objects -using a predicate that is intended to hold upon exit from the function. -The attribute may be applied to the function type of a function declaration. -A postcondition may introduce an identifier to represent -the glvalue result or the prvalue result object of the function. -When the declared return type of a non-templated function -contains a placeholder type, -the optional \grammarterm{identifier} shall only be present in a definition. -\begin{example} -\begin{codeblock} -int f(char * c) - [[ensures res: res > 0 && c != nullptr]]; - -int g(double * p) - [[ensures audit res: res != 0 && p != nullptr && *p <= 0.0]]; - -auto h(int x) - [[ensures res: true]]; // error: cannot name the return value -\end{codeblock} -\end{example} - -\pnum -A \grammarterm{contract-attribute-specifier} using \tcode{assert} -is an \defn{assertion}. -It expresses a condition that is intended to be satisfied -where it appears in a function body. -The attribute may be applied to a null statement\iref{stmt.expr}. -An assertion is checked by evaluating its predicate -as part of the evaluation of the null statement -it applies to. - -\pnum -Preconditions, postconditions, and assertions -are collectively called \defnx{contracts}{contract}. -The \grammarterm{conditional-expression} in a contract -is contextually converted to \tcode{bool}\iref{conv}; -the converted expression is called -the \defnx{predicate}{contract!predicate} of the contract. -\begin{note} -The predicate of a contract is potentially evaluated\iref{basic.def.odr}. -\end{note} - -\pnum -The only side effects of a predicate -that are allowed in a \grammarterm{contract-attribute-specifier} -are modifications of non-volatile objects -whose lifetime began and ended within the evaluation of the predicate. -An evaluation of a predicate that exits via an exception -invokes the function \tcode{std::terminate}\iref{except.terminate}. -The behavior of any other side effect is undefined. -\begin{example} -\begin{codeblock} -void push(int x, queue & q) - [[expects: !q.full()]] - [[ensures: !q.empty()]] -{ - @\commentellip@ - [[assert: q.is_valid()]]; - @\commentellip@ -} - -int min = -42; -constexpr int max = 42; - -constexpr int g(int x) - [[expects: min <= x]] // error - [[expects: x < max]] // OK -{ - @\commentellip@ - [[assert: 2*x < max]]; - [[assert: ++min > 0]]; // undefined behavior - @\commentellip@ -} -\end{codeblock} -\end{example} - -\rSec3[dcl.attr.contract.cond]{Contract conditions} - -\pnum -A \defn{contract condition} is a precondition or a postcondition. -The first declaration of a function shall specify -all contract conditions (if any) of the function. -Subsequent declarations shall either specify no contract conditions -or the same list of contract conditions; -no diagnostic is required -if corresponding conditions will always evaluate to the same value. -The list of contract conditions of a function shall be the same -if the declarations of that function appear in different translation units; -no diagnostic required. -If a friend declaration -is the first declaration of the function in a translation unit -and has a contract condition, -the declaration shall be a definition and -shall be the only declaration of the function in the translation unit. - -\pnum -Two lists of contract conditions are the same -if they consist of the same contract conditions in the same order. -Two contract conditions are the same -if their contract levels are the same and their predicates are the same. -Two predicates contained in \grammarterm{contract-attribute-specifier}{s} -are the same -if they would satisfy the one-definition rule\iref{basic.def.odr} -were they to appear in function definitions, -except for renaming of parameters, -return value identifiers (if any), -and template parameters. - -\pnum -\begin{note} -A function pointer cannot include contract conditions. -\begin{example} -\begin{codeblock} -typedef int (*fpt)() [[ensures r: r != 0]]; // error: contract condition not on a function declaration - -int g(int x) - [[expects: x >= 0]] - [[ensures r: r > x]] -{ - return x+1; -} - -int (*pf)(int) = g; // OK -int x = pf(5); // contract conditions of \tcode{g} are checked -\end{codeblock} -\end{example} -\end{note} - -\pnum -The predicate of a contract condition has the same semantic restrictions -as if it appeared as the first \grammarterm{expression-statement} -in the body of the function it applies to, -except that the return type of the function is -known in a contract condition appertaining to its definition, -even if the return type contains a placeholder type. - -\pnum -A precondition is checked by evaluating its predicate -immediately before starting evaluation of the function body. -\begin{note} -The function body includes -the \grammarterm{function-try-block}\iref{except} and -the \grammarterm{ctor-initializer}\iref{class.base.init}. -\end{note} -A postcondition is checked by evaluating its predicate -immediately before returning control to the caller of the function. -\begin{note} -The lifetime of local variables and temporaries has ended. -Exiting via an exception or via \tcode{longjmp}\iref{csetjmp.syn} -is not considered returning control to the caller of the function. -\end{note} - -\pnum -If a function has multiple preconditions, -their evaluation (if any) will be performed -in the order they appear lexically. -If a function has multiple postconditions, -their evaluation (if any) will be performed -in the order they appear lexically. -\begin{example} -\begin{codeblock} -void f(int * p) - [[expects: p != nullptr]] // \#1 - [[ensures: *p == 1]] // \#3 - [[expects: *p == 0]] // \#2 -{ - *p = 1; -} -\end{codeblock} -\end{example} - -\pnum -If a postcondition odr-uses\iref{basic.def.odr} -a non-reference parameter in its predicate -and the function body makes direct or indirect modifications of -the value of that parameter, -the behavior is undefined. -\begin{example} -\begin{codeblock} -int f(int x) - [[ensures r: r == x]] -{ - return ++x; // undefined behavior -} - -void g(int * p) - [[ensures: p != nullptr]] -{ - *p = 42; // OK, \tcode{p} is not modified -} - -int h(int x) - [[ensures r: r == x]] -{ - potentially_modify(x); // undefined behavior if \tcode{x} is modified - return x; -} -\end{codeblock} -\end{example} - -\rSec3[dcl.attr.contract.check]{Checking contracts} - -\pnum -If the \grammarterm{contract-level} -of a \grammarterm{contract-attribute-specifier} is absent, -it is assumed to be \tcode{default}. -\begin{note} -A \tcode{default} \grammarterm{contract-level} is expected to be used -for those contracts where -the cost of run-time checking is assumed to be -small (or at least not expensive) compared to -the cost of executing the function. -An \tcode{audit} \grammarterm{contract-level} is expected to be used -for those contracts where -the cost of run-time checking is assumed to be -large (or at least significant) compared to -the cost of executing the function. -An \tcode{axiom} \grammarterm{contract-level} is expected to be used -for those contracts that are formal comments -and are not evaluated at run-time. -\end{note} - -\pnum -\begin{note} -Multiple contract conditions may be applied to a function type -with the same or different \grammarterm{contract-level}{s}. -\begin{example} -\begin{codeblock} -int z; - -bool is_prime(int k); - -void f(int x) - [[expects: x > 0]] - [[expects audit: is_prime(x)]] - [[ensures: z > 10]] -{ - @\commentellip@ -} -\end{codeblock} -\end{example} -\end{note} - -\pnum -A translation may be performed -with one of the following \defnx{build levels}{build level}: -\term{off}, \term{default}, or \term{audit}. -A translation with build level set to \term{off} -performs no checking for any contract. -A translation with build level set to \term{default} -performs checking for \tcode{default} contracts. -A translation with build level set to \term{audit} -performs checking for \tcode{default} and \tcode{audit} contracts. -If no build level is explicitly selected, the build level is \term{default}. -The mechanism for selecting the build level is -\impldef{mechanism for selecting the build level}. -The translation of a program consisting of translation units -where the build level is not the same in all translation units -is conditionally-supported. -There should be no programmatic way of setting, modifying, or querying -the build level of a translation unit. - -\pnum -During constant expression evaluation\iref{expr.const}, -only predicates of checked contracts are evaluated. -In other contexts, -it is unspecified whether the predicate for a contract -that is not checked under the current build level is evaluated; -if the predicate of such a contract -would evaluate to \tcode{false}, the behavior is undefined. - -\pnum -The \defn{violation handler} of a program is a function of type -``\opt{\tcode{noexcept}} function of -(lvalue reference to \tcode{const std::contract_violation}) -returning \tcode{void}''. -The violation handler is invoked -when the predicate of a checked contract evaluates to \tcode{false} -(called a \defn{contract violation}). -There should be no programmatic way of -setting or modifying the violation handler. -It is \impldef{establishing of and argument for violation handler} -how the violation handler is established for a program and -how -the \tcode{std::contract_violation}\iref{support.contract.cviol} argument value -is set, -except as specified below. -If a precondition is violated, the source location of the violation is -\impldef{source location of precondition violation}. -\begin{note} -Implementations are encouraged but not required to report the caller site. -\end{note} -If a postcondition is violated, the source location of the violation is -the source location of the function definition. -If an assertion is violated, the source location of the violation is -the source location of the statement to which the assertion is applied. - -\pnum -If a violation handler exits by throwing an exception -and a contract is violated on a call to a function -with a non-throwing exception specification, -then the behavior is as if the exception escaped the function body. -\begin{note} -The function \tcode{std::terminate} is invoked\iref{except.terminate}. -\end{note} -\begin{example} -\begin{codeblock} -void f(int x) noexcept [[expects: x > 0]]; - -void g() { - f(0); // \tcode{std::terminate()} if violation handler throws - @\commentellip@ -} -\end{codeblock} -\end{example} - -\pnum -A translation may be performed with one of the following -\defnx{violation continuation modes}{violation continuation mode}: -\term{off} or \term{on}. -A translation with violation continuation mode set to \term{off} -terminates execution -by invoking the function \tcode{std::terminate}\iref{except.terminate} -after completing the execution of the violation handler. -A translation with a violation continuation mode set to \term{on} -continues execution after completing the execution of the violation handler. -If no continuation mode is explicitly selected, -the default continuation mode is \term{off}. -\begin{note} -A continuation mode set to \term{on} provides the opportunity -to install a logging handler to instrument a pre-existing code base -and fix errors before enforcing checks. -\end{note} -\begin{example} -\begin{codeblock} -void f(int x) [[expects: x > 0]]; - -void g() { - f(0); // \tcode{std::terminate()} after handler if continuation mode is off; - // proceeds after handler if continuation mode is on - @\commentellip@ -} -\end{codeblock} -\end{example} - -\indextext{attribute!contracts|)} - \rSec2[dcl.attr.deprecated]{Deprecated attribute}% \indextext{attribute!deprecated} @@ -9012,9 +8779,9 @@ unsafe. \end{note} It shall appear at most once in each \grammarterm{attribute-list}. An \grammarterm{attribute-argument-clause} may be present and, if present, it shall have the form: -\begin{codeblock} -( @\grammarterm{string-literal}@ ) -\end{codeblock} +\begin{ncbnf} +\terminal{(} string-literal \terminal{)} +\end{ncbnf} \begin{note} The \grammarterm{string-literal} in the \grammarterm{attribute-argument-clause} could be used to explain the rationale for deprecation and/or to suggest a replacing entity. \end{note} @@ -9062,7 +8829,10 @@ an enclosing \tcode{switch} statement\iref{stmt.switch}. The next statement that would be executed after a fallthrough statement shall be a labeled statement whose label is a case label or -default label for the same \tcode{switch} statement. +default label for the same \tcode{switch} statement and, +if the fallthrough statement is contained in an iteration statement, +the next statement shall be part of the same execution of +the substatement of the innermost enclosing iteration statement. The program is ill-formed if there is no such statement. \pnum @@ -9086,6 +8856,18 @@ g(); [[fallthrough]]; case 3: // warning on fallthrough discouraged + do { + [[fallthrough]]; // error: next statement is not part of the same substatement execution + } while (false); + case 6: + do { + [[fallthrough]]; // error: next statement is not part of the same substatement execution + } while (n--); + case 7: + while (false) { + [[fallthrough]]; // error: next statement is not part of the same substatement execution + } + case 5: h(); case 4: // implementation may warn on fallthrough i(); @@ -9207,29 +8989,81 @@ The \grammarterm{attribute-token} \tcode{nodiscard} may be applied to the \grammarterm{declarator-id} in a function declaration or to the declaration of a class or enumeration. -It shall appear at most once in each \grammarterm{attribute-list} and -no \grammarterm{attribute-argument-clause} shall be present. +It shall appear at most once in each \grammarterm{attribute-list}. +An \grammarterm{attribute-argument-clause} may be present +and, if present, shall have the form: + +\begin{ncbnf} +\terminal{(} string-literal \terminal{)} +\end{ncbnf} + +\pnum +A name or entity declared without the \tcode{nodiscard} attribute +can later be redeclared with the attribute and vice-versa. +\begin{note} +Thus, an entity initially declared without the attribute +can be marked as \tcode{nodiscard} +by a subsequent redeclaration. +However, after an entity is marked as \tcode{nodiscard}, +later redeclarations do not remove the \tcode{nodiscard} +from the entity. +\end{note} +Redeclarations using different forms of the attribute +(with or without the \grammarterm{attribute-argument-clause} +or with different \grammarterm{attribute-argument-clause}s) +are allowed. + +\pnum +A \defnadj{nodiscard}{type} is +a (possibly cv-qualified) class or enumeration type +marked \tcode{nodiscard} in a reachable declaration. +A \defnadj{nodiscard}{call} is either +\begin{itemize} +\item + a function call expression\iref{expr.call} + that calls a function declared \tcode{nodiscard} in a reachable declaration or + whose return type is a nodiscard type, or +\item + an explicit type + conversion~(\ref{expr.static.cast}, \ref{expr.cast}, \ref{expr.type.conv}) + that constructs an object through + a constructor declared \tcode{nodiscard} in a reachable declaration, or + that initializes an object of a nodiscard type. +\end{itemize} \pnum \begin{note} -A nodiscard call is a function call expression that -calls a function previously declared \tcode{nodiscard}, or -whose return type is a possibly cv-qualified class or enumeration type -marked \tcode{nodiscard}. Appearance of a nodiscard call as +Appearance of a nodiscard call as a potentially-evaluated discarded-value expression\iref{expr.prop} is discouraged unless explicitly cast to \tcode{void}. Implementations should issue a warning in such cases. This is typically because discarding the return value of a nodiscard call has surprising consequences. +The \grammarterm{string-literal} +in a \tcode{nodiscard} \grammarterm{attribute-argument-clause} +is intended to be used in the message of the warning +as the rationale for why the result should not be discarded. \end{note} \pnum \begin{example} \begin{codeblock} +struct [[nodiscard]] my_scopeguard { @\commentellip@ }; +struct my_unique { + my_unique() = default; // does not acquire resource + [[nodiscard]] my_unique(int fd) { @\commentellip@ } // acquires resource + ~my_unique() noexcept { @\commentellip@ } // releases resource, if any + @\commentellip@ +}; struct [[nodiscard]] error_info { @\commentellip@ }; error_info enable_missile_safety_mode(); void launch_missiles(); void test_missiles() { + my_scopeguard(); // warning encouraged + (void)my_scopeguard(), // warning not encouraged, cast to \tcode{void} + launch_missiles(); // comma operator, statement continues + my_unique(42); // warning encouraged + my_unique(); // warning not encouraged enable_missile_safety_mode(); // warning encouraged launch_missiles(); } diff --git a/source/diagnostics.tex b/source/diagnostics.tex index 63dfcbd9d2..8ef0376b6d 100644 --- a/source/diagnostics.tex +++ b/source/diagnostics.tex @@ -799,14 +799,9 @@ // \ref{syserr.compare}, comparison functions bool operator==(const error_code& lhs, const error_code& rhs) noexcept; bool operator==(const error_code& lhs, const error_condition& rhs) noexcept; - bool operator==(const error_condition& lhs, const error_code& rhs) noexcept; bool operator==(const error_condition& lhs, const error_condition& rhs) noexcept; - bool operator!=(const error_code& lhs, const error_code& rhs) noexcept; - bool operator!=(const error_code& lhs, const error_condition& rhs) noexcept; - bool operator!=(const error_condition& lhs, const error_code& rhs) noexcept; - bool operator!=(const error_condition& lhs, const error_condition& rhs) noexcept; - bool operator< (const error_code& lhs, const error_code& rhs) noexcept; - bool operator< (const error_condition& lhs, const error_condition& rhs) noexcept; + strong_ordering operator<=>(const error_code& lhs, const error_code& rhs) noexcept; + strong_ordering operator<=>(const error_condition& lhs, const error_condition& rhs) noexcept; // \ref{syserr.hash}, hash support template struct hash; @@ -868,8 +863,7 @@ virtual string message(int ev) const = 0; bool operator==(const error_category& rhs) const noexcept; - bool operator!=(const error_category& rhs) const noexcept; - bool operator< (const error_category& rhs) const noexcept; + strong_ordering operator<=>(const error_category& rhs) const noexcept; }; const error_category& generic_category() noexcept; @@ -942,26 +936,18 @@ \returns \tcode{this == \&rhs}. \end{itemdescr} -\indexlibrarymember{operator"!=}{error_category}% +\indexlibrarymember{operator<=>}{error_category}% \begin{itemdecl} -bool operator!=(const error_category& rhs) const noexcept; +strong_ordering operator<=>(const error_category& rhs) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{!(*this == rhs)}. -\end{itemdescr} - -\indexlibrarymember{operator<}{error_category}% -\begin{itemdecl} -bool operator<(const error_category& rhs) const noexcept; -\end{itemdecl} +\returns \tcode{compare_three_way()(this, \&rhs)}. -\begin{itemdescr} -\pnum -\returns \tcode{less()(this, \&rhs)}. - -\begin{note} \tcode{less}\iref{comparisons} provides a total ordering for pointers. \end{note} +\begin{note} +\tcode{compare_three_way}\iref{cmp.object} provides a total ordering for pointers. +\end{note} \end{itemdescr} \rSec3[syserr.errcat.derived]{Program-defined classes derived from \tcode{error_category}} @@ -1446,20 +1432,6 @@ \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator==}{error_condition}% -\indexlibrarymember{operator==}{error_code}% -\begin{itemdecl} -bool operator==(const error_condition& lhs, const error_code& rhs) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\begin{codeblock} -rhs.category().equivalent(rhs.value(), lhs) || lhs.category().equivalent(rhs, lhs.value()) -\end{codeblock} -\end{itemdescr} - \indexlibrarymember{operator==}{error_condition}% \begin{itemdecl} bool operator==(const error_condition& lhs, const error_condition& rhs) noexcept; @@ -1473,45 +1445,32 @@ \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator"!=}{error_code}% -\indexlibrarymember{operator"!=}{error_condition}% +\indexlibrarymember{operator<=>}{error_code}% \begin{itemdecl} -bool operator!=(const error_code& lhs, const error_code& rhs) noexcept; -bool operator!=(const error_code& lhs, const error_condition& rhs) noexcept; -bool operator!=(const error_condition& lhs, const error_code& rhs) noexcept; -bool operator!=(const error_condition& lhs, const error_condition& rhs) noexcept; +strong_ordering operator<=>(const error_code& lhs, const error_code& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{!(lhs == rhs)}. -\end{itemdescr} - -\indexlibrarymember{operator<}{error_code}% -\begin{itemdecl} -bool operator<(const error_code& lhs, const error_code& rhs) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns +\effects +Equivalent to: \begin{codeblock} -lhs.category() < rhs.category() || -(lhs.category() == rhs.category() && lhs.value() < rhs.value()) +if (auto c = lhs.category() <=> rhs.category(); c != 0) return c; +return lhs.value() <=> rhs.value(); \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator<}{error_condition}% +\indexlibrarymember{operator<=>}{error_condition}% \begin{itemdecl} -bool operator<(const error_condition& lhs, const error_condition& rhs) noexcept; +strong_ordering operator<=>(const error_condition& lhs, const error_condition& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \begin{codeblock} -lhs.category() < rhs.category() || -(lhs.category() == rhs.category() && lhs.value() < rhs.value()) +if (auto c = lhs.category() <=> rhs.category(); c != 0) return c; +return lhs.value() <=> rhs.value(); \end{codeblock} \end{itemdescr} diff --git a/source/exceptions.tex b/source/exceptions.tex index f51a90e76a..e219237b0b 100644 --- a/source/exceptions.tex +++ b/source/exceptions.tex @@ -1034,19 +1034,6 @@ \tcode{std::atexit} or \tcode{std::at_quick_exit} exits via an exception\iref{support.start.term}, or -\item% -when evaluation of the predicate of a contract\iref{dcl.attr.contract} -exits via an exception, or - -\item% -when the violation handler invoked -for a failed contract condition check\iref{dcl.attr.contract} -on a \tcode{noexcept} function exits via an exception, or - -\item% -when the violation handler has completed after a failed contract check -and the continuation mode is \term{off}, or - \item% when a \grammarterm{throw-expression}\iref{expr.throw} diff --git a/source/expressions.tex b/source/expressions.tex index d21a71f3b5..add9621513 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -324,25 +324,6 @@ \tcode{T} is a cv-unqualified non-class, non-array type, the type of the expression is adjusted to \tcode{T} prior to any further analysis. -\pnum -The \defnadj{cv-combined}{type} of two types \tcode{T1} and \tcode{T2} -is a type \tcode{T3} -similar to \tcode{T1} whose cv-qualification signature\iref{conv.qual} is: -\begin{itemize} -\item -for every $i > 0$, $\cv{}^3_i$ is the union of -$\cv{}^1_i$ and $\cv{}^2_i$; - -\item -if the resulting $\cv{}^3_i$ is different from -$\cv{}^1_i$ or $\cv{}^2_i$, then -\tcode{const} is added to every $\cv{}^3_k$ for $0 < k < i$. -\end{itemize} - -\begin{note} Given similar types \tcode{T1} and \tcode{T2}, this -construction ensures that -both can be converted to \tcode{T3}. \end{note} - \pnum \indextext{pointer!composite pointer type}% The \defn{composite pointer type} of @@ -736,8 +717,11 @@ the cv-qualifiers $\cv{}_i$ of the array. \begin{example} The type denoted by the \grammarterm{type-id} \tcode{const int **} -has two cv-decompositions, -taking \tcode{U} as ``\tcode{int}'' and as ``pointer to \tcode{const int}''. +has three cv-decompositions, +taking \tcode{U} +as ``\tcode{int}'', +as ``pointer to \tcode{const int}'', and +as ``pointer to pointer to \tcode{const int}''. \end{example} The $n$-tuple of cv-qualifiers after the first one in the longest cv-decomposition of \tcode{T}, that is, @@ -746,36 +730,38 @@ \pnum \indextext{type!similar|see{similar types}}% -Two types $\tcode{T}_1$ and $\tcode{T}_2$ are \defnx{similar}{similar types} if +Two types \tcode{T1} and \tcode{T2} are \defnx{similar}{similar types} if they have cv-decompositions with the same $n$ -such that corresponding $P_i$ components are the same +such that corresponding $P_i$ components are either the same +or one is ``array of $N_i$'' and the other is ``array of unknown bound of'', and the types denoted by \tcode{U} are the same. \pnum -A prvalue of type $\tcode{T}_1$ -can be converted to type $\tcode{T}_2$ -if the following conditions are satisfied, -% NB: forbid line break between 'where' and 'cv' -% to stop superscript j from running into -% descender of p on the previous line. -where~$\cv{}_i^j$ denotes the cv-qualifiers in the cv-qualification signature of $\tcode{T}_j$:% -\footnote{These rules ensure that const-safety is preserved by the conversion.} - +The \defnadj{cv-combined}{type} of two types \tcode{T1} and \tcode{T2} +is the type \tcode{T3} +similar to \tcode{T1} whose cv-decomposition is such that: \begin{itemize} -\item $\tcode{T}_1$ and $\tcode{T}_2$ are similar. - -\item For every $i > 0$, if \tcode{const} is in $\cv{}_i^1$ then \tcode{const} is in $\cv{}_i^2$, and similarly for \tcode{volatile}. - -\item If the $\cv{}_i^1$ and $\cv{}_i^2$ are different, -then \tcode{const} is in every $\cv{}_k^2$ for $0 < k < i$. +\item +for every $i > 0$, $\cv{}^3_i$ is the union of +$\cv{}^1_i$ and $\cv{}^2_i$; +\item +if either $P^1_i$ or $P^2_i$ is ``array of unknown bound of'', +$P^3_i$ is ``array of unknown bound of'', otherwise it is $P^1_i$; +\item +if the resulting $\cv{}^3_i$ is different from $\cv{}^1_i$ or $\cv{}^2_i$, +or the resulting $P^3_i$ is different from $P^1_i$ or $P^2_i$, +then \tcode{const} is added to every $\cv{}^3_k$ for $0 < k < i$. \end{itemize} - +where $\cv{}^j_i$ and $P^j_i$ are the components of +the cv-decomposition of $\tcode{T}j$. +A prvalue of type \tcode{T1} +can be converted to type \tcode{T2} +if the cv-combined type of \tcode{T1} and \tcode{T2} is \tcode{T2}. \begin{note} If a program could assign a pointer of type \tcode{T**} to a pointer of type \tcode{const} \tcode{T**} (that is, if line \#1 below were allowed), a program could inadvertently modify a const object (as it is done on line \#2). For example, - \begin{codeblock} int main() { const char c = 'c'; @@ -786,6 +772,11 @@ } \end{codeblock} \end{note} +\begin{note} +Given similar types \tcode{T1} and \tcode{T2}, this +construction ensures that +both can be converted to the cv-combined type of \tcode{T1} and \tcode{T2}. +\end{note} \pnum \begin{note} @@ -801,8 +792,8 @@ \pnum \begin{note} -Function types (including those used in pointer to member function -types) are never cv-qualified\iref{dcl.fct}. +Function types (including those used in pointer-to-member-function types) +are never cv-qualified\iref{dcl.fct}. \end{note} \indextext{conversion!qualification|)} @@ -1207,14 +1198,14 @@ \begin{example} \begin{codeblock} class Outer { - int a[sizeof(*this)]; // error: not inside a member function - unsigned int sz = sizeof(*this); // OK: in default member initializer + int a[sizeof(*this)]; // error: not inside a member function + unsigned int sz = sizeof(*this); // OK: in default member initializer void f() { - int b[sizeof(*this)]; // OK + int b[sizeof(*this)]; // OK struct Inner { - int c[sizeof(*this)]; // error: not inside a member function of \tcode{Inner} + int c[sizeof(*this)]; // error: not inside a member function of \tcode{Inner} }; } }; @@ -1295,7 +1286,7 @@ \begin{example} \begin{codeblock} template concept C = true; -static_assert(C); // OK +static_assert(C); // OK \end{codeblock} \end{example} \begin{note} @@ -1586,10 +1577,10 @@ \tcode{return} statements as described in~\ref{dcl.spec.auto}. \begin{example} \begin{codeblock} -auto x1 = [](int i){ return i; }; // OK: return type is \tcode{int} -auto x2 = []{ return { 1, 2 }; }; // error: deducing return type from \grammarterm{braced-init-list} +auto x1 = [](int i){ return i; }; // OK: return type is \tcode{int} +auto x2 = []{ return { 1, 2 }; }; // error: deducing return type from \grammarterm{braced-init-list} int j; -auto x3 = []()->auto&& { return j; }; // OK: return type is \tcode{int\&} +auto x3 = []()->auto&& { return j; }; // OK: return type is \tcode{int\&} \end{codeblock} \end{example} @@ -1602,8 +1593,8 @@ or if the lambda has a \grammarterm{template-parameter-list}. \begin{example} \begin{codeblock} -int i = [](int i, auto a) { return i; }(3, 4); // OK: a generic lambda -int j = [](T t, int i) { return i; }(3, 4); // OK: a generic lambda +int i = [](int i, auto a) { return i; }(3, 4); // OK: a generic lambda +int j = [](T t, int i) { return i; }(3, 4); // OK: a generic lambda \end{codeblock} \end{example} @@ -1660,10 +1651,10 @@ \begin{example} \begin{codeblock} auto glambda = [](auto a, auto&& b) { return a < b; }; -bool b = glambda(3, 3.14); // OK +bool b = glambda(3, 3.14); // OK auto vglambda = [](auto printer) { - return [=](auto&& ... ts) { // OK: \tcode{ts} is a function parameter pack + return [=](auto&& ... ts) { // OK: \tcode{ts} is a function parameter pack printer(std::forward(ts)...); return [=]() { @@ -1673,8 +1664,8 @@ }; auto p = vglambda( [](auto v1, auto v2, auto v3) { std::cout << v1 << v2 << v3; } ); -auto q = p(1, 'a', 3.14); // OK: outputs \tcode{1a3.14} -q(); // OK: outputs \tcode{1a3.14} +auto q = p(1, 'a', 3.14); // OK: outputs \tcode{1a3.14} +q(); // OK: outputs \tcode{1a3.14} \end{codeblock} \end{example} @@ -2519,7 +2510,7 @@ template concept R = requires (T i) { typename T::type; - {*i} -> const typename T::type&; + {*i} -> convertible_to; }; \end{codeblock} A \grammarterm{requires-expression} can also be used in a @@ -2588,7 +2579,7 @@ \begin{codeblock} template concept C = requires { - new int[-(int)sizeof(T)]; // ill-formed, no diagnostic required + new int[-(int)sizeof(T)]; // ill-formed, no diagnostic required }; \end{codeblock} \end{example} @@ -2613,7 +2604,7 @@ \begin{codeblock} template concept C = requires (T a, T b) { - a + b; // \tcode{C} is \tcode{true} if \tcode{a + b} is a valid expression + a + b; // \tcode{C} is \tcode{true} if \tcode{a + b} is a valid expression }; \end{codeblock} \end{example} @@ -2659,7 +2650,6 @@ \begin{bnf} \nontermdef{return-type-requirement}\br - trailing-return-type\br \terminal{->} type-constraint \end{bnf} @@ -2687,19 +2677,8 @@ into the \grammarterm{return-type-requirement} is performed. \item -If the \grammarterm{return-type-requirement} is a -\grammarterm{trailing-return-type}\iref{dcl.decl}, -%%% FIXME: is -> shall be -\tcode{E} is implicitly convertible to -the type named by the \grammarterm{trailing-return-type}. -If conversion fails, the enclosing \grammarterm{requires-expression} -is \tcode{false}. - -\item -If the \grammarterm{return-type-requirement} -is of the form \tcode{->} \grammarterm{type-constraint}, then -the contextually-determined type being constrained -is \tcode{decltype((E))}. +The contextually-determined type being constrained +by the \grammarterm{type-constraint} is \tcode{decltype((E))}. The immediately-declared constraint\iref{temp} of \tcode{decltype((E))} shall be satisfied. \begin{example} @@ -2736,15 +2715,14 @@ \begin{codeblock} template concept C2 = requires(T x) { - {*x} -> typename T::inner; + {*x} -> same_as; }; \end{codeblock} The \grammarterm{compound-requirement} in \tcode{C2} requires that \tcode{*x} is a valid expression, that \tcode{typename T::inner} is a valid type, and -that \tcode{*x} is implicitly convertible to -\tcode{typename T::inner}. +that \tcode{same_as} is satisfied. \begin{codeblock} template concept C3 = @@ -2774,7 +2752,7 @@ by the substituted template arguments, if any. Substitution of template arguments into a \grammarterm{nested-requirement} does not result in substitution into the \grammarterm{constraint-expression} -other than as specified in \ref{temp.constr.decl}. +other than as specified in \ref{temp.constr.constr}. \begin{example} \begin{codeblock} template concept C = sizeof(U) == 1; @@ -2792,8 +2770,8 @@ \begin{example} \begin{codeblock} template concept C = requires (T a) { - requires sizeof(a) == 4; // OK - requires a == 0; // error: evaluation of a constraint variable + requires sizeof(a) == 4; // OK + requires a == 0; // error: evaluation of a constraint variable } \end{codeblock} \end{example} @@ -2862,6 +2840,14 @@ if that operand is an lvalue and an xvalue otherwise. The expression \tcode{E1} is sequenced before the expression \tcode{E2}. +\pnum +\begin{note} +A comma expression\iref{expr.comma} +appearing as the \grammarterm{expr-or-braced-init-list} +of a subscripting expression is deprecated; +see \ref{depr.comma.subscript}. +\end{note} + \pnum \begin{note} Despite its asymmetric appearance, subscripting is a commutative @@ -3018,7 +3004,7 @@ void f() { std::string s = "but I have heard it works even if you don't believe in it"; s.replace(0, 4, "").replace(s.find("even"), 4, "only").replace(s.find(" don't"), 6, ""); - assert(s == "I have heard it works only if you believe in it"); // OK + assert(s == "I have heard it works only if you believe in it"); // OK } \end{codeblock} \end{example} @@ -3103,10 +3089,11 @@ After these conversions, if the argument does not have arithmetic, enumeration, pointer, pointer-to-member, or class type, the program is ill-formed. Passing a potentially-evaluated -argument of class type\iref{class} having a non-trivial -copy constructor, a non-trivial move constructor, +argument of class type\iref{class} having an eligible non-trivial +copy constructor, an eligible non-trivial move constructor, or a -non-trivial destructor, with no corresponding parameter, is conditionally-supported with +non-trivial destructor\iref{special}, +with no corresponding parameter, is conditionally-supported with \impldef{passing argument of class type through ellipsis} semantics. If the argument has integral or enumeration type that is subject to the integral promotions\iref{conv.prom}, or a floating-point type that is subject to the @@ -3327,8 +3314,10 @@ \end{note} The operand shall be a modifiable lvalue. The type of the operand shall be an arithmetic type other than \cv{}~\tcode{bool}, -or a pointer to a complete object type. The value -of the operand object is modified by adding \tcode{1} to it. +or a pointer to a complete object type. +An operand with \tcode{volatile}-qualified type is deprecated; +see~\ref{depr.volatile.type}. +The value of the operand object is modified by adding \tcode{1} to it. The \indextext{value computation}% value computation of the \tcode{++} expression is sequenced before the @@ -3763,9 +3752,11 @@ \tcode{D} is a complete class type and \tcode{B} is a base class\iref{class.derived} of \tcode{D}, if \cvqual{cv2} is the same cv-qualification -as, or greater cv-qualification than, \cvqual{cv1}.\footnote{Function types -(including those used in pointer-to-member-function -types) are never cv-qualified; see~\ref{dcl.fct}.} +as, or greater cv-qualification than, \cvqual{cv1}. +\begin{note} +Function types (including those used in pointer-to-member-function types) +are never cv-qualified\iref{dcl.fct}. +\end{note} If no valid standard conversion from ``pointer to member of \tcode{B} of type \tcode{T}'' to ``pointer to member of \tcode{D} of type \tcode{T}'' @@ -3934,11 +3925,11 @@ conversion is unspecified, except in the following cases: \begin{itemize} -\item converting a prvalue of type ``pointer to member function'' to a +\item Converting a prvalue of type ``pointer to member function'' to a different pointer-to-member-function type and back to its original type yields the original pointer-to-member value. -\item converting a prvalue of type ``pointer to data member of \tcode{X} +\item Converting a prvalue of type ``pointer to data member of \tcode{X} of type \tcode{T1}'' to the type ``pointer to data member of \tcode{Y} of type \tcode{T2}'' (where the alignment requirements of \tcode{T2} are no stricter than those of \tcode{T1}) and back to its original type @@ -3988,16 +3979,19 @@ \pnum For two similar types \tcode{T1} and \tcode{T2}\iref{conv.qual}, a prvalue of type \tcode{T1} may be explicitly -converted to the type \tcode{T2} using a \tcode{const_cast}. The result -of a \tcode{const_cast} refers to the original entity. +converted to the type \tcode{T2} using a \tcode{const_cast} +if, considering the cv-decompositions of both types, +each $P^1_i$ is the same as $P^2_i$ for all $i$. +The result of a \tcode{const_cast} refers to the original entity. \begin{example} \begin{codeblock} -typedef int *A[3]; // array of 3 pointer to \tcode{int} -typedef const int *const CA[3]; // array of 3 const pointer to \tcode{const int} +typedef int *A[3]; // array of 3 pointer to \tcode{int} +typedef const int *const CA[3]; // array of 3 const pointer to \tcode{const int} -CA &&r = A{}; // OK, reference binds to temporary array object after qualification conversion to type \tcode{CA} -A &&r1 = const_cast(CA{}); // error: temporary array decayed to pointer -A &&r2 = const_cast(CA{}); // OK +CA &&r = A{}; // OK, reference binds to temporary array object + // after qualification conversion to type \tcode{CA} +A &&r1 = const_cast(CA{}); // error: temporary array decayed to pointer +A &&r2 = const_cast(CA{}); // OK \end{codeblock} \end{example} @@ -4280,6 +4274,8 @@ The operand shall be a modifiable lvalue. The type of the operand shall be an arithmetic type other than \cv{}~\tcode{bool}, or a pointer to a completely-defined object type. +An operand with \tcode{volatile}-qualified type is deprecated; +see~\ref{depr.volatile.type}. The result is the updated operand; it is an lvalue, and it is a bit-field if the operand is a bit-field. The expression \tcode{++x} is equivalent to \tcode{x+=1}. @@ -4618,9 +4614,6 @@ \begin{note} A \grammarterm{noexcept-expression} is an integral constant expression\iref{expr.const}. -The type \tcode{std::size_t} is defined in the standard header -\indexhdr{cstddef}% -\tcode{}~(\ref{cstddef.syn}, \ref{support.types.layout}). \end{note} \pnum @@ -4905,7 +4898,19 @@ An implementation is allowed to omit a call to a replaceable global allocation function~(\ref{new.delete.single}, \ref{new.delete.array}). When it does so, the storage is instead provided by the implementation or provided by extending -the allocation of another \grammarterm{new-expression}. The implementation may +the allocation of another \grammarterm{new-expression}. + +\pnum +During an evaluation of a constant expression, +a call to an allocation function is always omitted. +\begin{note} +Only \grammarterm{new-expression}{s} that would otherwise result in +a call to a replaceable global allocation function +can be evaluated in constant expressions\iref{expr.const}. +\end{note} + +\pnum +The implementation may extend the allocation of a \grammarterm{new-expression} \tcode{e1} to provide storage for a \grammarterm{new-expression} \tcode{e2} if the following would be true were the allocation not extended: @@ -4933,7 +4938,7 @@ \begin{example} \begin{codeblock} - void mergeable(int x) { + void can_merge(int x) { // These allocations are safe for merging: std::unique_ptr a{new (std::nothrow) char[8]}; std::unique_ptr b{new (std::nothrow) char[8]}; @@ -4942,7 +4947,7 @@ g(a.get(), b.get(), c.get()); } - void unmergeable(int x) { + void cannot_merge(int x) { std::unique_ptr a{new char[8]}; try { // Merging this allocation would change its catch handler. @@ -6606,7 +6611,7 @@ completely handle the exception itself, can be written like this: \begin{codeblock} try { - // ... + // ... } catch (...) { // catch all exceptions // respond (partially) to exception throw; // pass the exception to some other handler @@ -6681,23 +6686,10 @@ \pnum \indextext{assignment!conversion by}% -If the left operand is not of class type, the expression is implicitly +The expression is implicitly converted\iref{conv} to the cv-unqualified type of the left operand. -\pnum -\indextext{class object!assignment to}% -\indextext{type!incomplete}% -If the left operand is of class type, the class shall be complete. -Assignment to objects of a class is defined by the copy/move assignment -operator~(\ref{class.copy.assign}, \ref{over.ass}). - -\pnum -\begin{note} -For class objects, assignment is not in general the same as -initialization~(\ref{dcl.init}, \ref{class.copy.ctor}, \ref{class.copy.assign}, \ref{class.init}). -\end{note} - \pnum \indextext{reference!assignment to}% When the left operand of an assignment operator @@ -6705,10 +6697,19 @@ resulting value of the bit-field is \impldefplain{value of bit-field that cannot represent!assigned value}. +\pnum +A simple assignment whose left operand is of +a \tcode{volatile}-qualified type is deprecated\iref{depr.volatile.type} +unless the assignment is either a discarded-value expression or +appears in an unevaluated context. + \pnum The behavior of an expression of the form \tcode{E1 \placeholder{op}= E2} is equivalent to \tcode{E1 = E1 \placeholder{op} E2} except -that \tcode{E1} is evaluated only once. In \tcode{+=} and \tcode{-=}, +that \tcode{E1} is evaluated only once. +Such expressions are deprecated +if \tcode{E1} has \tcode{volatile}-qualified type; see~\ref{depr.volatile.type}. +For \tcode{+=} and \tcode{-=}, \tcode{E1} shall either have arithmetic type or be a pointer to a possibly cv-qualified completely-defined object type. In all other cases, \tcode{E1} shall have arithmetic type. @@ -6737,11 +6738,11 @@ \begin{example} \begin{codeblock} complex z; -z = { 1,2 }; // meaning \tcode{z.operator=(\{1,2\})} -z += { 1, 2 }; // meaning \tcode{z.operator+=(\{1,2\})} +z = { 1,2 }; // meaning \tcode{z.operator=(\{1,2\})} +z += { 1, 2 }; // meaning \tcode{z.operator+=(\{1,2\})} int a, b; -a = b = { 1 }; // meaning \tcode{a=b=1;} -a = { 1 } = b; // syntax error +a = b = { 1 }; // meaning \tcode{a=b=1;} +a = { 1 } = b; // syntax error \end{codeblock} \end{example} @@ -6792,6 +6793,14 @@ \tcode{5}. \end{example} +\pnum +\begin{note} +A comma expression +appearing as the \grammarterm{expr-or-braced-init-list} +of a subscripting expression\iref{expr.sub} is deprecated; +see \ref{depr.comma.subscript}. +\end{note} + \rSec1[expr.const]{Constant expressions}% \indextext{expression!constant} @@ -6812,55 +6821,75 @@ \end{bnf} \pnum -A \defn{constant initializer} for a variable or temporary object \tcode{o} is -an initializer for which interpreting its full-expression -as a \grammarterm{constant-expression} results in a constant expression, -except that if \tcode{o} is an object, -such an initializer may also invoke constexpr constructors -for \tcode{o} and its subobjects -even if those objects are of non-literal class types. -\begin{note} -Such a class may have a non-trivial destructor. -Within this evaluation, -\tcode{std::is_constant_evaluated()}\iref{meta.const.eval} -returns \tcode{true}. +A variable or temporary object \tcode{o} is \defn{constant-initialized} if +\begin{itemize} +\item + either it has an initializer or + its default-initialization results in some initialization being performed, and +\item + its initialization full-expression is a constant expression + when interpreted as a \grammarterm{constant-expression}, + except that if \tcode{o} is an object, + the initialization full-expression + may also invoke constexpr constructors + for \tcode{o} and its subobjects + even if those objects are of non-literal class types. + \begin{note} + Such a class may have a non-trivial destructor. + Within this evaluation, + \tcode{std::is_constant_evaluated()}\iref{meta.const.eval} + returns \tcode{true}. \end{note} +\end{itemize} \pnum -A variable is -\defn{usable in constant expressions} after +A variable is \defn{usable in constant expressions} after its initializing declaration is encountered if it is a constexpr variable, or -it is of reference type or of const-qualified integral or enumeration type, and -its initializer is a constant initializer. +it is a constant-initialized variable +of reference type or of const-qualified integral or enumeration type. +An object or reference is \defn{usable in constant expressions} if it is +\begin{itemize} +\item a variable that is usable in constant expressions, or +\item a template parameter object\iref{temp.param}, or +\item a string literal object\iref{lex.string}, or +\item a non-mutable subobject or reference member of any of the above, or +\item a complete temporary object of + non-volatile const-qualified integral or enumeration type + that is initialized with a constant expression. +\end{itemize} \pnum An expression \tcode{e} is a \defnadj{core constant}{expression} unless the evaluation of \tcode{e}, following the rules of the abstract -machine\iref{intro.execution}, would evaluate one of the following expressions: +machine\iref{intro.execution}, would evaluate one of the following: \begin{itemize} \item \tcode{this}\iref{expr.prim.this}, except in a constexpr -function or a constexpr constructor that is being evaluated as part +function\iref{dcl.constexpr} that is being evaluated as part of \tcode{e}; \item -an invocation of a function other than -a constexpr constructor for a literal class, -a constexpr function, -or an implicit invocation of a trivial destructor\iref{class.dtor} +an invocation of a non-constexpr function \begin{note} Overload resolution\iref{over.match} -is applied as usual \end{note}; +is applied as usual. +\end{note}; + +\item +an invocation of an undefined constexpr function; \item -an invocation of an undefined constexpr function or an -undefined constexpr constructor; +an invocation of an instantiated constexpr function +that fails to satisfy the requirements +for a constexpr function; \item -an invocation of an instantiated constexpr function or -constexpr constructor that fails to satisfy the requirements -for a constexpr function or -constexpr constructor\iref{dcl.constexpr}; +an invocation of a virtual function\iref{class.virtual} +for an object unless + \begin{itemize} + \item the object is usable in constant expressions or + \item its lifetime began within the evaluation of \tcode{e}; + \end{itemize} \item an expression that would exceed the implementation-defined @@ -6894,6 +6923,10 @@ that is applied to a glvalue that refers to a non-active member of a union or a subobject thereof; +\item +an lvalue-to-rvalue conversion that is applied to +an object with an indeterminate value\iref{basic.indet}; + \item an invocation of an implicitly-defined copy/move constructor or copy/move assignment operator @@ -6913,10 +6946,6 @@ its lifetime began within the evaluation of \tcode{e}; \end{itemize} -\item -a checked contract\iref{dcl.attr.contract} -whose predicate evaluates to \tcode{false}; - \item in a \grammarterm{lambda-expression}, a reference to \tcode{this} or to a variable with @@ -6928,8 +6957,8 @@ void g() { const int n = 0; [=] { - constexpr int i = n; // OK, \tcode{n} is not odr-used here - constexpr int j = *&n; // ill-formed, \tcode{\&n} would be an odr-use of \tcode{n} + constexpr int i = n; // OK, \tcode{n} is not odr-used here + constexpr int j = *&n; // ill-formed, \tcode{\&n} would be an odr-use of \tcode{n} }; } \end{codeblock} @@ -6960,9 +6989,6 @@ \item a \tcode{reinterpret_cast}\iref{expr.reinterpret.cast}; -\item -a pseudo-destructor call\iref{expr.prim.id.dtor}; - \item modification of an object~(\ref{expr.ass}, \ref{expr.post.incr}, \ref{expr.pre.incr}) @@ -6971,10 +6997,27 @@ whose lifetime began within the evaluation of \tcode{e}; \item -a \grammarterm{new-expression}\iref{expr.new}; +a \grammarterm{new-expression}\iref{expr.new}, +unless the selected allocation function is +a replaceable global allocation function~(\ref{new.delete.single}, +\ref{new.delete.array}) and +the allocated storage is deallocated within the evaluation of \tcode{e}; + +\item +a \grammarterm{delete-expression}\iref{expr.delete}, +unless it deallocates a region of storage +allocated within the evaluation of \tcode{e}; \item -a \grammarterm{delete-expression}\iref{expr.delete}; +a call to an instance of +\tcode{std::allocator::allocate}\iref{allocator.members}, +unless the allocated storage is deallocated within the evaluation of \tcode{e}; + +\item +a call to an instance of +\tcode{std::allocator::deallocate}\iref{allocator.members}, +unless it deallocates a region of storage +allocated within the evaluation of \tcode{e}; \item an \grammarterm{await-expression}\iref{expr.await}; @@ -6990,7 +7033,10 @@ \item a \grammarterm{throw-expression}\iref{expr.throw} or a dynamic cast\iref{expr.dynamic.cast} or \tcode{typeid}\iref{expr.typeid} expression -that would throw an exception; or +that would throw an exception; + +\item +an \grammarterm{asm-declaration}\iref{dcl.asm}; or \item an invocation of the \tcode{va_arg} macro\iref{cstdarg.syn}. @@ -7042,6 +7088,50 @@ \end{codeblock} \end{example} +\pnum +For the purposes of determining +whether an expression is a core constant expression, +the evaluation of a call to a member function of \tcode{std::allocator} +as defined in \ref{allocator.members}, where \tcode{T} is a literal type, +does not disqualify the expression from being a core constant expression, +even if the actual evaluation of such a call +would otherwise fail the requirements for a core constant expression. +Similarly, the evaluation of a call to +\tcode{std::destroy_at}, +\tcode{std::ranges::destroy_at}, +\tcode{std::construct_at}, or +\tcode{std::ranges::construct_at} +is a valid core constant expression unless: +\begin{itemize} +\item + for a call to \tcode{std::construct_at} or \tcode{std::ranges::construct_at}, + the first argument, of type \tcode{T*}, + does not point to storage allocated with \tcode{std::allocator} or + the evaluation of the underlying constructor call + is not a core constant expression, or +\item + for a call to \tcode{std::destroy_at} or \tcode{std::ranges::destroy_at}, + the first argument, of type \tcode{T*}, + does not point to storage allocated with \tcode{std::allocator} or + the evaluation of the underlying destructor call + is not a core constant expression. +\end{itemize} + +\pnum +An object \tcode{a} is said to have \defnadj{constant}{destruction} if: +\begin{itemize} +\item + it is not of class type nor (possibly multi-dimensional) array thereof, or +\item + it is of class type or (possibly multi-dimensional) array thereof, + that class type has a constexpr destructor, and + for a hypothetical expression \tcode{e} + whose only effect is to destroy \tcode{a}, + \tcode{e} would be a core constant expression + if the lifetime of \tcode{a} and its non-mutable subobjects + (but not its mutable subobjects) were considered to start within \tcode{e}. +\end{itemize} + \pnum An \defnadj{integral constant}{expression} is an expression of integral or @@ -7069,8 +7159,8 @@ }; template struct X { }; constexpr A a = alignof(int); -alignas(a) int n; // error: ambiguous conversion -struct B { int n : a; }; // error: ambiguous conversion +alignas(a) int n; // error: ambiguous conversion +struct B { int n : a; }; // error: ambiguous conversion \end{codeblock} \end{example} @@ -7166,8 +7256,8 @@ \begin{codeblock} bool f() { - char array[1 + int(1 + 0.2 - 0.1 - 0.1)]; // Must be evaluated during translation - int size = 1 + int(1 + 0.2 - 0.1 - 0.1); // May be evaluated at runtime + char array[1 + int(1 + 0.2 - 0.1 - 0.1)]; // Must be evaluated during translation + int size = 1 + int(1 + 0.2 - 0.1 - 0.1); // May be evaluated at runtime return sizeof(array) == size; } \end{codeblock} diff --git a/source/future.tex b/source/future.tex index 5c541d9da3..f726e1cd03 100644 --- a/source/future.tex +++ b/source/future.tex @@ -54,6 +54,24 @@ \end{codeblock} \end{example} +\rSec1[depr.comma.subscript]{Comma operator in subscript expressions} + +\pnum +A comma expression\iref{expr.comma} +appearing as the \grammarterm{expr-or-braced-init-list} +of a subscripting expression\iref{expr.sub} is deprecated. +\begin{note} +A parenthesized comma expression is not deprecated. +\end{note} +\begin{example} +\begin{codeblock} +void f(int *a, int b, int c) { + a[b,c]; // deprecated + a[(b,c)]; // OK +} +\end{codeblock} +\end{example} + \rSec1[depr.array.comp]{Array comparisons} \pnum @@ -73,6 +91,27 @@ \end{codeblock} \end{example} +\rSec1[depr.volatile.type]{Deprecated \tcode{volatile} types} + +\pnum +Postfix \tcode{++} and \tcode{\dcr} expressions\iref{expr.post.incr} and +prefix \tcode{++} and \tcode{\dcr} expressions\iref{expr.pre.incr} +of \tcode{volatile}-qualified arithmetic and pointer types are deprecated. + +\pnum +Certain assignments +where the left operand is a \tcode{volatile}-qualified non-class type +are deprecated; see~\ref{expr.ass}. + +\pnum +A function type\iref{dcl.fct} +with a parameter with \tcode{volatile}-qualified type or +with a \tcode{volatile}-qualified return type is deprecated. + +\pnum +A structured binding\iref{dcl.struct.bind} of a \tcode{volatile}-qualified type +is deprecated. + \rSec1[depr.static.constexpr]{Redeclaration of \tcode{static constexpr} data members} \pnum @@ -2379,7 +2418,7 @@ \pnum \requires The \tcode{source} and \range{first}{last} sequences are UTF-8 encoded. The value type of \tcode{Source} - and \tcode{InputIterator} is \tcode{char}. + and \tcode{InputIterator} is \tcode{char} or \tcode{char8_t}. \tcode{Source} meets the requirements specified in \ref{fs.path.req}. \pnum diff --git a/source/iostreams.tex b/source/iostreams.tex index 72291bd914..52b9db824e 100644 --- a/source/iostreams.tex +++ b/source/iostreams.tex @@ -5829,6 +5829,24 @@ template basic_ostream& operator<<(basic_ostream&, unsigned char); + template + basic_ostream& operator<<(basic_ostream&, wchar_t) = delete; + template + basic_ostream& operator<<(basic_ostream&, char8_t) = delete; + template + basic_ostream& operator<<(basic_ostream&, char16_t) = delete; + template + basic_ostream& operator<<(basic_ostream&, char32_t) = delete; + template + basic_ostream& + operator<<(basic_ostream&, char8_t) = delete; + template + basic_ostream& + operator<<(basic_ostream&, char16_t) = delete; + template + basic_ostream& + operator<<(basic_ostream&, char32_t) = delete; + template basic_ostream& operator<<(basic_ostream&, const charT*); template @@ -5840,6 +5858,28 @@ basic_ostream& operator<<(basic_ostream&, const signed char*); template basic_ostream& operator<<(basic_ostream&, const unsigned char*); + + template + basic_ostream& + operator<<(basic_ostream&, const wchar_t*) = delete; + template + basic_ostream& + operator<<(basic_ostream&, const char8_t*) = delete; + template + basic_ostream& + operator<<(basic_ostream&, const char16_t*) = delete; + template + basic_ostream& + operator<<(basic_ostream&, const char32_t*) = delete; + template + basic_ostream& + operator<<(basic_ostream&, const char8_t*) = delete; + template + basic_ostream& + operator<<(basic_ostream&, const char16_t*) = delete; + template + basic_ostream& + operator<<(basic_ostream&, const char32_t*) = delete; } \end{codeblock} @@ -5887,6 +5927,12 @@ rethrows the exception without completing its actions, otherwise it does not throw anything and treat as an error. +\pnum +\begin{note} +The deleted overloads of \tcode{operator<<} +prevent formatting characters as integers and strings as pointers. +\end{note} + \rSec4[ostream.cons]{Constructors} \indexlibrary{\idxcode{basic_ostream}!constructor}% @@ -7379,19 +7425,48 @@ basic_stringbuf() : basic_stringbuf(ios_base::in | ios_base::out) {} explicit basic_stringbuf(ios_base::openmode which); explicit basic_stringbuf( - const basic_string& str, + const basic_string& s, + ios_base::openmode which = ios_base::in | ios_base::out); + explicit basic_stringbuf(const Allocator& a) + : basic_stringbuf(ios_base::in | ios_base::out, a) {} + basic_stringbuf(ios_base::openmode which, const Allocator& a); + explicit basic_stringbuf( + basic_string&& s, ios_base::openmode which = ios_base::in | ios_base::out); + template + basic_stringbuf( + const basic_string& s, const Allocator& a) + : basic_stringbuf(s, ios_base::in | ios_base::out, a) {} + template + basic_stringbuf( + const basic_string& s, + ios_base::openmode which, const Allocator& a); + template + explicit basic_stringbuf( + const basic_string& s, + ios_base::openmode which = ios_base::in | ios_base::out); basic_stringbuf(const basic_stringbuf& rhs) = delete; basic_stringbuf(basic_stringbuf&& rhs); + basic_stringbuf(basic_stringbuf&& rhs, const Allocator& a); // \ref{stringbuf.assign}, assign and swap basic_stringbuf& operator=(const basic_stringbuf& rhs) = delete; basic_stringbuf& operator=(basic_stringbuf&& rhs); - void swap(basic_stringbuf& rhs); + void swap(basic_stringbuf& rhs) noexcept(@\seebelow@); + + // \ref{stringbuf.members}, getters and setters + allocator_type get_allocator() const noexcept; + + basic_string str() const &; + template + basic_string str(const SAlloc& sa) const; + basic_string str() &&; + basic_string_view view() const noexcept; - // \ref{stringbuf.members}, get and set - basic_string str() const; void str(const basic_string& s); + template + void str(const basic_string& s); + void str(basic_string&& s); protected: // \ref{stringbuf.virtuals}, overridden virtual functions @@ -7408,12 +7483,14 @@ = ios_base::in | ios_base::out) override; private: - ios_base::openmode mode; // \expos + ios_base::openmode mode; // \expos + basic_string buf; // \expos + void init_buf_ptrs(); // \expos }; template void swap(basic_stringbuf& x, - basic_stringbuf& y); + basic_stringbuf& y) noexcept(noexcept(x.swap(y))); } \end{codeblock} @@ -7429,15 +7506,21 @@ \tcode{basic_string}. \pnum -For the sake of exposition, the maintained data is presented here as: +For the sake of exposition, +the maintained data and internal pointer initialization is presented here as: \begin{itemize} \item -\tcode{ios_base::openmode mode}, -has -\tcode{in} -set if the input sequence can be read, and -\tcode{out} -set if the output sequence can be written. + \tcode{ios_base::openmode mode}, has + \tcode{in} set if the input sequence can be read, and + \tcode{out} set if the output sequence can be written. +\item + \tcode{basic_string buf} + contains the underlying character sequence. +\item + \tcode{init_buf_ptrs()} sets the base class' + get area\iref{streambuf.get.area} and + put area\iref{streambuf.put.area} pointers + after initializing, moving from, or assigning to \tcode{buf} accordingly. \end{itemize} \rSec3[stringbuf.cons]{Constructors} @@ -7450,10 +7533,8 @@ \begin{itemdescr} \pnum \effects -Constructs an object of class -\tcode{basic_stringbuf}, -initializing the base class with -\tcode{basic_streambuf()}\iref{streambuf.cons}, and initializing +Initializes the base class with +\tcode{basic_streambuf()}\iref{streambuf.cons}, and \tcode{mode} with \tcode{which}. It is @@ -7465,7 +7546,7 @@ \pnum \ensures -\tcode{str() == ""}. +\tcode{str().empty()} is \tcode{true}. \end{itemdescr} \indexlibrary{\idxcode{basic_stringbuf}!constructor}% @@ -7478,32 +7559,107 @@ \begin{itemdescr} \pnum \effects -Constructs an object of class -\tcode{basic_stringbuf}, -initializing the base class with -\tcode{basic_streambuf()}\iref{streambuf.cons}, and initializing -\tcode{mode} -with \tcode{which}. -Then calls \tcode{str(s)}. +Initializes the base class with +\tcode{basic_streambuf()}\iref{streambuf.cons}, +\tcode{mode} with \tcode{which}, and +\tcode{buf} with \tcode{s}, +then calls \tcode{init_buf_ptrs()}. +\end{itemdescr} + +\indexlibrary{\idxcode{basic_stringbuf}!constructor}% +\begin{itemdecl} +basic_stringbuf(ios_base::openmode which, const Allocator &a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the base class with +\tcode{basic_streambuf()}\iref{streambuf.cons}, +\tcode{mode} with \tcode{which}, and +\tcode{buf} with \tcode{a}, +then calls \tcode{init_buf_ptrs()}. + +\pnum +\ensures +\tcode{str().empty()} is \tcode{true}. +\end{itemdescr} + +\indexlibrary{\idxcode{basic_stringbuf}!constructor}% +\begin{itemdecl} +explicit basic_stringbuf( + basic_string&& s, + ios_base::openmode which = ios_base::in | ios_base::out); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the base class with \tcode{basic_streambuf()}\iref{streambuf.cons}, +\tcode{mode} with \tcode{which}, and +\tcode{buf} with \tcode{std::move(s)}, +then calls \tcode{init_buf_ptrs()}. +\end{itemdescr} + +\indexlibrary{\idxcode{basic_stringbuf}!constructor}% +\begin{itemdecl} +template + basic_stringbuf( + const basic_string& s, + ios_base::openmode which, const Allocator &a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the base class with \tcode{basic_streambuf()}\iref{streambuf.cons}, +\tcode{mode} with \tcode{which}, and +\tcode{buf} with \tcode{\{s,a\}}, +then calls \tcode{init_buf_ptrs()}. +\end{itemdescr} + +\indexlibrary{\idxcode{basic_stringbuf}!constructor}% +\begin{itemdecl} +template + explicit basic_stringbuf( + const basic_string& s, + ios_base::openmode which = ios_base::in | ios_base::out); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_same_v} is \tcode{false}. + +\pnum +\effects +Initializes the base class with \tcode{basic_streambuf()}\iref{streambuf.cons}, +\tcode{mode} with \tcode{which}, and +\tcode{buf} with \tcode{s}, +then calls \tcode{init_buf_ptrs()}. \end{itemdescr} \indexlibrary{\idxcode{basic_stringbuf}!constructor}% \begin{itemdecl} basic_stringbuf(basic_stringbuf&& rhs); +basic_stringbuf(basic_stringbuf&& rhs, const Allocator& a); \end{itemdecl} \begin{itemdescr} \pnum -\effects Move constructs from the rvalue \tcode{rhs}. It -is +\effects +Copy constructs the base class from \tcode{rhs} and +initializes \tcode{mode} with \tcode{rhs.mode}. +In the first form \tcode{buf} is initialized +from \tcode{std::move(rhs).str()}. +In the second form \tcode{buf} is initialized +from \tcode{\{std::move(rhs).str(), a\}}. +It is \impldef{whether sequence pointers are copied by \tcode{basic_stringbuf} move constructor} whether the sequence pointers in \tcode{*this} (\tcode{eback()}, \tcode{gptr()}, \tcode{egptr()}, \tcode{pbase()}, \tcode{pptr()}, \tcode{epptr()}) obtain -the values which \tcode{rhs} had. Whether they do or not, \tcode{*this} -and \tcode{rhs} reference separate buffers (if any at all) after the -construction. The openmode, locale and any other state of \tcode{rhs} is -also copied. +the values which \tcode{rhs} had. \pnum \ensures Let \tcode{rhs_p} refer to the state of @@ -7522,6 +7678,9 @@ \item \tcode{if (pbase()) pbase() != rhs_a.pbase()} \item \tcode{if (pptr()) pptr() != rhs_a.pptr()} \item \tcode{if (epptr()) epptr() != rhs_a.epptr()} +\item \tcode{getloc() == rhs_p.getloc()} +\item \tcode{rhs} is empty but usable, + as if \tcode{std::move(rhs).str()} was called. \end{itemize} \end{itemdescr} @@ -7543,20 +7702,30 @@ \indexlibrarymember{swap}{basic_stringbuf}% \begin{itemdecl} -void swap(basic_stringbuf& rhs); +void swap(basic_stringbuf& rhs) noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} +\pnum +\expects \tcode{allocator_traits::propagate_on_container_swap::value} +is \tcode{true} or +\tcode{get_allocator() == s.get_allocator()} is \tcode{true}. + \pnum \effects Exchanges the state of \tcode{*this} and \tcode{rhs}. + +\pnum +\remarks The expression inside \tcode{noexcept} is equivalent to:\\ +\tcode{allocator_traits::propagate_on_container_swap::value ||}\\ +\tcode{allocator_traits::is_always_equal::value}. \end{itemdescr} \indexlibrarymember{swap}{basic_stringbuf}% \begin{itemdecl} template void swap(basic_stringbuf& x, - basic_stringbuf& y); + basic_stringbuf& y) noexcept(noexcept(x.swap(y))); \end{itemdecl} \begin{itemdescr} @@ -7566,32 +7735,149 @@ \rSec3[stringbuf.members]{Member functions} +\pnum +The member functions getting the underlying character sequence +all refer to a \tcode{high_mark} value, +where \tcode{high_mark} represents the position +one past the highest initialized character in the buffer. +Characters can be initialized by writing to the stream, +by constructing the \tcode{basic_stringbuf} +passing a \tcode{basic_string} argument, or +by calling one of the \tcode{str} member functions +passing a \tcode{basic_string} as an argument. +In the latter case, all characters initialized prior to the call +are now considered uninitialized +(except for those characters re-initialized by the new \tcode{basic_string}). + +\begin{itemdecl} +void init_buf_ptrs(); // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the input and output sequences from \tcode{buf} +according to \tcode{mode}. + +\pnum +\ensures +\begin{itemize} +\item If \tcode{ios_base::out} is set in \tcode{mode}, + \tcode{pbase()} points to \tcode{buf.front()} and + \tcode{epptr() >= pbase() + buf.size()} is \tcode{true}; + \begin{itemize} + \item in addition, if \tcode{ios_base::ate} is set in \tcode{mode}, + \tcode{pptr() == pbase() + buf.size()} is \tcode{true}, + \item otherwise \tcode{pptr() == pbase()} is \tcode{true}. + \end{itemize} +\item If \tcode{ios_base::in} is set in \tcode{mode}, + \tcode{eback()} points to \tcode{buf.front()}, and + \tcode{(gptr() == eback() \&\& egptr() == eback() + buf.size())} + is \tcode{true}. +\end{itemize} + +\pnum +\begin{note} +For efficiency reasons, +stream buffer operations might violate invariants of \tcode{buf} +while it is held encapsulated in the \tcode{basic_stringbuf}, +e.g., by writing to characters in the range +\range{\tcode{buf.data() + buf.size()}}{\tcode{buf.data() + buf.capacity()}}. +All operations retrieving a \tcode{basic_string} from \tcode{buf} +ensure that the \tcode{basic_string} invariants hold on the returned value. +\end{note} +\end{itemdescr} + +\indexlibrarymember{get_allocator}{basic_stringbuf}% +\begin{itemdecl} +allocator_type get_allocator() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns \tcode{buf.get_allocator()}. +\end{itemdescr} + \indexlibrarymember{str}{basic_stringbuf}% \begin{itemdecl} -basic_string str() const; +basic_string str() const &; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\begin{codeblock} +return basic_string(view(), get_allocator()); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{str}{basic_stringbuf}% +\begin{itemdecl} +template + basic_string str(const SAlloc& sa) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints \tcode{SAlloc} is a type that +qualifies as an allocator\iref{container.requirements.general}. + +\pnum +\effects Equivalent to: +\begin{codeblock} +return basic_string(view(), sa); +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +basic_string str() &&; \end{itemdecl} \begin{itemdescr} \pnum \returns -A -\tcode{basic_string} -object whose content is equal to the -\tcode{basic_stringbuf} -underlying character sequence. -If the \tcode{basic_stringbuf} was created only in input mode, the resultant -\tcode{basic_string} contains the character sequence in the range -\range{eback()}{egptr()}. If the \tcode{basic_stringbuf} was created with -\tcode{which \& ios_base::out} being nonzero then the resultant \tcode{basic_string} -contains the character sequence in the range \range{pbase()}{high_mark}, where -\tcode{high_mark} represents the position one past the highest initialized character -in the buffer. Characters can be initialized by writing to the stream, by constructing -the \tcode{basic_stringbuf} with a \tcode{basic_string}, or by calling the -\tcode{str(basic_string)} member function. In the case of calling the -\tcode{str(basic_string)} member function, all characters initialized prior to -the call are now considered uninitialized (except for those characters re-initialized -by the new \tcode{basic_string}). Otherwise the \tcode{basic_stringbuf} has been created -in neither input nor output mode and a zero length \tcode{basic_string} is returned. +A \tcode{basic_string} object +move constructed from +the \tcode{basic_stringbuf}'s underlying character sequence in \tcode{buf}. +This can be achieved by first adjusting \tcode{buf} to have +the same content as \tcode{view()}. + +\pnum +\ensures +The underlying character sequence \tcode{buf} is empty and +\tcode{pbase()}, \tcode{pptr()}, \tcode{epptr()}, \tcode{eback()}, +\tcode{gptr()}, and \tcode{egptr()} +are initialized as if by calling \tcode{init_buf_ptrs()} +with an empty \tcode{buf}. +\end{itemdescr} + +\indexlibrarymember{view}{basic_stringbuf}% +\begin{itemdecl} +basic_string_view view() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{sv} be \tcode{basic_string_view}. + +\pnum +\returns +A \tcode{sv} object referring to +the \tcode{basic_stringbuf}'s underlying character sequence in \tcode{buf}: +\begin{itemize} +\item If \tcode{ios_base::out} is set in \tcode{mode}, + then \tcode{sv(pbase(), high_mark-pbase())} is returned. +\item Otherwise, if \tcode{ios_base::in} is set in \tcode{mode}, + then \tcode{sv(eback(), egptr()-eback())} is returned. +\item Otherwise, \tcode{sv()} is returned. +\end{itemize} + +\pnum +\begin{note} +Using the returned \tcode{sv} object after +destruction or invalidation of the character sequence underlying \tcode{*this} +is undefined behavior, unless \tcode{sv.empty()} is \tcode{true}. +\end{note} \end{itemdescr} \indexlibrarymember{str}{basic_stringbuf}% @@ -7602,17 +7888,43 @@ \begin{itemdescr} \pnum \effects -Copies the content of \tcode{s} into the \tcode{basic_stringbuf} underlying character -sequence and initializes the input and output sequences according to \tcode{mode}. +Equivalent to: +\begin{codeblock} +buf = s; +init_buf_ptrs(); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{str}{basic_stringbuf}% +\begin{itemdecl} +template + void str(const basic_string& s); +\end{itemdecl} +\begin{itemdescr} \pnum -\ensures If \tcode{mode \& ios_base::out} is nonzero, \tcode{pbase()} points to the -first underlying character and \tcode{epptr()} \tcode{>= pbase() + s.size()} holds; in -addition, if \tcode{mode \& ios_base::ate} is nonzero, -\tcode{pptr() == pbase() + s.size()} -holds, otherwise \tcode{pptr() == pbase()} is \tcode{true}. If \tcode{mode \& ios_base::in} is -nonzero, \tcode{eback()} points to the first underlying character, and both \tcode{gptr() -== eback()} and \tcode{egptr() == eback() + s.size()} hold. +\constraints \tcode{is_same_v} is \tcode{false}. + +\pnum +\effects Equivalent to: +\begin{codeblock} +buf = s; +init_buf_ptrs(); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{str}{basic_stringbuf}% +\begin{itemdecl} +void str(basic_string&& s); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\begin{codeblock} +buf = std::move(s); +init_buf_ptrs(); +\end{codeblock} \end{itemdescr} \rSec3[stringbuf.virtuals]{Overridden virtual functions} @@ -7904,8 +8216,24 @@ basic_istringstream() : basic_istringstream(ios_base::in) {} explicit basic_istringstream(ios_base::openmode which); explicit basic_istringstream( - const basic_string& str, + const basic_string& s, + ios_base::openmode which = ios_base::in); + basic_istringstream(ios_base::openmode which, const Allocator& a); + explicit basic_istringstream( + basic_string&& s, ios_base::openmode which = ios_base::in); + template + basic_istringstream( + const basic_string& s, const Allocator& a) + : basic_istringstream(s, ios_base::in, a) {} + template + basic_istringstream( + const basic_string& s, + ios_base::openmode which, const Allocator& a); + template + explicit basic_istringstream( + const basic_string& s, + ios_base::openmode which = ios_base::in); basic_istringstream(const basic_istringstream& rhs) = delete; basic_istringstream(basic_istringstream&& rhs); @@ -7916,9 +8244,17 @@ // \ref{istringstream.members}, members basic_stringbuf* rdbuf() const; + basic_string str() const &; + template + basic_string str(const SAlloc& sa) const; + basic_string str() &&; + basic_string_view view() const noexcept; - basic_string str() const; void str(const basic_string& s); + template + void str(const basic_string& s); + void str(basic_string&& s); + private: basic_stringbuf sb; // \expos }; @@ -7953,30 +8289,90 @@ \begin{itemdescr} \pnum \effects -Constructs an object of class -\tcode{basic_istringstream}, -initializing the base class with +Initializes the base class with \tcode{basic_istream(addressof(sb))}\iref{istream} -and initializing \tcode{sb} with\linebreak % avoid Overfull +and \tcode{sb} with \tcode{basic_stringbuf(which | ios_base::in)}\iref{stringbuf.cons}. \end{itemdescr} \indexlibrary{\idxcode{basic_istringstream}!constructor}% \begin{itemdecl} explicit basic_istringstream( - const basic_string& str, + const basic_string& s, ios_base::openmode which = ios_base::in); \end{itemdecl} \begin{itemdescr} \pnum \effects -Constructs an object of class -\tcode{basic_istringstream}, -initializing the base class with +Initializes the base class with \tcode{basic_istream(addressof(sb))}\iref{istream} -and initializing \tcode{sb} with\linebreak % avoid Overfull -\tcode{basic_stringbuf(str, which | ios_base::in)}\iref{stringbuf.cons}. +and \tcode{sb} with +\tcode{basic_stringbuf(s, which | ios_base::in)}\linebreak(\ref{stringbuf.cons}). % avoid Overfull +\end{itemdescr} + +\indexlibrary{\idxcode{basic_istringstream}!constructor}% +\begin{itemdecl} +basic_istringstream(ios_base::openmode which, const Allocator& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the base class with +\tcode{basic_istream(addressof(sb))}\iref{istream} +and \tcode{sb} with +\tcode{basic_stringbuf(which | ios_base::in, a)}\iref{stringbuf.cons}. +\end{itemdescr} + +\indexlibrary{\idxcode{basic_istringstream}!constructor}% +\begin{itemdecl} +explicit basic_istringstream( + basic_string&& s, + ios_base::openmode which = ios_base::in); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the base class with +\tcode{basic_istream(addressof(sb))}\iref{istream} +and \tcode{sb} with +\tcode{basic_stringbuf(std::move(s), which | ios_base::\brk{}in)}\iref{stringbuf.cons}. +\end{itemdescr} + +\indexlibrary{\idxcode{basic_istringstream}!constructor}% +\begin{itemdecl} +template + basic_istringstream( + const basic_string& s, + ios_base::openmode which, const Allocator& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the base class with +\tcode{basic_istream(addressof(sb))}\iref{istream} +and \tcode{sb} with +\tcode{basic_stringbuf(s, which | ios_base::in, a)}\linebreak(\ref{stringbuf.cons}). % avoid Overfull +\end{itemdescr} + +\indexlibrary{\idxcode{basic_istringstream}!constructor}% +\begin{itemdecl} +template + explicit basic_istringstream( + const basic_string& s, + ios_base::openmode which = ios_base::in); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the base class with +\tcode{basic_istream(addressof(sb))}\iref{istream} +and \tcode{sb} with +\tcode{basic_stringbuf(s, which | ios_base::in)}\iref{stringbuf.cons}. \end{itemdescr} \indexlibrary{\idxcode{basic_istringstream}!constructor}% @@ -8017,10 +8413,11 @@ \begin{itemdescr} \pnum -\effects Exchanges the state of \tcode{*this} and -\tcode{rhs} by calling -\tcode{basic_istream::swap(rhs)} and -\tcode{sb.swap(rhs.sb)}. +\effects Equivalent to: +\begin{codeblock} +basic_istream::swap(rhs); +sb.swap(rhs.sb); +\end{codeblock} \end{itemdescr} @@ -8051,13 +8448,43 @@ \indexlibrarymember{str}{basic_istringstream}% \begin{itemdecl} -basic_string str() const; +basic_string str() const &; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{rdbuf()->str()}. +\effects Equivalent to: \tcode{return rdbuf()->str();} +\end{itemdescr} + +\indexlibrarymember{str}{basic_istringstream}% +\begin{itemdecl} +template + basic_string str(const SAlloc& sa) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: \tcode{return rdbuf()->str(sa);} +\end{itemdescr} + +\indexlibrarymember{str}{basic_istringstream}% +\begin{itemdecl} +basic_string str() &&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: \tcode{return std::move(*rdbuf()).str();} +\end{itemdescr} + +\indexlibrarymember{view}{basic_istringstream}% +\begin{itemdecl} +basic_string_view view() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: \tcode{return rdbuf()->view();} \end{itemdescr} \indexlibrarymember{str}{basic_istringstream}% @@ -8068,8 +8495,29 @@ \begin{itemdescr} \pnum \effects -Calls -\tcode{rdbuf()->str(s)}. +Equivalent to: \tcode{rdbuf()->str(s);} +\end{itemdescr} + +\indexlibrarymember{str}{basic_istringstream}% +\begin{itemdecl} +template + void str(const basic_string& s); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{rdbuf()->str(s);} +\end{itemdescr} + +\indexlibrarymember{str}{basic_istringstream}% +\begin{itemdecl} +void str(basic_string&& s); +\end{itemdecl} +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{rdbuf()->str(std::move(s));} \end{itemdescr} \rSec2[ostringstream]{Class template \tcode{basic_ostringstream}} @@ -8092,8 +8540,24 @@ basic_ostringstream() : basic_ostringstream(ios_base::out) {} explicit basic_ostringstream(ios_base::openmode which); explicit basic_ostringstream( - const basic_string& str, + const basic_string& s, ios_base::openmode which = ios_base::out); + basic_ostringstream(ios_base::openmode which, const Allocator& a); + explicit basic_ostringstream( + basic_string&& s, + ios_base::openmode which = ios_base::out); + template + basic_ostringstream( + const basic_string& s, const Allocator& a) + : basic_ostringstream(s, ios_base::out, a) {} + template + basic_ostringstream( + const basic_string& s, + ios_base::openmode which, const Allocator& a); + template + explicit basic_ostringstream( + const basic_string& s, + ios_base::openmode which = ios_base::out); basic_ostringstream(const basic_ostringstream& rhs) = delete; basic_ostringstream(basic_ostringstream&& rhs); @@ -8105,8 +8569,17 @@ // \ref{ostringstream.members}, members basic_stringbuf* rdbuf() const; - basic_string str() const; + basic_string str() const &; + template + basic_string str(const SAlloc& sa) const; + basic_string str() &&; + basic_string_view view() const noexcept; + void str(const basic_string& s); + template + void str(const basic_string& s); + void str(basic_string&& s); + private: basic_stringbuf sb; // \expos }; @@ -8131,40 +8604,103 @@ \tcode{sb}, the \tcode{stringbuf} object. \end{itemize} -\rSec3[ostringstream.cons]{Constructors} +\rSec3[ostringstream.cons]{Constructors} + +\indexlibrary{\idxcode{basic_ostringstream}!constructor}% +\begin{itemdecl} +explicit basic_ostringstream(ios_base::openmode which); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the base class with +\tcode{basic_ostream(addressof(sb))}\iref{ostream} +and \tcode{sb} with +\tcode{basic_stringbuf(which | ios_base::out)}\iref{stringbuf.cons}. +\end{itemdescr} + +\indexlibrary{\idxcode{basic_ostringstream}!constructor}% +\begin{itemdecl} +explicit basic_ostringstream( + const basic_string& s, + ios_base::openmode which = ios_base::out); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the base class with +\tcode{basic_ostream(addressof(sb))}\iref{ostream} +and \tcode{sb} with +\tcode{basic_stringbuf(s, which | ios_base::out)}\linebreak(\ref{stringbuf.cons}). % avoid Overfull +\end{itemdescr} + +\indexlibrary{\idxcode{basic_ostringstream}!constructor}% +\begin{itemdecl} +basic_ostringstream(ios_base::openmode which, const Allocator& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the base class with +\tcode{basic_ostream(addressof(sb))}\iref{ostream} +and \tcode{sb} with +\tcode{basic_stringbuf(which | ios_base::out, a)}\linebreak(\ref{stringbuf.cons}). % avoid Overfull +\end{itemdescr} + +\indexlibrary{\idxcode{basic_ostringstream}!constructor}% +\begin{itemdecl} +explicit basic_ostringstream( + basic_string&& s, + ios_base::openmode which = ios_base::out); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the base class with +\tcode{basic_ostream(addressof(sb))}\iref{ostream} +and \tcode{sb} with +\tcode{basic_stringbuf(std::move(s), which | ios_base::\brk{}out)}\iref{stringbuf.cons}. +\end{itemdescr} \indexlibrary{\idxcode{basic_ostringstream}!constructor}% \begin{itemdecl} -explicit basic_ostringstream(ios_base::openmode which); +template + basic_ostringstream( + const basic_string& s, + ios_base::openmode which, const Allocator& a); \end{itemdecl} \begin{itemdescr} \pnum \effects -Constructs an object of class -\tcode{basic_ostringstream}, -initializing the base class with +Initializes the base class with \tcode{basic_ostream(addressof(sb))}\iref{ostream} -and initializing \tcode{sb} with\linebreak % avoid Overfull -\tcode{basic_stringbuf(which | ios_base::out)}\iref{stringbuf.cons}. +and \tcode{sb} with +\tcode{basic_stringbuf(s, which | ios_base::out, a)}\linebreak(\ref{stringbuf.cons}). % avoid Overfull \end{itemdescr} \indexlibrary{\idxcode{basic_ostringstream}!constructor}% \begin{itemdecl} -explicit basic_ostringstream( - const basic_string& str, - ios_base::openmode which = ios_base::out); +template + explicit basic_ostringstream( + const basic_string& s, + ios_base::openmode which = ios_base::out); \end{itemdecl} \begin{itemdescr} +\pnum +\constraints \tcode{is_same_v} is \tcode{false}. + \pnum \effects -Constructs an object of class -\tcode{basic_ostringstream}, -initializing the base class with +Initializes the base class with \tcode{basic_ostream(addressof(sb))}\iref{ostream} -and initializing \tcode{sb} with\linebreak % avoid Overfull -\tcode{basic_stringbuf(str, which | ios_base::out)}\iref{stringbuf.cons}. +and \tcode{sb} with +\tcode{basic_stringbuf(s, which | ios_base::out)}\linebreak(\ref{stringbuf.cons}). % avoid Overfull \end{itemdescr} \indexlibrary{\idxcode{basic_ostringstream}!constructor}% @@ -8205,13 +8741,13 @@ \begin{itemdescr} \pnum -\effects Exchanges the state of \tcode{*this} and -\tcode{rhs} by calling -\tcode{basic_ostream::swap(rhs)} and -\tcode{sb.swap(rhs.sb)}. +\effects Equivalent to: +\begin{codeblock} +basic_ostream::swap(rhs); +sb.swap(rhs.sb); +\end{codeblock} \end{itemdescr} - \indexlibrarymember{swap}{basic_ostringstream}% \begin{itemdecl} template @@ -8239,13 +8775,47 @@ \indexlibrarymember{str}{basic_ostringstream}% \begin{itemdecl} -basic_string str() const; +basic_string str() const &; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{rdbuf()->str()}. +\effects +Equivalent to: \tcode{return rdbuf()->str();} +\end{itemdescr} + +\indexlibrarymember{str}{basic_ostringstream}% +\begin{itemdecl} +template + basic_string str(const SAlloc& sa) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return rdbuf()->str(sa);} +\end{itemdescr} + +\indexlibrarymember{str}{basic_ostringstream}% +\begin{itemdecl} +basic_string str() &&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return std::move(*rdbuf()).str();} +\end{itemdescr} + +\indexlibrarymember{view}{basic_ostringstream}% +\begin{itemdecl} +basic_string_view view() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return rdbuf()->view();} \end{itemdescr} \indexlibrarymember{str}{basic_ostringstream}% @@ -8256,8 +8826,30 @@ \begin{itemdescr} \pnum \effects -Calls -\tcode{rdbuf()->str(s)}. +Equivalent to: \tcode{rdbuf()->str(s);} +\end{itemdescr} + +\indexlibrarymember{str}{basic_ostringstream}% +\begin{itemdecl} +template + void str(const basic_string& s); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{rdbuf()->str(s);} +\end{itemdescr} + +\indexlibrarymember{str}{basic_ostringstream}% +\begin{itemdecl} +void str(basic_string&& s); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{rdbuf()->str(std::move(s));} \end{itemdescr} \rSec2[stringstream]{Class template \tcode{basic_stringstream}} @@ -8280,8 +8872,24 @@ basic_stringstream() : basic_stringstream(ios_base::out | ios_base::in) {} explicit basic_stringstream(ios_base::openmode which); explicit basic_stringstream( - const basic_string& str, + const basic_string& s, + ios_base::openmode which = ios_base::out | ios_base::in); + basic_stringstream(ios_base::openmode which, const Allocator& a); + explicit basic_stringstream( + basic_string&& s, ios_base::openmode which = ios_base::out | ios_base::in); + template + basic_stringstream( + const basic_string& s, const Allocator& a) + : basic_stringstream(s, ios_base::out | ios_base::in, a) {} + template + basic_stringstream( + const basic_string& s, + ios_base::openmode which, const Allocator& a); + template + explicit basic_stringstream( + const basic_string& s, + ios_base::openmode which = ios_base::out | ios_base::in); basic_stringstream(const basic_stringstream& rhs) = delete; basic_stringstream(basic_stringstream&& rhs); @@ -8292,8 +8900,17 @@ // \ref{stringstream.members}, members basic_stringbuf* rdbuf() const; - basic_string str() const; - void str(const basic_string& str); + + basic_string str() const &; + template + basic_string str(const SAlloc& sa) const; + basic_string str() &&; + basic_string_view view() const noexcept; + + void str(const basic_string& s); + template + void str(const basic_string& s); + void str(basic_string&& s); private: basic_stringbuf sb; // \expos @@ -8330,11 +8947,9 @@ \begin{itemdescr} \pnum \effects -Constructs an object of class -\tcode{basic_stringstream}, -initializing the base class with +Initializes the base class with \tcode{basic_iostream(addressof(sb))}\iref{iostream.cons} -and initializing +and \tcode{sb} with \tcode{basic_string\-buf(which)}. @@ -8343,21 +8958,86 @@ \indexlibrary{\idxcode{basic_stringstream}!constructor}% \begin{itemdecl} explicit basic_stringstream( - const basic_string& str, + const basic_string& s, ios_base::openmode which = ios_base::out | ios_base::in); \end{itemdecl} \begin{itemdescr} \pnum \effects -Constructs an object of class -\tcode{basic_stringstream}, -initializing the base class with +Initializes the base class with \tcode{basic_iostream(addressof(sb))}\iref{iostream.cons} -and initializing +and \tcode{sb} with -\tcode{basic_string\-buf(str, which)}. +\tcode{basic_string\-buf(s, which)}. +\end{itemdescr} + +\indexlibrary{\idxcode{basic_stringstream}!constructor}% +\begin{itemdecl} +basic_stringstream(ios_base::openmode which, const Allocator& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the base class with +\tcode{basic_iostream(addressof(sb))}\iref{iostream.cons} +and \tcode{sb} with +\tcode{basic_stringbuf(which, a)}\iref{stringbuf.cons}. +\end{itemdescr} + +\indexlibrary{\idxcode{basic_stringstream}!constructor}% +\begin{itemdecl} +explicit basic_stringstream( + basic_string&& s, + ios_base::openmode which = ios_base::out | ios_base::in); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the base class with +\tcode{basic_iostream(addressof(sb))}\iref{iostream.cons} +and \tcode{sb} with +\tcode{basic_stringbuf(std::move(s), which)}\iref{stringbuf.cons}. +\end{itemdescr} + +\indexlibrary{\idxcode{basic_stringstream}!constructor}% +\begin{itemdecl} +template + basic_stringstream( + const basic_string& s, + ios_base::openmode which, const Allocator& a); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the base class with +\tcode{basic_iostream(addressof(sb))}\iref{iostream.cons} +and \tcode{sb} with +\tcode{basic_stringbuf(s, which, a)}\iref{stringbuf.cons}. +\end{itemdescr} + +\indexlibrary{\idxcode{basic_stringstream}!constructor}% +\begin{itemdecl} +template + explicit basic_stringstream( + const basic_string& s, + ios_base::openmode which = ios_base::out | ios_base::in); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints \tcode{is_same_v} is \tcode{false}. + +\pnum +\effects +Initializes the base class with +\tcode{basic_iostream(addressof(sb))}\iref{iostream.cons} +and \tcode{sb} with +\tcode{basic_stringbuf(s, which)}\iref{stringbuf.cons}. \end{itemdescr} \indexlibrary{\idxcode{basic_stringstream}!constructor}% @@ -8397,13 +9077,14 @@ \begin{itemdescr} \pnum -\effects Exchanges the state of \tcode{*this} and -\tcode{rhs} by calling -\tcode{basic_iostream::swap(rhs)} and -\tcode{sb.swap(rhs.sb)}. +\effects +Equivalent to: +\begin{codeblock} +basic_iostream::swap(rhs); +sb.swap(rhs.sb); +\end{codeblock} \end{itemdescr} - \indexlibrarymember{swap}{basic_stringstream}% \begin{itemdecl} template @@ -8431,25 +9112,81 @@ \indexlibrarymember{str}{basic_stringstream}% \begin{itemdecl} -basic_string str() const; +basic_string str() const &; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{rdbuf()->str()}. +\effects +Equivalent to: \tcode{return rdbuf()->str();} \end{itemdescr} \indexlibrarymember{str}{basic_stringstream}% \begin{itemdecl} -void str(const basic_string& str); +template + basic_string str(const SAlloc& sa) const; \end{itemdecl} \begin{itemdescr} \pnum \effects -Calls -\tcode{rdbuf()->str(str)}. +Equivalent to: \tcode{return rdbuf()->str(sa);} +\end{itemdescr} + +\indexlibrarymember{str}{basic_stringstream}% +\begin{itemdecl} +basic_string str() &&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return std::move(*rdbuf()).str();} +\end{itemdescr} + +\indexlibrarymember{view}{basic_stringstream}% +\begin{itemdecl} +basic_string_view view() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return rdbuf()->view();} +\end{itemdescr} + +\indexlibrarymember{str}{basic_stringstream}% +\begin{itemdecl} +void str(const basic_string& s); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{rdbuf()->str(s);} +\end{itemdescr} + +\indexlibrarymember{str}{basic_stringstream}% +\begin{itemdecl} +template + void str(const basic_string& s); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{rdbuf()->str(s);} +\end{itemdescr} + +\indexlibrarymember{str}{basic_stringstream}% +\begin{itemdecl} +void str(basic_string&& s); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{rdbuf()->str(std::move(s));} \end{itemdescr} \rSec1[file.streams]{File-based streams} @@ -10848,6 +11585,8 @@ uintmax_t capacity; uintmax_t free; uintmax_t available; + + friend bool operator==(const space_info&, const space_info&) = default; }; // \ref{fs.enum}, enumerations @@ -11197,11 +11936,7 @@ // \ref{fs.path.nonmember}, non-member operators friend bool operator==(const path& lhs, const path& rhs) noexcept; - friend bool operator!=(const path& lhs, const path& rhs) noexcept; - friend bool operator< (const path& lhs, const path& rhs) noexcept; - friend bool operator<=(const path& lhs, const path& rhs) noexcept; - friend bool operator> (const path& lhs, const path& rhs) noexcept; - friend bool operator>=(const path& lhs, const path& rhs) noexcept; + friend strong_ordering operator<=>(const path& lhs, const path& rhs) noexcept; friend path operator/ (const path& lhs, const path& rhs); @@ -11919,11 +12654,8 @@ path& operator+=(const string_type& x); path& operator+=(basic_string_view x); path& operator+=(const value_type* x); -path& operator+=(value_type x); template path& operator+=(const Source& x); -template - path& operator+=(EcharT x); template path& concat(const Source& x); \end{itemdecl} @@ -11940,6 +12672,19 @@ \returns \tcode{*this}. \end{itemdescr} +\indexlibrarymember{operator+=}{path}% +\indexlibrarymember{concat}{path}% +\begin{itemdecl} +path& operator+=(value_type x); +template + path& operator+=(EcharT x); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: \tcode{return *this += basic_string_view(\&x, 1);} +\end{itemdescr} + \indexlibrarymember{concat}{path}% \begin{itemdecl} template @@ -12783,7 +13528,7 @@ \begin{itemdescr} \pnum -\returns \tcode{!(lhs < rhs) \&\& !(rhs < lhs)}. +\returns \tcode{lhs.compare(rhs) == 0}. \indextext{path equality} \pnum @@ -12803,54 +13548,14 @@ file'', and choose the appropriate function accordingly. \end{note} \end{itemdescr} -\indexlibrarymember{operator"!=}{path}% -\begin{itemdecl} -friend bool operator!=(const path& lhs, const path& rhs) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{!(lhs == rhs)}. -\end{itemdescr} - -\indexlibrarymember{operator<}{path}% -\begin{itemdecl} -friend bool operator< (const path& lhs, const path& rhs) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{lhs.compare(rhs) < 0}. -\end{itemdescr} - -\indexlibrarymember{operator<=}{path}% -\begin{itemdecl} -friend bool operator<=(const path& lhs, const path& rhs) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{!(rhs < lhs)}. -\end{itemdescr} - -\indexlibrarymember{operator>}{path}% -\begin{itemdecl} -friend bool operator> (const path& lhs, const path& rhs) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{rhs < lhs}. -\end{itemdescr} - -\indexlibrarymember{operator>=}{path}% +\indexlibrarymember{operator<=>}{path}% \begin{itemdecl} -friend bool operator>=(const path& lhs, const path& rhs) noexcept; +friend strong_ordering operator<=>(const path& lhs, const path& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{!(lhs < rhs)}. +\returns \tcode{lhs.compare(rhs) <=> 0}. \end{itemdescr} \indexlibrarymember{operator/}{path}% @@ -13244,6 +13949,9 @@ // \ref{fs.file.status.obs}, observers file_type type() const noexcept; perms permissions() const noexcept; + + friend bool operator==(const file_status& lhs, const file_status& rhs) noexcept + { return lhs.type() == rhs.type() && lhs.permissions() == rhs.permissions(); } }; } \end{codeblock} @@ -13369,11 +14077,7 @@ file_status symlink_status(error_code& ec) const noexcept; bool operator==(const directory_entry& rhs) const noexcept; - bool operator!=(const directory_entry& rhs) const noexcept; - bool operator< (const directory_entry& rhs) const noexcept; - bool operator> (const directory_entry& rhs) const noexcept; - bool operator<=(const directory_entry& rhs) const noexcept; - bool operator>=(const directory_entry& rhs) const noexcept; + strong_ordering operator<=>(const directory_entry& rhs) const noexcept; private: filesystem::path pathobject; // \expos @@ -13745,54 +14449,14 @@ \returns \tcode{pathobject == rhs.pathobject}. \end{itemdescr} -\indexlibrarymember{operator"!=}{directory_entry}% -\begin{itemdecl} -bool operator!=(const directory_entry& rhs) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{pathobject != rhs.pathobject}. -\end{itemdescr} - -\indexlibrarymember{operator<}{directory_entry}% -\begin{itemdecl} -bool operator< (const directory_entry& rhs) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{pathobject < rhs.pathobject}. -\end{itemdescr} - -\indexlibrarymember{operator>}{directory_entry}% -\begin{itemdecl} -bool operator> (const directory_entry& rhs) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{pathobject > rhs.pathobject}. -\end{itemdescr} - -\indexlibrarymember{operator<=}{directory_entry}% -\begin{itemdecl} -bool operator<=(const directory_entry& rhs) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{pathobject <= rhs.pathobject}. -\end{itemdescr} - -\indexlibrarymember{operator>=}{directory_entry}% +\indexlibrarymember{operator<=>}{directory_entry}% \begin{itemdecl} -bool operator>=(const directory_entry& rhs) const noexcept; +strong_ordering operator<=>(const directory_entry& rhs) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{pathobject >= rhs.pathobject}. +\returns \tcode{pathobject <=> rhs.pathobject}. \end{itemdescr} \rSec2[fs.class.directory.iterator]{Class \tcode{directory_iterator}} diff --git a/source/iterators.tex b/source/iterators.tex index 9d7ab18636..cace82470d 100644 --- a/source/iterators.tex +++ b/source/iterators.tex @@ -57,7 +57,7 @@ // \ref{iterator.traits}, iterator traits template struct iterator_traits; - template struct iterator_traits; + template requires is_object_v struct iterator_traits; template<@\placeholder{dereferenceable}@ T> using iter_reference_t = decltype(*declval()); @@ -81,128 +81,128 @@ = decltype(ranges::iter_move(declval())); // \ref{iterator.concepts}, iterator concepts - // \ref{iterator.concept.readable}, concept \tcode{Readable} + // \ref{iterator.concept.readable}, concept \libconcept{readable} template - concept Readable = @\seebelow@; + concept readable = @\seebelow@; - template + template using iter_common_reference_t = common_reference_t, iter_value_t&>; - // \ref{iterator.concept.writable}, concept \tcode{Writable} + // \ref{iterator.concept.writable}, concept \libconcept{writable} template - concept Writable = @\seebelow@; + concept writable = @\seebelow@; - // \ref{iterator.concept.winc}, concept \tcode{WeaklyIncrementable} + // \ref{iterator.concept.winc}, concept \libconcept{weakly_incrementable} template - concept WeaklyIncrementable = @\seebelow@; + concept weakly_incrementable = @\seebelow@; - // \ref{iterator.concept.inc}, concept \tcode{Incrementable} + // \ref{iterator.concept.inc}, concept \libconcept{incrementable} template - concept Incrementable = @\seebelow@; + concept incrementable = @\seebelow@; - // \ref{iterator.concept.iterator}, concept \tcode{Iterator} + // \ref{iterator.concept.iterator}, concept \libconcept{input_or_output_iterator} template - concept Iterator = @\seebelow@; + concept input_or_output_iterator = @\seebelow@; - // \ref{iterator.concept.sentinel}, concept \tcode{Sentinel} + // \ref{iterator.concept.sentinel}, concept \libconcept{sentinel_for} template - concept Sentinel = @\seebelow@; + concept sentinel_for = @\seebelow@; - // \ref{iterator.concept.sizedsentinel}, concept \tcode{SizedSentinel} + // \ref{iterator.concept.sizedsentinel}, concept \libconcept{sized_sentinel_for} template inline constexpr bool disable_sized_sentinel = false; template - concept SizedSentinel = @\seebelow@; + concept sized_sentinel_for = @\seebelow@; - // \ref{iterator.concept.input}, concept \tcode{InputIterator} + // \ref{iterator.concept.input}, concept \libconcept{input_iterator} template - concept InputIterator = @\seebelow@; + concept input_iterator = @\seebelow@; - // \ref{iterator.concept.output}, concept \tcode{OutputIterator} + // \ref{iterator.concept.output}, concept \libconcept{output_iterator} template - concept OutputIterator = @\seebelow@; + concept output_iterator = @\seebelow@; - // \ref{iterator.concept.forward}, concept \tcode{ForwardIterator} + // \ref{iterator.concept.forward}, concept \libconcept{forward_iterator} template - concept ForwardIterator = @\seebelow@; + concept forward_iterator = @\seebelow@; - // \ref{iterator.concept.bidir}, concept \tcode{BidirectionalIterator} + // \ref{iterator.concept.bidir}, concept \libconcept{bidirectional_iterator} template - concept BidirectionalIterator = @\seebelow@; + concept bidirectional_iterator = @\seebelow@; - // \ref{iterator.concept.random.access}, concept \tcode{RandomAccessIterator} + // \ref{iterator.concept.random.access}, concept \libconcept{random_access_iterator} template - concept RandomAccessIterator = @\seebelow@; + concept random_access_iterator = @\seebelow@; - // \ref{iterator.concept.contiguous}, concept \tcode{ContiguousIterator} + // \ref{iterator.concept.contiguous}, concept \libconcept{contiguous_iterator} template - concept ContiguousIterator = @\seebelow@; + concept contiguous_iterator = @\seebelow@; // \ref{indirectcallable}, indirect callable requirements // \ref{indirectcallable.indirectinvocable}, indirect callables template - concept IndirectUnaryInvocable = @\seebelow@; + concept indirectly_unary_invocable = @\seebelow@; template - concept IndirectRegularUnaryInvocable = @\seebelow@; + concept indirectly_regular_unary_invocable = @\seebelow@; template - concept IndirectUnaryPredicate = @\seebelow@; + concept indirect_unary_predicate = @\seebelow@; template - concept IndirectRelation = @\seebelow@; + concept indirect_relation = @\seebelow@; template - concept IndirectStrictWeakOrder = @\seebelow@; + concept indirect_strict_weak_order = @\seebelow@; template - requires (Readable && ...) && Invocable...> + requires (readable && ...) && invocable...> using indirect_result_t = invoke_result_t...>; // \ref{projected}, projected - template Proj> + template Proj> struct projected; - template + template struct incrementable_traits>; // \ref{alg.req}, common algorithm requirements - // \ref{alg.req.ind.move}, concept \tcode{IndirectlyMovable} + // \ref{alg.req.ind.move}, concept \libconcept{indirectly_movable} template - concept IndirectlyMovable = @\seebelow@; + concept indirectly_movable = @\seebelow@; template - concept IndirectlyMovableStorable = @\seebelow@; + concept indirectly_movable_storable = @\seebelow@; - // \ref{alg.req.ind.copy}, concept \tcode{IndirectlyCopyable} + // \ref{alg.req.ind.copy}, concept \libconcept{indirectly_copyable} template - concept IndirectlyCopyable = @\seebelow@; + concept indirectly_copyable = @\seebelow@; template - concept IndirectlyCopyableStorable = @\seebelow@; + concept indirectly_copyable_storable = @\seebelow@; - // \ref{alg.req.ind.swap}, concept \tcode{IndirectlySwappable} + // \ref{alg.req.ind.swap}, concept \libconcept{indirectly_swappable} template - concept IndirectlySwappable = @\seebelow@; + concept indirectly_swappable = @\seebelow@; - // \ref{alg.req.ind.cmp}, concept \tcode{IndirectlyComparable} + // \ref{alg.req.ind.cmp}, concept \libconcept{indirectly_comparable} template - concept IndirectlyComparable = @\seebelow@; + concept indirectly_comparable = @\seebelow@; - // \ref{alg.req.permutable}, concept \tcode{Permutable} + // \ref{alg.req.permutable}, concept \libconcept{permutable} template - concept Permutable = @\seebelow@; + concept permutable = @\seebelow@; - // \ref{alg.req.mergeable}, concept \tcode{Mergeable} + // \ref{alg.req.mergeable}, concept \libconcept{mergeable} template - concept Mergeable = @\seebelow@; + concept mergeable = @\seebelow@; - // \ref{alg.req.sortable}, concept \tcode{Sortable} + // \ref{alg.req.sortable}, concept \libconcept{sortable} template - concept Sortable = @\seebelow@; + concept sortable = @\seebelow@; // \ref{iterator.primitives}, primitives // \ref{std.iterator.tags}, iterator tags @@ -232,35 +232,35 @@ // \ref{range.iter.ops}, range iterator operations namespace ranges { // \ref{range.iter.op.advance}, \tcode{ranges::advance} - template + template constexpr void advance(I& i, iter_difference_t n); - template S> + template S> constexpr void advance(I& i, S bound); - template S> + template S> constexpr iter_difference_t advance(I& i, iter_difference_t n, S bound); // \ref{range.iter.op.distance}, \tcode{ranges::distance} - template S> + template S> constexpr iter_difference_t distance(I first, S last); - template - constexpr iter_difference_t> distance(R&& r); + template + constexpr range_difference_t distance(R&& r); // \ref{range.iter.op.next}, \tcode{ranges::next} - template + template constexpr I next(I x); - template + template constexpr I next(I x, iter_difference_t n); - template S> + template S> constexpr I next(I x, S bound); - template S> + template S> constexpr I next(I x, iter_difference_t n, S bound); // \ref{range.iter.op.prev}, \tcode{ranges::prev} - template + template constexpr I prev(I x); - template + template constexpr I prev(I x, iter_difference_t n); - template + template constexpr I prev(I x, iter_difference_t n, I bound); } @@ -292,6 +292,10 @@ constexpr bool operator>=( const reverse_iterator& x, const reverse_iterator& y); + template Iterator2> + constexpr compare_three_way_result_t + operator<=>(const reverse_iterator& x, + const reverse_iterator& y); template constexpr auto operator-( @@ -307,7 +311,7 @@ constexpr reverse_iterator make_reverse_iterator(Iterator i); template - requires (!SizedSentinel) + requires (!sized_sentinel_for) inline constexpr bool disable_sized_sentinel, reverse_iterator> = true; @@ -331,9 +335,6 @@ template constexpr bool operator==( const move_iterator& x, const move_iterator& y); - template - constexpr bool operator!=( - const move_iterator& x, const move_iterator& y); template constexpr bool operator<( const move_iterator& x, const move_iterator& y); @@ -346,6 +347,10 @@ template constexpr bool operator>=( const move_iterator& x, const move_iterator& y); + template Iterator2> + constexpr compare_three_way_result_t + operator<=>(const move_iterator& x, + const move_iterator& y); template constexpr auto operator-( @@ -358,17 +363,17 @@ template constexpr move_iterator make_move_iterator(Iterator i); - template class move_sentinel; + template class move_sentinel; // \ref{iterators.common}, common iterators - template S> - requires (!Same) + template S> + requires (!same_as) class common_iterator; template struct incrementable_traits>; - template + template struct iterator_traits>; // \ref{default.sentinels}, default sentinels @@ -376,12 +381,12 @@ inline constexpr default_sentinel_t default_sentinel{}; // \ref{iterators.counted}, counted iterators - template class counted_iterator; + template class counted_iterator; template struct incrementable_traits>; - template + template struct iterator_traits>; // \ref{unreachable.sentinels}, unreachable sentinels @@ -395,9 +400,6 @@ template bool operator==(const istream_iterator& x, const istream_iterator& y); - template - bool operator!=(const istream_iterator& x, - const istream_iterator& y); template> class ostream_iterator; @@ -407,9 +409,6 @@ template bool operator==(const istreambuf_iterator& a, const istreambuf_iterator& b); - template - bool operator!=(const istreambuf_iterator& a, - const istreambuf_iterator& b); template> class ostreambuf_iterator; @@ -477,7 +476,7 @@ is valid where \tcode{o} is a value of type \tcode{T}. For every iterator type \tcode{X}, -there is a corresponding signed integer type called the +there is a corresponding signed integer-like type\iref{iterator.concept.winc} called the \term{difference type} of the iterator. @@ -514,16 +513,18 @@ \pnum The six categories of iterators correspond to the iterator concepts -\libconcept{Input\-Iterator}\iref{iterator.concept.input}, -\libconcept{Output\-Iterator}\iref{iterator.concept.output}, -\libconcept{Forward\-Iterator}\iref{iterator.concept.forward}, -\libconcept{Bidirectional\-Iterator}\iref{iterator.concept.bidir} -\libconcept{RandomAccess\-Iterator}\iref{iterator.concept.random.access}, +\begin{itemize} +\item \libconcept{input_iterator}\iref{iterator.concept.input}, +\item \libconcept{output_iterator}\iref{iterator.concept.output}, +\item \libconcept{forward_iterator}\iref{iterator.concept.forward}, +\item \libconcept{bidirectional_iterator}\iref{iterator.concept.bidir} +\item \libconcept{random_access_iterator}\iref{iterator.concept.random.access}, and -\libconcept{Contiguous\-Iterator}\iref{iterator.concept.contiguous}, +\item \libconcept{contiguous_iterator}\iref{iterator.concept.contiguous}, +\end{itemize} respectively. The generic term \defn{iterator} refers to any type that models the -\libconcept{Iterator} concept\iref{iterator.concept.iterator}. +\libconcept{input_or_output_iterator} concept\iref{iterator.concept.iterator}. \pnum Forward iterators meet all the requirements of input @@ -669,7 +670,7 @@ it is often necessary to determine the difference type that corresponds to a particular incrementable type. Accordingly, it is required that if \tcode{WI} is the name of a type that models the -\tcode{WeaklyIncrementable} concept\iref{iterator.concept.winc}, +\libconcept{weakly_incrementable} concept\iref{iterator.concept.winc}, the type \begin{codeblock} iter_difference_t @@ -699,7 +700,7 @@ template requires (!requires { typename T::difference_type; } && - requires(const T& a, const T& b) { { a - b } -> Integral; }) + requires(const T& a, const T& b) { { a - b } -> integral; }) struct incrementable_traits { using difference_type = make_signed_t() - declval())>; }; @@ -731,7 +732,7 @@ To implement algorithms only in terms of readable types, it is often necessary to determine the value type that corresponds to a particular readable type. Accordingly, it is required that if \tcode{R} is the name of a type that -models the \tcode{Readable} concept\iref{iterator.concept.readable}, +models the \libconcept{readable} concept\iref{iterator.concept.readable}, the type \begin{codeblock} iter_value_t @@ -796,15 +797,15 @@ \pnum \begin{note} Some legacy output iterators define a nested type named \tcode{value_type} -that is an alias for \tcode{void}. These types are not \tcode{Readable} +that is an alias for \tcode{void}. These types are not \tcode{readable} and have no associated value types. \end{note} \pnum \begin{note} -Smart pointers like \tcode{shared_ptr} are \tcode{Readable} and +Smart pointers like \tcode{shared_ptr} are \tcode{readable} and have an associated value type, but a smart pointer like \tcode{shared_ptr} -is not \tcode{Readable} and has no associated value type. +is not \tcode{readable} and has no associated value type. \end{note} \rSec3[iterator.traits]{Iterator traits} @@ -856,53 +857,53 @@ \begin{codeblock} template concept @\placeholder{cpp17-iterator}@ = - Copyable && requires(I i) { + copyable && requires(I i) { { *i } -> @\placeholder{can-reference}@; - { ++i } -> Same; + { ++i } -> same_as; { *i++ } -> @\placeholder{can-reference}@; }; template concept @\placeholder{cpp17-input-iterator}@ = - @\placeholder{cpp17-iterator}@ && EqualityComparable && requires(I i) { + @\placeholder{cpp17-iterator}@ && equality_comparable && requires(I i) { typename incrementable_traits::difference_type; typename readable_traits::value_type; typename common_reference_t&&, typename readable_traits::value_type&>; typename common_reference_t::value_type&>; - requires SignedIntegral::difference_type>; + requires signed_integral::difference_type>; }; template concept @\placeholder{cpp17-forward-iterator}@ = - @\placeholder{cpp17-input-iterator}@ && Constructible && + @\placeholder{cpp17-input-iterator}@ && constructible_from && is_lvalue_reference_v> && - Same>, typename readable_traits::value_type> && + same_as>, typename readable_traits::value_type> && requires(I i) { - { i++ } -> const I&; - { *i++ } -> Same>; + { i++ } -> convertible_to; + { *i++ } -> same_as>; }; template concept @\placeholder{cpp17-bidirectional-iterator}@ = @\placeholder{cpp17-forward-iterator}@ && requires(I i) { - { --i } -> Same; - { i-- } -> const I&; - { *i-- } -> Same>; + { --i } -> same_as; + { i-- } -> convertible_to; + { *i-- } -> same_as>; }; template concept @\placeholder{cpp17-random-access-iterator}@ = - @\placeholder{cpp17-bidirectional-iterator}@ && StrictTotallyOrdered && + @\placeholder{cpp17-bidirectional-iterator}@ && totally_ordered && requires(I i, typename incrementable_traits::difference_type n) { - { i += n } -> Same; - { i -= n } -> Same; - { i + n } -> Same; - { n + i } -> Same; - { i - n } -> Same; - { i - i } -> Same; - { i[n] } -> iter_reference_t; + { i += n } -> same_as; + { i -= n } -> same_as; + { i + n } -> same_as; + { n + i } -> same_as; + { i - n } -> same_as; + { i - i } -> same_as; + { i[n] } -> convertible_to>; }; \end{codeblock} @@ -1121,13 +1122,13 @@ ill-formed with no diagnostic required. \item Otherwise, if the types of \tcode{E1} and \tcode{E2} each model -\tcode{Readable}, and if the reference types of \tcode{E1} and \tcode{E2} -model \libconcept{SwappableWith}\iref{concept.swappable}, +\tcode{readable}, and if the reference types of \tcode{E1} and \tcode{E2} +model \libconcept{swappable_with}\iref{concept.swappable}, then \tcode{ranges::swap(*E1, *E2)}. \item Otherwise, if the types \tcode{T1} and \tcode{T2} of \tcode{E1} and -\tcode{E2} model \tcode{IndirectlyMovableStorable} and -\tcode{IndirectlyMovableStorable}, then +\tcode{E2} model \tcode{\libconcept{indirectly_movable_storable}} and +\tcode{indirectly_movable_storable}, then \tcode{(void)(*E1 = \placeholdernc{iter-exchange-move}(E2, E1))}, except that \tcode{E1} is evaluated only once. @@ -1188,45 +1189,45 @@ and \tcode{\placeholder{ITER_CONCEPT}(I)} denotes \tcode{random_access_iterator_tag}. \end{example} -\rSec3[iterator.concept.readable]{Concept \libconcept{Readable}} +\rSec3[iterator.concept.readable]{Concept \libconcept{readable}} \pnum Types that are readable by applying \tcode{operator*} -model the \libconcept{Readable} concept, including +model the \libconcept{readable} concept, including pointers, smart pointers, and iterators. -\indexlibrary{\idxcode{Readable}}% +\indexlibrary{\idxcode{readable}}% \begin{codeblock} template - concept Readable = + concept readable = requires { typename iter_value_t; typename iter_reference_t; typename iter_rvalue_reference_t; } && - CommonReference&&, iter_value_t&> && - CommonReference&&, iter_rvalue_reference_t&&> && - CommonReference&&, const iter_value_t&>; + common_reference_with&&, iter_value_t&> && + common_reference_with&&, iter_rvalue_reference_t&&> && + common_reference_with&&, const iter_value_t&>; \end{codeblock} \pnum -Given a value \tcode{i} of type \tcode{I}, \tcode{I} models \libconcept{Readable} +Given a value \tcode{i} of type \tcode{I}, \tcode{I} models \libconcept{readable} only if the expression \tcode{*i} is equality-preserving. \begin{note} The expression \tcode{*i} is indirectly required to be valid via the exposition-only \placeholder{dereferenceable} concept\iref{iterator.synopsis}. \end{note} -\rSec3[iterator.concept.writable]{Concept \tcode{Writable}} +\rSec3[iterator.concept.writable]{Concept \libconcept{writable}} \pnum -The \tcode{Writable} concept specifies the requirements for writing a value +The \libconcept{writable} concept specifies the requirements for writing a value into an iterator's referenced object. -\indexlibrary{\idxcode{Writable}}% +\indexlibrary{\idxcode{writable}}% \begin{codeblock} template - concept Writable = + concept writable = requires(Out&& o, T&& t) { *o = std::forward(t); // not required to be equality-preserving *std::forward(o) = std::forward(t); // not required to be equality-preserving @@ -1240,11 +1241,11 @@ \pnum Let \tcode{E} be an an expression such that \tcode{decltype((E))} is \tcode{T}, and let \tcode{o} be a dereferenceable object of type \tcode{Out}. -\tcode{Out} and \tcode{T} model \tcode{Writable} only if +\tcode{Out} and \tcode{T} model \tcode{\libconcept{writable}} only if \begin{itemize} \item If \tcode{Out} and \tcode{T} model - \tcode{Readable \&\& Same, decay_t{>}}, + \tcode{readable \&\& same_as, decay_t{>}}, then \tcode{*o} after any above assignment is equal to the value of \tcode{E} before the assignment. \end{itemize} @@ -1264,38 +1265,149 @@ \pnum \begin{note} -\tcode{Writable} has the awkward \tcode{const_cast} expressions to reject +\tcode{writable} has the awkward \tcode{const_cast} expressions to reject iterators with prvalue non-proxy reference types that permit rvalue assignment but do not also permit \tcode{const} rvalue assignment. Consequently, an iterator type \tcode{I} that returns \tcode{std::string} -by value does not model \libconcept{Writable}. +by value does not model \tcode{\libconcept{writable}}. \end{note} -\rSec3[iterator.concept.winc]{Concept \tcode{WeaklyIncrementable}} +\rSec3[iterator.concept.winc]{Concept \libconcept{weakly_incrementable}} \pnum -The \tcode{WeaklyIncrementable} concept specifies the requirements on +The \libconcept{weakly_incrementable} concept specifies the requirements on types that can be incremented with the pre- and post-increment operators. The increment operations are not required to be equality-preserving, -nor is the type required to be \libconcept{EqualityComparable}. +nor is the type required to be \libconcept{equality_comparable}. -\indexlibrary{\idxcode{WeaklyIncrementable}}% +\indexlibrary{\idxcode{weakly_incrementable}}% \begin{codeblock} +template + inline constexpr bool @\placeholder{is-integer-like}@ = @\seebelow@; @\itcorr[-2]@ // \expos + +template + inline constexpr bool @\placeholder{is-signed-integer-like}@ = @\seebelow@; @\itcorr[-2]@ // \expos + template - concept WeaklyIncrementable = - Semiregular && + concept weakly_incrementable = + default_constructible && movable && requires(I i) { typename iter_difference_t; - requires SignedIntegral>; - { ++i } -> Same; // not required to be equality-preserving - i++; // not required to be equality-preserving + requires @\placeholdernc{is-signed-integer-like}@>; + { ++i } -> same_as; // not required to be equality-preserving + i++; // not required to be equality-preserving }; \end{codeblock} +\pnum +A type \tcode{I} is an \defnadj{integer-class}{type} +if it is in a set of implementation-defined class types +that behave as integer types do, as defined in below. + +\pnum +The range of representable values of an integer-class type +is the continuous set of values over which it is defined. +The values 0 and 1 are part of the range of every integer-class type. +If any negative numbers are part of the range, +the type is a \defnadj{signed-integer-class}{type}; +otherwise, it is an \defnadj{unsigned-integer-class}{type}. + +\pnum +For every integer-class type \tcode{I}, +let \tcode{B(I)} be a hypothetical extended integral type +of the same signedness with the smallest width\iref{basic.fundamental} +capable of representing the same range of values. +The width of \tcode{I} is equal to the width of \tcode{B(I)}. + +\pnum +Let \tcode{a} and \tcode{b} be objects of integer-class type \tcode{I}, +let \tcode{x} and \tcode{y} be objects of type \tcode{B(I)} as described above +that represent the same values as \tcode{a} and \tcode{b} respectively, and +let \tcode{c} be an lvalue of any integral type. +\begin{itemize} +\item + For every unary operator \tcode{@} for which the expression \tcode{@x} + is well-formed, \tcode{@a} shall also be well-formed + and have the same value, effects, and value category as \tcode{@x} + provided that value is representable by \tcode{I}. + If \tcode{@x} has type \tcode{bool}, so too does \tcode{@a}; + if \tcode{@x} has type \tcode{B(I)}, then \tcode{@a} has type \tcode{I}. +\item + For every assignment operator \tcode{@=} + for which \tcode{c @= x} is well-formed, + \tcode{c @= a} shall also be well-formed and + shall have the same value and effects as \tcode{c @= x}. + The expression \tcode{c @= a} shall be an lvalue referring to \tcode{c}. +\item + For every binary operator \tcode{@} for which \tcode{x @ y} is well-formed, + \tcode{a @ b} shall also be well-formed and + shall have the same value, effects, and value category as \tcode{x @ y} + provided that value is representable by \tcode{I}. + If \tcode{x @ y} has type \tcode{bool}, so too does \tcode{a @ b}; + if \tcode{x @ y} has type \tcode{B(I)}, then \tcode{a @ b} has type \tcode{I}. +\end{itemize} + +\pnum +All integer-class types are explicitly convertible to all integral types and +implicitly and explicitly convertible from all integral types. + +\pnum +All integer-class types are contextually convertible to \tcode{bool} +as if by \tcode{bool(a != I(0))}, where \tcode{a} is an +instance of the integral-class type \tcode{I}. + +\pnum +All integer-class types model +\libconcept{regular}\iref{concepts.object} and +\libconcept{totally_ordered}\iref{concept.totallyordered}. + +\pnum +A value-initialized object of integer-class type has value 0. + +\pnum +For every (possibly cv-qualified) integer-class type \tcode{I}, +\tcode{numeric_limits} is specialized such that: +\begin{itemize} +\item + \tcode{numeric_limits::is_specialized} is \tcode{true}, +\item + \tcode{numeric_limits::is_signed} is \tcode{true} + if and only if \tcode{I} is a signed-integer-class type, +\item + \tcode{numeric_limits::is_integer} is \tcode{true}, +\item + \tcode{numeric_limits::is_exact} is \tcode{true}, +\item + \tcode{numeric_limits::digits} is equal to the width of the integer-class type, +\item + \tcode{numeric_limits::digits10} is equal to \tcode{static_cast(digits * log10(2))}, and +\item + \tcode{numeric_limits::min()} and \tcode{numeric_limits::max()} return + the lowest and highest representable values of \tcode{I}, respectively, and + \tcode{numeric_limits::lowest()} returns \tcode{numeric_limits::\brk{}min()}. +\end{itemize} + +\pnum +A type \tcode{I} is \defn{integer-like} +if it models \tcode{\libconcept{integral}} or +if it is an integer-class type. +A type \tcode{I} is \defn{signed-integer-like} +if it models \tcode{\libconcept{signed_integral}} or +if it is a signed-integer-class type. +A type \tcode{I} is \defn{unsigned-integer-like} +if it models \tcode{\libconcept{unsigned_integral}} or +if it is an unsigned-integer-class type. + +\pnum +\tcode{\placeholdernc{is-integer-like}} is \tcode{true} +if and only if \tcode{I} is an integer-like type. +\tcode{\placeholdernc{is-signed-integer-like}} is \tcode{true} +if and only if I is a signed-integer-like type. + \pnum Let \tcode{i} be an object of type \tcode{I}. When \tcode{i} is in the domain of both pre- and post-increment, \tcode{i} is said to be \term{incrementable}. -\tcode{I} models \tcode{WeaklyIncrementable} only if +\tcode{I} models \tcode{\libconcept{weakly_incrementable}} only if \begin{itemize} \item The expressions \tcode{++i} and \tcode{i++} have the same domain. @@ -1308,7 +1420,7 @@ \pnum \begin{note} -For \tcode{WeaklyIncrementable} types, \tcode{a} equals \tcode{b} does not imply that \tcode{++a} +For \tcode{weakly_incrementable} types, \tcode{a} equals \tcode{b} does not imply that \tcode{++a} equals \tcode{++b}. (Equality does not guarantee the substitution property or referential transparency.) Algorithms on weakly incrementable types should never attempt to pass through the same incrementable value twice. They should be single-pass algorithms. These algorithms @@ -1316,31 +1428,31 @@ template. \end{note} -\rSec3[iterator.concept.inc]{Concept \tcode{Incrementable}} +\rSec3[iterator.concept.inc]{Concept \libconcept{incrementable}} \pnum -The \tcode{Incrementable} concept specifies requirements on types that can be incremented with the pre- +The \libconcept{incrementable} concept specifies requirements on types that can be incremented with the pre- and post-increment operators. The increment operations are required to be equality-preserving, -and the type is required to be \libconcept{EqualityComparable}. +and the type is required to be \libconcept{equality_comparable}. \begin{note} This supersedes the annotations on the increment expressions -in the definition of \tcode{WeaklyIncrementable}. +in the definition of \tcode{weakly_incrementable}. \end{note} -\indexlibrary{\idxcode{Incrementable}}% +\indexlibrary{\idxcode{incrementable}}% \begin{codeblock} template - concept Incrementable = - Regular && - WeaklyIncrementable && + concept incrementable = + regular && + weakly_incrementable && requires(I i) { - { i++ } -> Same; + { i++ } -> same_as; }; \end{codeblock} \pnum Let \tcode{a} and \tcode{b} be incrementable objects of type \tcode{I}. -\tcode{I} models \libconcept{Incrementable} only if +\tcode{I} models \libconcept{incrementable} only if \begin{itemize} \item If \tcode{bool(a == b)} then \tcode{bool(a++ == b)}. @@ -1355,14 +1467,14 @@ \tcode{++a} equals \tcode{++b} (which is not true for weakly incrementable types) allows the use of multi-pass one-directional -algorithms with types that model \libconcept{Increment\-able}. +algorithms with types that model \libconcept{incrementable}. \end{note} -\rSec3[iterator.concept.iterator]{Concept \tcode{Iterator}} +\rSec3[iterator.concept.iterator]{Concept \libconcept{input_or_output_iterator}} \pnum -The \libconcept{Iterator} concept forms the basis -of the iterator concept taxonomy; every iterator models \libconcept{Iterator}. +The \libconcept{input_or_output_iterator} concept forms the basis +of the iterator concept taxonomy; every iterator models \libconcept{input_or_output_iterator}. This concept specifies operations for dereferencing and incrementing an iterator. Most algorithms will require additional operations to compare iterators with sentinels\iref{iterator.concept.sentinel}, to @@ -1370,29 +1482,35 @@ to provide a richer set of iterator movements (\ref{iterator.concept.forward}, \ref{iterator.concept.bidir}, \ref{iterator.concept.random.access}). -\indexlibrary{\idxcode{Iterator}}% +\indexlibrary{\idxcode{input_or_output_iterator}}% \begin{codeblock} template - concept Iterator = + concept input_or_output_iterator = requires(I i) { { *i } -> @\placeholder{can-reference}@; } && - WeaklyIncrementable; + weakly_incrementable; \end{codeblock} -\rSec3[iterator.concept.sentinel]{Concept \tcode{Sentinel}} +\pnum +\begin{note} +Unlike the \oldconcept{Iterator} requirements, +the \libconcept{input_or_output_iterator} concept does not require copyability. +\end{note} + +\rSec3[iterator.concept.sentinel]{Concept \libconcept{sentinel_for}} \pnum -The \libconcept{Sentinel} concept specifies the relationship -between an \libconcept{Iterator} type and a \libconcept{Semiregular} type +The \libconcept{sentinel_for} concept specifies the relationship +between an \libconcept{input_or_output_iterator} type and a \libconcept{semiregular} type whose values denote a range. -\indexlibrary{\idxcode{Sentinel}}% +\indexlibrary{\idxcode{sentinel_for}}% \begin{itemdecl} template - concept Sentinel = - Semiregular && - Iterator && + concept sentinel_for = + semiregular && + input_or_output_iterator && @\placeholder{weakly-equality-comparable-with}@; // See \ref{concept.equalitycomparable} \end{itemdecl} @@ -1400,7 +1518,7 @@ \pnum Let \tcode{s} and \tcode{i} be values of type \tcode{S} and \tcode{I} such that \range{i}{s} denotes a range. Types -\tcode{S} and \tcode{I} model \tcode{Sentinel} only if +\tcode{S} and \tcode{I} model \tcode{\libconcept{sentinel_for}} only if \begin{itemize} \item \tcode{i == s} is well-defined. @@ -1418,24 +1536,25 @@ to \tcode{i}. Consequently, \tcode{i == s} is no longer required to be well-defined. -\rSec3[iterator.concept.sizedsentinel]{Concept \tcode{SizedSentinel}} +\rSec3[iterator.concept.sizedsentinel]{Concept \libconcept{sized_sentinel_for}} \pnum -The \libconcept{SizedSentinel} concept specifies -requirements on an \libconcept{Iterator} and a \libconcept{Sentinel} +The \libconcept{sized_sentinel_for} concept specifies +requirements on an \libconcept{input_or_output_iterator} and +a corresponding \libconcept{sentinel_for} that allow the use of the \tcode{-} operator to compute the distance between them in constant time. -\indexlibrary{\idxcode{SizedSentinel}}% +\indexlibrary{\idxcode{sized_sentinel_for}}% \begin{itemdecl} template - concept SizedSentinel = - Sentinel && + concept sized_sentinel_for = + sentinel_for && !disable_sized_sentinel, remove_cv_t> && requires(const I& i, const S& s) { - { s - i } -> Same>; - { i - s } -> Same>; + { s - i } -> same_as>; + { i - s } -> same_as>; }; \end{itemdecl} @@ -1445,7 +1564,7 @@ a sentinel of type \tcode{S} such that \range{i}{s} denotes a range. Let $N$ be the smallest number of applications of \tcode{++i} necessary to make \tcode{bool(i == s)} be \tcode{true}. -\tcode{S} and \tcode{I} model \tcode{SizedSentinel} only if +\tcode{S} and \tcode{I} model \tcode{\libconcept{sized_sentinel_for}} only if \begin{itemize} \item If $N$ is representable by \tcode{iter_difference_t}, @@ -1456,58 +1575,76 @@ \end{itemize} \end{itemdescr} +\indexlibrary{\idxcode{disable_sized_sentinel}}% +\begin{itemdecl} +template + inline constexpr bool disable_sized_sentinel = false; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\remarks +Pursuant to \ref{namespace.std}, +users may specialize \tcode{disable_sized_sentinel} +for cv-unqualified non-array object types \tcode{S} and \tcode{I} +if \tcode{S} and/or \tcode{I} is a program-defined type. +Such specializations shall +be usable in constant expressions\iref{expr.const} and +have type \tcode{const bool}. + \pnum \begin{note} \tcode{disable_sized_sentinel} allows use of sentinels and iterators with -the library that satisfy but do not in fact model \libconcept{SizedSentinel}. +the library that satisfy but do not in fact model \libconcept{sized_sentinel_for}. \end{note} \pnum \begin{example} -The \libconcept{SizedSentinel} concept is modeled by pairs of -\libconcept{RandomAccessIterator}s\iref{iterator.concept.random.access} and by +The \libconcept{sized_sentinel_for} concept is modeled by pairs of +\libconcept{random_access_iterator}s\iref{iterator.concept.random.access} and by counted iterators and their sentinels\iref{counted.iterator}. \end{example} +\end{itemdescr} -\rSec3[iterator.concept.input]{Concept \tcode{InputIterator}} +\rSec3[iterator.concept.input]{Concept \libconcept{input_iterator}} \pnum -The \tcode{InputIterator} concept defines requirements for a type +The \libconcept{input_iterator} concept defines requirements for a type whose referenced values can be read (from the requirement for -\tcode{Readable}\iref{iterator.concept.readable}) and which can be both pre- and +\libconcept{readable}\iref{iterator.concept.readable}) and which can be both pre- and post-incremented. \begin{note} Unlike the \oldconcept{InputIterator} requirements\iref{input.iterators}, -the \libconcept{InputIterator} concept does not need +the \libconcept{input_iterator} concept does not need equality comparison since iterators are typically compared to sentinels. \end{note} -\indexlibrary{\idxcode{InputIterator}}% +\indexlibrary{\idxcode{input_iterator}}% \begin{codeblock} template - concept InputIterator = - Iterator && - Readable && + concept input_iterator = + input_or_output_iterator && + readable && requires { typename @\placeholdernc{ITER_CONCEPT}@(I); } && - DerivedFrom<@\placeholdernc{ITER_CONCEPT}@(I), input_iterator_tag>; + derived_from<@\placeholdernc{ITER_CONCEPT}@(I), input_iterator_tag>; \end{codeblock} -\rSec3[iterator.concept.output]{Concept \tcode{OutputIterator}} +\rSec3[iterator.concept.output]{Concept \libconcept{output_iterator}} \pnum -The \tcode{OutputIterator} concept defines requirements for a type that +The \libconcept{output_iterator} concept defines requirements for a type that can be used to write values (from the requirement for -\tcode{Writable}\iref{iterator.concept.writable}) and which can be both pre- and post-incremented. +\libconcept{writable}\iref{iterator.concept.writable}) and which can be both pre- and post-incremented. \begin{note} -Output iterators are not required to model \libconcept{EqualityComparable}. +Output iterators are not required to model \libconcept{equality_comparable}. \end{note} -\indexlibrary{\idxcode{OutputIterator}}% +\indexlibrary{\idxcode{output_iterator}}% \begin{codeblock} template - concept OutputIterator = - Iterator && - Writable && + concept output_iterator = + input_or_output_iterator && + writable && requires(I i, T&& t) { *i++ = std::forward(t); // not required to be equality-preserving }; @@ -1515,7 +1652,7 @@ \pnum Let \tcode{E} be an expression such that \tcode{decltype((E))} is \tcode{T}, and let \tcode{i} be a -dereferenceable object of type \tcode{I}. \tcode{I} and \tcode{T} model \tcode{OutputIterator} only if +dereferenceable object of type \tcode{I}. \tcode{I} and \tcode{T} model \tcode{\libconcept{output_iterator}} only if \tcode{*i++ = E;} has effects equivalent to: \begin{codeblock} *i = E; @@ -1528,20 +1665,21 @@ They should be single-pass algorithms. \end{note} -\rSec3[iterator.concept.forward]{Concept \tcode{ForwardIterator}} +\rSec3[iterator.concept.forward]{Concept \libconcept{forward_iterator}} \pnum -The \libconcept{ForwardIterator} concept adds equality comparison and +The \libconcept{forward_iterator} concept adds +copyability, equality comparison, and the multi-pass guarantee, specified below. -\indexlibrary{\idxcode{ForwardIterator}}% +\indexlibrary{\idxcode{forward_iterator}}% \begin{codeblock} template - concept ForwardIterator = - InputIterator && - DerivedFrom<@\placeholdernc{ITER_CONCEPT}@(I), forward_iterator_tag> && - Incrementable && - Sentinel; + concept forward_iterator = + input_iterator && + derived_from<@\placeholdernc{ITER_CONCEPT}@(I), forward_iterator_tag> && + incrementable && + sentinel_for; \end{codeblock} \pnum @@ -1579,21 +1717,21 @@ allow the use of multi-pass one-directional algorithms with forward iterators. \end{note} -\rSec3[iterator.concept.bidir]{Concept \libconcept{BidirectionalIterator}} +\rSec3[iterator.concept.bidir]{Concept \libconcept{bidirectional_iterator}} \pnum -The \libconcept{BidirectionalIterator} concept adds the ability +The \libconcept{bidirectional_iterator} concept adds the ability to move an iterator backward as well as forward. -\indexlibrary{\idxcode{BidirectionalIterator}}% +\indexlibrary{\idxcode{bidirectional_iterator}}% \begin{codeblock} template - concept BidirectionalIterator = - ForwardIterator && - DerivedFrom<@\placeholdernc{ITER_CONCEPT}@(I), bidirectional_iterator_tag> && + concept bidirectional_iterator = + forward_iterator && + derived_from<@\placeholdernc{ITER_CONCEPT}@(I), bidirectional_iterator_tag> && requires(I i) { - { --i } -> Same; - { i-- } -> Same; + { --i } -> same_as; + { i-- } -> same_as; }; \end{codeblock} @@ -1604,7 +1742,7 @@ \pnum Let \tcode{a} and \tcode{b} be equal objects of type \tcode{I}. -\tcode{I} models \libconcept{BidirectionalIterator} only if: +\tcode{I} models \libconcept{bidirectional_iterator} only if: \begin{itemize} \item If \tcode{a} and \tcode{b} are decrementable, @@ -1620,29 +1758,29 @@ \tcode{bool(--(++a) == b)}. \end{itemize} -\rSec3[iterator.concept.random.access]{Concept \libconcept{RandomAccessIterator}} +\rSec3[iterator.concept.random.access]{Concept \libconcept{random_access_iterator}} \pnum -The \libconcept{RandomAccessIterator} concept adds support for +The \libconcept{random_access_iterator} concept adds support for constant-time advancement with \tcode{+=}, \tcode{+}, \tcode{-=}, and \tcode{-}, as well as the computation of distance in constant time with \tcode{-}. Random access iterators also support array notation via subscripting. -\indexlibrary{\idxcode{RandomAccessIterator}}% +\indexlibrary{\idxcode{random_access_iterator}}% \begin{codeblock} template - concept RandomAccessIterator = - BidirectionalIterator && - DerivedFrom<@\placeholdernc{ITER_CONCEPT}@(I), random_access_iterator_tag> && - StrictTotallyOrdered && - SizedSentinel && + concept random_access_iterator = + bidirectional_iterator && + derived_from<@\placeholdernc{ITER_CONCEPT}@(I), random_access_iterator_tag> && + totally_ordered && + sized_sentinel_for && requires(I i, const I j, const iter_difference_t n) { - { i += n } -> Same; - { j + n } -> Same; - { n + j } -> Same; - { i -= n } -> Same; - { j - n } -> Same; - { j[n] } -> Same>; + { i += n } -> same_as; + { j + n } -> same_as; + { n + j } -> same_as; + { i -= n } -> same_as; + { j - n } -> same_as; + { j[n] } -> same_as>; }; \end{codeblock} @@ -1652,7 +1790,7 @@ after \tcode{n} applications of \tcode{++a}, let \tcode{D} be \tcode{iter_difference_t}, and let \tcode{n} denote a value of type \tcode{D}. -\tcode{I} models \libconcept{RandomAccessIterator} only if +\tcode{I} models \libconcept{random_access_iterator} only if \begin{itemize} \item \tcode{(a += n)} is equal to \tcode{b}. @@ -1674,30 +1812,37 @@ \item \tcode{bool(a <= b)} is \tcode{true}. \end{itemize} -\rSec3[iterator.concept.contiguous]{Concept \libconcept{ContiguousIterator}} +\rSec3[iterator.concept.contiguous]{Concept \libconcept{contiguous_iterator}} \pnum -The \libconcept{ContiguousIterator} concept provides a guarantee that +The \libconcept{contiguous_iterator} concept provides a guarantee that the denoted elements are stored contiguously in memory. -\indexlibrary{\idxcode{ContiguousIterator}}% +\indexlibrary{\idxcode{contiguous_iterator}}% \begin{codeblock} template - concept @\libconcept{ContiguousIterator}@ = - RandomAccessIterator && - DerivedFrom<@\placeholdernc{ITER_CONCEPT}@(I), contiguous_iterator_tag> && + concept @\libconcept{contiguous_iterator}@ = + random_access_iterator && + derived_from<@\placeholdernc{ITER_CONCEPT}@(I), contiguous_iterator_tag> && is_lvalue_reference_v> && - Same, remove_cvref_t>>; + same_as, remove_cvref_t>> && + requires(const I& i) { + { to_address(i) } -> same_as>>; + }; \end{codeblock} \pnum -Let \tcode{a} and \tcode{b} be dereferenceable iterators of type \tcode{I} -such that \tcode{b} is reachable from \tcode{a}, +Let \tcode{a} and \tcode{b} be dereferenceable iterators and +\tcode{c} be a non-dereferenceable iterator of type \tcode{I} +such that \tcode{b} is reachable from \tcode{a} and +\tcode{c} is reachable from \tcode{b}, and let \tcode{D} be \tcode{iter_difference_t}. -The type \tcode{I} models \libconcept{ContiguousIterator} only if -\tcode{addressof(*(a + D(b - a)))} -is equal to -\tcode{addressof(*a) + D(b - a)}. +The type \tcode{I} models \libconcept{contiguous_iterator} only if +\begin{itemize} +\item \tcode{to_address(a) == addressof(*a)}, +\item \tcode{to_address(b) == to_address(a) + D(b - a)}, and +\item \tcode{to_address(c) == to_address(a) + D(c - a)}. +\end{itemize} \rSec2[iterator.cpp17]{\Cpp{}17 iterator requirements} @@ -1749,6 +1894,8 @@ \oldconcept{Destructible} requirements\iref{utility.arg.requirements} and lvalues of type \tcode{X} are swappable\iref{swappable.requirements}, and +\item \tcode{iterator_traits::difference_type} is a signed integer type or \tcode{void}, and + \item the expressions in \tref{iterator} are valid and have the indicated semantics. \end{itemize} @@ -2171,62 +2318,62 @@ The indirect callable concepts are used to constrain those algorithms that accept callable objects~(\ref{func.def}) as arguments. -\indexlibrary{\idxcode{IndirectUnaryInvocable}}% -\indexlibrary{\idxcode{IndirectRegularUnaryInvocable}}% -\indexlibrary{\idxcode{IndirectUnaryPredicate}}% -\indexlibrary{\idxcode{IndirectRelation}}% -\indexlibrary{\idxcode{IndirectStrictWeakOrder}}% +\indexlibrary{\idxcode{indirectly_unary_invocable}}% +\indexlibrary{\idxcode{indirectly_regular_unary_invocable}}% +\indexlibrary{\idxcode{indirect_unary_predicate}}% +\indexlibrary{\idxcode{indirect_relation}}% +\indexlibrary{\idxcode{indirect_strict_weak_order}}% \begin{codeblock} namespace std { template - concept IndirectUnaryInvocable = - Readable && - CopyConstructible && - Invocable&> && - Invocable> && - Invocable> && - CommonReference< + concept indirectly_unary_invocable = + readable && + copy_constructible && + invocable&> && + invocable> && + invocable> && + common_reference_with< invoke_result_t&>, invoke_result_t>>; template - concept IndirectRegularUnaryInvocable = - Readable && - CopyConstructible && - RegularInvocable&> && - RegularInvocable> && - RegularInvocable> && - CommonReference< + concept indirectly_regular_unary_invocable = + readable && + copy_constructible && + regular_invocable&> && + regular_invocable> && + regular_invocable> && + common_reference_with< invoke_result_t&>, invoke_result_t>>; template - concept IndirectUnaryPredicate = - Readable && - CopyConstructible && - Predicate&> && - Predicate> && - Predicate>; + concept indirect_unary_predicate = + readable && + copy_constructible && + predicate&> && + predicate> && + predicate>; template - concept IndirectRelation = - Readable && Readable && - CopyConstructible && - Relation&, iter_value_t&> && - Relation&, iter_reference_t> && - Relation, iter_value_t&> && - Relation, iter_reference_t> && - Relation, iter_common_reference_t>; + concept indirect_relation = + readable && readable && + copy_constructible && + relation&, iter_value_t&> && + relation&, iter_reference_t> && + relation, iter_value_t&> && + relation, iter_reference_t> && + relation, iter_common_reference_t>; template - concept IndirectStrictWeakOrder = - Readable && Readable && - CopyConstructible && - StrictWeakOrder&, iter_value_t&> && - StrictWeakOrder&, iter_reference_t> && - StrictWeakOrder, iter_value_t&> && - StrictWeakOrder, iter_reference_t> && - StrictWeakOrder, iter_common_reference_t>; + concept indirect_strict_weak_order = + readable && readable && + copy_constructible && + strict_weak_order&, iter_value_t&> && + strict_weak_order&, iter_reference_t> && + strict_weak_order, iter_value_t&> && + strict_weak_order, iter_reference_t> && + strict_weak_order, iter_common_reference_t>; } \end{codeblock} @@ -2235,21 +2382,21 @@ \pnum Class template \tcode{projected} is used to constrain algorithms that accept callable objects and projections\iref{defns.projection}. -It combines a \libconcept{Readable} type \tcode{I} and -a callable object type \tcode{Proj} into a new \libconcept{Readable} type +It combines a \libconcept{readable} type \tcode{I} and +a callable object type \tcode{Proj} into a new \libconcept{readable} type whose \tcode{reference} type is the result of applying \tcode{Proj} to the \tcode{iter_reference_t} of \tcode{I}. \indexlibrary{\idxcode{projected}}% \begin{codeblock} namespace std { - template Proj> + template Proj> struct projected { using value_type = remove_cvref_t>; indirect_result_t operator*() const; // \notdef }; - template + template struct incrementable_traits> { using difference_type = iter_difference_t; }; @@ -2265,17 +2412,17 @@ to families of algorithms. These group together iterator requirements of algorithm families. There are three relational concepts that specify -how element values are transferred between \libconcept{Readable} and -\libconcept{Writable} types: -\libconcept{Indirectly\-Movable}, -\libconcept{Indir\-ect\-ly\-Copy\-able}, and -\libconcept{Indirectly\-Swappable}. +how element values are transferred between \libconcept{readable} and +\libconcept{writable} types: +\libconcept{indirectly_movable}, +\libconcept{indirectly_copyable}, and +\libconcept{indirectly_swappable}. There are three relational concepts for rearrangements: -\libconcept{Permut\-able}, -\libconcept{Mergeable}, and -\libconcept{Sortable}. +\libconcept{permutable}, +\libconcept{mergeable}, and +\libconcept{sortable}. There is one relational concept for comparing values from different sequences: -\libconcept{IndirectlyComparable}. +\libconcept{indirectly_comparable}. \pnum \begin{note} @@ -2284,41 +2431,41 @@ in addition to those that appear in the concepts' bodies\iref{range.cmp}. \end{note} -\rSec3[alg.req.ind.move]{Concept \libconcept{IndirectlyMovable}} +\rSec3[alg.req.ind.move]{Concept \libconcept{indirectly_movable}} \pnum -The \libconcept{IndirectlyMovable} concept specifies the relationship between -a \libconcept{Readable} type and a \libconcept{Writable} type between which +The \libconcept{indirectly_movable} concept specifies the relationship between +a \libconcept{readable} type and a \libconcept{writable} type between which values may be moved. -\indexlibrary{\idxcode{IndirectlyMovable}}% +\indexlibrary{\idxcode{indirectly_movable}}% \begin{codeblock} template - concept IndirectlyMovable = - Readable && - Writable>; + concept indirectly_movable = + readable && + writable>; \end{codeblock} \pnum -The \libconcept{IndirectlyMovableStorable} concept augments -\libconcept{IndirectlyMovable} with additional requirements enabling +The \libconcept{indirectly_movable_storable} concept augments +\libconcept{indirectly_movable} with additional requirements enabling the transfer to be performed through an intermediate object of the -\libconcept{Readable} type's value type. +\libconcept{readable} type's value type. -\indexlibrary{\idxcode{IndirectlyMovableStorable}}% +\indexlibrary{\idxcode{indirectly_movable_storable}}% \begin{codeblock} template - concept IndirectlyMovableStorable = - IndirectlyMovable && - Writable> && - Movable> && - Constructible, iter_rvalue_reference_t> && - Assignable&, iter_rvalue_reference_t>; + concept indirectly_movable_storable = + indirectly_movable && + writable> && + movable> && + constructible_from, iter_rvalue_reference_t> && + assignable_from&, iter_rvalue_reference_t>; \end{codeblock} \pnum Let \tcode{i} be a dereferenceable value of type \tcode{In}. -\tcode{In} and \tcode{Out} model \tcode{IndirectlyMovableStorable} +\tcode{In} and \tcode{Out} model \tcode{\libconcept{indirectly_movable_storable}} only if after the initialization of the object \tcode{obj} in \begin{codeblock} iter_value_t obj(ranges::iter_move(i)); @@ -2328,42 +2475,42 @@ the resulting state of the value denoted by \tcode{*i} is valid but unspecified\iref{lib.types.movedfrom}. -\rSec3[alg.req.ind.copy]{Concept \libconcept{IndirectlyCopyable}} +\rSec3[alg.req.ind.copy]{Concept \libconcept{indirectly_copyable}} \pnum -The \libconcept{IndirectlyCopyable} concept specifies the relationship between -a \libconcept{Readable} type and a \libconcept{Writable} type between which +The \libconcept{indirectly_copyable} concept specifies the relationship between +a \libconcept{readable} type and a \libconcept{writable} type between which values may be copied. -\indexlibrary{\idxcode{IndirectlyCopyable}}% +\indexlibrary{\idxcode{indirectly_copyable}}% \begin{codeblock} template - concept IndirectlyCopyable = - Readable && - Writable>; + concept indirectly_copyable = + readable && + writable>; \end{codeblock} \pnum -The \libconcept{IndirectlyCopyableStorable} concept augments -\libconcept{IndirectlyCopyable} with additional requirements enabling +The \libconcept{indirectly_copyable_storable} concept augments +\libconcept{indirectly_copyable} with additional requirements enabling the transfer to be performed through an intermediate object of the -\libconcept{Readable} type's value type. It also requires the capability +\libconcept{readable} type's value type. It also requires the capability to make copies of values. -\indexlibrary{\idxcode{IndirectlyCopyableStorable}}% +\indexlibrary{\idxcode{indirectly_copyable_storable}}% \begin{codeblock} template - concept IndirectlyCopyableStorable = - IndirectlyCopyable && - Writable&> && - Copyable> && - Constructible, iter_reference_t> && - Assignable&, iter_reference_t>; + concept indirectly_copyable_storable = + indirectly_copyable && + writable&> && + copyable> && + constructible_from, iter_reference_t> && + assignable_from&, iter_reference_t>; \end{codeblock} \pnum Let \tcode{i} be a dereferenceable value of type \tcode{In}. -\tcode{In} and \tcode{Out} model \tcode{IndirectlyCopyableStorable} +\tcode{In} and \tcode{Out} model \tcode{\libconcept{indirectly_copyable_storable}} only if after the initialization of the object \tcode{obj} in \begin{codeblock} iter_value_t obj(*i); @@ -2373,17 +2520,17 @@ of the value denoted by \tcode{*i} is valid but unspecified\iref{lib.types.movedfrom}. -\rSec3[alg.req.ind.swap]{Concept \libconcept{IndirectlySwappable}} +\rSec3[alg.req.ind.swap]{Concept \libconcept{indirectly_swappable}} \pnum -The \libconcept{IndirectlySwappable} concept specifies a swappable relationship -between the values referenced by two \libconcept{Readable} types. +The \libconcept{indirectly_swappable} concept specifies a swappable relationship +between the values referenced by two \libconcept{readable} types. -\indexlibrary{\idxcode{IndirectlySwappable}}% +\indexlibrary{\idxcode{indirectly_swappable}}% \begin{codeblock} template - concept IndirectlySwappable = - Readable && Readable && + concept indirectly_swappable = + readable && readable && requires(I1& i1, I2& i2) { ranges::iter_swap(i1, i1); ranges::iter_swap(i2, i2); @@ -2392,67 +2539,67 @@ }; \end{codeblock} -\rSec3[alg.req.ind.cmp]{Concept \libconcept{IndirectlyComparable}} +\rSec3[alg.req.ind.cmp]{Concept \libconcept{indirectly_comparable}} \pnum -The \libconcept{IndirectlyComparable} concept specifies +The \libconcept{indirectly_comparable} concept specifies the common requirements of algorithms that compare values from two different sequences. -\indexlibrary{\idxcode{IndirectlyComparable}}% +\indexlibrary{\idxcode{indirectly_comparable}}% \begin{codeblock} template - concept IndirectlyComparable = - IndirectRelation, projected>; + concept indirectly_comparable = + indirect_relation, projected>; \end{codeblock} -\rSec3[alg.req.permutable]{Concept \libconcept{Permutable}} +\rSec3[alg.req.permutable]{Concept \libconcept{permutable}} \pnum -The \libconcept{Permutable} concept specifies the common requirements +The \libconcept{permutable} concept specifies the common requirements of algorithms that reorder elements in place by moving or swapping them. -\indexlibrary{\idxcode{Permutable}}% +\indexlibrary{\idxcode{permutable}}% \begin{codeblock} template - concept Permutable = - ForwardIterator && - IndirectlyMovableStorable && - IndirectlySwappable; + concept permutable = + forward_iterator && + indirectly_movable_storable && + indirectly_swappable; \end{codeblock} -\rSec3[alg.req.mergeable]{Concept \libconcept{Mergeable}} +\rSec3[alg.req.mergeable]{Concept \libconcept{mergeable}} \pnum -The \libconcept{Mergeable} concept specifies the requirements of algorithms +The \libconcept{mergeable} concept specifies the requirements of algorithms that merge sorted sequences into an output sequence by copying elements. -\indexlibrary{\idxcode{Mergeable}}% +\indexlibrary{\idxcode{mergeable}}% \begin{codeblock} template - concept Mergeable = - InputIterator && - InputIterator && - WeaklyIncrementable && - IndirectlyCopyable && - IndirectlyCopyable && - IndirectStrictWeakOrder, projected>; + concept mergeable = + input_iterator && + input_iterator && + weakly_incrementable && + indirectly_copyable && + indirectly_copyable && + indirect_strict_weak_order, projected>; \end{codeblock} -\rSec3[alg.req.sortable]{Concept \libconcept{Sortable}} +\rSec3[alg.req.sortable]{Concept \libconcept{sortable}} \pnum -The \libconcept{Sortable} concept specifies the common requirements of +The \libconcept{sortable} concept specifies the common requirements of algorithms that permute sequences into ordered sequences (e.g., \tcode{sort}). -\indexlibrary{\idxcode{Sortable}}% +\indexlibrary{\idxcode{sortable}}% \begin{codeblock} template - concept Sortable = - Permutable && - IndirectStrictWeakOrder>; + concept sortable = + permutable && + indirect_strict_weak_order>; \end{codeblock} \rSec1[iterator.primitives]{Iterator primitives} @@ -2658,8 +2805,8 @@ possible for a concrete iterator type. \begin{example} \tcode{ranges::advance} uses the \tcode{+} operator to move a -\libconcept{RandomAccessIterator} forward \tcode{n} steps in constant time. -For an iterator type that does not model \libconcept{RandomAccessIterator}, +\libconcept{random_access_iterator} forward \tcode{n} steps in constant time. +For an iterator type that does not model \libconcept{random_access_iterator}, \tcode{ranges::advance} instead performs \tcode{n} individual increments with the \tcode{++} operator. \end{example} @@ -2696,20 +2843,20 @@ \indexlibrary{\idxcode{advance}}% \begin{itemdecl} -template +template constexpr void ranges::advance(I& i, iter_difference_t n); \end{itemdecl} \begin{itemdescr} \pnum \expects -If \tcode{I} does not model \libconcept{BidirectionalIterator}, +If \tcode{I} does not model \libconcept{bidirectional_iterator}, \tcode{n} is not negative. \pnum \effects \begin{itemize} -\item If \tcode{I} models \libconcept{RandomAccessIterator}, +\item If \tcode{I} models \libconcept{random_access_iterator}, equivalent to \tcode{i += n}. \item Otherwise, if \tcode{n} is non-negative, increments \tcode{i} by \tcode{n}. @@ -2719,7 +2866,7 @@ \indexlibrary{\idxcode{advance}}% \begin{itemdecl} -template S> +template S> constexpr void ranges::advance(I& i, S bound); \end{itemdecl} @@ -2731,9 +2878,9 @@ \pnum \effects \begin{itemize} -\item If \tcode{I} and \tcode{S} model \tcode{Assignable}, +\item If \tcode{I} and \tcode{S} model \tcode{\libconcept{assignable_from}}, equivalent to \tcode{i = std::move(bound)}. -\item Otherwise, if \tcode{S} and \tcode{I} model \tcode{SizedSentinel}, +\item Otherwise, if \tcode{S} and \tcode{I} model \tcode{\libconcept{sized_sentinel_for}}, equivalent to \tcode{ranges::advance(i, bound - i)}. \item Otherwise, while \tcode{bool(i != bound)} is \tcode{true}, increments \tcode{i}. @@ -2742,7 +2889,7 @@ \indexlibrary{\idxcode{advance}}% \begin{itemdecl} -template S> +template S> constexpr iter_difference_t ranges::advance(I& i, iter_difference_t n, S bound); \end{itemdecl} @@ -2752,13 +2899,13 @@ If \tcode{n > 0}, \range{i}{bound} denotes a range. If \tcode{n == 0}, \range{i}{bound} or \range{bound}{i} denotes a range. If \tcode{n < 0}, \range{bound}{i} denotes a range, -\tcode{I} models \libconcept{BidirectionalIterator}, and -\tcode{I} and \tcode{S} model \tcode{Same}. +\tcode{I} models \libconcept{bidirectional_iterator}, and +\tcode{I} and \tcode{S} model \tcode{\libconcept{same_as}}. \pnum \effects \begin{itemize} -\item If \tcode{S} and \tcode{I} model \tcode{SizedSentinel}: +\item If \tcode{S} and \tcode{I} model \tcode{\libconcept{sized_sentinel_for}}: \begin{itemize} \item If \brk{}$|\tcode{n}| \ge |\tcode{bound - i}|$, equivalent to \tcode{ranges::advance(i, bound)}. @@ -2784,7 +2931,7 @@ \rSec3[range.iter.op.distance]{\tcode{ranges::distance}} \indexlibrary{\idxcode{distance}}% \begin{itemdecl} -template S> +template S> constexpr iter_difference_t ranges::distance(I first, S last); \end{itemdecl} @@ -2794,11 +2941,11 @@ \range{first}{last} denotes a range, or \range{last}{first} denotes a range and \tcode{S} and \tcode{I} model -\tcode{Same \&\& SizedSentinel}. +\tcode{same_as \&\& sized_sentinel_for}. \pnum \effects -If \tcode{S} and \tcode{I} model \tcode{SizedSentinel}, +If \tcode{S} and \tcode{I} model \tcode{\libconcept{sized_sentinel_for}}, returns \tcode{(last - first)}; otherwise, returns the number of increments needed to get from \tcode{first} @@ -2808,16 +2955,16 @@ \indexlibrary{\idxcode{distance}}% \begin{itemdecl} -template - constexpr iter_difference_t> ranges::distance(R&& r); +template + constexpr range_difference_t ranges::distance(R&& r); \end{itemdecl} \begin{itemdescr} \pnum \effects -If \tcode{R} models \libconcept{SizedRange}, equivalent to: +If \tcode{R} models \libconcept{sized_range}, equivalent to: \begin{codeblock} -return ranges::size(r); // \ref{range.prim.size} +return static_cast>(ranges::size(r)); // \ref{range.prim.size} \end{codeblock} Otherwise, equivalent to: \begin{codeblock} @@ -2829,7 +2976,7 @@ \indexlibrary{\idxcode{next}}% \begin{itemdecl} -template +template constexpr I ranges::next(I x); \end{itemdecl} @@ -2840,7 +2987,7 @@ \indexlibrary{\idxcode{next}}% \begin{itemdecl} -template +template constexpr I ranges::next(I x, iter_difference_t n); \end{itemdecl} @@ -2851,7 +2998,7 @@ \indexlibrary{\idxcode{next}}% \begin{itemdecl} -template S> +template S> constexpr I ranges::next(I x, S bound); \end{itemdecl} @@ -2862,7 +3009,7 @@ \indexlibrary{\idxcode{next}}% \begin{itemdecl} -template S> +template S> constexpr I ranges::next(I x, iter_difference_t n, S bound); \end{itemdecl} @@ -2874,7 +3021,7 @@ \rSec3[range.iter.op.prev]{\tcode{ranges::prev}} \indexlibrary{\idxcode{prev}}% \begin{itemdecl} -template +template constexpr I ranges::prev(I x); \end{itemdecl} @@ -2885,7 +3032,7 @@ \indexlibrary{\idxcode{prev}}% \begin{itemdecl} -template +template constexpr I ranges::prev(I x, iter_difference_t n); \end{itemdecl} @@ -2896,7 +3043,7 @@ \indexlibrary{\idxcode{prev}}% \begin{itemdecl} -template +template constexpr I ranges::prev(I x, iter_difference_t n, I bound); \end{itemdecl} @@ -2950,7 +3097,7 @@ friend constexpr iter_rvalue_reference_t iter_move(const reverse_iterator& i) noexcept(@\seebelow@); - template Iterator2> + template Iterator2> friend constexpr void iter_swap(const reverse_iterator& x, const reverse_iterator& y) noexcept(@\seebelow@); @@ -2966,7 +3113,7 @@ \begin{itemize} \item \tcode{random_access_iterator_tag} if \tcode{Iterator} models -\libconcept{RandomAccessIterator}, and +\libconcept{random_access_iterator}, and \item \tcode{bidirectional_iterator_tag} otherwise. \end{itemize} @@ -2978,7 +3125,7 @@ \tcode{random_access_iterator_tag} if the type \tcode{iterator_traits<\brk{}Iterator>::iterator_category} models -\libconcept{DerivedFrom}, and +\tcode{\libconcept{derived_from}}, and \item \tcode{iterator_traits<\brk{}Iterator>::iterator_category} otherwise. \end{itemize} @@ -2991,7 +3138,7 @@ shall either meet the requirements of a \oldconcept{BidirectionalIterator}\iref{bidirectional.iterators} or model -\libconcept{BidirectionalIterator}\iref{iterator.concept.bidir}. +\libconcept{bidirectional_iterator}\iref{iterator.concept.bidir}. \pnum Additionally, @@ -2999,7 +3146,7 @@ shall either meet the requirements of a \oldconcept{RandomAccessIterator}\iref{random.access.iterators} or model -\libconcept{RandomAccessIterator}\iref{iterator.concept.random.access} +\libconcept{random_access_iterator}\iref{iterator.concept.random.access} if the definitions of any of the members \begin{itemize} \item @@ -3377,6 +3524,26 @@ \tcode{x.base() <= y.base()}. \end{itemdescr} +\indexlibrarymember{operator<=>}{reverse_iterator}% +\begin{itemdecl} +template Iterator2> + constexpr compare_three_way_result_t + operator<=>(const reverse_iterator& x, + const reverse_iterator& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{y.base() <=> x.base()}. + +\pnum +\begin{note} +The argument order in the \returns element is reversed +because this is a reverse iterator. +\end{note} +\end{itemdescr} + \rSec3[reverse.iter.nonmember]{Non-member functions} \indexlibrarymember{operator-}{reverse_iterator}% @@ -3431,7 +3598,7 @@ \indexlibrarymember{iter_swap}{reverse_iterator}% \begin{itemdecl} -template Iterator2> +template Iterator2> friend constexpr void iter_swap(const reverse_iterator& x, const reverse_iterator& y) noexcept(@\seebelow@); @@ -3909,7 +4076,8 @@ template constexpr move_iterator(const move_iterator& u); template constexpr move_iterator& operator=(const move_iterator& u); - constexpr iterator_type base() const; + constexpr iterator_type base() const &; + constexpr iterator_type base() &&; constexpr reference operator*() const; constexpr move_iterator& operator++(); @@ -3923,28 +4091,19 @@ constexpr move_iterator& operator-=(difference_type n); constexpr reference operator[](difference_type n) const; - template S> + template S> friend constexpr bool operator==(const move_iterator& x, const move_sentinel& y); - template S> - friend constexpr bool - operator==(const move_sentinel& x, const move_iterator& y); - template S> - friend constexpr bool - operator!=(const move_iterator& x, const move_sentinel& y); - template S> - friend constexpr bool - operator!=(const move_sentinel& x, const move_iterator& y); - template S> + template S> friend constexpr iter_difference_t operator-(const move_sentinel& x, const move_iterator& y); - template S> + template S> friend constexpr iter_difference_t operator-(const move_iterator& x, const move_sentinel& y); friend constexpr iter_rvalue_reference_t iter_move(const move_iterator& i) noexcept(noexcept(ranges::iter_move(i.current))); - template Iterator2> + template Iterator2> friend constexpr void iter_swap(const move_iterator& x, const move_iterator& y) noexcept(noexcept(ranges::iter_swap(x.current, y.current))); @@ -3962,7 +4121,7 @@ \tcode{random_access_iterator_tag} if the type \tcode{iterator_traits<\brk{}Iterator>::iterator_category} models -\libconcept{DerivedFrom<\tcode{random_access_iterator_tag}>}, and +\tcode{\libconcept{derived_from}}, and \item \tcode{iterator_traits<\brk{}Iterator>::iterator_category} otherwise. \end{itemize} @@ -3972,16 +4131,16 @@ \pnum The template parameter \tcode{Iterator} shall either meet the \oldconcept{InputIterator} requirements\iref{input.iterators} -or model \libconcept{InputIterator}\iref{iterator.concept.input}. +or model \libconcept{input_iterator}\iref{iterator.concept.input}. Additionally, if any of the bidirectional traversal functions are instantiated, the template parameter shall either meet the \oldconcept{BidirectionalIterator} requirements\iref{bidirectional.iterators} -or model \libconcept{BidirectionalIterator}\iref{iterator.concept.bidir}. +or model \libconcept{bidirectional_iterator}\iref{iterator.concept.bidir}. If any of the random access traversal functions are instantiated, the template parameter shall either meet the \oldconcept{RandomAccessIterator} requirements\iref{random.access.iterators} or model -\libconcept{RandomAccess\-Iterator}\iref{iterator.concept.random.access}. +\libconcept{random_access_iterator}\iref{iterator.concept.random.access}. \rSec3[move.iter.cons]{Construction and assignment} @@ -4007,7 +4166,7 @@ \begin{itemdescr} \pnum \effects Constructs a \tcode{move_iterator}, initializing -\tcode{current} with \tcode{i}. +\tcode{current} with \tcode{std::move(i)}. \end{itemdescr} @@ -4043,14 +4202,30 @@ \indexlibrarymember{base}{move_iterator}% \begin{itemdecl} -constexpr Iterator base() const; +constexpr Iterator base() const &; \end{itemdecl} \begin{itemdescr} +\pnum +\constraints \tcode{Iterator} satisfies \libconcept{copy_constructible}. + +\pnum +\expects \tcode{Iterator} models \libconcept{copy_constructible}. + \pnum \returns \tcode{current}. \end{itemdescr} +\indexlibrarymember{base}{move_iterator}% +\begin{itemdecl} +constexpr Iterator base() &&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns \tcode{std::move(current)}. +\end{itemdescr} + \rSec3[move.iter.elem]{Element access} \indexlibrarymember{operator*}{move_iterator}% @@ -4096,7 +4271,7 @@ \begin{itemdescr} \pnum \effects -If \tcode{Iterator} models \libconcept{ForwardIterator}, equivalent to: +If \tcode{Iterator} models \libconcept{forward_iterator}, equivalent to: \begin{codeblock} move_iterator tmp = *this; ++current; @@ -4187,12 +4362,9 @@ template constexpr bool operator==(const move_iterator& x, const move_iterator& y); -template S> +template S> friend constexpr bool operator==(const move_iterator& x, const move_sentinel& y); -template S> - friend constexpr bool operator==(const move_sentinel& x, - const move_iterator& y); \end{itemdecl} \begin{itemdescr} @@ -4205,29 +4377,6 @@ \returns \tcode{x.base() == y.base()}. \end{itemdescr} -\indexlibrarymember{operator"!=}{move_iterator}% -\begin{itemdecl} -template - constexpr bool operator!=(const move_iterator& x, - const move_iterator& y); -template S> - friend constexpr bool operator!=(const move_iterator& x, - const move_sentinel& y); -template S> - friend constexpr bool operator!=(const move_sentinel& x, - const move_iterator& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\constraints -\tcode{x.base() == y.base()} is well-formed and -convertible to \tcode{bool}. - -\pnum -\returns \tcode{!(x == y)}. -\end{itemdescr} - \indexlibrarymember{operator<}{move_iterator}% \begin{itemdecl} template @@ -4292,6 +4441,20 @@ \returns \tcode{!(x < y)}. \end{itemdescr} +\indexlibrarymember{operator<=>}{move_iterator}% +\begin{itemdecl} +template Iterator2> + constexpr compare_three_way_result_t + operator<=>(const move_iterator& x, + const move_iterator& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{x.base() <=> y.base()}. +\end{itemdescr} + \rSec3[move.iter.nonmember]{Non-member functions} \indexlibrarymember{operator-}{move_iterator}% @@ -4300,10 +4463,10 @@ constexpr auto operator-(const move_iterator& x, const move_iterator& y) -> decltype(x.base() - y.base()); -template S> +template S> friend constexpr iter_difference_t operator-(const move_sentinel& x, const move_iterator& y); -template S> +template S> friend constexpr iter_difference_t operator-(const move_iterator& x, const move_sentinel& y); \end{itemdecl} @@ -4343,7 +4506,7 @@ \indexlibrarymember{iter_swap}{move_iterator}% \begin{itemdecl} -template Iterator2> +template Iterator2> friend constexpr void iter_swap(const move_iterator& x, const move_iterator& y) noexcept(noexcept(ranges::iter_swap(x.current, y.current))); @@ -4370,9 +4533,9 @@ \pnum Class template \tcode{move_sentinel} is a sentinel adaptor useful for denoting ranges together with \tcode{move_iterator}. When an input iterator type -\tcode{I} and sentinel type \tcode{S} model \tcode{Sentinel}, +\tcode{I} and sentinel type \tcode{S} model \tcode{\libconcept{sentinel_for}}, \tcode{move_sentinel} and \tcode{move_iterator} model -\tcode{Sentinel, move_iterator{>}} as well. +\tcode{sentinel_for, move_iterator{>}} as well. \pnum \begin{example} @@ -4380,9 +4543,9 @@ \tcode{copy_if} using \tcode{move_iterator} and \tcode{move_sentinel}: \begin{codeblock} -template S, WeaklyIncrementable O, - IndirectUnaryPredicate Pred> - requires IndirectlyMovable +template S, weakly_incrementable O, + indirect_unary_predicate Pred> + requires indirectly_movable void move_if(I first, S last, O out, Pred pred) { std::ranges::copy_if(move_iterator{first}, move_sentinel{last}, out, pred); } @@ -4392,16 +4555,16 @@ \indexlibrary{\idxcode{move_sentinel}}% \begin{codeblock} namespace std { - template + template class move_sentinel { public: constexpr move_sentinel(); constexpr explicit move_sentinel(S s); template - requires ConvertibleTo + requires convertible_to constexpr move_sentinel(const move_sentinel& s); template - requires Assignable + requires assignable_from constexpr move_sentinel& operator=(const move_sentinel& s); constexpr S base() const; @@ -4438,7 +4601,7 @@ \indexlibrary{\idxcode{move_sentinel}!constructor}% \begin{itemdecl} template - requires ConvertibleTo + requires convertible_to constexpr move_sentinel(const move_sentinel& s); \end{itemdecl} @@ -4451,7 +4614,7 @@ \indexlibrary{\idxcode{move_sentinel}!\idxcode{operator=}}% \begin{itemdecl} template - requires Assignable + requires assignable_from constexpr move_sentinel& operator=(const move_sentinel& s); \end{itemdecl} @@ -4494,20 +4657,20 @@ \indexlibrary{\idxcode{common_iterator}}% \begin{codeblock} namespace std { - template S> - requires (!Same) + template S> + requires (!same_as) class common_iterator { public: constexpr common_iterator() = default; constexpr common_iterator(I i); constexpr common_iterator(S s); template - requires ConvertibleTo && ConvertibleTo + requires convertible_to && convertible_to constexpr common_iterator(const common_iterator& x); template - requires ConvertibleTo && ConvertibleTo && - Assignable && Assignable + requires convertible_to && convertible_to && + assignable_from && assignable_from common_iterator& operator=(const common_iterator& x); decltype(auto) operator*(); @@ -4519,28 +4682,24 @@ common_iterator& operator++(); decltype(auto) operator++(int); - template S2> - requires Sentinel + template S2> + requires sentinel_for friend bool operator==( const common_iterator& x, const common_iterator& y); - template S2> - requires Sentinel && EqualityComparableWith + template S2> + requires sentinel_for && equality_comparable_with friend bool operator==( const common_iterator& x, const common_iterator& y); - template S2> - requires Sentinel - friend bool operator!=( - const common_iterator& x, const common_iterator& y); - template I2, SizedSentinel S2> - requires SizedSentinel + template I2, sized_sentinel_for S2> + requires sized_sentinel_for friend iter_difference_t operator-( const common_iterator& x, const common_iterator& y); friend iter_rvalue_reference_t iter_move(const common_iterator& i) noexcept(noexcept(ranges::iter_move(declval()))) - requires InputIterator; - template I2, class S2> + requires input_iterator; + template I2, class S2> friend void iter_swap(const common_iterator& x, const common_iterator& y) noexcept(noexcept(ranges::iter_swap(declval(), declval()))); @@ -4553,7 +4712,7 @@ using difference_type = iter_difference_t; }; - template + template struct iterator_traits> { using iterator_concept = @\seebelow@; using iterator_category = @\seebelow@; @@ -4573,14 +4732,14 @@ \begin{itemize} \item \tcode{iterator_concept} denotes \tcode{forward_iterator_tag} -if \tcode{I} models \libconcept{ForwardIterator}; +if \tcode{I} models \libconcept{forward_iterator}; otherwise it denotes \tcode{input_iterator_tag}. \item \tcode{iterator_category} denotes \tcode{forward_iterator_tag} if \tcode{iterator_traits::iterator_category} -models \tcode{DerivedFrom}; +models \tcode{derived_from}; otherwise it denotes \tcode{input_iterator_tag}. \item @@ -4617,7 +4776,7 @@ \indexlibrary{\idxcode{common_iterator}!constructor}% \begin{itemdecl} template - requires ConvertibleTo && ConvertibleTo + requires convertible_to && convertible_to constexpr common_iterator(const common_iterator& x); \end{itemdecl} @@ -4635,8 +4794,8 @@ \indexlibrarymember{operator=}{common_iterator}% \begin{itemdecl} template - requires ConvertibleTo && ConvertibleTo && - Assignable && Assignable + requires convertible_to && convertible_to && + assignable_from && assignable_from common_iterator& operator=(const common_iterator& x); \end{itemdecl} @@ -4686,10 +4845,10 @@ \pnum The expression in the requires clause is equivalent to: \begin{codeblock} -Readable && +readable && (requires(const I& i) { i.operator->(); } || is_reference_v> || - Constructible, iter_reference_t>) + constructible_from, iter_reference_t>) \end{codeblock} \pnum @@ -4757,7 +4916,7 @@ \pnum \effects -If \tcode{I} models \libconcept{ForwardIterator}, equivalent to: +If \tcode{I} models \libconcept{forward_iterator}, equivalent to: \begin{codeblock} common_iterator tmp = *this; ++*this; @@ -4770,8 +4929,8 @@ \indexlibrarymember{operator==}{common_iterator}% \begin{itemdecl} -template S2> - requires Sentinel +template S2> + requires sentinel_for friend bool operator==( const common_iterator& x, const common_iterator& y); \end{itemdecl} @@ -4791,8 +4950,8 @@ \indexlibrarymember{operator==}{common_iterator}% \begin{itemdecl} -template S2> - requires Sentinel && EqualityComparableWith +template S2> + requires sentinel_for && equality_comparable_with friend bool operator==( const common_iterator& x, const common_iterator& y); \end{itemdecl} @@ -4810,23 +4969,10 @@ $i$ is \tcode{x.v_.index()} and $j$ is \tcode{y.v_.index()}. \end{itemdescr} -\indexlibrarymember{operator"!=}{common_iterator}% -\begin{itemdecl} -template S2> - requires Sentinel -friend bool operator!=( - const common_iterator& x, const common_iterator& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: \tcode{return !(x == y);} -\end{itemdescr} - \indexlibrarymember{operator-}{common_iterator}% \begin{itemdecl} -template I2, SizedSentinel S2> - requires SizedSentinel +template I2, sized_sentinel_for S2> + requires sized_sentinel_for friend iter_difference_t operator-( const common_iterator& x, const common_iterator& y); \end{itemdecl} @@ -4850,7 +4996,7 @@ \begin{itemdecl} friend iter_rvalue_reference_t iter_move(const common_iterator& i) noexcept(noexcept(ranges::iter_move(declval()))) - requires InputIterator; + requires input_iterator; \end{itemdecl} \begin{itemdescr} @@ -4863,7 +5009,7 @@ \indexlibrarymember{iter_swap}{common_iterator}% \begin{itemdecl} -template I2, class S2> +template I2, class S2> friend void iter_swap(const common_iterator& x, const common_iterator& y) noexcept(noexcept(ranges::iter_swap(declval(), declval()))); \end{itemdecl} @@ -4930,7 +5076,7 @@ \indexlibrary{\idxcode{counted_iterator}}% \begin{codeblock} namespace std { - template + template class counted_iterator { public: using iterator_type = I; @@ -4938,14 +5084,15 @@ constexpr counted_iterator() = default; constexpr counted_iterator(I x, iter_difference_t n); template - requires ConvertibleTo + requires convertible_to constexpr counted_iterator(const counted_iterator& x); template - requires Assignable + requires assignable_from constexpr counted_iterator& operator=(const counted_iterator& x); - constexpr I base() const; + constexpr I base() const & requires copy_constructible; + constexpr I base() &&; constexpr iter_difference_t count() const noexcept; constexpr decltype(auto) operator*(); constexpr decltype(auto) operator*() const @@ -4954,23 +5101,23 @@ constexpr counted_iterator& operator++(); decltype(auto) operator++(int); constexpr counted_iterator operator++(int) - requires ForwardIterator; + requires forward_iterator; constexpr counted_iterator& operator--() - requires BidirectionalIterator; + requires bidirectional_iterator; constexpr counted_iterator operator--(int) - requires BidirectionalIterator; + requires bidirectional_iterator; constexpr counted_iterator operator+(iter_difference_t n) const - requires RandomAccessIterator; + requires random_access_iterator; friend constexpr counted_iterator operator+( iter_difference_t n, const counted_iterator& x) - requires RandomAccessIterator; + requires random_access_iterator; constexpr counted_iterator& operator+=(iter_difference_t n) - requires RandomAccessIterator; + requires random_access_iterator; constexpr counted_iterator operator-(iter_difference_t n) const - requires RandomAccessIterator; - template I2> + requires random_access_iterator; + template I2> friend constexpr iter_difference_t operator-( const counted_iterator& x, const counted_iterator& y); friend constexpr iter_difference_t operator-( @@ -4978,44 +5125,25 @@ friend constexpr iter_difference_t operator-( default_sentinel_t, const counted_iterator& y); constexpr counted_iterator& operator-=(iter_difference_t n) - requires RandomAccessIterator; + requires random_access_iterator; constexpr decltype(auto) operator[](iter_difference_t n) const - requires RandomAccessIterator; + requires random_access_iterator; - template I2> + template I2> friend constexpr bool operator==( const counted_iterator& x, const counted_iterator& y); friend constexpr bool operator==( const counted_iterator& x, default_sentinel_t); - friend constexpr bool operator==( - default_sentinel_t, const counted_iterator& x); - - template I2> - friend constexpr bool operator!=( - const counted_iterator& x, const counted_iterator& y); - friend constexpr bool operator!=( - const counted_iterator& x, default_sentinel_t y); - friend constexpr bool operator!=( - default_sentinel_t x, const counted_iterator& y); - template I2> - friend constexpr bool operator<( - const counted_iterator& x, const counted_iterator& y); - template I2> - friend constexpr bool operator>( - const counted_iterator& x, const counted_iterator& y); - template I2> - friend constexpr bool operator<=( - const counted_iterator& x, const counted_iterator& y); - template I2> - friend constexpr bool operator>=( + template I2> + friend constexpr strong_ordering operator<=>( const counted_iterator& x, const counted_iterator& y); friend constexpr iter_rvalue_reference_t iter_move(const counted_iterator& i) noexcept(noexcept(ranges::iter_move(i.current))) - requires InputIterator; - template I2> + requires input_iterator; + template I2> friend constexpr void iter_swap(const counted_iterator& x, const counted_iterator& y) noexcept(noexcept(ranges::iter_swap(x.current, y.current))); @@ -5029,7 +5157,7 @@ using difference_type = iter_difference_t; }; - template + template struct iterator_traits> : iterator_traits { using pointer = void; }; @@ -5056,7 +5184,7 @@ \indexlibrary{\idxcode{counted_iterator}!constructor}% \begin{itemdecl} template - requires ConvertibleTo + requires convertible_to constexpr counted_iterator(const counted_iterator& x); \end{itemdecl} @@ -5070,7 +5198,7 @@ \indexlibrarymember{operator=}{counted_iterator}% \begin{itemdecl} template - requires Assignable + requires assignable_from constexpr counted_iterator& operator=(const counted_iterator& x); \end{itemdecl} @@ -5088,7 +5216,7 @@ \indexlibrarymember{base}{counted_iterator}% \begin{itemdecl} -constexpr I base() const; +constexpr I base() const & requires copy_constructible; \end{itemdecl} \begin{itemdescr} @@ -5096,6 +5224,16 @@ \effects Equivalent to: \tcode{return current;} \end{itemdescr} +\indexlibrarymember{base}{counted_iterator}% +\begin{itemdecl} +constexpr I base() &&; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns \tcode{std::move(current)}. +\end{itemdescr} + \indexlibrarymember{count}{counted_iterator}% \begin{itemdecl} constexpr iter_difference_t count() const noexcept; @@ -5123,7 +5261,7 @@ \indexlibrarymember{operator[]}{counted_iterator}% \begin{itemdecl} constexpr decltype(auto) operator[](iter_difference_t n) const - requires RandomAccessIterator; + requires random_access_iterator; \end{itemdecl} \begin{itemdescr} @@ -5175,7 +5313,7 @@ \indexlibrarymember{operator++}{counted_iterator}% \begin{itemdecl} constexpr counted_iterator operator++(int) - requires ForwardIterator; + requires forward_iterator; \end{itemdecl} \begin{itemdescr} @@ -5191,7 +5329,7 @@ \indexlibrarymember{operator{-}-}{counted_iterator}% \begin{itemdecl} constexpr counted_iterator& operator--(); - requires BidirectionalIterator + requires bidirectional_iterator \end{itemdecl} \begin{itemdescr} @@ -5207,7 +5345,7 @@ \indexlibrarymember{operator{-}-}{counted_iterator}% \begin{itemdecl} constexpr counted_iterator operator--(int) - requires BidirectionalIterator; + requires bidirectional_iterator; \end{itemdecl} \begin{itemdescr} @@ -5223,7 +5361,7 @@ \indexlibrarymember{operator+}{counted_iterator}% \begin{itemdecl} constexpr counted_iterator operator+(iter_difference_t n) const - requires RandomAccessIterator; + requires random_access_iterator; \end{itemdecl} \begin{itemdescr} @@ -5235,7 +5373,7 @@ \begin{itemdecl} friend constexpr counted_iterator operator+( iter_difference_t n, const counted_iterator& x) - requires RandomAccessIterator; + requires random_access_iterator; \end{itemdecl} \begin{itemdescr} @@ -5246,7 +5384,7 @@ \indexlibrarymember{operator+=}{counted_iterator}% \begin{itemdecl} constexpr counted_iterator& operator+=(iter_difference_t n) - requires RandomAccessIterator; + requires random_access_iterator; \end{itemdecl} \begin{itemdescr} @@ -5265,7 +5403,7 @@ \indexlibrarymember{operator-}{counted_iterator}% \begin{itemdecl} constexpr counted_iterator operator-(iter_difference_t n) const - requires RandomAccessIterator; + requires random_access_iterator; \end{itemdecl} \begin{itemdescr} @@ -5275,7 +5413,7 @@ \indexlibrarymember{operator-}{counted_iterator}% \begin{itemdecl} -template I2> +template I2> friend constexpr iter_difference_t operator-( const counted_iterator& x, const counted_iterator& y); \end{itemdecl} @@ -5316,7 +5454,7 @@ \indexlibrarymember{operator-=}{counted_iterator}% \begin{itemdecl} constexpr counted_iterator& operator-=(iter_difference_t n) - requires RandomAccessIterator; + requires random_access_iterator; \end{itemdecl} \begin{itemdescr} @@ -5336,7 +5474,7 @@ \indexlibrarymember{operator==}{counted_iterator}% \begin{itemdecl} -template I2> +template I2> friend constexpr bool operator==( const counted_iterator& x, const counted_iterator& y); \end{itemdecl} @@ -5355,8 +5493,6 @@ \begin{itemdecl} friend constexpr bool operator==( const counted_iterator& x, default_sentinel_t); -friend constexpr bool operator==( - default_sentinel_t, const counted_iterator& x); \end{itemdecl} \begin{itemdescr} @@ -5364,26 +5500,10 @@ \effects Equivalent to: \tcode{return x.length == 0;} \end{itemdescr} -\indexlibrarymember{operator"!=}{counted_iterator}% -\begin{itemdecl} -template I2> - friend constexpr bool operator!=( - const counted_iterator& x, const counted_iterator& y); -friend constexpr bool operator!=( - const counted_iterator& x, default_sentinel_t y); -friend constexpr bool operator!=( - default_sentinel_t x, const counted_iterator& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: \tcode{return !(x == y);} -\end{itemdescr} - -\indexlibrarymember{operator<}{counted_iterator}% +\indexlibrarymember{operator<=>}{counted_iterator}% \begin{itemdecl} -template I2> - friend constexpr bool operator<( +template I2> + friend constexpr strong_ordering operator<=>( const counted_iterator& x, const counted_iterator& y); \end{itemdecl} @@ -5394,51 +5514,16 @@ elements of the same sequence\iref{counted.iterator}. \pnum -\effects Equivalent to: \tcode{return y.length < x.length;} +\effects +Equivalent to: \tcode{return y.length <=> x.length;} \pnum \begin{note} -The argument order in the \effects{} element is reversed +The argument order in the \effects element is reversed because \tcode{length} counts down, not up. \end{note} \end{itemdescr} -\indexlibrarymember{operator>}{counted_iterator}% -\begin{itemdecl} -template I2> - friend constexpr bool operator>( - const counted_iterator& x, const counted_iterator& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: \tcode{return y < x;} -\end{itemdescr} - -\indexlibrarymember{operator<=}{counted_iterator}% -\begin{itemdecl} -template I2> - friend constexpr bool operator<=( - const counted_iterator& x, const counted_iterator& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: \tcode{return !(y < x);} -\end{itemdescr} - -\indexlibrarymember{operator>=}{counted_iterator}% -\begin{itemdecl} -template I2> - friend constexpr bool operator>=( - const counted_iterator& x, const counted_iterator& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: \tcode{return !(x < y);} -\end{itemdescr} - \rSec3[counted.iter.cust]{Customizations} \indexlibrarymember{iter_move}{counted_iterator}% @@ -5446,7 +5531,7 @@ friend constexpr iter_rvalue_reference_t iter_move(const counted_iterator& i) noexcept(noexcept(ranges::iter_move(i.current))) - requires InputIterator; + requires input_iterator; \end{itemdecl} \begin{itemdescr} @@ -5456,7 +5541,7 @@ \indexlibrarymember{iter_swap}{counted_iterator}% \begin{itemdecl} -template I2> +template I2> friend constexpr void iter_swap(const counted_iterator& x, const counted_iterator& y) noexcept(noexcept(ranges::iter_swap(x.current, y.current))); @@ -5474,7 +5559,7 @@ \indexlibrary{\idxcode{unreachable_sentinel_t}}% \pnum Class \tcode{unreachable_sentinel_t} can be used with -any \libconcept{WeaklyIncrementable} type +any \libconcept{weakly_incrementable} type to denote the ``upper bound'' of an unbounded interval. \pnum @@ -5491,51 +5576,17 @@ conditional branch. \end{example} +\indexlibrarymember{operator==}{unreachable_sentinel_t}% \begin{codeblock} namespace std { struct unreachable_sentinel_t { - template - friend constexpr bool operator==(unreachable_sentinel_t, const I&) noexcept; - template - friend constexpr bool operator==(const I&, unreachable_sentinel_t) noexcept; - template - friend constexpr bool operator!=(unreachable_sentinel_t, const I&) noexcept; - template - friend constexpr bool operator!=(const I&, unreachable_sentinel_t) noexcept; + template + friend constexpr bool operator==(unreachable_sentinel_t, const I&) noexcept + { return false; } }; } \end{codeblock} -\rSec3[unreachable.sentinel.cmp]{Comparisons} - -\indexlibrary{\idxcode{operator==}!\idxcode{unreachable_sentinel_t}}% -\indexlibrary{\idxcode{unreachable_sentinel_t}!\idxcode{operator==}}% -\begin{itemdecl} -template - friend constexpr bool operator==(unreachable_sentinel_t, const I&) noexcept; -template - friend constexpr bool operator==(const I&, unreachable_sentinel_t) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{false}. -\end{itemdescr} - -\indexlibrary{\idxcode{operator"!=}!\idxcode{unreachable_sentinel_t}}% -\indexlibrary{\idxcode{unreachable_sentinel_t}!\idxcode{operator"!=}}% -\begin{itemdecl} -template - friend constexpr bool operator!=(unreachable_sentinel_t, const I&) noexcept; -template - friend constexpr bool operator!=(const I&, unreachable_sentinel_t) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{true}. -\end{itemdescr} - \rSec1[stream.iterators]{Stream iterators} \pnum @@ -5593,9 +5644,6 @@ istream_iterator operator++(int); friend bool operator==(const istream_iterator& i, default_sentinel_t); - friend bool operator==(default_sentinel_t, const istream_iterator& i); - friend bool operator!=(const istream_iterator& x, default_sentinel_t y); - friend bool operator!=(default_sentinel_t x, const istream_iterator& y); private: basic_istream* in_stream; // \expos @@ -5760,7 +5808,6 @@ \indexlibrarymember{operator==}{istream_iterator}% \begin{itemdecl} -friend bool operator==(default_sentinel_t, const istream_iterator& i); friend bool operator==(const istream_iterator& i, default_sentinel_t); \end{itemdecl} @@ -5770,21 +5817,6 @@ \tcode{!i.in_stream}. \end{itemdescr} -\indexlibrarymember{operator"!=}{istream_iterator}% -\begin{itemdecl} -template - bool operator!=(const istream_iterator& x, - const istream_iterator& y); -friend bool operator!=(default_sentinel_t x, const istream_iterator& y); -friend bool operator!=(const istream_iterator& x, default_sentinel_t y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{!(x == y)} -\end{itemdescr} - \rSec2[ostream.iterator]{Class template \tcode{ostream_iterator}} \pnum @@ -5974,10 +6006,7 @@ @\placeholder{proxy}@ operator++(int); bool equal(const istreambuf_iterator& b) const; - friend bool operator==(default_sentinel_t s, const istreambuf_iterator& i); friend bool operator==(const istreambuf_iterator& i, default_sentinel_t s); - friend bool operator!=(default_sentinel_t a, const istreambuf_iterator& b); - friend bool operator!=(const istreambuf_iterator& a, default_sentinel_t b); private: streambuf_type* sbuf_; // \expos @@ -6144,7 +6173,6 @@ \indexlibrarymember{operator==}{istreambuf_iterator}% \begin{itemdecl} -friend bool operator==(default_sentinel_t s, const istreambuf_iterator& i); friend bool operator==(const istreambuf_iterator& i, default_sentinel_t s); \end{itemdecl} @@ -6153,21 +6181,6 @@ \returns \tcode{i.equal(s)}. \end{itemdescr} -\indexlibrarymember{operator"!=}{istreambuf_iterator}% -\begin{itemdecl} -template - bool operator!=(const istreambuf_iterator& a, - const istreambuf_iterator& b); -friend bool operator!=(default_sentinel_t a, const istreambuf_iterator& b); -friend bool operator!=(const istreambuf_iterator& a, default_sentinel_t b); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{!a.equal(b)}. -\end{itemdescr} - \rSec2[ostreambuf.iterator]{Class template \tcode{ostreambuf_iterator}} \pnum diff --git a/source/lex.tex b/source/lex.tex index 24dda44cd0..647871d028 100644 --- a/source/lex.tex +++ b/source/lex.tex @@ -273,6 +273,7 @@ \begin{bnf} \nontermdef{preprocessing-token}\br header-name\br + import-keyword\br identifier\br pp-number\br character-literal\br @@ -338,17 +339,13 @@ except that a \grammarterm{header-name}\iref{lex.header} is only formed \begin{itemize} \item -within a \tcode{\#include} directive\iref{cpp.include}, +after the \tcode{include} or \tcode{import} preprocessing token in an +\tcode{\#include}\iref{cpp.include} or +\tcode{import}\iref{cpp.import} directive, or \item -within a \grammarterm{has-include-expression}, or +within a \grammarterm{has-include-expression}. -\item -outside of any preprocessing directive, -if applying phase 4 of translation to the sequence -of preprocessing tokens produced thus far -is valid and -results in an \grammarterm{import-seq}\iref{cpp.module}. \end{itemize} \end{itemize} @@ -359,6 +356,11 @@ \end{codeblock} \end{example} +\pnum +The \grammarterm{import-keyword} is produced +by processing an \tcode{import} directive\iref{cpp.import} and +has no associated grammar productions. + \pnum \begin{example} The program fragment \tcode{0xe+foo} is parsed as a preprocessing number token (one that is not a valid floating or integer @@ -659,8 +661,6 @@ \end{floattable} \pnum -\indextext{\idxcode{audit}}% -\indextext{\idxcode{axiom}}% \indextext{\idxcode{import}}% \indextext{\idxcode{final}}% \indextext{\idxcode{module}}% @@ -673,14 +673,13 @@ token as a regular \grammarterm{identifier}. \begin{multicolfloattable}{Identifiers with special meaning}{lex.name.special} -{lll} -\keyword{audit} \\ -\keyword{axiom} \\ -\columnbreak +{llll} \keyword{final} \\ +\columnbreak \keyword{import} \\ \columnbreak \keyword{module} \\ +\columnbreak \keyword{override} \\ \end{multicolfloattable} @@ -735,8 +734,9 @@ \keyword{concept} \\ \keyword{const} \\ \keyword{consteval} \\ -\columnbreak \keyword{constexpr} \\ +\columnbreak +\keyword{constinit} \\ \keyword{const_cast} \\ \keyword{continue} \\ \keyword{co_await} \\ @@ -752,8 +752,8 @@ \keyword{enum} \\ \keyword{explicit} \\ \keyword{export} \\ -\columnbreak \keyword{extern} \\ +\columnbreak \keyword{false} \\ \keyword{float} \\ \keyword{for} \\ @@ -769,9 +769,9 @@ \keyword{noexcept} \\ \keyword{nullptr} \\ \keyword{operator} \\ -\columnbreak \keyword{private} \\ \keyword{protected} \\ +\columnbreak \keyword{public} \\ \keyword{register} \\ \keyword{reinterpret_cast} \\ @@ -786,10 +786,10 @@ \keyword{struct} \\ \keyword{switch} \\ \keyword{template} \\ -\columnbreak \keyword{this} \\ \keyword{thread_local} \\ \keyword{throw} \\ +\columnbreak \keyword{true} \\ \keyword{try} \\ \keyword{typedef} \\ diff --git a/source/lib-intro.tex b/source/lib-intro.tex index 049ba253ce..a02432e3f0 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -512,7 +512,7 @@ requirement. Names in \tcode{constant width} type refer to library concepts which are presented as a concept definition\iref{temp}, possibly with additional prose semantic requirements. For example, -\libconcept{Destructible}\iref{concept.destructible} +\libconcept{destructible}\iref{concept.destructible} is such a named requirement. \pnum @@ -532,8 +532,8 @@ total functions; that is, some arguments to a required operation may result in the required semantics failing to be met. \begin{example} -The required \tcode{<} operator of the \libconcept{StrictTotallyOrdered} -concept\iref{concept.stricttotallyordered} does not meet the +The required \tcode{<} operator of the \libconcept{totally_ordered} +concept\iref{concept.totallyordered} does not meet the semantic requirements of that concept when operating on NaNs. \end{example} This does not affect whether a type models the concept. @@ -609,12 +609,6 @@ \item \expects the conditions (sometimes termed preconditions) that the function assumes to hold whenever it is called. -\begin{example} -An implementation might express such conditions -via an attribute such as \tcode{[[expects]]}\iref{dcl.attr.contract}. -However, some such conditions might not lend themselves -to expression via code. -\end{example} \item \effects the actions performed by the function. @@ -713,13 +707,32 @@ The declaration of such a function is followed by a comment ending in \expos. \pnum -The following function is defined for exposition only +The following are defined for exposition only to aid in the specification of the library: \indexlibrary{decay-copy@\tcode{\placeholder{decay-copy}}}% \begin{codeblock} template constexpr decay_t @\placeholdernc{decay-copy}@(T&& v) noexcept(is_nothrow_convertible_v>) // \expos { return std::forward(v); } + +constexpr auto @\placeholdernc{synth-three-way}@ = + [](const T& t, const U& u) + requires requires { + { t < u } -> convertible_to; + { u < t } -> convertible_to; + } + { + if constexpr (three_way_comparable_with) { + return t <=> u; + } else { + if (t < u) return weak_ordering::less; + if (u < t) return weak_ordering::greater; + return weak_ordering::equivalent; + } + }; + +template +using @\placeholdernc{synth-three-way-result}@ = decltype(@\placeholdernc{synth-three-way}@(declval(), declval())); \end{codeblock} \rSec3[type.descriptions]{Type descriptions} @@ -998,7 +1011,7 @@ \pnum The type of a customization point object shall model -\libconcept{Semiregular}\iref{concepts.object}. +\libconcept{semiregular}\iref{concepts.object}. \pnum All instances of a specific customization point object type shall @@ -1006,7 +1019,7 @@ \pnum The type \tcode{T} of a customization point object shall model -\tcode{\libconcept{Invocable}}\iref{concept.invocable} +\tcode{\libconcept{invocable}}\iref{concept.invocable} when the types in \tcode{Args...} meet the requirements specified in that customization point object's definition. When the types of \tcode{Args...} do not meet the customization point object's requirements, \tcode{T} shall not have @@ -1046,75 +1059,6 @@ the implementation provides explicit definitions for such member function signatures, or for virtual destructors that can be generated by default. -\rSec3[operators]{Operators} - -\pnum -In this library, whenever a declaration is provided for an \tcode{operator!=}, -\tcode{operator>}, \tcode{operator<=}, or \tcode{operator>=} -for a type \tcode{T}, -its requirements and semantics are as follows, -unless explicitly specified otherwise. - -\indexlibrary{\idxcode{operator"!=}}% -\begin{itemdecl} -bool operator!=(const T& x, const T& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\requires -Type \tcode{T} is \oldconcept{EqualityComparable} (\tref{cpp17.equalitycomparable}). - -\pnum -\returns -\tcode{!(x == y)}. -\end{itemdescr} - -\indexlibrary{\idxcode{operator>}}% -\begin{itemdecl} -bool operator>(const T& x, const T& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\requires -Type \tcode{T} is \oldconcept{LessThanComparable} (\tref{cpp17.lessthancomparable}). - -\pnum -\returns -\tcode{y < x}. -\end{itemdescr} - -\indexlibrary{\idxcode{operator<=}}% -\begin{itemdecl} -bool operator<=(const T& x, const T& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\requires -Type \tcode{T} is \oldconcept{LessThanComparable} (\tref{cpp17.lessthancomparable}). - -\pnum -\returns -\tcode{!(y < x)}. -\end{itemdescr} - -\indexlibrary{\idxcode{operator>=}}% -\begin{itemdecl} -bool operator>=(const T& x, const T& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\requires -Type \tcode{T} is \oldconcept{LessThanComparable} (\tref{cpp17.lessthancomparable}). - -\pnum -\returns -\tcode{!(x < y)}. -\end{itemdescr} - \rSec3[objects.within.classes]{Private members} \pnum @@ -1220,6 +1164,7 @@ \tcode{} \\ \tcode{} \\ \tcode{} \\ +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -1229,11 +1174,12 @@ \tcode{} \\ \tcode{} \\ \tcode{} \\ -\tcode{} \\ +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ +\tcode{} \\ \columnbreak \tcode{} \\ \tcode{} \\ @@ -1246,6 +1192,7 @@ \tcode{} \\ \tcode{} \\ \tcode{} \\ +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -1253,8 +1200,9 @@ \tcode{} \\ \tcode{} \\ \tcode{} \\ -\columnbreak \tcode{} \\ +\columnbreak +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -1264,15 +1212,18 @@ \tcode{} \\ \tcode{} \\ \tcode{} \\ +\tcode{} \\ \tcode{} \\ \tcode{} \\ +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ +\tcode{} \\ \tcode{} \\ -\tcode{} \\ \columnbreak +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -1332,6 +1283,23 @@ \tcode{} \\ \end{multicolfloattable} +\pnum +The headers listed in \tref{headers.cpp}, or, +for a freestanding implementation, +the subset of such headers that are provided by the implementation, +are collectively known as +the \defnadj{importable}{\Cpp{} library headers}. +\begin{note} +Importable \Cpp{} library headers can be +imported as module units\iref{module.import}. +\end{note} +\begin{example} +\begin{codeblock} +import ; // imports the \tcode{} header unit +std::vector vi; // OK +\end{codeblock} +\end{example} + \pnum Except as noted in \ref{library} through \ref{\lastlibchapter} and \ref{depr}, the contents of each header \tcode{c\placeholder{name}} is @@ -1501,6 +1469,7 @@ \ref{support.start.term} & Start and termination & \tcode{} \\ \rowsep \ref{support.dynamic} & Dynamic memory management & \tcode{} \\ \rowsep \ref{support.rtti} & Type identification & \tcode{} \\ \rowsep +\ref{support.srcloc} & Source location & \tcode{} \\ \rowsep \ref{support.exception} & Exception handling & \tcode{} \\ \rowsep \ref{support.initlist} & Initializer lists & \tcode{} \\ \rowsep \ref{support.coroutine} & Coroutines support & \tcode{} \\ \rowsep @@ -1527,7 +1496,18 @@ and \indexlibrary{\idxcode{quick_exit}}% \tcode{quick_exit}\iref{support.start.term}. -The other headers listed in this table shall meet the same requirements as for a hosted implementation. +The supplied version of the header \tcode{} +shall meet the same requirements as for a hosted implementation +except that support for +always lock-free integral atomic types\iref{atomics.lockfree} +is \impldef{support for always lock-free integral atomic types in +freestanding environments}, and +whether or not the type aliases \tcode{atomic_signed_lock_free} and +\tcode{atomic_unsigned_lock_free} are defined\iref{atomics.alias} +is \impldef{type aliases \idxcode{atomic_signed_lock_free} and +\idxcode{atomic_unsigned_lock_free} in freestanding environments}. +The other headers listed in this table +shall meet the same requirements as for a hosted implementation. \rSec2[using]{Using the library} @@ -1545,9 +1525,12 @@ The entities in the \Cpp{} standard library are defined in headers, whose contents are made available to a translation unit when it contains the appropriate \indextext{unit!translation}% -\tcode{\#include} -preprocessing directive\iref{cpp.include}.% \indextext{\idxcode{\#include}}% +\tcode{\#include} +preprocessing directive\iref{cpp.include} +or the appropriate +\indextext{\idxcode{import}}% +\tcode{import} declaration\iref{module.import}. \indextext{source file} \pnum @@ -1569,7 +1552,10 @@ \pnum A translation unit shall include a header only outside of any \indextext{unit!translation}% -declaration or definition, and shall include the header lexically +declaration or definition and, +in the case of a module unit, +only in its \grammarterm{global-module-fragment}, and +shall include the header or import the corresponding header unit lexically before the first reference in that translation unit to any of the entities declared in that header. No diagnostic is required. @@ -1743,7 +1729,12 @@ {p{1in}p{4.15in}} \topline \hdstyle{Expression} & \hdstyle{Post-condition} \\ \capsep -\tcode{u.\~T()} & All resources owned by \tcode{u} are reclaimed, no exception is propagated. \\ +\tcode{u.\~T()} & All resources owned by \tcode{u} are reclaimed, no exception is propagated. \\ \rowsep +\multicolumn{2}{|l|}{ + \begin{note} + Array types and non-object types are not \oldconcept{Destructible}. + \end{note} +} \\ \end{concepttable} \rSec3[swappable.requirements]{Swappable requirements} @@ -2031,8 +2022,6 @@ \tcode{args} & a function parameter pack with the pattern \tcode{Args\&\&} \\ \end{libreqtab2} -\clearpage - \begin{libreqtab4d} {\oldconcept{Allocator} requirements} {cpp17.allocator} @@ -2631,9 +2620,8 @@ A translation unit shall not \tcode{\#define} or \tcode{\#undef} names lexically identical to keywords, -to the identifiers listed in \tref{lex.name.special}, -to the \grammarterm{attribute-token}{s} described in~\ref{dcl.attr}, or -to the identifiers \tcode{expects} or \tcode{ensures}, +to the identifiers listed in \tref{lex.name.special}, or +to the \grammarterm{attribute-token}{s} described in~\ref{dcl.attr}, except that the names \tcode{likely} and \tcode{unlikely} may be defined as function-like macros~\iref{cpp.replace}. @@ -2884,17 +2872,17 @@ \begin{itemize} \item -for replacement functions\iref{new.delete}, if the installed replacement function does not +For replacement functions\iref{new.delete}, if the installed replacement function does not implement the semantics of the applicable \required paragraph. \item -for handler functions~(\ref{new.handler}, \ref{terminate.handler}), +For handler functions~(\ref{new.handler}, \ref{terminate.handler}), if the installed handler function does not implement the semantics of the applicable \required -paragraph +paragraph. \item -for types used as template arguments when instantiating a template component, +For types used as template arguments when instantiating a template component, if the operations on the type do not implement the semantics of the applicable \emph{Requirements} subclause~(\ref{allocator.requirements}, \ref{container.requirements}, \ref{iterator.requirements}, @@ -2902,13 +2890,13 @@ Operations on such types can report a failure by throwing an exception unless otherwise specified. \item -if any replacement function or handler function or destructor operation exits via an exception, +If any replacement function or handler function or destructor operation exits via an exception, unless specifically allowed in the applicable \required paragraph. \item -if an incomplete type\iref{basic.types} is used as a template +If an incomplete type\iref{basic.types} is used as a template argument when instantiating a template component or evaluating a concept, unless specifically allowed for that component. \end{itemize} diff --git a/source/locales.tex b/source/locales.tex index 06c5c740cd..11a2836e83 100644 --- a/source/locales.tex +++ b/source/locales.tex @@ -147,7 +147,6 @@ basic_string name() const; bool operator==(const locale& other) const; - bool operator!=(const locale& other) const; template bool operator()(const basic_string& s1, @@ -808,16 +807,6 @@ otherwise. \end{itemdescr} -\indexlibrarymember{locale}{operator"!=}% -\begin{itemdecl} -bool operator!=(const locale& other) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{!(*this == other)}. -\end{itemdescr} - \indexlibrarymember{locale}{operator()}% \begin{itemdecl} template @@ -4826,11 +4815,13 @@ \pnum \returns The specializations required in \tref{locale.spec}\iref{locale.category}, namely -\tcode{moneypunct}, -\tcode{moneypunct<\brk{}wchar_t>}, -\tcode{moneypunct}, +\begin{itemize} +\item \tcode{moneypunct}, +\item \tcode{moneypunct}, +\item \tcode{moneypunct}, and -\tcode{moneypunct}, +\item \tcode{moneypunct}, +\end{itemize} return an object of type \tcode{pattern} initialized to diff --git a/source/macros.tex b/source/macros.tex index 0659030280..5e81f4df44 100644 --- a/source/macros.tex +++ b/source/macros.tex @@ -165,6 +165,7 @@ \newcommand{\idxcode}[1]{#1@\tcode{#1}} \newcommand{\idxhdr}[1]{#1@\tcode{<#1>}} \newcommand{\idxgram}[1]{#1@\gterm{#1}} +\newcommand{\idxterm}[1]{#1@\term{#1}} \newcommand{\idxxname}[1]{__#1@\xname{#1}} % class member library index @@ -331,6 +332,12 @@ \newcommand{\oldconcept}[1]{\textit{Cpp17#1}} \newcommand{\oldconceptdefn}[1]{\defn{Cpp17#1}} \newcommand{\idxoldconcept}[1]{Cpp17#1@\textit{Cpp17#1}} +% FIXME: A "new" oldconcept (added after C++17), +% which doesn't get a Cpp17 prefix. +\newcommand{\newoldconcept}[1]{\textit{#1}} +\newcommand{\newoldconceptdefn}[1]{\defn{#1}} +\newcommand{\idxnewoldconcept}[1]{#1@\textit{#1}} + \newcommand{\libconcept}[1]{\tcode{#1}} %% Ranges diff --git a/source/modules.tex b/source/modules.tex index f36a1c3c7e..005a7ef1e3 100644 --- a/source/modules.tex +++ b/source/modules.tex @@ -34,6 +34,16 @@ The identifiers \tcode{module} and \tcode{import} shall not appear as \grammarterm{identifier}{s} in a \grammarterm{module-name} or \grammarterm{module-partition}. +\indextext{module!reserved name of}% +All \grammarterm{module-name}{s} either beginning with an \grammarterm{identifier} +consisting of \tcode{std} followed by zero or more \grammarterm{digit}{s} or +containing a reserved identifier\iref{lex.name} +are reserved and shall not be specified in a \grammarterm{module-declaration}; +no diagnostic is required. +If any \grammarterm{identifier} in a reserved \grammarterm{module-name} +is a reserved identifier, +the module name is reserved for use by \Cpp{} implementations; +otherwise it is reserved for future standardization. The optional \grammarterm{attribute-specifier-seq} appertains to the \grammarterm{module-declaration}. @@ -411,9 +421,9 @@ \begin{bnf} \nontermdef{module-import-declaration}\br - \opt{\keyword{export}} \keyword{import} module-name \opt{attribute-specifier-seq} \terminal{;}\br - \opt{\keyword{export}} \keyword{import} module-partition \opt{attribute-specifier-seq} \terminal{;}\br - \opt{\keyword{export}} \keyword{import} header-name \opt{attribute-specifier-seq} \terminal{;} + \opt{\keyword{export}} import-keyword module-name \opt{attribute-specifier-seq} \terminal{;}\br + \opt{\keyword{export}} import-keyword module-partition \opt{attribute-specifier-seq} \terminal{;}\br + \opt{\keyword{export}} import-keyword header-name \opt{attribute-specifier-seq} \terminal{;} \end{bnf} \pnum @@ -466,7 +476,8 @@ \end{note} An \defnadj{importable}{header} is a member of an \impldef{how the set of importable headers is determined} -set of headers. +set of headers that +includes all importable \Cpp{} library headers\iref{headers}. \tcode{H} shall identify an importable header. Two \grammarterm{module-import-declaration}{s} @@ -478,7 +489,7 @@ a \grammarterm{header-name} is also recognized by the preprocessor, and results in macros defined at the end of phase 4 of translation of the header unit -being made visible as described in \ref{cpp.module}. +being made visible as described in \ref{cpp.import}. \end{note} A declaration of a name with internal linkage is permitted within a header unit despite all @@ -736,7 +747,7 @@ // even though it is not used in this call } template int use_g() { - N::X x; // \tcode{N::X}, \tcode{N}, and \tcode{::} are decl-reachable from \tcode{use_f} + N::X x; // \tcode{N::X}, \tcode{N}, and \tcode{::} are decl-reachable from \tcode{use_g} return g((T(), x)); // \tcode{N::g} is not decl-reachable from \tcode{use_g} } template int use_h() { @@ -858,7 +869,7 @@ \item the point at the end of translation unit \#3, and \item the point of the call to \tcode{g(0)}, \end{itemize} -so the definition of \tcode{X} is not necessarily reachable, +so the definition of \tcode{X} need not be reachable, as described in \ref{module.reach}. \end{example} @@ -897,16 +908,14 @@ \pnum A declaration $D$ is -\defnx{reachable}{reachable!declaration} or -\defnx{necessarily reachable}{reachable!necessarily!declaration}, -respectively, if, +\defnx{reachable}{reachable!declaration} if, for any point $P$ in the instantiation context\iref{module.context}, \begin{itemize} \item $D$ appears prior to $P$ in the same translation unit, or \item $D$ is not discarded\iref{module.global}, appears in a translation unit that is -reachable or necessarily reachable from $P$, respectively, +reachable from $P$, and either does not appear within a \grammarterm{private-module-fragment} or appears in a \grammarterm{private-module-fragment} diff --git a/source/numerics.tex b/source/numerics.tex index 5f1defb9d6..7dbfdb9854 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -12,8 +12,8 @@ complex number types, random number generation, numeric (% \textit{n}-at-a-time) -arrays, generalized numeric algorithms, -and mathematical functions for floating-point types, +arrays, generalized numeric algorithms, and +mathematical constants and functions for floating-point types, as summarized in \tref{numerics.summary}. \begin{libsumtab}{Numerics library summary}{numerics.summary} @@ -24,7 +24,8 @@ \ref{rand} & Random number generation & \tcode{} \\ \rowsep \ref{numarray} & Numeric arrays & \tcode{} \\ \rowsep \ref{c.math} & Mathematical functions for floating-point types & - \tcode{}, \tcode{} \\ + \tcode{}, \tcode{} \\ \rowsep +\ref{numbers} & Numbers & \tcode{} \\ \end{libsumtab} \rSec1[numeric.requirements]{Numeric type requirements} @@ -162,7 +163,9 @@ The floating-point environment has thread storage duration\iref{basic.stc.thread}. The initial state for a thread's floating-point environment is the state of the floating-point environment of the thread that constructs -the corresponding \tcode{thread} object\iref{thread.thread.class} at the time it +the corresponding \tcode{thread} object\iref{thread.thread.class} +or \tcode{jthread} object\iref{thread.jthread.class} +at the time it constructed the object. \begin{note} That is, the child thread gets the floating-point state of the parent thread at the time of the child's creation. \end{note} @@ -247,11 +250,6 @@ template constexpr bool operator==(const complex&, const complex&); template constexpr bool operator==(const complex&, const T&); - template constexpr bool operator==(const T&, const complex&); - - template constexpr bool operator!=(const complex&, const complex&); - template constexpr bool operator!=(const complex&, const T&); - template constexpr bool operator!=(const T&, const complex&); template basic_istream& operator>>(basic_istream&, complex&); @@ -739,7 +737,6 @@ \begin{itemdecl} template constexpr bool operator==(const complex& lhs, const complex& rhs); template constexpr bool operator==(const complex& lhs, const T& rhs); -template constexpr bool operator==(const T& lhs, const complex& rhs); \end{itemdecl} \begin{itemdescr} @@ -756,19 +753,6 @@ arguments. \end{itemdescr} -\indexlibrarymember{operator"!=}{complex}% -\begin{itemdecl} -template constexpr bool operator!=(const complex& lhs, const complex& rhs); -template constexpr bool operator!=(const complex& lhs, const T& rhs); -template constexpr bool operator!=(const T& lhs, const complex& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{rhs.real() != lhs.real() || rhs.imag() != lhs.imag()}. -\end{itemdescr} - \indexlibrarymember{operator>>}{complex}% \begin{itemdecl} template @@ -1247,7 +1231,6 @@ \rSec2[complex.literals]{Suffixes for complex number literals} \indextext{literal!complex}% -\indexlibrary{\tcode{complex}!literals}% \pnum This subclause describes literal suffixes for constructing complex number literals. The suffixes \tcode{i}, \tcode{il}, and \tcode{if} create complex numbers of @@ -1305,18 +1288,43 @@ \begin{codeblock} namespace std { // \ref{bit.cast}, \tcode{bit_cast} - template + template constexpr To bit_cast(const From& from) noexcept; // \ref{bit.pow.two}, integral powers of 2 template constexpr bool ispow2(T x) noexcept; template - constexpr T ceil2(T x) noexcept; + constexpr T ceil2(T x); template constexpr T floor2(T x) noexcept; template constexpr T log2p1(T x) noexcept; + + // \ref{bit.rotate}, rotating + template + [[nodiscard]] constexpr T rotl(T x, int s) noexcept; + template + [[nodiscard]] constexpr T rotr(T x, int s) noexcept; + + // \ref{bit.count}, counting + template + constexpr int countl_zero(T x) noexcept; + template + constexpr int countl_one(T x) noexcept; + template + constexpr int countr_zero(T x) noexcept; + template + constexpr int countr_one(T x) noexcept; + template + constexpr int popcount(T x) noexcept; + + // \ref{bit.endian}, endian + enum class endian { + little = @\seebelow@, + big = @\seebelow@, + native = @\seebelow@ + }; } \end{codeblock} @@ -1324,7 +1332,7 @@ \indexlibrary{\idxcode{bit_cast}}% \begin{itemdecl} -template +template constexpr To bit_cast(const From& from) noexcept; \end{itemdecl} @@ -1382,21 +1390,34 @@ \indexlibrary{\idxcode{ceil2}}% \begin{itemdecl} template - constexpr T ceil2(T x) noexcept; + constexpr T ceil2(T x); \end{itemdecl} \begin{itemdescr} +\pnum +Let $N$ be the smallest power of 2 greater than or equal to \tcode{x}. + +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +\expects +$N$ is representable as a value of type \tcode{T}. + \pnum \returns -The minimal value \tcode{y} such that -\tcode{ispow2(y)} is \tcode{true} and \tcode{y >= x}; -if \tcode{y} is not representable as a value of type \tcode{T}, -the result is an unspecified value. +$N$. + +\pnum +\throws +Nothing. \pnum \remarks -This function shall not participate in overload resolution -unless \tcode{T} is an unsigned integer type\iref{basic.fundamental}. +A function call expression +that violates the precondition in the \expects element +is not a core constant expression\iref{expr.const}. \end{itemdescr} \indexlibrary{\idxcode{floor2}}% @@ -1437,6 +1458,190 @@ unless \tcode{T} is an unsigned integer type\iref{basic.fundamental}. \end{itemdescr} +\rSec2[bit.rotate]{Rotating} + +In the following descriptions, +let \tcode{N} denote \tcode{numeric_limits::digits}. + +\begin{itemdecl} +template + [[nodiscard]] constexpr T rotl(T x, int s) noexcept; +\end{itemdecl} + +\indexlibrary{\idxcode{rotl}}% +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +Let \tcode{r} be \tcode{s \% N}. + +\pnum +\returns +If \tcode{r} is \tcode{0}, \tcode{x}; +if \tcode{r} is positive, \tcode{(x << r) | (x >> (N - r))}; +if \tcode{r} is negative, \tcode{rotr(x, -r)}. +\end{itemdescr} + +\begin{itemdecl} +template + [[nodiscard]] constexpr T rotr(T x, int s) noexcept; +\end{itemdecl} + +\indexlibrary{\idxcode{rotr}}% +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +Let \tcode{r} be \tcode{s \% N}. + +\pnum +\returns +If \tcode{r} is \tcode{0}, \tcode{x}; +if \tcode{r} is positive, \tcode{(x >> r) | (x << (N - r))}; +if \tcode{r} is negative, \tcode{rotl(x, -r)}. +\end{itemdescr} + +\rSec2[bit.count]{Counting} + +In the following descriptions, +let \tcode{N} denote \tcode{numeric_limits::digits}. + +\begin{itemdecl} +template + constexpr int countl_zero(T x) noexcept; +\end{itemdecl} + +\indexlibrary{\idxcode{countl_zero}}% +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +\returns +The number of consecutive \tcode{0} bits in the value of \tcode{x}, +starting from the most significant bit. +\begin{note} +Returns \tcode{N} if \tcode{x == 0}. +\end{note} +\end{itemdescr} + +\begin{itemdecl} +template + constexpr int countl_one(T x) noexcept; +\end{itemdecl} + +\indexlibrary{\idxcode{countl_one}}% +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +\returns +The number of consecutive \tcode{1} bits in the value of \tcode{x}, +starting from the most significant bit. +\begin{note} +Returns \tcode{N} if \tcode{x == numeric_limits::max()}. +\end{note} +\end{itemdescr} + +\begin{itemdecl} +template + constexpr int countr_zero(T x) noexcept; +\end{itemdecl} + +\indexlibrary{\idxcode{countr_zero}}% +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +\returns +The number of consecutive \tcode{0} bits in the value of \tcode{x}, +starting from the least significant bit. +\begin{note} +Returns \tcode{N} if \tcode{x == 0}. +\end{note} +\end{itemdescr} + +\begin{itemdecl} +template + constexpr int countr_one(T x) noexcept; +\end{itemdecl} + +\indexlibrary{\idxcode{countr_one}}% +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +\returns +The number of consecutive \tcode{1} bits in the value of \tcode{x}, +starting from the least significant bit. +\begin{note} +Returns \tcode{N} if \tcode{x == numeric_limits::max()}. +\end{note} +\end{itemdescr} + +\begin{itemdecl} +template + constexpr int popcount(T x) noexcept; +\end{itemdecl} + +\indexlibrary{\idxcode{popcount}}% +\begin{itemdescr} +\pnum +\constraints +\tcode{T} is an unsigned integer type\iref{basic.fundamental}. + +\pnum +\returns +The number of \tcode{1} bits in the value of \tcode{x}. +\end{itemdescr} + +\rSec2[bit.endian]{Endian} + +\pnum +Two common methods of byte ordering in multibyte scalar types are big-endian +and little-endian in the execution environment. Big-endian is a format for +storage of binary data in which the most significant byte is placed first, +with the rest in descending order. Little-endian is a format for storage of +binary data in which the least significant byte is placed first, with the rest +in ascending order. This subclause describes the endianness of the scalar types +of the execution environment. + +\indexlibrary{\idxcode{endian}}% +\indexlibrarymember{little}{endian}% +\indexlibrarymember{big}{endian}% +\indexlibrarymember{native}{endian}% +\begin{itemdecl} +enum class endian { + little = @\seebelow@, + big = @\seebelow@, + native = @\seebelow@ +}; +\end{itemdecl} + +\begin{itemdescr} +\pnum +If all scalar types have size 1 byte, then all of \tcode{endian::little}, +\tcode{endian::big}, and \tcode{endian::native} have the same value. +Otherwise, \tcode{endian::little} is not equal to \tcode{endian::big}. +If all scalar types are big-endian, \tcode{endian::native} is +equal to \tcode{endian::big}. +If all scalar types are little-endian, \tcode{endian::native} is +equal to \tcode{endian::little}. +Otherwise, \tcode{endian::native} is not equal +to either \tcode{endian::big} or \tcode{endian::little}. +\end{itemdescr} + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1554,7 +1759,7 @@ namespace std { // \ref{rand.req.urng}, uniform random bit generator requirements template - concept UniformRandomBitGenerator = @\seebelow@; + concept uniform_random_bit_generator = @\seebelow@; // \ref{rand.eng.lcong}, class template \tcode{linear_congruential_engine} template @@ -1947,17 +2152,17 @@ \begin{codeblock} template - concept UniformRandomBitGenerator = - Invocable && UnsignedIntegral> && + concept uniform_random_bit_generator = + invocable && unsigned_integral> && requires { - { G::min() } -> Same>; - { G::max() } -> Same>; + { G::min() } -> same_as>; + { G::max() } -> same_as>; }; \end{codeblock} \pnum Let \tcode{g} be an object of type \tcode{G}. \tcode{G} models -\libconcept{UniformRandomBitGenerator} only if +\libconcept{uniform_random_bit_generator} only if \begin{itemize} \item both \tcode{G::min()} and \tcode{G::max()} are constant @@ -1972,7 +2177,7 @@ \indextext{uniform random bit generator!requirements|)}% \pnum A class \tcode{G} meets the \term{uniform random bit generator} requirements if -\tcode{G} models \libconcept{UniformRandomBitGenerator}, +\tcode{G} models \libconcept{uniform_random_bit_generator}, \tcode{invoke_result_t} is an unsigned integer type\iref{basic.fundamental}, and \tcode{G} provides a nested \grammarterm{typedef-name} \tcode{result_type} @@ -7747,6 +7952,8 @@ size_t start() const; size_t size() const; size_t stride() const; + + friend bool operator==(const slice& x, const slice& y); }; } \end{codeblock} @@ -7808,6 +8015,22 @@ \complexity Constant time. \end{itemdescr} +\rSec3[slice.ops]{Operators} + +\indexlibrarymember{stride}{slice}% +\begin{itemdecl} +friend bool operator==(const slice& x, const slice& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return x.start() == y.start() && x.size() == y.size() && x.stride() == y.stride(); +\end{codeblock} +\end{itemdescr} + \rSec2[template.slice.array]{Class template \tcode{slice_array}} \rSec3[template.slice.array.overview]{Overview} @@ -8491,12 +8714,12 @@ In the \tcode{begin} and \tcode{end} function templates that follow, \unspec{1} is a type that meets the requirements of a mutable \oldconcept{RandomAccessIterator}\iref{random.access.iterators} -and models \libconcept{ContiguousIterator}\iref{iterator.concept.contiguous}, +and models \libconcept{contiguous_iterator}\iref{iterator.concept.contiguous}, whose \tcode{value_type} is the template parameter \tcode{T} and whose \tcode{reference} type is \tcode{T\&}. \unspec{2} is a type that meets the requirements of a constant \oldconcept{RandomAccessIterator} -and models \libconcept{ContiguousIterator}, +and models \libconcept{contiguous_iterator}, whose \tcode{value_type} is the template parameter \tcode{T} and whose \tcode{reference} type is \tcode{const T\&}. @@ -10238,3 +10461,85 @@ \end{itemdescr} \indextext{mathematical special functions|)} + +\rSec1[numbers]{Numbers} + +\rSec2[numbers.syn]{Header \tcode{} synopsis} +\indexhdr{numbers}% + +\begin{codeblock} +namespace std::numbers { + template inline constexpr T e_v = @\unspec@; + template inline constexpr T log2e_v = @\unspec@; + template inline constexpr T log10e_v = @\unspec@; + template inline constexpr T pi_v = @\unspec@; + template inline constexpr T inv_pi_v = @\unspec@; + template inline constexpr T inv_sqrtpi_v = @\unspec@; + template inline constexpr T ln2_v = @\unspec@; + template inline constexpr T ln10_v = @\unspec@; + template inline constexpr T sqrt2_v = @\unspec@; + template inline constexpr T sqrt3_v = @\unspec@; + template inline constexpr T inv_sqrt3_v = @\unspec@; + template inline constexpr T egamma_v = @\unspec@; + template inline constexpr T phi_v = @\unspec@; + + template inline constexpr T e_v = @\seebelow@; + template inline constexpr T log2e_v = @\seebelow@; + template inline constexpr T log10e_v = @\seebelow@; + template inline constexpr T pi_v = @\seebelow@; + template inline constexpr T inv_pi_v = @\seebelow@; + template inline constexpr T inv_sqrtpi_v = @\seebelow@; + template inline constexpr T ln2_v = @\seebelow@; + template inline constexpr T ln10_v = @\seebelow@; + template inline constexpr T sqrt2_v = @\seebelow@; + template inline constexpr T sqrt3_v = @\seebelow@; + template inline constexpr T inv_sqrt3_v = @\seebelow@; + template inline constexpr T egamma_v = @\seebelow@; + template inline constexpr T phi_v = @\seebelow@; + + inline constexpr double e = e_v; + inline constexpr double log2e = log2e_v; + inline constexpr double log10e = log10e_v; + inline constexpr double pi = pi_v; + inline constexpr double inv_pi = inv_pi_v; + inline constexpr double inv_sqrtpi = inv_sqrtpi_v; + inline constexpr double ln2 = ln2_v; + inline constexpr double ln10 = ln10_v; + inline constexpr double sqrt2 = sqrt2_v; + inline constexpr double sqrt3 = sqrt3_v; + inline constexpr double inv_sqrt3 = inv_sqrt3_v; + inline constexpr double egamma = egamma_v; + inline constexpr double phi = phi_v; +} +\end{codeblock} + +\rSec2[math.constants]{Mathematical constants} + +\pnum +The library-defined partial specializations +of mathematical constant variable templates +are initialized with the nearest representable values of +$\mathrm{e}$, +$\log_{2} \mathrm{e}$, +$\log_{10} \mathrm{e}$, +$\pi$, +$\frac{1}{\pi}$, +$\frac{1}{\sqrt{\pi}}$, +$\ln 2$, +$\ln 10$, +$\sqrt{2}$, +$\sqrt{3}$, +$\frac{1}{\sqrt{3}}$, +the Euler-Mascheroni $\gamma$ constant, and +the golden ratio $\phi$ constant $\frac{1+\sqrt{5}}{2}$, +respectively. + +\pnum +Pursuant to \ref{namespace.std}, +a program may partially or explicitly specialize +a mathematical constant variable template +provided that the specialization depends on a program-defined type. + +\pnum +A program that instantiates a primary template +of a mathematical constant variable template is ill-formed. diff --git a/source/overloading.tex b/source/overloading.tex index a079cdde3c..ec51c9720a 100644 --- a/source/overloading.tex +++ b/source/overloading.tex @@ -474,6 +474,12 @@ in which it is used, the program is ill-formed. +\pnum +Overload resolution results in a \defnadj{usable}{function} +if overload resolution succeeds and +the selected function is not deleted and +is accessible from the context in which overload resolution was performed. + \rSec2[over.match.funcs]{Candidate functions and argument lists}% \indextext{overloading!candidate functions|(}% \indextext{overloading!argument lists|(} @@ -1071,13 +1077,15 @@ that is not a function template specialization. \end{itemize} +\item +The rewritten candidate set is determined as follows: +\begin{itemize} \item For the relational\iref{expr.rel} operators, the rewritten candidates include -all member, non-member, and built-in candidates -for the operator \tcode{<=>} -for which the rewritten expression -\tcode{(x <=> y) @ 0} is well-formed using that \tcode{operator<=>}. +all non-rewritten candidates +for the expression \tcode{x <=> y}. +\item For the relational\iref{expr.rel} and three-way comparison\iref{expr.spaceship} @@ -1085,30 +1093,28 @@ the rewritten candidates also include a synthesized candidate, with the order of the two parameters reversed, -for each member, non-member, and built-in candidate -for the operator \tcode{<=>} -for which the rewritten expression -\tcode{0 @ (y <=> x)} is well-formed using that \tcode{operator<=>}. +for each non-rewritten candidate +for the expression +\tcode{y <=> x}. +\item For the \tcode{!=} operator\iref{expr.eq}, the rewritten candidates -include all member, non-member, and built-in candidates -for the operator \tcode{==} -for which the rewritten expression \tcode{(x == y)} is well-formed -when contextually converted to \tcode{bool} using that operator \tcode{==}. +include all non-rewritten candidates +for the expression \tcode{x == y}. +\item For the equality operators, the rewritten candidates also include a synthesized candidate, with the order of the two parameters reversed, -for each member, non-member, and built-in candidate for the operator \tcode{==} -for which the rewritten expression \tcode{(y == x)} is well-formed -when contextually converted to \tcode{bool} using that operator \tcode{==}. +for each non-rewritten candidate +for the expression \tcode{y == x}. +\item +For all other operators, the rewritten candidate set is empty. +\end{itemize} \begin{note} A candidate synthesized from a member candidate has its implicit object parameter as the second parameter, thus implicit conversions are considered for the first, but not for the second, parameter. \end{note} -In each case, rewritten candidates are not considered -in the context of the rewritten expression. -For all other operators, the rewritten candidate set is empty. \end{itemize} \pnum @@ -1159,26 +1165,39 @@ \end{example} \pnum -If a rewritten candidate is selected by overload resolution -for a relational or three-way comparison operator \tcode{@}, +If a rewritten \tcode{operator<=>} candidate +is selected by overload resolution +for an operator \tcode{@}, \tcode{x @ y} -is interpreted as the rewritten expression: +is interpreted as \tcode{0 @ (y <=> x)} if the selected candidate is a synthesized candidate with reversed order of parameters, or \tcode{(x <=> y) @ 0} otherwise, using the selected rewritten \tcode{operator<=>} candidate. -If a rewritten candidate is selected by overload resolution -for a \tcode{!=} operator, -\tcode{x != y} is interpreted as \tcode{(y == x) ?\ false :\ true} -if the selected candidate is a synthesized candidate -with reversed order of parameters, or -\tcode{(x == y) ?\ false :\ true} otherwise, -using the selected rewritten \tcode{operator==} candidate. -If a rewritten candidate is selected by overload resolution -for an \tcode{==} operator, -\tcode{x == y} is interpreted as \tcode{(y == x) ?\ true :\ false} -using the selected rewritten \tcode{operator==} candidate. +Rewritten candidates for the operator \tcode{@} +are not considered in the context of the resulting expression. + +\pnum +If a rewritten \tcode{operator==} candidate +is selected by overload resolution +for an operator \tcode{@}, +its return type shall be \cv{} \tcode{bool}, and +\tcode{x @ y} is interpreted as: +\begin{itemize} +\item +if \tcode{@} is \tcode{!=} +and the selected candidate is a synthesized candidate +with reversed order of parameters, +\tcode{!(y == x)}, +\item +otherwise, if \tcode{@} is \tcode{!=}, +\tcode{!(x == y)}, +\item +otherwise (when \tcode{@} is \tcode{==}), +\tcode{y == x}, +\end{itemize} +in each case using the selected rewritten \tcode{operator==} candidate. \pnum If a built-in candidate is selected by overload resolution, the @@ -1480,7 +1499,8 @@ \pnum When resolving a placeholder for a deduced class type\iref{dcl.type.class.deduct} where the \grammarterm{template-name} names a primary class template \tcode{C}, -a set of functions and function templates is formed comprising: +a set of functions and function templates, called the guides of \tcode{C}, +is formed comprising: \begin{itemize} \item If \tcode{C} is defined, @@ -1528,13 +1548,110 @@ of the \grammarterm{deduction-guide}. \end{itemize} \end{itemize} +In addition, if \tcode{C} is defined +and its definition satisfies the conditions for +an aggregate class\iref{dcl.init.aggr} +with the assumption that any dependent base class has +no virtual functions and no virtual base classes, and +the initializer is a non-empty \grammarterm{braced-init-list} or +parenthesized \grammarterm{expression-list}, +the set contains an additional function template, +called the \defnadj{aggregate deduction}{candidate}, defined as follows. +Let $x_1, \dotsc, x_n$ be the elements +of the \grammarterm{initializer-list} or +\grammarterm{designated-initializer-list} +of the \grammarterm{braced-init-list}, or +of the \grammarterm{expression-list}. +For each $x_i$, let $e_i$ be the corresponding element +of \tcode{C} or of one of its (possibly recursive) subaggregates +that would be initialized by $x_i$\iref{dcl.init.aggr} +if brace elision is not considered for any element +that has a dependent type. +If there is no such element $e_i$, the program is ill-formed. +The aggregate deduction candidate is derived as above +from a hypothetical constructor $\tcode{C}(\tcode{T}_1, \dotsc, \tcode{T}_n)$, +where $\tcode{T}_i$ is the declared type of the element $e_i$. + +\pnum +When resolving a placeholder for a deduced class type\iref{dcl.type.simple} +where the \grammarterm{template-name} names an alias template \tcode{A}, +the \grammarterm{defining-type-id} of \tcode{A} must be of the form +\begin{ncsimplebnf} +\opt{\keyword{typename}} \opt{nested-name-specifier} \opt{\keyword{template}} simple-template-id +\end{ncsimplebnf} +as specified in \ref{dcl.type.simple}. +The guides of \tcode{A} are the set of functions or function templates +formed as follows. +For each function or function template \tcode{f} in the guides of +the template named by the \grammarterm{simple-template-id} +of the \grammarterm{defining-type-id}, +the template arguments of the return type of \tcode{f} +are deduced +from the \grammarterm{defining-type-id} of \tcode{A} +according to the process in \ref{temp.deduct.type} +with the exception that deduction does not fail +if not all template arguments are deduced. +Let \tcode{g} denote the result of substituting +these deductions into \tcode{f}. +If substitution succeeds, +form a function or function template \tcode{f'} +with the following properties and add it to the set +of guides of \tcode{A}: +\begin{itemize} +\item +The function type of \tcode{f'} is the function type of \tcode{g}. + +\item +If \tcode{f} is a function template, +\tcode{f'} is a function template whose +template parameter list consists of +all the template parameters of \tcode{A} +(including their default template arguments) +that appear in the above deductions or +(recursively) in their default template arguments, +followed by the template parameters of \tcode{f} that were not deduced +(including their default template arguments), +otherwise \tcode{f'} is not a function template. + +\item +The associated constraints\iref{temp.constr.decl} are +the conjunction of the associated constraints of \tcode{g} and +a constraint that is satisfied if and only if +the arguments of \tcode{A} are deducible (see below) from the return type. + +\item +If \tcode{f} is a copy deduction candidate\iref{over.match.class.deduct}, +then \tcode{f'} is considered to be so as well. + +\item +If \tcode{f} was generated +from a \grammarterm{deduction-guide}\iref{over.match.class.deduct}, +then \tcode{f'} is considered to be so as well. + +\item +The \grammarterm{explicit-specifier} of \tcode{f'} is +the \grammarterm{explicit-specifier} of \tcode{g} (if any). +\end{itemize} + +\indextext{template!deducible arguments of}% +\pnum +The arguments of a template \tcode{A} are said to be +deducible from a type \tcode{T} if, given a class template +\begin{codeblock} +template class AA; +\end{codeblock} +with a single partial specialization +whose template parameter list is that of \tcode{A} and +whose template argument list is a specialization of \tcode{A} +with the template argument list of \tcode{A}\iref{temp.dep.type}, +\tcode{AA} matches the partial specialization. \pnum Initialization and overload resolution are performed as described in \ref{dcl.init} and \ref{over.match.ctor}, \ref{over.match.copy}, or \ref{over.match.list} (as appropriate for the type of initialization performed) for an object of a hypothetical class type, where -the selected functions and function templates are considered to be the +the guides of the template named by the placeholder are considered to be the constructors of that class type for the purpose of forming an overload set, and the initializer is provided by the context in which class template argument deduction was performed. @@ -1542,8 +1659,9 @@ (considering initializer-list constructors) is omitted if the initializer list consists of a single expression of type \cv{}~\tcode{U}, -where \tcode{U} is a specialization of \tcode{C} or -a class derived from a specialization of \tcode{C}. +where \tcode{U} is, or is derived from, +a specialization of the class template +directly or indirectly named by the placeholder. If the function or function template was generated from a constructor or \grammarterm{deduction-guide} that had an \grammarterm{explicit-specifier}, @@ -1582,6 +1700,102 @@ }; B b{(int*)0, (char*)0}; // OK, deduces \tcode{B} + +template +struct S { + T x; + T y; +}; + +template +struct C { + S s; + T t; +}; + +template +struct D { + S s; + T t; +}; + +C c1 = {1, 2}; // error: deduction failed +C c2 = {1, 2, 3}; // error: deduction failed +C c3 = {{1u, 2u}, 3}; // OK, deduces \tcode{C} + +D d1 = {1, 2}; // error: deduction failed +D d2 = {1, 2, 3}; // OK, braces elided, deduces \tcode{D} + +template +struct E { + T t; + decltype(t) t2; +}; + +E e1 = {1, 2}; // OK, deduces \tcode{E} +\end{codeblock} +\end{example} + +\pnum +\begin{example} +\begin{codeblock} +template struct C { + C(T, U); // \#1 +}; +template + C(T, U) -> C>; // \#2 + +template using A = C; +template using B = A; + +int i{}; +double d{}; +A a1(&i, &i); // deduces \tcode{A} +A a2(i, i); // error: cannot deduce \tcode{V *} from \tcode{i} +A a3(&i, &d); // error: \#1: cannot deduce \tcode{(V*, V*)} from \tcode{(int *, double *)} + // \#2: cannot deduce \tcode{A} from \tcode{C} +B b1(&i, &i); // deduces \tcode{B} +B b2(&d, &d); // error: cannot deduce \tcode{B} from \tcode{C} +\end{codeblock} +Possible exposition-only implementation of the above procedure: +\begin{codeblock} +// The following concept ensures a specialization of \tcode{A} is deduced. +template class AA; +template class AA> { }; +template concept deduces_A = requires { sizeof(AA); }; + +// \tcode{f1} is formed from the constructor \#1 of \tcode{C}, generating the following function template +template + auto f1(T, U) -> C; + +// Deducing arguments for \tcode{C} from \tcode{C} deduces \tcode{T} as \tcode{V *} and \tcode{U} as \tcode{V *}; +// \tcode{f1'} is obtained by transforming \tcode{f1} as described by the above procedure. +template requires deduces_A> + auto f1_prime(V *, V*) -> C; + +// \tcode{f2} is formed from the deduction-guide \#2 of \tcode{C} +template auto f2(T, U) -> C>; + +// Deducing arguments for \tcode{C>} from \tcode{C} deduces \tcode{T} as \tcode{V *}; +// \tcode{f2'} is obtained by transforming \tcode{f2} as described by the above procedure. +template + requires deduces_A>> + auto f2_prime(V *, U) -> C>; + +// The following concept ensures a specialization of \tcode{B} is deduced. +template class BB; +template class BB> { }; +template concept deduces_B = requires { sizeof(BB); }; + +// The guides for \tcode{B} derived from the above \tcode{f1'} and \tcode{f2'} for \tcode{A} are as follows: +template + requires deduces_A> && deduces_B> + auto f1_prime_for_B(W *, W *) -> C; + +template + requires deduces_A>> && + deduces_B>> + auto f2_prime_for_B(W *, U) -> C>; \end{codeblock} \end{example}% \indextext{overloading!argument lists|)}% @@ -2412,10 +2626,13 @@ \end{example} \pnum -Otherwise, if the parameter type is ``array of \tcode{N} \tcode{X}'', -if there exists an implicit conversion sequence for each element of the array -from the corresponding element of the initializer list (or from \tcode{\{\}} -if there is no such element), the implicit conversion sequence is +Otherwise, if the parameter type is ``array of \tcode{N} \tcode{X}'' +or ``array of unknown bound of \tcode{X}'', +if there exists an implicit conversion sequence +from each element of the initializer list +(and from \tcode{\{\}} in the former case +if \tcode{N} exceeds the number of elements in the initializer list) +to \tcode{X}, the implicit conversion sequence is the worst such implicit conversion sequence. \pnum @@ -2584,19 +2801,35 @@ \tcode{L2} does not, or, if not that, \item -\tcode{L1} converts to type ``array of \tcode{N1} \tcode{T}'', \tcode{L2} converts to -type ``array of \tcode{N2} \tcode{T}'', and \tcode{N1} is smaller than \tcode{N2}, +\tcode{L1} and \tcode{L2} convert to arrays of the same element type, and +either the number of elements $n_1$ initialized by \tcode{L1} +is less than the number of elements $n_2$ initialized by \tcode{L2}, or +$n_1 = n_2$ and +\tcode{L2} converts to an array of unknown bound and \tcode{L1} does not, \end{itemize} even if one of the other rules in this paragraph would otherwise apply. \begin{example} \begin{codeblock} - void f1(int); // \#1 - void f1(std::initializer_list); // \#2 - void g1() { f1({42}); } // chooses \#2 +void f1(int); // \#1 +void f1(std::initializer_list); // \#2 +void g1() { f1({42}); } // chooses \#2 - void f2(std::pair); // \#3 - void f2(std::initializer_list); // \#4 - void g2() { f2({"foo","bar"}); } // chooses \#4 +void f2(std::pair); // \#3 +void f2(std::initializer_list); // \#4 +void g2() { f2({"foo","bar"}); } // chooses \#4 +\end{codeblock} +\end{example} +\begin{example} +\begin{codeblock} +void f(int (&&)[] ); // \#1 +void f(double (&&)[] ); // \#2 +void f(int (&&)[2]); // \#3 + +f( {1} ); // Calls \#1: Better than \#2 due to conversion, better than \#3 due to bounds +f( {1.0} ); // Calls \#2: Identity conversion is better than floating-integral conversion +f( {1.0, 2.0} ); // Calls \#2: Identity conversion is better than floating-integral conversion +f( {1, 2} ); // Calls \#3: Converting to array of known bound is better than to unknown bound, + // and an identity conversion is better than floating-integral conversion \end{codeblock} \end{example} @@ -2680,16 +2913,10 @@ or, if not that, \item -\tcode{S1} -and -\tcode{S2} -differ only in their qualification conversion and yield similar types -\tcode{T1} -and -\tcode{T2}\iref{conv.qual}, respectively, and the cv-qualification signature of type -\tcode{T1} -is a proper subset of the cv-qualification signature of type -\tcode{T2} +\tcode{S1} and \tcode{S2} differ only +in their qualification conversion\iref{conv.qual} and +yield similar types \tcode{T1} and \tcode{T2}, respectively, +where \tcode{T1} can be converted to \tcode{T2} by a qualification conversion. \begin{example} \begin{codeblock} int f(const volatile int *); diff --git a/source/preprocessor.tex b/source/preprocessor.tex index 1f2c35d974..1e8d2a83a0 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -11,10 +11,14 @@ \pnum A \defn{preprocessing directive} consists of a sequence of preprocessing tokens that satisfies the following constraints: -The first token in the sequence is a -\tcode{\#} -preprocessing token that (at the start of translation phase 4) -either is the first character in the source file +The first token in the sequence, +referred to as a \defnadj{directive-introducing}{token}, +is a \tcode{\#} preprocessing token, +an \tcode{import} preprocessing token, or +an \tcode{export} preprocessing token +immediately followed by an \tcode{import} preprocessing token, +that (at the start of translation phase 4) +either begins with the first character in the source file (optionally after white space containing no new-line characters) or follows white space containing at least one new-line character. The last token in the sequence is the first new-line character @@ -50,6 +54,7 @@ \begin{bnf}\obeyspaces \nontermdef{control-line}\br \terminal{\# include} pp-tokens new-line\br + \opt{\terminal{export}} \terminal{import} pp-tokens new-line\br \terminal{\# define } identifier replacement-list new-line\br \terminal{\# define } identifier lparen \opt{identifier-list} \terminal{)} replacement-list new-line\br \terminal{\# define } identifier lparen \terminal{... )} replacement-list new-line\br @@ -149,9 +154,8 @@ The only white-space characters that shall appear between preprocessing tokens within a preprocessing directive -(from just after the introducing -\tcode{\#} -preprocessing token through just before the terminating new-line character) +(from just after the directive-introducing token +through just before the terminating new-line character) are space and horizontal-tab (including spaces that have replaced comments or possibly other white-space characters @@ -243,7 +247,7 @@ if the identifier is currently defined as a macro name (that is, if it is predefined -or if it has one or more active macro definitions\iref{cpp.module}, +or if it has one or more active macro definitions\iref{cpp.import}, for example because it has been the subject of a \tcode{\#define} @@ -276,7 +280,8 @@ matching the form of an \grammarterm{integer-literal} if the implementation supports an attribute with the name specified by interpreting -the \grammarterm{pp-tokens} as an \grammarterm{attribute-token}, +the \grammarterm{pp-tokens}, after macro expansion, +as an \grammarterm{attribute-token}, and by \tcode{0} otherwise. The program is ill-formed if the \grammarterm{pp-tokens} do not match the form of an \grammarterm{attribute-token}. @@ -298,16 +303,13 @@ {ll} \topline \lhdr{Attribute} & \rhdr{Value} \\ \rowsep -\tcode{assert} & \tcode{201806L} \\ \tcode{carries_dependency} & \tcode{200809L} \\ \tcode{deprecated} & \tcode{201309L} \\ -\tcode{ensures} & \tcode{201806L} \\ -\tcode{expects} & \tcode{201806L} \\ \tcode{fallthrough} & \tcode{201603L} \\ \tcode{likely} & \tcode{201803L} \\ \tcode{maybe_unused} & \tcode{201603L} \\ \tcode{no_unique_address} & \tcode{201803L} \\ -\tcode{nodiscard} & \tcode{201603L} \\ +\tcode{nodiscard} & \tcode{201907L} \\ \tcode{noreturn} & \tcode{200809L} \\ \tcode{unlikely} & \tcode{201803L} \\ \end{floattable} @@ -356,8 +358,10 @@ \pnum After all replacements due to macro expansion and -evaluations of \grammarterm{defined-macro-expression}{s} and -\grammarterm{has-include-expression}{s} +evaluations of +\grammarterm{defined-macro-expression}s, +\grammarterm{has-include-expression}s, and +\grammarterm{has-attribute-expression}s have been performed, all remaining identifiers and keywords, except for @@ -621,10 +625,13 @@ \pnum If the header identified by the \grammarterm{header-name} denotes an importable header\iref{module.import}, -the preprocessing directive -is instead replaced by the \grammarterm{preprocessing-token}{s} +it is +\impldef{whether source file inclusion of importable header +is replaced with \tcode{import} directive} +whether the \tcode{\#include} preprocessing directive +is instead replaced by an \tcode{import} directive\iref{cpp.import} of the form \begin{ncbnf} -\terminal{import} header-name \terminal{;} +\terminal{import} header-name \terminal{;} new-line \end{ncbnf} \pnum @@ -662,104 +669,40 @@ \end{codeblock} \end{example} -\rSec1[cpp.glob.frag]{Global module fragment} - -\begin{bnf} -\nontermdef{pp-global-module-fragment}\br - \terminal{module} \terminal{;} pp-balanced-token-seq \terminal{module} -\end{bnf} - -\pnum -If the first two preprocessing tokens at the start of phase 4 of translation -are \tcode{module} \tcode{;}, -the result of preprocessing shall begin with -a \grammarterm{pp-global-module-fragment} -for which all \grammarterm{preprocessing-token}{s} -in the \grammarterm{pp-balanced-token-seq} -were produced directly or indirectly by source file inclusion\iref{cpp.include}, -and for which the second \tcode{module} \grammarterm{preprocessing-token} -was not produced by source file inclusion or -macro replacement\iref{cpp.replace}. -Otherwise, -the first two preprocessing tokens at the end of phase 4 of translation -shall not be \tcode{module} \tcode{;}. - -\rSec1[cpp.module]{Header units} +\rSec1[cpp.import]{Header unit importation} \indextext{header unit!preprocessing}% -\indextext{macro import|(}% - -\begin{bnf} -\nontermdef{import-seq}\br - \opt{top-level-token-seq} \opt{\terminal{export}} \terminal{import} -\end{bnf} - -\begin{bnf} -\nontermdef{top-level-token-seq}\br - \descr{any \grammarterm{pp-balanced-token-seq} ending in \terminal{;} or \terminal{\}}} -\end{bnf} +\indextext{macro!import|(}% \begin{bnf} \nontermdef{pp-import}\br - \terminal{import} header-name \opt{pp-import-suffix} \terminal{;}\br - \terminal{import} header-name-tokens \opt{pp-import-suffix} \terminal{;} -\end{bnf} - -\begin{bnf} -\nontermdef{pp-import-suffix}\br - pp-import-suffix-token\br - pp-import-suffix pp-import-suffix-token -\end{bnf} - -\begin{bnf} -\nontermdef{pp-import-suffix-token}\br - \descr{any \grammarterm{pp-balanced-token} other than \terminal{;}} -\end{bnf} - -\begin{bnf} -\nontermdef{pp-balanced-token-seq}\br - pp-balanced-token\br - pp-balanced-token-seq pp-balanced-token -\end{bnf} - -\begin{bnf} -\nontermdef{pp-balanced-token}\br - pp-ldelim \opt{pp-balanced-token-seq} pp-rdelim\br - \descr{any \grammarterm{preprocessing-token} other than a \grammarterm{pp-ldelim} or \grammarterm{pp-rdelim}} -\end{bnf} - -\begin{bnf} -\nontermdef{pp-ldelim} \descr{one of}\br - \terminal{( [ \{ <: <\%} -\end{bnf} - -\begin{bnf} -\nontermdef{pp-rdelim} \descr{one of}\br - \terminal{) ] \} :> \%>} + \opt{\terminal{export}} \terminal{import} header-name \opt{pp-tokens} \terminal{;} new-line\br + \opt{\terminal{export}} \terminal{import} header-name-tokens \opt{pp-tokens} \terminal{;} new-line\br + \opt{\terminal{export}} \terminal{import} pp-tokens \terminal{;} new-line \end{bnf} \pnum -A sequence of \grammarterm{preprocessing-token}{s} -matching the form of a \grammarterm{pp-import} +The preprocessing tokens after the \tcode{import} preprocessing token +in the \tcode{import} \grammarterm{control-line} +are processed just as in normal text +(i.e., each identifier currently defined as a macro name +is replaced by its replacement list of preprocessing tokens). +An \tcode{import} directive +matching the first two forms of a \grammarterm{pp-import} instructs the preprocessor to import macros from the header unit\iref{module.import} denoted by the \grammarterm{header-name}. -A \grammarterm{pp-import} is only recognized -when the sequence of tokens -produced by phase 4 of translation -up to the \tcode{import} token -forms an \grammarterm{import-seq}, -and the \tcode{import} token is not within -the \grammarterm{header-name-tokens} or \grammarterm{pp-import-suffix} -of another \grammarterm{pp-import}. -The \tcode{;} \grammarterm{preprocessing-token} -terminating a \grammarterm{pp-import} -shall not have been produced by -macro replacement\iref{cpp.replace}. -The \defnadj{point of}{macro import} for a \grammarterm{pp-import} is -immediately after the \tcode{;} terminating the \grammarterm{pp-import}. - -\pnum -In the second form of \grammarterm{pp-import}, +\indextext{point of!macro import|see{macro, point of import}}% +The \defnx{point of macro import}{macro!point of import} for the +first two forms of \grammarterm{pp-import} is +immediately after the \grammarterm{new-line} terminating +the \grammarterm{pp-import}. +The last form of \grammarterm{pp-import} is only considered +if the first two forms did not match. + +\pnum +In all three forms of \grammarterm{pp-import}, +the \tcode{import} token is replaced by the \grammarterm{import-keyword} token. +Additionally, in the second form of \grammarterm{pp-import}, a \grammarterm{header-name} token is formed as if the \grammarterm{header-name-tokens} were the \grammarterm{pp-tokens} of a \tcode{\#include} directive. @@ -773,14 +716,15 @@ \pnum Each \tcode{\#define} directive encountered when preprocessing each translation unit in a program results in a distinct -\defn{macro definition}. +\defnx{macro definition}{macro!definition}. Importing macros from a header unit makes macro definitions from a translation unit visible in other translation units. Each macro definition has at most one point of definition in each translation unit and at most one point of undefinition, as follows: \begin{itemize} \item -The \defnx{point of definition}{macro definition!point of definition} +\indextext{point of!macro definition|see{macro, point of definition}}% +The \defnx{point of definition}{macro!point of definition} of a macro definition within a translation unit is the point at which its \tcode{\#define} directive occurs (in the translation unit containing the \tcode{\#define} directive), or, @@ -791,7 +735,8 @@ macro definition, if any (in any other translation unit). \item -The \defnx{point of undefinition}{macro definition!point of undefinition} +\indextext{point of!macro undefinition|see{macro, point of undefinition}}% +The \defnx{point of undefinition}{macro!point of undefinition} of a macro definition within a translation unit is the first point at which a \tcode{\#undef} directive naming the macro occurs after its point of definition, or the first point @@ -800,7 +745,8 @@ \end{itemize} \pnum -A macro directive is \defnx{active}{macro definition!active} at a source location +\indextext{active macro directive|see{macro, active}}% +A macro directive is \defnx{active}{macro!active} at a source location if it has a point of definition in that translation unit preceding the location, and does not have a point of undefinition in that translation unit preceding the location. @@ -837,12 +783,55 @@ \begin{codeblocktu}{Importable header \tcode{"d.h"}} import "a.h"; // point of definition of \#1, \#2, and \#3, point of undefinition of \#1 in \tcode{"d.h"} import "c.h"; // point of definition of \#4 and \#5 in \tcode{"d.h"} -int a = Y; // OK, active macro definitions \#2 and \#3 are valid redefinitions -int c = Z; // error: active macro definitions \#2 and \#3 are not valid redefinitions of \tcode{Z} +int a = Y; // OK, active macro definitions \#2 and \#4 are valid redefinitions +int c = Z; // error: active macro definitions \#3 and \#5 are not valid redefinitions of \tcode{Z} \end{codeblocktu} \end{example} +\indextext{macro!import|)} + +\rSec1[cpp.glob.frag]{Global module fragment} + +\begin{bnf} +\nontermdef{pp-global-module-fragment}\br + \terminal{module} \terminal{;} pp-balanced-token-seq \terminal{module} +\end{bnf} + +\begin{bnf} +\nontermdef{pp-balanced-token-seq}\br + pp-balanced-token\br + pp-balanced-token-seq pp-balanced-token +\end{bnf} + +\begin{bnf} +\nontermdef{pp-balanced-token}\br + pp-ldelim \opt{pp-balanced-token-seq} pp-rdelim\br + \descr{any \grammarterm{preprocessing-token} other than a \grammarterm{pp-ldelim} or \grammarterm{pp-rdelim}} +\end{bnf} + +\begin{bnf} +\nontermdef{pp-ldelim} \descr{one of}\br + \terminal{( [ \{ <: <\%} +\end{bnf} -\indextext{macro import|)}% +\begin{bnf} +\nontermdef{pp-rdelim} \descr{one of}\br + \terminal{) ] \} :> \%>} +\end{bnf} + +\pnum +If the first two preprocessing tokens at the start of phase 4 of translation +are \tcode{module} \tcode{;}, +the result of preprocessing shall begin with +a \grammarterm{pp-global-module-fragment} +for which all \grammarterm{preprocessing-token}{s} +in the \grammarterm{pp-balanced-token-seq} +were produced directly or indirectly by source file inclusion\iref{cpp.include}, +and for which the second \tcode{module} \grammarterm{preprocessing-token} +was not produced by source file inclusion or +macro replacement\iref{cpp.replace}. +Otherwise, +the first two preprocessing tokens at the end of phase 4 of translation +shall not be \tcode{module} \tcode{;}. \rSec1[cpp.replace]{Macro replacement}% \indextext{macro!replacement|(}% @@ -858,7 +847,6 @@ \pnum An identifier currently defined as an -\indextext{object-like macro|see{macro, object-like}}% \indextext{macro!object-like}% object-like macro (see below) may be redefined by another \tcode{\#define} @@ -866,7 +854,6 @@ object-like macro definition and the two replacement lists are identical, otherwise the program is ill-formed. Likewise, an identifier currently defined as a -\indextext{function-like macro|see{macro, function-like}}% \indextext{macro!function-like}% function-like macro (see below) may be redefined by another \tcode{\#define} @@ -934,7 +921,7 @@ \end{ncsimplebnf} defines an -\defnx{object-like macro}{macro!object-like} that +\defnadj{object-like}{macro} that causes each subsequent instance of the macro name\footnote{Since, by macro-replacement time, all character literals and string literals are preprocessing tokens, not sequences possibly containing identifier-like subsequences @@ -955,7 +942,7 @@ \terminal{\# define} identifier lparen \terminal{...} \terminal{)} replacement-list new-line\br \terminal{\# define} identifier lparen identifier-list \terminal{, ...} \terminal{)} replacement-list new-line \end{ncsimplebnf} -defines a \defnx{function-like macro}{macro!function-like} +defines a \defnadj{function-like}{macro} with parameters, whose use is similar syntactically to a function call. The parameters @@ -1681,11 +1668,13 @@ \defnxname{cpp_capture_star_this} & \tcode{201603L} \\ \rowsep \defnxname{cpp_char8_t} & \tcode{201811L} \\ \rowsep \defnxname{cpp_conditional_explicit} & \tcode{201806L} \\ \rowsep -\defnxname{cpp_constexpr} & \tcode{201603L} \\ \rowsep +\defnxname{cpp_constexpr} & \tcode{201907L} \\ \rowsep +\defnxname{cpp_constexpr_dynamic_alloc} & \tcode{201907L} \\ \rowsep +\defnxname{cpp_constinit} & \tcode{201907L} \\ \rowsep \defnxname{cpp_coroutines} & \tcode{201902L} \\ \rowsep \defnxname{cpp_decltype} & \tcode{200707L} \\ \rowsep \defnxname{cpp_decltype_auto} & \tcode{201304L} \\ \rowsep -\defnxname{cpp_deduction_guides} & \tcode{201703L} \\ \rowsep +\defnxname{cpp_deduction_guides} & \tcode{201907L} \\ \rowsep \defnxname{cpp_delegating_constructors} & \tcode{200604L} \\ \rowsep \defnxname{cpp_enumerator_attributes} & \tcode{201411L} \\ \rowsep \defnxname{cpp_fold_expressions} & \tcode{201603L} \\ \rowsep @@ -1694,12 +1683,13 @@ \defnxname{cpp_hex_float} & \tcode{201603L} \\ \rowsep \defnxname{cpp_if_constexpr} & \tcode{201606L} \\ \rowsep \defnxname{cpp_impl_destroying_delete} & \tcode{201806L} \\ \rowsep -\defnxname{cpp_impl_three_way_comparison} & \tcode{201711L} \\ \rowsep +\defnxname{cpp_impl_three_way_comparison} & \tcode{201907L} \\ \rowsep \defnxname{cpp_inheriting_constructors} & \tcode{201511L} \\ \rowsep \defnxname{cpp_init_captures} & \tcode{201304L} \\ \rowsep \defnxname{cpp_initializer_lists} & \tcode{200806L} \\ \rowsep \defnxname{cpp_inline_variables} & \tcode{201606L} \\ \rowsep \defnxname{cpp_lambdas} & \tcode{200907L} \\ \rowsep +\defnxname{cpp_modules} & \tcode{201907L} \\ \rowsep \defnxname{cpp_namespace_attributes} & \tcode{201411L} \\ \rowsep \defnxname{cpp_noexcept_function_type} & \tcode{201510L} \\ \rowsep \defnxname{cpp_nontype_template_args} & \tcode{201411L} \\ \rowsep @@ -1719,6 +1709,7 @@ \defnxname{cpp_unicode_characters} & \tcode{200704L} \\ \rowsep \defnxname{cpp_unicode_literals} & \tcode{200710L} \\ \rowsep \defnxname{cpp_user_defined_literals} & \tcode{200809L} \\ \rowsep +\defnxname{cpp_using_enum} & \tcode{201907L} \\ \rowsep \defnxname{cpp_variable_templates} & \tcode{201304L} \\ \rowsep \defnxname{cpp_variadic_templates} & \tcode{200704L} \\ \rowsep \defnxname{cpp_variadic_using} & \tcode{201611L} \\ \rowsep diff --git a/source/ranges.tex b/source/ranges.tex index b6c81d768d..1c03d71922 100644 --- a/source/ranges.tex +++ b/source/ranges.tex @@ -48,20 +48,27 @@ // \ref{range.range}, ranges template - using iterator_t = decltype(ranges::begin(declval())); - - template - using sentinel_t = decltype(ranges::end(declval())); - - template - concept Range = @\seebelow@; + concept range = @\seebelow@; + + template + using iterator_t = decltype(ranges::begin(declval())); + template + using sentinel_t = decltype(ranges::end(declval())); + template + using range_difference_t = iter_difference_t>; + template + using range_value_t = iter_value_t>; + template + using range_reference_t = iter_reference_t>; + template + using range_rvalue_reference_t = iter_rvalue_reference_t>; // \ref{range.sized}, sized ranges template inline constexpr bool disable_sized_range = false; template - concept SizedRange = @\seebelow@; + concept sized_range = @\seebelow@; // \ref{range.view}, views template @@ -70,52 +77,52 @@ struct view_base { }; template - concept View = @\seebelow@; + concept view = @\seebelow@; // \ref{range.refinements}, other range refinements template - concept OutputRange = @\seebelow@; + concept output_range = @\seebelow@; template - concept InputRange = @\seebelow@; + concept input_range = @\seebelow@; template - concept ForwardRange = @\seebelow@; + concept forward_range = @\seebelow@; template - concept BidirectionalRange = @\seebelow@; + concept bidirectional_range = @\seebelow@; template - concept RandomAccessRange = @\seebelow@; + concept random_access_range = @\seebelow@; template - concept ContiguousRange = @\seebelow@; + concept contiguous_range = @\seebelow@; template - concept CommonRange = @\seebelow@; + concept common_range = @\seebelow@; template - concept ViewableRange = @\seebelow@; + concept viewable_range = @\seebelow@; // \ref{view.interface}, class template \tcode{view_interface} template - requires is_class_v && Same> + requires is_class_v && same_as> class view_interface; // \ref{range.subrange}, sub-ranges enum class subrange_kind : bool { unsized, sized }; - template S = I, subrange_kind K = @\seebelow@> - requires (K == subrange_kind::sized || !SizedSentinel) + template S = I, subrange_kind K = @\seebelow@> + requires (K == subrange_kind::sized || !sized_sentinel_for) class subrange; // \ref{range.dangling}, dangling iterator handling struct dangling; - template + template using safe_iterator_t = conditional_t<@\placeholder{forwarding-range}@, iterator_t, dangling>; - template + template using safe_subrange_t = conditional_t<@\placeholder{forwarding-range}@, subrange>, dangling>; @@ -124,96 +131,142 @@ requires is_object_v class empty_view; - namespace view { + namespace views { template inline constexpr empty_view empty{}; } // \ref{range.single}, single view - template + template requires is_object_v class single_view; - namespace view { inline constexpr @\unspec@ single = @\unspec@; } + namespace views { inline constexpr @\unspec@ single = @\unspec@; } // \ref{range.iota}, iota view - template + template requires @\placeholder{weakly-equality-comparable-with}@ class iota_view; - namespace view { inline constexpr @\unspec@ iota = @\unspec@; } + namespace views { inline constexpr @\unspec@ iota = @\unspec@; } // \ref{range.all}, all view - namespace view { inline constexpr @\unspec@ all = @\unspec@; } + namespace views { inline constexpr @\unspec@ all = @\unspec@; } - template - using all_view = decltype(view::all(declval())); + template + using all_view = decltype(views::all(declval())); - template + template requires is_object_v class ref_view; // \ref{range.filter}, filter view - template> Pred> - requires View && is_object_v + template> Pred> + requires view && is_object_v class filter_view; - namespace view { inline constexpr @\unspec@ filter = @\unspec@; } + namespace views { inline constexpr @\unspec@ filter = @\unspec@; } // \ref{range.transform}, transform view - template - requires View && is_object_v && - RegularInvocable>> + template + requires view && is_object_v && + regular_invocable> class transform_view; - namespace view { inline constexpr @\unspec@ transform = @\unspec@; } + namespace views { inline constexpr @\unspec@ transform = @\unspec@; } // \ref{range.take}, take view - template class take_view; + template class take_view; + + namespace views { inline constexpr @\unspec@ take = @\unspec@; } + + // \ref{range.take.while}, take while view + template + requires input_range && is_object_v && + indirect_unary_predicate> + class take_while_view; + + namespace views { inline constexpr @\unspec@ take_while = @\unspec@; } + + // \ref{range.drop}, drop view + template + class drop_view; - namespace view { inline constexpr @\unspec@ take = @\unspec@; } + namespace views { inline constexpr @\unspec@ drop = @\unspec@; } + + // \ref{range.drop.while}, drop while view + template + requires input_range && is_object_v && + indirect_unary_predicate> + class drop_while_view; + + namespace views { inline constexpr @\unspec@ drop_while = @\unspec@; } // \ref{range.join}, join view - template - requires View && InputRange>> && - (is_reference_v>> || - View>>) + template + requires view && input_range> && + (is_reference_v> || + view>) class join_view; - namespace view { inline constexpr @\unspec@ join = @\unspec@; } + namespace views { inline constexpr @\unspec@ join = @\unspec@; } // \ref{range.split}, split view template concept @\placeholder{tiny-range}@ = @\seebelow@; // \expos - template - requires View && View && - IndirectlyComparable, iterator_t, ranges::equal_to> && - (ForwardRange || @\placeholder{tiny-range}@) + template + requires view && view && + indirectly_comparable, iterator_t, ranges::equal_to> && + (forward_range || @\placeholder{tiny-range}@) class split_view; - namespace view { inline constexpr @\unspec@ split = @\unspec@; } + namespace views { inline constexpr @\unspec@ split = @\unspec@; } // \ref{range.counted}, counted view - namespace view { inline constexpr @\unspec@ counted = @\unspec@; } + namespace views { inline constexpr @\unspec@ counted = @\unspec@; } // \ref{range.common}, common view - template - requires (!CommonRange) + template + requires (!common_range) class common_view; - namespace view { inline constexpr @\unspec@ common = @\unspec@; } + namespace views { inline constexpr @\unspec@ common = @\unspec@; } // \ref{range.reverse}, reverse view - template - requires BidirectionalRange + template + requires bidirectional_range class reverse_view; - namespace view { inline constexpr @\unspec@ reverse = @\unspec@; } + namespace views { inline constexpr @\unspec@ reverse = @\unspec@; } + + // \ref{range.istream}, istream view + template> + requires @\seebelow@ + class basic_istream_view; + template + basic_istream_view istream_view(basic_istream& s); + + // \ref{range.elements}, elements view + template + requires @\seebelow@; + class elements_view; + + template + using keys_view = elements_view, 0>; + template + using values_view = elements_view, 1>; + + namespace views { + template + inline constexpr @\unspec@ elements = @\unspec@ ; + inline constexpr @\unspec@ keys = @\unspec@ ; + inline constexpr @\unspec@ values = @\unspec@ ; + } } namespace std { - namespace view = ranges::view; + namespace views = ranges::views; template struct tuple_size> @@ -229,6 +282,20 @@ } \end{codeblock} +\pnum +\indextext{make-unigned-like@\exposid{make-unsigned-like}}% +\indextext{make-unigned-like-t@\exposid{make-unsigned-like-t}}% +Within this clause, +for some integer-like type \tcode{X}\iref{iterator.concept.winc}, +\tcode{\placeholdernc{make-unsigned-like-t}(X)} denotes +\tcode{make_unsigned_t} if \tcode{X} is an integer type; +otherwise, it denotes a corresponding unspecified unsigned-integer-like type +of the same width as \tcode{X}. +For an object \tcode{x} of type \tcode{X}, +\tcode{\placeholdernc{make-unsigned-like}(x)} is +\tcode{x} explicitly converted to +\tcode{\placeholdernc{make-unsigned-like-t}(X)}. + \rSec1[range.access]{Range access} \pnum @@ -250,11 +317,13 @@ \item Otherwise, if \tcode{E} is an lvalue, \tcode{\placeholdernc{decay-copy}(E.begin())} - if it is a valid expression and its type \tcode{I} models \tcode{Iterator}. + if it is a valid expression and its type \tcode{I} models + \libconcept{input_or_output_iterator}. \item Otherwise, \tcode{\placeholdernc{decay-copy}(begin(E))} if it is a - valid expression and its type \tcode{I} models \tcode{Iterator} with overload + valid expression and its type \tcode{I} models + \libconcept{input_or_output_iterator} with overload resolution performed in a context that includes the declarations: \begin{codeblock} template void begin(T&&) = delete; @@ -274,7 +343,7 @@ \pnum \begin{note} Whenever \tcode{ranges::begin(E)} is a valid expression, its type models -\tcode{Iterator}. +\tcode{input_or_output_iterator}. \end{note} \rSec2[range.access.end]{\tcode{ranges::end}} @@ -293,12 +362,17 @@ Otherwise, if \tcode{E} is an lvalue, \tcode{\placeholdernc{decay-copy}(E.end())} if it is a valid expression and its type \tcode{S} models - \tcode{Sentinel}. + \begin{codeblock} + sentinel_for + \end{codeblock} \item Otherwise, \tcode{\placeholdernc{decay-copy}(end(E))} if it is a valid expression and its type \tcode{S} models - \tcode{Sentinel} with overload + \begin{codeblock} + sentinel_for + \end{codeblock} + with overload resolution performed in a context that includes the declarations: \begin{codeblock} template void end(T&&) = delete; @@ -320,7 +394,7 @@ Whenever \tcode{ranges::end(E)} is a valid expression, the types \tcode{S} and \tcode{I} of \tcode{ranges::end(E)} and \tcode{ranges::begin(E)} -model \libconcept{Sentinel}. +model \tcode{\libconcept{sentinel_for}}. \end{note} \rSec2[range.access.cbegin]{\tcode{ranges::cbegin}} @@ -337,7 +411,7 @@ \pnum \begin{note} Whenever \tcode{ranges::cbegin(E)} is a valid expression, its type models -\tcode{Iterator}. +\libconcept{input_or_output_iterator}. \end{note} \rSec2[range.access.cend]{\tcode{ranges::cend}} @@ -357,7 +431,7 @@ Whenever \tcode{ranges::cend(E)} is a valid expression, the types \tcode{S} and \tcode{I} of \tcode{ranges::cend(E)} and \tcode{ranges::cbegin(E)} -model \libconcept{Sentinel}. +model \tcode{\libconcept{sentinel_for}}. \end{note} \rSec2[range.access.rbegin]{\tcode{ranges::rbegin}} @@ -370,11 +444,13 @@ \begin{itemize} \item If \tcode{E} is an lvalue, \tcode{\placeholdernc{decay-copy}(E.rbegin())} - if it is a valid expression and its type \tcode{I} models \tcode{Iterator}. + if it is a valid expression and its type \tcode{I} models + \libconcept{input_or_output_iterator}. \item Otherwise, \tcode{\placeholdernc{decay-copy}(rbegin(E))} if it is a valid - expression and its type \tcode{I} models \tcode{Iterator} with overload + expression and its type \tcode{I} models + \libconcept{input_or_output_iterator} with overload resolution performed in a context that includes the declaration: \begin{codeblock} template void rbegin(T&&) = delete; @@ -386,7 +462,7 @@ Otherwise, \tcode{make_reverse_iterator(ranges::end(E))} if both \tcode{ranges::begin(E)} and \tcode{ranges::end(\brk{}E)} are valid expressions of the same type \tcode{I} which models - \libconcept{BidirectionalIterator}\iref{iterator.concept.bidir}. + \libconcept{bidirectional_iterator}\iref{iterator.concept.bidir}. \item Otherwise, \tcode{ranges::rbegin(E)} is ill-formed. @@ -399,7 +475,7 @@ \pnum \begin{note} Whenever \tcode{ranges::rbegin(E)} is a valid expression, its type models -\tcode{Iterator}. +\libconcept{input_or_output_iterator}. \end{note} \rSec2[range.access.rend]{\tcode{ranges::rend}} @@ -413,12 +489,17 @@ \item If \tcode{E} is an lvalue, \tcode{\placeholdernc{decay-copy}(E.rend())} if it is a valid expression and its type \tcode{S} models - \tcode{Sentinel<\brk{}decltype(ranges::rbegin(E))>}. + \begin{codeblock} + sentinel_for + \end{codeblock} \item Otherwise, \tcode{\placeholdernc{decay-copy}(rend(E))} if it is a valid expression and its type \tcode{S} models - \tcode{Sentinel} with overload + \begin{codeblock} + sentinel_for + \end{codeblock} + with overload resolution performed in a context that includes the declaration: \begin{codeblock} template void rend(T&&) = delete; @@ -430,7 +511,7 @@ Otherwise, \tcode{make_reverse_iterator(ranges::begin(E))} if both \tcode{ranges::begin(E)} and \tcode{ranges::\brk{}end(E)} are valid expressions of the same type \tcode{I} which models - \tcode{BidirectionalIterator}\iref{iterator.concept.bidir}. + \libconcept{bidirectional_iterator}\iref{iterator.concept.bidir}. \item Otherwise, \tcode{ranges::rend(E)} is ill-formed. @@ -445,7 +526,7 @@ Whenever \tcode{ranges::rend(E)} is a valid expression, the types \tcode{S} and \tcode{I} of \tcode{ranges::rend(E)} and \tcode{ranges::rbegin(E)} -model \libconcept{Sentinel}. +model \tcode{\libconcept{sentinel_for}}. \end{note} \rSec2[range.access.crbegin]{\tcode{ranges::crbegin}} @@ -463,7 +544,7 @@ \pnum \begin{note} Whenever \tcode{ranges::crbegin(E)} is a valid expression, its -type models \tcode{Iterator}. +type models \libconcept{input_or_output_iterator}. \end{note} \rSec2[range.access.crend]{\tcode{ranges::crend}} @@ -483,7 +564,7 @@ Whenever \tcode{ranges::crend(E)} is a valid expression, the types \tcode{S} and \tcode{I} of \tcode{ranges::crend(E)} and \tcode{ranges::crbegin(E)} -model \libconcept{Sentinel}. +model \tcode{\libconcept{sentinel_for}}. \end{note} \rSec2[range.prim.size]{\tcode{ranges::size}} @@ -506,12 +587,12 @@ \item \tcode{\placeholdernc{decay-copy}(E.size())} if it is a valid expression and its type \tcode{I} - models \libconcept{Integral}. + is integer-like\iref{iterator.concept.winc}. \item Otherwise, \tcode{\placeholdernc{decay-copy}(size(E))} if it is a valid expression and its type \tcode{I} - models \libconcept{Integral} + is integer-like with overload resolution performed in a context that includes the declaration: \begin{codeblock} @@ -522,12 +603,12 @@ \end{itemize} \item - Otherwise, \tcode{(ranges::end(E) - ranges::begin(E))} + Otherwise, \tcode{\placeholdernc{make-unsigned-like}(ranges::end(E) - ranges::begin(E))}\iref{range.subrange} if it is a valid expression and the types \tcode{I} and \tcode{S} of \tcode{ranges::begin(E)} and \tcode{ranges::end(E)} (respectively) model both - \tcode{SizedSentinel}\iref{iterator.concept.sizedsentinel} and - \tcode{Forward\-Iterator}. + \tcode{\libconcept{sized_sentinel_for}}\iref{iterator.concept.sizedsentinel} and + \tcode{\libconcept{forward_iterator}}. However, \tcode{E} is evaluated only once. \item @@ -541,7 +622,7 @@ \pnum \begin{note} Whenever \tcode{ranges::size(E)} is a valid expression, its -type models \libconcept{Integral}. +type is integer-like. \end{note} \rSec2[range.prim.empty]{\tcode{ranges::empty}} @@ -563,7 +644,7 @@ \tcode{bool(ranges::begin(E) == ranges::end(E))} except that \tcode{E} is only evaluated once, if \tcode{EQ} is a valid expression and - the type of \tcode{ranges::begin(E)} models \libconcept{ForwardIterator}. + the type of \tcode{ranges::begin(E)} models \libconcept{forward_iterator}. \item Otherwise, \tcode{ranges::empty(E)} is ill-formed. @@ -593,12 +674,8 @@ \item Otherwise, if \tcode{ranges::begin(E)} is a valid expression whose type models - \tcode{ContiguousIterator}, - \begin{codeblock} - ranges::begin(E) == ranges::end(E) ? nullptr : addressof(*ranges::begin(E)) - \end{codeblock} - - except that \tcode{E} is evaluated only once. + \libconcept{contiguous_iterator}, + \tcode{to_address(ranges::begin(E))}. \item Otherwise, \tcode{ranges::data(E)} is ill-formed. @@ -640,33 +717,33 @@ Ranges are an abstraction that allow a \Cpp{} program to operate on elements of data structures uniformly. Calling \tcode{ranges::begin} on a range returns an object -whose type models \libconcept{Iterator}\iref{iterator.concept.iterator}. +whose type models \libconcept{input_or_output_iterator}\iref{iterator.concept.iterator}. Calling \tcode{ranges::end} on a range returns an object whose type \tcode{S}, together with the type \tcode{I} of the object returned by \tcode{ranges::begin}, -models \libconcept{Sentinel}. +models \tcode{\libconcept{sentinel_for}}. The library formalizes the interfaces, semantics, and complexity of ranges to enable algorithms and range adaptors that work efficiently on different types of sequences. \pnum -The \libconcept{Range} concept requires that +The \libconcept{range} concept requires that \tcode{ranges::begin} and \tcode{ranges::end} return an iterator and a sentinel, respectively. -The \libconcept{SizedRange} concept refines \libconcept{Range} with +The \libconcept{sized_range} concept refines \libconcept{range} with the requirement that the number of elements in the range can be determined in constant time using the \tcode{ranges::size} function. -The \tcode{View} concept specifies requirements on a \libconcept{Range} type +The \libconcept{view} concept specifies requirements on a \libconcept{range} type with constant-time copy and assign operations. \pnum -Several refinements of \libconcept{Range} group requirements +Several refinements of \libconcept{range} group requirements that arise frequently in concepts and algorithms. Common ranges are ranges for which \tcode{ranges::begin} and \tcode{ranges::end} return objects of the same type. Random access ranges are ranges for which \tcode{ranges::begin} returns a type that models -\libconcept{RandomAccessIterator}\iref{iterator.concept.random.access}. +\libconcept{random_access_iterator}\iref{iterator.concept.random.access}. (Contiguous, bidirectional, forward, input, and output ranges are defined similarly.) Viewable ranges can be converted to views. @@ -674,11 +751,11 @@ \rSec2[range.range]{Ranges} \pnum -The \libconcept{Range} concept defines the requirements of a type that allows +The \libconcept{range} concept defines the requirements of a type that allows iteration over its elements by providing an iterator and sentinel that denote the elements of the range. -\indexlibrary{\idxcode{Range}}% +\indexlibrary{\idxcode{range}}% \begin{itemdecl} template concept @\placeholder{range-impl}@ = // \expos @@ -688,11 +765,11 @@ }; template - concept Range = @\placeholdernc{range-impl}@; + concept range = @\placeholdernc{range-impl}@; template concept @\placeholder{forwarding-range}@ = // \expos - Range && @\placeholder{range-impl}@; + range && @\placeholder{range-impl}@; \end{itemdecl} \begin{itemdescr} @@ -719,18 +796,18 @@ are amortized constant time and non-modifying, and \item if the type of \tcode{ranges::begin(E)} models -\libconcept{ForwardIterator}, \tcode{ranges::begin(E)} is equality-preserving. +\libconcept{forward_iterator}, \tcode{ranges::begin(E)} is equality-preserving. \end{itemize} \pnum \begin{note} Equality preservation of both \tcode{ranges::begin} and -\tcode{ranges::end} enables passing a \libconcept{Range} whose iterator -type models \libconcept{ForwardIterator} to multiple +\tcode{ranges::end} enables passing a \libconcept{range} whose iterator +type models \libconcept{forward_iterator} to multiple algorithms and making multiple passes over the range by repeated calls to \tcode{ranges::begin} and \tcode{ranges::end}. Since \tcode{ranges::begin} is not required to be equality-preserving -when the return type does not model \libconcept{ForwardIterator}, repeated calls +when the return type does not model \libconcept{forward_iterator}, repeated calls might not return equal values or might not be well-defined; \tcode{ranges::begin} should be called at most once for such a range. \end{note} @@ -770,15 +847,15 @@ \rSec2[range.sized]{Sized ranges} \pnum -The \libconcept{SizedRange} concept specifies the requirements -of a \libconcept{Range} type that knows its size in constant time with the +The \libconcept{sized_range} concept specifies the requirements +of a \libconcept{range} type that knows its size in constant time with the \tcode{size} function. -\indexlibrary{\idxcode{SizedRange}}% +\indexlibrary{\idxcode{sized_range}}% \begin{itemdecl} template - concept SizedRange = - Range && + concept sized_range = + range && !disable_sized_range> && requires(T& t) { ranges::size(t); }; \end{itemdecl} @@ -786,21 +863,21 @@ \begin{itemdescr} \pnum Given an lvalue \tcode{t} of type \tcode{remove_reference_t}, \tcode{T} -models \libconcept{SizedRange} only if +models \libconcept{sized_range} only if \begin{itemize} \item \tcode{ranges::size(t)} is \bigoh{1}, does not modify \tcode{t}, and is equal to \tcode{ranges::distance(t)}, and -\item if \tcode{iterator_t} models \libconcept{ForwardIterator}, +\item if \tcode{iterator_t} models \libconcept{forward_iterator}, \tcode{ranges::size(t)} is well-defined regardless of the evaluation of \tcode{ranges::begin(t)}. \begin{note} \tcode{ranges::size(t)} is otherwise not required to be well-defined after evaluating \tcode{ranges::begin(t)}. For example, \tcode{ranges::size(t)} might be well-defined -for a \libconcept{SizedRange} whose iterator type -does not model \libconcept{ForwardIterator} +for a \libconcept{sized_range} whose iterator type +does not model \libconcept{forward_iterator} only if evaluated before the first call to \tcode{ranges::begin(t)}. \end{note} \end{itemize} @@ -809,63 +886,86 @@ \begin{note} The complexity requirement for the evaluation of \tcode{ranges::size} is non-amortized, unlike the case for the complexity of the evaluations of -\tcode{ranges::begin} and \tcode{ranges::end} in the \tcode{Range} concept. +\tcode{ranges::begin} and \tcode{ranges::end} in the \libconcept{range} concept. \end{note} +\end{itemdescr} + +\indexlibrary{\idxcode{disable_sized_range}}% +\begin{itemdecl} +template + inline constexpr bool disable_sized_range = false; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\remarks +Pursuant to \ref{namespace.std}, +users may specialize \tcode{disable_sized_range} +for cv-unqualified program-defined types. +Such specializations shall +be usable in constant expressions\iref{expr.const} and +have type \tcode{const bool}. \pnum \begin{note} \tcode{disable_sized_range} allows use of range types with the library -that satisfy but do not in fact model \libconcept{SizedRange}. +that satisfy but do not in fact model \libconcept{sized_range}. \end{note} \end{itemdescr} \rSec2[range.view]{Views} +\indexlibrary{\idxcode{view}}% +\begin{itemdecl} +template + concept view = + range && semiregular && enable_view; +\end{itemdecl} + +\begin{itemdescr} +% FIXME: This should explicitly say when view is modeled. \pnum -The \tcode{View} concept specifies the requirements of a \libconcept{Range} type +The \libconcept{view} concept specifies the requirements of a \libconcept{range} type that has constant time copy, move, and assignment operators; that is, the cost of these operations is not proportional to the number of elements in the -\tcode{View}. +\tcode{view}. \pnum \begin{example} -Examples of \tcode{View}s are: +Examples of \tcode{view}s are: \begin{itemize} -\item A \libconcept{Range} type that wraps a pair of iterators. +\item A \libconcept{range} type that wraps a pair of iterators. -\item A \libconcept{Range} type that holds its elements by \tcode{shared_ptr} +\item A \libconcept{range} type that holds its elements by \tcode{shared_ptr} and shares ownership with all its copies. -\item A \libconcept{Range} type that generates its elements on demand. +\item A \libconcept{range} type that generates its elements on demand. \end{itemize} Most containers\iref{containers} are not views since copying the container copies the elements, which cannot be done in constant time. \end{example} +\end{itemdescr} + +\pnum +Since the difference between \libconcept{range} and \libconcept{view} is largely +semantic, the two are differentiated with the help of \tcode{enable_view}. \indexlibrary{\idxcode{enable_view}}% -\indexlibrary{\idxcode{View}}% \begin{itemdecl} template inline constexpr bool enable_view = @\seebelow@; - -template - concept View = - Range && Semiregular && enable_view; \end{itemdecl} \begin{itemdescr} \pnum -Since the difference between \libconcept{Range} and \libconcept{View} is largely -semantic, the two are differentiated with the help of \tcode{enable_view}. - -\pnum +\remarks For a type \tcode{T}, the default value of \tcode{enable_view} is: \begin{itemize} -\item If \tcode{DerivedFrom} is \tcode{true}, \tcode{true}. +\item If \tcode{derived_from} is \tcode{true}, \tcode{true}. \item Otherwise, if \tcode{T} is a specialization of class template \tcode{initializer_list}\iref{support.initlist}, \tcode{set}\iref{set}, @@ -873,9 +973,9 @@ \tcode{unordered_set}\iref{unord.set}, \tcode{unordered_multiset}\iref{unord.multiset}, or \tcode{match_results}\iref{re.results}, \tcode{false}. -\item Otherwise, if both \tcode{T} and \tcode{const T} model \libconcept{Range} - and \tcode{iter_reference_t{>}} is not the same type as - \tcode{iter_reference_t{>}}, +\item Otherwise, if both \tcode{T} and \tcode{const T} model \libconcept{range} + and \tcode{range_reference_t} is not the same type as + \tcode{range_reference_t}, \tcode{false}. \begin{note} Deep \tcode{const}-ness implies element ownership, @@ -886,85 +986,89 @@ \pnum Pursuant to \ref{namespace.std}, users may specialize \tcode{enable_view} -to \tcode{true} for types which model \libconcept{View}, +to \tcode{true} +for cv-unqualified program-defined types which model \libconcept{view}, and \tcode{false} for types which do not. +Such specializations shall +be usable in constant expressions\iref{expr.const} and +have type \tcode{const bool}. \end{itemdescr} \rSec2[range.refinements]{Other range refinements} \pnum -The \tcode{OutputRange} concept specifies requirements of a -\libconcept{Range} type for which \tcode{ranges::begin} returns -a model of \tcode{OutputIterator}\iref{iterator.concept.output}. -\tcode{InputRange}, \tcode{ForwardRange}, \tcode{BidirectionalRange}, -and \tcode{RandomAccessRange} are defined similarly. +The \libconcept{output_range} concept specifies requirements of a +\libconcept{range} type for which \tcode{ranges::begin} returns +a model of \libconcept{output_iterator}\iref{iterator.concept.output}. +\libconcept{input_range}, \libconcept{forward_range}, \libconcept{bidirectional_range}, +and \libconcept{random_access_range} are defined similarly. -\indexlibrary{\idxcode{OutputRange}}% -\indexlibrary{\idxcode{InputRange}}% -\indexlibrary{\idxcode{ForwardRange}}% -\indexlibrary{\idxcode{BidirectionalRange}}% -\indexlibrary{\idxcode{RandomAccessRange}}% +\indexlibrary{\idxcode{output_range}}% +\indexlibrary{\idxcode{input_range}}% +\indexlibrary{\idxcode{forward_range}}% +\indexlibrary{\idxcode{bidirectional_range}}% +\indexlibrary{\idxcode{random_access_range}}% \begin{itemdecl} template - concept OutputRange = - Range && OutputIterator, T>; + concept output_range = + range && output_iterator, T>; template - concept InputRange = - Range && InputIterator>; + concept input_range = + range && input_iterator>; template - concept ForwardRange = - InputRange && ForwardIterator>; + concept forward_range = + input_range && forward_iterator>; template - concept BidirectionalRange = - ForwardRange && BidirectionalIterator>; + concept bidirectional_range = + forward_range && bidirectional_iterator>; template - concept RandomAccessRange = - BidirectionalRange && RandomAccessIterator>; + concept random_access_range = + bidirectional_range && random_access_iterator>; \end{itemdecl} \pnum -\tcode{ContiguousRange} additionally requires that +\tcode{contiguous_range} additionally requires that the \tcode{ranges::data} customization point\iref{range.prim.data} is usable with the range. -\indexlibrary{\idxcode{ContiguousRange}}% +\indexlibrary{\idxcode{contiguous_range}}% \begin{itemdecl} template - concept ContiguousRange = - RandomAccessRange && ContiguousIterator> && + concept contiguous_range = + random_access_range && contiguous_iterator> && requires(T& t) { - { ranges::data(t) } -> Same>>>; + { ranges::data(t) } -> same_as>>; }; \end{itemdecl} \pnum -The \tcode{CommonRange} concept specifies requirements of -a \libconcept{Range} type for which \tcode{ranges::begin} and +The \libconcept{common_range} concept specifies requirements of +a \libconcept{range} type for which \tcode{ranges::begin} and \tcode{ranges::end} return objects of the same type. \begin{example} -The standard containers\iref{containers} model \tcode{CommonRange}. +The standard containers\iref{containers} model \libconcept{common_range}. \end{example} -\indexlibrary{\idxcode{CommonRange}}% +\indexlibrary{\idxcode{common_range}}% \begin{itemdecl} template - concept CommonRange = - Range && Same, sentinel_t>; + concept common_range = + range && same_as, sentinel_t>; \end{itemdecl} \pnum -The \libconcept{ViewableRange} concept specifies the requirements of a -\libconcept{Range} type that can be converted to a \libconcept{View} safely. +The \libconcept{viewable_range} concept specifies the requirements of a +\libconcept{range} type that can be converted to a \libconcept{view} safely. -\indexlibrary{\idxcode{ViewableRange}}% +\indexlibrary{\idxcode{viewable_range}}% \begin{itemdecl} template - concept ViewableRange = - Range && (@\placeholder{forwarding-range}@ || View>); + concept viewable_range = + range && (@\placeholder{forwarding-range}@ || view>); \end{itemdecl} \rSec1[range.utility]{Range utilities} @@ -982,31 +1086,31 @@ \begin{codeblock} template concept @\placeholder{simple-view}@ = // \expos - View && Range && - Same, iterator_t> && - Same, sentinel_t>; + view && range && + same_as, iterator_t> && + same_as, sentinel_t>; -template +template concept @\placeholder{has-arrow}@ = // \expos is_pointer_v || requires(I i) { i.operator->(); }; template concept @\placeholder{not-same-as}@ = // \expos - !Same, remove_cvref_t>; + !same_as, remove_cvref_t>; \end{codeblock} \rSec2[view.interface]{View interface} \pnum The class template \tcode{view_interface} is a helper for defining -\tcode{View}-like types that offer a container-like interface. It is +\tcode{view}-like types that offer a container-like interface. It is parameterized with the type that is derived from it. \indexlibrary{\idxcode{view_interface}}% \begin{codeblock} namespace std::ranges { template - requires is_class_v && Same> + requires is_class_v && same_as> class view_interface : public view_base { private: constexpr D& derived() noexcept { // \expos @@ -1016,10 +1120,10 @@ return static_cast(*this); } public: - constexpr bool empty() requires ForwardRange { + constexpr bool empty() requires forward_range { return ranges::begin(derived()) == ranges::end(derived()); } - constexpr bool empty() const requires ForwardRange { + constexpr bool empty() const requires forward_range { return ranges::begin(derived()) == ranges::end(derived()); } @@ -1032,36 +1136,36 @@ return !ranges::empty(derived()); } - constexpr auto data() requires ContiguousIterator> { - return ranges::empty(derived()) ? nullptr : addressof(*ranges::begin(derived())); + constexpr auto data() requires contiguous_iterator> { + return to_address(ranges::begin(derived())); } constexpr auto data() const - requires Range && ContiguousIterator> { - return ranges::empty(derived()) ? nullptr : addressof(*ranges::begin(derived())); + requires range && contiguous_iterator> { + return to_address(ranges::begin(derived())); } - constexpr auto size() requires ForwardRange && - SizedSentinel, iterator_t> { + constexpr auto size() requires forward_range && + sized_sentinel_for, iterator_t> { return ranges::end(derived()) - ranges::begin(derived()); } - constexpr auto size() const requires ForwardRange && - SizedSentinel, iterator_t> { + constexpr auto size() const requires forward_range && + sized_sentinel_for, iterator_t> { return ranges::end(derived()) - ranges::begin(derived()); } - constexpr decltype(auto) front() requires ForwardRange; - constexpr decltype(auto) front() const requires ForwardRange; + constexpr decltype(auto) front() requires forward_range; + constexpr decltype(auto) front() const requires forward_range; - constexpr decltype(auto) back() requires BidirectionalRange && CommonRange; + constexpr decltype(auto) back() requires bidirectional_range && common_range; constexpr decltype(auto) back() const - requires BidirectionalRange && CommonRange; + requires bidirectional_range && common_range; - template - constexpr decltype(auto) operator[](iter_difference_t> n) { + template + constexpr decltype(auto) operator[](range_difference_t n) { return ranges::begin(derived())[n]; } - template - constexpr decltype(auto) operator[](iter_difference_t> n) const { + template + constexpr decltype(auto) operator[](range_difference_t n) const { return ranges::begin(derived())[n]; } }; @@ -1073,14 +1177,14 @@ incomplete type. Before any member of the resulting specialization of \tcode{view_interface} other than special member functions is referenced, \tcode{D} shall be complete, and -model both \libconcept{DerivedFrom>} and \libconcept{View}. +model both \tcode{\libconcept{derived_from}>} and \libconcept{view}. \rSec3[view.interface.members]{Members} \indexlibrary{\idxcode{view_interface}!\idxcode{front}}% \begin{itemdecl} -constexpr decltype(auto) front() requires ForwardRange; -constexpr decltype(auto) front() const requires ForwardRange; +constexpr decltype(auto) front() requires forward_range; +constexpr decltype(auto) front() const requires forward_range; \end{itemdecl} \begin{itemdescr} @@ -1093,9 +1197,9 @@ \indexlibrary{\idxcode{view_interface}!\idxcode{back}}% \begin{itemdecl} -constexpr decltype(auto) back() requires BidirectionalRange && CommonRange; +constexpr decltype(auto) back() requires bidirectional_range && common_range; constexpr decltype(auto) back() const - requires BidirectionalRange && CommonRange; + requires bidirectional_range && common_range; \end{itemdecl} \begin{itemdescr} @@ -1111,68 +1215,68 @@ \pnum The \tcode{subrange} class template combines together an iterator and a sentinel into a single object that models the -\libconcept{View} concept. Additionally, it models the -\libconcept{SizedRange} concept when the final template parameter is +\libconcept{view} concept. Additionally, it models the +\libconcept{sized_range} concept when the final template parameter is \tcode{subrange_kind::sized}. \indexlibrary{\idxcode{subrange}}% \begin{codeblock} namespace std::ranges { template - concept @\placeholdernc{pair-like}@ = // \expos + concept @\placeholdernc{pair-like}@ = // \expos !is_reference_v && requires(T t) { typename tuple_size::type; // ensures \tcode{tuple_size} is complete - requires DerivedFrom, integral_constant>; + requires derived_from, integral_constant>; typename tuple_element_t<0, remove_const_t>; typename tuple_element_t<1, remove_const_t>; - { get<0>(t) } -> const tuple_element_t<0, T>&; - { get<1>(t) } -> const tuple_element_t<1, T>&; + { get<0>(t) } -> convertible_to&>; + { get<1>(t) } -> convertible_to&>; }; template - concept @\placeholdernc{pair-like-convertible-to}@ = // \expos - !Range && @\placeholder{pair-like}@> && + concept @\placeholdernc{pair-like-convertible-to}@ = // \expos + !range && @\placeholder{pair-like}@> && requires(T&& t) { - { get<0>(std::forward(t)) } -> ConvertibleTo; - { get<1>(std::forward(t)) } -> ConvertibleTo; + { get<0>(std::forward(t)) } -> convertible_to; + { get<1>(std::forward(t)) } -> convertible_to; }; template - concept @\placeholdernc{pair-like-convertible-from}@ = // \expos - !Range && @\placeholdernc{pair-like}@ && Constructible; + concept @\placeholdernc{pair-like-convertible-from}@ = // \expos + !range && @\placeholdernc{pair-like}@ && constructible_from; template - concept @\placeholdernc{iterator-sentinel-pair}@ = // \expos - !Range && @\placeholdernc{pair-like}@ && - Sentinel, tuple_element_t<0, T>>; + concept @\placeholdernc{iterator-sentinel-pair}@ = // \expos + !range && @\placeholdernc{pair-like}@ && + sentinel_for, tuple_element_t<0, T>>; - template S = I, subrange_kind K = - SizedSentinel ? subrange_kind::sized : subrange_kind::unsized> - requires (K == subrange_kind::sized || !SizedSentinel) + template S = I, subrange_kind K = + sized_sentinel_for ? subrange_kind::sized : subrange_kind::unsized> + requires (K == subrange_kind::sized || !sized_sentinel_for) class subrange : public view_interface> { private: - static constexpr bool StoreSize = // \expos - K == subrange_kind::sized && !SizedSentinel; - I begin_ = I(); // \expos - S end_ = S(); // \expos - iter_difference_t size_ = 0; // \expos; present only - // when \tcode{StoreSize} is \tcode{true} + static constexpr bool StoreSize = // \expos + K == subrange_kind::sized && !sized_sentinel_for; + I begin_ = I(); // \expos + S end_ = S(); // \expos + @\placeholdernc{make-unsigned-like-t}@(iter_difference_t) size_ = 0; // \expos; present only + // when \tcode{StoreSize} is \tcode{true} public: subrange() = default; constexpr subrange(I i, S s) requires (!StoreSize); - constexpr subrange(I i, S s, iter_difference_t n) + constexpr subrange(I i, S s, @\placeholdernc{make-unsigned-like-t}@(iter_difference_t) n) requires (K == subrange_kind::sized); template<@\placeholdernc{not-same-as}@ R> requires @\placeholdernc{forwarding-range}@ && - ConvertibleTo, I> && ConvertibleTo, S> - constexpr subrange(R&& r) requires (!StoreSize || SizedRange); + convertible_to, I> && convertible_to, S> + constexpr subrange(R&& r) requires (!StoreSize || sized_range); template<@\placeholdernc{forwarding-range}@ R> - requires ConvertibleTo, I> && ConvertibleTo, S> - constexpr subrange(R&& r, iter_difference_t n) + requires convertible_to, I> && convertible_to, S> + constexpr subrange(R&& r, @\placeholdernc{make-unsigned-like-t}@(iter_difference_t) n) requires (K == subrange_kind::sized) : subrange{ranges::begin(r), ranges::end(r), n} {} @@ -1185,7 +1289,7 @@ {} template<@\placeholdernc{pair-like-convertible-to}@ PairLike> - constexpr subrange(PairLike&& r, iter_difference_t n) + constexpr subrange(PairLike&& r, @\placeholdernc{make-unsigned-like-t}@(iter_difference_t) n) requires (K == subrange_kind::sized) : subrange{std::get<0>(std::forward(r)), std::get<1>(std::forward(r)), n} @@ -1199,36 +1303,37 @@ constexpr S end() const; constexpr bool empty() const; - constexpr iter_difference_t size() const + constexpr @\placeholdernc{make-unsigned-like-t}@(iter_difference_t) size() const requires (K == subrange_kind::sized); [[nodiscard]] constexpr subrange next(iter_difference_t n = 1) const; [[nodiscard]] constexpr subrange prev(iter_difference_t n = 1) const - requires BidirectionalIterator; + requires bidirectional_iterator; constexpr subrange& advance(iter_difference_t n); friend constexpr I begin(subrange&& r) { return r.begin(); } friend constexpr S end(subrange&& r) { return r.end(); } }; - template S> - subrange(I, S, iter_difference_t) -> subrange; + template S> + subrange(I, S, @\placeholdernc{make-unsigned-like-t}@(iter_difference_t)) -> + subrange; template<@\placeholder{iterator-sentinel-pair}@ P> subrange(P) -> subrange, tuple_element_t<1, P>>; template<@\placeholder{iterator-sentinel-pair}@ P> - subrange(P, iter_difference_t>) -> + subrange(P, @\placeholdernc{make-unsigned-like-t}@(iter_difference_t>)) -> subrange, tuple_element_t<1, P>, subrange_kind::sized>; template<@\placeholder{forwarding-range}@ R> subrange(R&&) -> subrange, sentinel_t, - (SizedRange || SizedSentinel, iterator_t>) + (sized_range || sized_sentinel_for, iterator_t>) ? subrange_kind::sized : subrange_kind::unsized>; template<@\placeholder{forwarding-range}@ R> - subrange(R&&, iter_difference_t>) -> + subrange(R&&, @\placeholdernc{make-unsigned-like-t}@(range_difference_t)) -> subrange, sentinel_t, subrange_kind::sized>; template @@ -1259,14 +1364,14 @@ \indexlibrary{\idxcode{subrange}!\idxcode{subrange}}% \begin{itemdecl} -constexpr subrange(I i, S s, iter_difference_t n) +constexpr subrange(I i, S s, @\placeholdernc{make-unsigned-like-t}@(iter_difference_t) n) requires (K == subrange_kind::sized); \end{itemdecl} \begin{itemdescr} \pnum \expects \range{i}{s} is a valid range, and -\tcode{n == ranges::distance(i, s)}. +\tcode{n == \placeholdernc{make-unsigned-like}(ranges::distance(i, s))}. \pnum \effects Initializes \tcode{begin_} with \tcode{i} and \tcode{end_} with @@ -1276,9 +1381,9 @@ \pnum \begin{note} Accepting the length of the range and storing it to later return from -\tcode{size()} enables \tcode{subrange} to model \libconcept{SizedRange} even +\tcode{size()} enables \tcode{subrange} to model \libconcept{sized_range} even when it stores an iterator and sentinel that do not model -\libconcept{SizedSentinel}. +\libconcept{sized_sentinel_for}. \end{note} \end{itemdescr} @@ -1286,8 +1391,8 @@ \begin{itemdecl} template<@\placeholdernc{not-same-as}@ R> requires @\placeholdernc{forwarding-range}@ && - ConvertibleTo, I> && ConvertibleTo, S> -constexpr subrange(R&& r) requires (!StoreSize || SizedRange); + convertible_to, I> && convertible_to, S> +constexpr subrange(R&& r) requires (!StoreSize || sized_range); \end{itemdecl} \begin{itemdescr} @@ -1346,7 +1451,7 @@ \indexlibrary{\idxcode{size}!\idxcode{subrange}}% \begin{itemdecl} -constexpr iter_difference_t size() const +constexpr @\placeholdernc{make-unsigned-like-t}@(iter_difference_t) size() const requires (K == subrange_kind::sized); \end{itemdecl} @@ -1355,7 +1460,7 @@ \effects \begin{itemize} \item If \tcode{StoreSize} is \tcode{true}, equivalent to: \tcode{return size_;} -\item Otherwise, equivalent to: \tcode{return end_ - begin_;} +\item Otherwise, equivalent to: \tcode{return \placeholdernc{make-unsigned-like-t}(end_ - begin_);} \end{itemize} \end{itemdescr} @@ -1375,7 +1480,7 @@ \pnum \begin{note} -If \tcode{I} does not model \libconcept{ForwardIterator}, \tcode{next} +If \tcode{I} does not model \libconcept{forward_iterator}, \tcode{next} can invalidate \tcode{*this}. \end{note} \end{itemdescr} @@ -1383,7 +1488,7 @@ \indexlibrary{\idxcode{prev}!\idxcode{subrange}}% \begin{itemdecl} [[nodiscard]] constexpr subrange prev(iter_difference_t n = 1) const - requires BidirectionalIterator; + requires bidirectional_iterator; \end{itemdecl} \begin{itemdescr} @@ -1407,7 +1512,11 @@ \begin{itemize} \item If \tcode{StoreSize} is \tcode{true}, \begin{codeblock} -size_ -= n - ranges::advance(begin_, n, end_); +auto d = n - ranges::advance(begin_, n, end_); +if (d >= 0) + size_ -= @\placeholdernc{make-unsigned-like}@(d); +else + size_ += @\placeholdernc{make-unsigned-like}@(-d); return *this; \end{codeblock} \item Otherwise, @@ -1442,10 +1551,10 @@ The tag type \tcode{dangling} is used together with the template aliases \tcode{safe_iterator_t} and \tcode{safe_subrange_t} to indicate that an algorithm -that typically returns an iterator into or subrange of a \tcode{Range} argument +that typically returns an iterator into or subrange of a \tcode{range} argument does not return an iterator or subrange which could potentially reference a range -whose lifetime has ended for a particular rvalue \tcode{Range} argument +whose lifetime has ended for a particular rvalue \tcode{range} argument which does not model \tcode{\placeholder{forwarding-range}}\iref{range.range}. \begin{codeblock} namespace std::ranges { @@ -1462,12 +1571,12 @@ \begin{codeblock} vector f(); auto result1 = ranges::find(f(), 42); // \#1 -static_assert(Same); +static_assert(same_as); auto vec = f(); auto result2 = ranges::find(vec, 42); // \#2 -static_assert(Same::iterator>); +static_assert(same_as::iterator>); auto result3 = ranges::find(subrange{vec}, 42); // \#3 -static_assert(Same::iterator>); +static_assert(same_as::iterator>); \end{codeblock} The call to \tcode{ranges::find} at \#1 returns \tcode{ranges::dangling} since \tcode{f()} is an rvalue \tcode{vector}; @@ -1482,17 +1591,17 @@ \pnum This subclause defines \term{range factories}, -which are utilities to create a \libconcept{View}. +which are utilities to create a \libconcept{view}. \pnum -Range factories are declared in namespace \tcode{std::ranges::view}. +Range factories are declared in namespace \tcode{std::ranges::views}. \rSec2[range.empty]{Empty view} \rSec3[range.empty.overview]{Overview} \pnum -\tcode{empty_view} produces a \libconcept{View} of no elements of +\tcode{empty_view} produces a \libconcept{view} of no elements of a particular type. \pnum @@ -1515,7 +1624,7 @@ static constexpr T* begin() noexcept { return nullptr; } static constexpr T* end() noexcept { return nullptr; } static constexpr T* data() noexcept { return nullptr; } - static constexpr ptrdiff_t size() noexcept { return 0; } + static constexpr size_t size() noexcept { return 0; } static constexpr bool empty() noexcept { return true; } friend constexpr T* begin(empty_view) noexcept { return nullptr; } @@ -1529,7 +1638,7 @@ \rSec3[range.single.overview]{Overview} \pnum -\tcode{single_view} produces a \libconcept{View} that contains +\tcode{single_view} produces a \libconcept{view} that contains exactly one element of a specified value. \pnum @@ -1537,7 +1646,7 @@ \begin{codeblock} single_view s{4}; for (int i : s) - cout << i; // prints 4 + cout << i; // prints \tcode{4} \end{codeblock} \end{example} @@ -1545,7 +1654,7 @@ \begin{codeblock} namespace std::ranges { - template + template requires is_object_v class single_view : public view_interface> { private: @@ -1555,14 +1664,14 @@ constexpr explicit single_view(const T& t); constexpr explicit single_view(T&& t); template - requires Constructible + requires constructible_from constexpr single_view(in_place_t, Args&&... args); constexpr T* begin() noexcept; constexpr const T* begin() const noexcept; constexpr T* end() noexcept; constexpr const T* end() const noexcept; - static constexpr ptrdiff_t size() noexcept; + static constexpr size_t size() noexcept; constexpr T* data() noexcept; constexpr const T* data() const noexcept; }; @@ -1625,7 +1734,7 @@ \indexlibrary{\idxcode{size}!\idxcode{single_view}}% \begin{itemdecl} -static constexpr ptrdiff_t size() noexcept; +static constexpr size_t size() noexcept; \end{itemdecl} \begin{itemdescr} @@ -1644,13 +1753,13 @@ \effects Equivalent to: \tcode{return value_.operator->();} \end{itemdescr} -\rSec3[range.single.adaptor]{\tcode{view::single}} +\rSec3[range.single.adaptor]{\tcode{views::single}} \pnum -The name \tcode{view::single} denotes a +The name \tcode{views::single} denotes a customization point object\iref{customization.point.object}. For some subexpression \tcode{E}, the expression -\tcode{view::single(E)} is expression-equivalent to +\tcode{views::single(E)} is expression-equivalent to \tcode{single_view\{E\}}. \rSec2[range.iota]{Iota view} @@ -1674,13 +1783,13 @@ \begin{codeblock} namespace std::ranges { template - concept @\placeholdernc{Decrementable}@ = // \expos + concept @\placeholdernc{decrementable}@ = // \expos @\seebelow@; template - concept @\placeholdernc{Advanceable}@ = // \expos + concept @\placeholdernc{advanceable}@ = // \expos @\seebelow@; - template + template requires @\placeholdernc{weakly-equality-comparable-with}@ class iota_view : public view_interface> { private: @@ -1697,30 +1806,49 @@ type_identity_t bound); constexpr iterator begin() const; - constexpr sentinel end() const; - constexpr iterator end() const requires Same; + constexpr auto end() const; + constexpr iterator end() const requires same_as; - constexpr auto size() const - requires (Same && @\placeholdernc{Advanceable}@) || - (Integral && Integral) || - SizedSentinel - { return bound_ - value_; } + constexpr auto size() const requires @\seebelow@; }; template - requires (!Integral || !Integral || is_signed_v == is_signed_v) - iota_view(W, Bound) -> iota_view; + requires (!@\placeholdernc{is-integer-like}@ || !@\placeholdernc{is-integer-like}@ || + (@\placeholdernc{is-signed-integer-like}@ == @\placeholdernc{is-signed-integer-like}@)) + iota_view(W, Bound) -> iota_view; } \end{codeblock} \pnum -The exposition-only \tcode{\placeholder{Decrementable}} concept is equivalent to: +Let \tcode{\placeholdernc{IOTA-DIFF-T}(W)} be defined as follows: +\begin{itemize} +\item + If \tcode{W} is not an integral type, or + if it is an integral type and \tcode{sizeof(iter_difference_t)} + is greater than \tcode{sizeof(W)}, + then \tcode{\placeholdernc{IOTA-DIFF-T}(W)} denotes \tcode{iter_difference_t}. +\item + Otherwise, \tcode{\placeholdernc{IOTA-DIFF-T}(W)} + is a signed integer type of width greater than the width of \tcode{W} + if such a type exists. +\item + Otherwise, \tcode{\placeholdernc{IOTA-DIFF-T}(W)} + is an unspecified signed-integer-like type\iref{iterator.concept.winc} + of width not less than the width of \tcode{W}. + \begin{note} + It is unspecified + whether this type satisfies \libconcept{weakly_incrementable}. + \end{note} +\end{itemize} + +\pnum +The exposition-only \tcode{\placeholder{decrementable}} concept is equivalent to: \begin{itemdecl} template - concept @\placeholder{Decrementable}@ = - Incrementable && requires(I i) { - { --i } -> Same; - { i-- } -> Same; + concept @\placeholder{decrementable}@ = + incrementable && requires(I i) { + { --i } -> same_as; + { i-- } -> same_as; }; \end{itemdecl} @@ -1731,7 +1859,7 @@ \pnum Let \tcode{a} and \tcode{b} be equal objects of type \tcode{I}. -\tcode{I} models \tcode{\placeholdernc{Decrementable}} only if +\tcode{I} models \tcode{\placeholdernc{decrementable}} only if \begin{itemize} \item If \tcode{a} and \tcode{b} are decrementable, then the following are all true: @@ -1747,44 +1875,44 @@ \end{itemdescr} \pnum -The exposition-only \tcode{\placeholder{Advanceable}} concept is equivalent to: +The exposition-only \tcode{\placeholder{advanceable}} concept is equivalent to: \begin{itemdecl} template - concept @\placeholder{Advanceable}@ = - @\placeholdernc{Decrementable}@ && StrictTotallyOrdered && - requires(I i, const I j, const iter_difference_t n) { - { i += n } -> Same; - { i -= n } -> Same; - { j + n } -> Same; - { n + j } -> Same; - { j - n } -> Same; - { j - j } -> Same>; + concept @\placeholder{advanceable}@ = + @\placeholdernc{decrementable}@ && totally_ordered && + requires(I i, const I j, const @\placeholdernc{IOTA-DIFF-T}@(I) n) { + { i += n } -> same_as; + { i -= n } -> same_as; + I(j + n); + I(n + j); + I(j - n); + { j - j } -> convertible_to<@\placeholdernc{IOTA-DIFF-T}@(I)>; }; \end{itemdecl} +Let \tcode{D} be \tcode{\placeholdernc{IOTA-DIFF-T}(I)}. Let \tcode{a} and \tcode{b} be objects of type \tcode{I} such that \tcode{b} is reachable from \tcode{a} after \tcode{n} applications of \tcode{++a}, -for some value \tcode{n} of type \tcode{iter_difference_t}, -and let \tcode{D} be \tcode{iter_difference_t}. -\tcode{I} models \tcode{\placeholdernc{Advanceable}} only if +for some value \tcode{n} of type \tcode{D}. +\tcode{I} models \tcode{\placeholdernc{advanceable}} only if \begin{itemize} \item \tcode{(a += n)} is equal to \tcode{b}. \item \tcode{addressof(a += n)} is equal to \tcode{addressof(a)}. -\item \tcode{(a + n)} is equal to \tcode{(a += n)}. +\item \tcode{I(a + n)} is equal to \tcode{(a += n)}. \item For any two positive values \tcode{x} and \tcode{y} of type \tcode{D}, - if \tcode{(a + D(x + y))} is well-defined, then - \tcode{(a + D(x + y))} is equal to \tcode{((a + x) + y)}. -\item \tcode{(a + D(0))} is equal to \tcode{a}. -\item If \tcode{(a + D(n - 1))} is well-defined, then - \tcode{(a + n)} is equal to \tcode{++(a + D(n - 1))}. + if \tcode{I(a + D(x + y))} is well-defined, then + \tcode{I(a + D(x + y))} is equal to \tcode{I(I(a + x) + y)}. +\item \tcode{I(a + D(0))} is equal to \tcode{a}. +\item If \tcode{I(a + D(n - 1))} is well-defined, then + \tcode{I(a + n)} is equal to \tcode{[](I c) \{ return ++c; \}(I(a + D(n - 1)))}. \item \tcode{(b += -n)} is equal to \tcode{a}. \item \tcode{(b -= n)} is equal to \tcode{a}. \item \tcode{addressof(b -= n)} is equal to \tcode{addressof(b)}. -\item \tcode{(b - n)} is equal to \tcode{(b -= n)}. -\item \tcode{(b - a)} is equal to \tcode{n}. -\item \tcode{(a - b)} is equal to \tcode{-n}. +\item \tcode{I(b - n)} is equal to \tcode{(b -= n)}. +\item \tcode{D(b - a)} is equal to \tcode{n}. +\item \tcode{D(a - b)} is equal to \tcode{D(-n)}. \item \tcode{bool(a <= b)} is \tcode{true}. \end{itemize} @@ -1813,6 +1941,8 @@ \expects \tcode{Bound} denotes \tcode{unreachable_sentinel_t} or \tcode{bound} is reachable from \tcode{value}. +When \tcode{W} and \tcode{Bound} model \libconcept{totally_ordered_with}, +then \tcode{bool(value <= bound)} is \tcode{true}. \pnum \effects Initializes \tcode{value_} with \tcode{value} and @@ -1831,17 +1961,23 @@ \indexlibrary{\idxcode{end}!\idxcode{iota_view}}% \begin{itemdecl} -constexpr sentinel end() const; +constexpr auto end() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return sentinel\{bound_\};} +\effects Equivalent to: +\begin{codeblock} +if constexpr (same_as) + return unreachable_sentinel; +else + return sentinel{bound_}; +\end{codeblock} \end{itemdescr} \indexlibrary{\idxcode{end}!\idxcode{iota_view}}% \begin{itemdecl} -constexpr iterator end() const requires Same; +constexpr iterator end() const requires same_as; \end{itemdecl} \begin{itemdescr} @@ -1849,6 +1985,33 @@ \effects Equivalent to: \tcode{return iterator\{bound_\};} \end{itemdescr} +\indexlibrarymember{size}{iota_view}% +\begin{itemdecl} +constexpr auto size() const requires @\seebelow@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\begin{codeblock} +if constexpr (@\placeholdernc{is-integer-like}@ && @\placeholdernc{is-integer-like}@) + return (value_ < 0) + ? ((bound_ < 0) + ? @\placeholdernc{make-unsigned-like}@(-value_) - @\placeholdernc{make-unsigned-like}@(-bound_) + : @\placeholdernc{make-unsigned-like}@(bound_) + @\placeholdernc{make-unsigned-like}@(-value_)) + : @\placeholdernc{make-unsigned-like}@(bound_) - @\placeholdernc{make-unsigned-like}@(value_); +else + return @\placeholdernc{make-unsigned-like}@(bound_ - value_); +\end{codeblock} + +\pnum +\remarks The expression in the \grammarterm{requires-clause} is equivalent to +\begin{codeblock} +(same_as && @\placeholder{advanceable}@) || (integral && integral) || + sized_sentinel_for +\end{codeblock} +\end{itemdescr} + \rSec3[range.iota.iterator]{Class \tcode{iota_view::iterator}} \begin{codeblock} @@ -1860,7 +2023,7 @@ public: using iterator_category = @\seebelow@; using value_type = W; - using difference_type = iter_difference_t; + using difference_type = @\placeholdernc{IOTA-DIFF-T}@(W); iterator() = default; constexpr explicit iterator(W value); @@ -1869,41 +2032,42 @@ constexpr iterator& operator++(); constexpr void operator++(int); - constexpr iterator operator++(int) requires Incrementable; + constexpr iterator operator++(int) requires incrementable; - constexpr iterator& operator--() requires @\placeholdernc{Decrementable}@; - constexpr iterator operator--(int) requires @\placeholdernc{Decrementable}@; + constexpr iterator& operator--() requires @\placeholdernc{decrementable}@; + constexpr iterator operator--(int) requires @\placeholdernc{decrementable}@; constexpr iterator& operator+=(difference_type n) - requires @\placeholdernc{Advanceable}@; + requires @\placeholdernc{advanceable}@; constexpr iterator& operator-=(difference_type n) - requires @\placeholdernc{Advanceable}@; + requires @\placeholdernc{advanceable}@; constexpr W operator[](difference_type n) const - requires @\placeholdernc{Advanceable}@; + requires @\placeholdernc{advanceable}@; friend constexpr bool operator==(const iterator& x, const iterator& y) - requires EqualityComparable; - friend constexpr bool operator!=(const iterator& x, const iterator& y) - requires EqualityComparable; + requires equality_comparable; friend constexpr bool operator<(const iterator& x, const iterator& y) - requires StrictTotallyOrdered; + requires totally_ordered; friend constexpr bool operator>(const iterator& x, const iterator& y) - requires StrictTotallyOrdered; + requires totally_ordered; friend constexpr bool operator<=(const iterator& x, const iterator& y) - requires StrictTotallyOrdered; + requires totally_ordered; friend constexpr bool operator>=(const iterator& x, const iterator& y) - requires StrictTotallyOrdered; + requires totally_ordered; + friend constexpr compare_three_way_result_t operator<=>( + const iterator& x, const iterator& y) + requires totally_ordered && three_way_comparable; friend constexpr iterator operator+(iterator i, difference_type n) - requires @\placeholdernc{Advanceable}@; + requires @\placeholdernc{advanceable}@; friend constexpr iterator operator+(difference_type n, iterator i) - requires @\placeholdernc{Advanceable}@; + requires @\placeholdernc{advanceable}@; friend constexpr iterator operator-(iterator i, difference_type n) - requires @\placeholdernc{Advanceable}@; + requires @\placeholdernc{advanceable}@; friend constexpr difference_type operator-(const iterator& x, const iterator& y) - requires @\placeholdernc{Advanceable}@; + requires @\placeholdernc{advanceable}@; }; } \end{codeblock} @@ -1911,11 +2075,11 @@ \pnum \tcode{iterator::iterator_category} is defined as follows: \begin{itemize} -\item If \tcode{W} models \tcode{\placeholder{Advanceable}}, then +\item If \tcode{W} models \tcode{\placeholder{advanceable}}, then \tcode{iterator_category} is \tcode{random_access_iterator_tag}. -\item Otherwise, if \tcode{W} models \tcode{\placeholder{Decrementable}}, then +\item Otherwise, if \tcode{W} models \tcode{\placeholder{decrementable}}, then \tcode{iterator_category} is \tcode{bidirectional_iterator_tag}. -\item Otherwise, if \tcode{W} models \libconcept{Incrementable}, then +\item Otherwise, if \tcode{W} models \libconcept{incrementable}, then \tcode{iterator_category} is \tcode{forward_iterator_tag}. \item Otherwise, \tcode{iterator_category} is \tcode{input_iterator_tag}. \end{itemize} @@ -1977,7 +2141,7 @@ \indexlibrary{\idxcode{operator++}!\idxcode{iota_view::iterator}} \begin{itemdecl} -constexpr iterator operator++(int) requires Incrementable; +constexpr iterator operator++(int) requires incrementable; \end{itemdecl} \begin{itemdescr} @@ -1992,7 +2156,7 @@ \indexlibrary{\idxcode{operator\dcr}!\idxcode{iota_view::iterator}} \begin{itemdecl} -constexpr iterator& operator--() requires @\placeholdernc{Decrementable}@; +constexpr iterator& operator--() requires @\placeholdernc{decrementable}@; \end{itemdecl} \begin{itemdescr} @@ -2006,7 +2170,7 @@ \indexlibrary{\idxcode{operator\dcr}!\idxcode{iota_view::iterator}} \begin{itemdecl} -constexpr iterator operator--(int) requires @\placeholdernc{Decrementable}@; +constexpr iterator operator--(int) requires @\placeholdernc{decrementable}@; \end{itemdecl} \begin{itemdescr} @@ -2022,14 +2186,21 @@ \indexlibrary{\idxcode{operator+=}!\idxcode{iota_view::iterator}} \begin{itemdecl} constexpr iterator& operator+=(difference_type n) - requires @\placeholdernc{Advanceable}@; + requires @\placeholdernc{advanceable}@; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} -value_ += n; +if constexpr (@\placeholdernc{is-integer-like}@ && !@\placeholdernc{is-signed-integer-like}@) { + if (n >= difference_type(0)) + value_ += static_cast(n); + else + value_ -= static_cast(-n); +} else { + value_ += n; +} return *this; \end{codeblock} \end{itemdescr} @@ -2037,14 +2208,21 @@ \indexlibrary{\idxcode{operator-=}!\idxcode{iota_view::iterator}} \begin{itemdecl} constexpr iterator& operator-=(difference_type n) - requires @\placeholdernc{Advanceable}@; + requires @\placeholdernc{advanceable}@; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} -value_ -= n; +if constexpr (@\placeholdernc{is-integer-like}@ && !@\placeholdernc{is-signed-integer-like}@) { + if (n >= difference_type(0)) + value_ -= static_cast(n); + else + value_ += static_cast(-n); +} else { + value_ -= n; +} return *this; \end{codeblock} \end{itemdescr} @@ -2052,18 +2230,18 @@ \indexlibrary{\idxcode{operator[]}!\idxcode{iota_view::iterator}} \begin{itemdecl} constexpr W operator[](difference_type n) const - requires @\placeholdernc{Advanceable}@; + requires @\placeholdernc{advanceable}@; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return value_ + n;} +\effects Equivalent to: \tcode{return W(value_ + n);} \end{itemdescr} \indexlibrary{\idxcode{operator==}!\idxcode{iota_view::iterator}} \begin{itemdecl} friend constexpr bool operator==(const iterator& x, const iterator& y) - requires EqualityComparable; + requires equality_comparable; \end{itemdecl} \begin{itemdescr} @@ -2071,21 +2249,10 @@ \effects Equivalent to: \tcode{return x.value_ == y.value_;} \end{itemdescr} -\indexlibrary{\idxcode{operator"!=}!\idxcode{iota_view::iterator}} -\begin{itemdecl} -friend constexpr bool operator!=(const iterator& x, const iterator& y) - requires EqualityComparable; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: \tcode{return !(x == y);} -\end{itemdescr} - \indexlibrary{\idxcode{operator<}!\idxcode{iota_view::iterator}} \begin{itemdecl} friend constexpr bool operator<(const iterator& x, const iterator& y) - requires StrictTotallyOrdered; + requires totally_ordered; \end{itemdecl} \begin{itemdescr} @@ -2096,7 +2263,7 @@ \indexlibrary{\idxcode{operator>}!\idxcode{iota_view::iterator}} \begin{itemdecl} friend constexpr bool operator>(const iterator& x, const iterator& y) - requires StrictTotallyOrdered; + requires totally_ordered; \end{itemdecl} \begin{itemdescr} @@ -2107,7 +2274,7 @@ \indexlibrary{\idxcode{operator<=}!\idxcode{iota_view::iterator}} \begin{itemdecl} friend constexpr bool operator<=(const iterator& x, const iterator& y) - requires StrictTotallyOrdered; + requires totally_ordered; \end{itemdecl} \begin{itemdescr} @@ -2118,7 +2285,7 @@ \indexlibrary{\idxcode{operator>=}!\idxcode{iota_view::iterator}} \begin{itemdecl} friend constexpr bool operator>=(const iterator& x, const iterator& y) - requires StrictTotallyOrdered; + requires totally_ordered; \end{itemdecl} \begin{itemdescr} @@ -2126,21 +2293,34 @@ \effects Equivalent to: \tcode{return !(x < y);} \end{itemdescr} +\indexlibrary{\idxcode{operator<=>}!\idxcode{iota_view::iterator}} +\begin{itemdecl} +friend constexpr compare_three_way_result_t + operator<=>(const iterator& x, const iterator& y) + requires totally_ordered && three_way_comparable; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.value_ <=> y.value_;} +\end{itemdescr} + \indexlibrary{\idxcode{operator+}!\idxcode{iota_view::iterator}} \begin{itemdecl} friend constexpr iterator operator+(iterator i, difference_type n) - requires @\placeholdernc{Advanceable}@; + requires @\placeholdernc{advanceable}@; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return iterator\{i.value_ + n\};} +\effects Equivalent to: \tcode{return i += n;} \end{itemdescr} \indexlibrary{\idxcode{operator+}!\idxcode{iota_view::iterator}} \begin{itemdecl} friend constexpr iterator operator+(difference_type n, iterator i) - requires @\placeholdernc{Advanceable}@; + requires @\placeholdernc{advanceable}@; \end{itemdecl} \begin{itemdescr} @@ -2151,23 +2331,36 @@ \indexlibrary{\idxcode{operator-}!\idxcode{iota_view::iterator}} \begin{itemdecl} friend constexpr iterator operator-(iterator i, difference_type n) - requires @\placeholdernc{Advanceable}@; + requires @\placeholdernc{advanceable}@; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return i + -n;} +\effects Equivalent to: \tcode{return i -= n;} \end{itemdescr} \indexlibrary{\idxcode{operator-}!\idxcode{iota_view::iterator}} \begin{itemdecl} friend constexpr difference_type operator-(const iterator& x, const iterator& y) - requires @\placeholdernc{Advanceable}@; + requires @\placeholdernc{advanceable}@; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return x.value_ - y.value_;} +\effects Equivalent to: +\begin{codeblock} +using D = difference_type; +if constexpr (@\placeholder{is-integer-like}@) { + if constexpr (@\placeholder{is-signed-integer-like}@) + return D(D(x.value_) - D(y.value_)); + else + return (y.value_ > x.value_) + ? D(-D(y.value_ - x.value_)) + : D(x.value_ - y.value_); +} else { + return x.value_ - y.value_; +} +\end{codeblock} \end{itemdescr} \rSec3[range.iota.sentinel]{Class \tcode{iota_view::sentinel}} @@ -2183,9 +2376,11 @@ constexpr explicit sentinel(Bound bound); friend constexpr bool operator==(const iterator& x, const sentinel& y); - friend constexpr bool operator==(const sentinel& x, const iterator& y); - friend constexpr bool operator!=(const iterator& x, const sentinel& y); - friend constexpr bool operator!=(const sentinel& x, const iterator& y); + + friend constexpr iter_difference_t operator-(const iterator& x, const sentinel& y) + requires sized_sentinel_for; + friend constexpr iter_difference_t operator-(const sentinel& x, const iterator& y) + requires sized_sentinel_for; }; } \end{codeblock} @@ -2210,43 +2405,33 @@ \effects Equivalent to: \tcode{return x.value_ == y.bound_;} \end{itemdescr} -\indexlibrary{\idxcode{operator==}!\idxcode{iota_view::sentinel}} -\begin{itemdecl} -friend constexpr bool operator==(const sentinel& x, const iterator& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: \tcode{return y == x;} -\end{itemdescr} - -\indexlibrary{\idxcode{operator"!=}!\idxcode{iota_view::sentinel}} \begin{itemdecl} -friend constexpr bool operator!=(const iterator& x, const sentinel& y); +friend constexpr iter_difference_t operator-(const iterator& x, const sentinel& y) + requires sized_sentinel_for; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return !(x == y);} +\effects Equivalent to: \tcode{return x.value_ - y.bound_;} \end{itemdescr} -\indexlibrary{\idxcode{operator"!=}!\idxcode{iota_view::sentinel}} \begin{itemdecl} -friend constexpr bool operator!=(const sentinel& x, const iterator& y); +friend constexpr iter_difference_t operator-(const sentinel& x, const iterator& y) + requires sized_sentinel_for; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return !(y == x);} +\effects Equivalent to: \tcode{return -(y - x);} \end{itemdescr} -\rSec3[range.iota.adaptor]{\tcode{view::iota}} +\rSec3[range.iota.adaptor]{\tcode{views::iota}} \pnum -The name \tcode{view::iota} denotes a +The name \tcode{views::iota} denotes a customization point object\iref{customization.point.object}. For some subexpressions \tcode{E} and \tcode{F}, the expressions -\tcode{view::iota(E)} and \tcode{view::iota(E, F)} +\tcode{views::iota(E)} and \tcode{views::iota(E, F)} are expression-equivalent to \tcode{iota_view\{E\}} and \tcode{iota_view\{E, F\}}, respectively. @@ -2254,12 +2439,12 @@ \pnum This subclause defines \term{range adaptors}, which are utilities that transform a -\libconcept{Range} into a \libconcept{View} with custom behaviors. These +\libconcept{range} into a \libconcept{view} with custom behaviors. These adaptors can be chained to create pipelines of range transformations that evaluate lazily as the resulting view is iterated. \pnum -Range adaptors are declared in namespace \tcode{std::ranges::view}. +Range adaptors are declared in namespace \tcode{std::ranges::views}. \pnum The bitwise \logop{OR} operator is overloaded for the purpose of creating adaptor chain @@ -2272,10 +2457,10 @@ vector ints{0,1,2,3,4,5}; auto even = [](int i){ return 0 == i % 2; }; auto square = [](int i) { return i * i; }; -for (int i : ints | view::filter(even) | view::transform(square)) { +for (int i : ints | views::filter(even) | views::transform(square)) { cout << i << ' '; // prints: 0 4 16 } -assert(ranges::equal(ints | view::filter(even), view::filter(ints, even))); +assert(ranges::equal(ints | views::filter(even), views::filter(ints, even))); \end{codeblock} \end{example} @@ -2283,10 +2468,10 @@ \pnum A \term{range adaptor closure object} is a unary function object that accepts -a \libconcept{ViewableRange} argument and returns a \libconcept{View}. For +a \libconcept{viewable_range} argument and returns a \libconcept{view}. For a range adaptor closure object \tcode{C} and an expression \tcode{R} such that -\tcode{decltype((R))} models \libconcept{ViewableRange}, the following -expressions are equivalent and yield a \libconcept{View}: +\tcode{decltype((R))} models \libconcept{viewable_range}, the following +expressions are equivalent and yield a \libconcept{view}: \begin{codeblock} C(R) @@ -2305,8 +2490,8 @@ \pnum A \term{range adaptor object} is a customization point object\iref{customization.point.object} -that accepts a \libconcept{ViewableRange} as its first argument and returns a -\libconcept{View}. +that accepts a \libconcept{viewable_range} as its first argument and returns a +\libconcept{view}. \pnum If a range adaptor object accepts only one argument, @@ -2336,9 +2521,9 @@ \begin{itemize} \item \tcode{\placeholder{semiregular-box}} constrains its type parameter \tcode{T} with -\tcode{\libconcept{CopyConstructible} \&\& is_object_v}. +\tcode{\libconcept{copy_constructible} \&\& is_object_v}. -\item If \tcode{T} models \libconcept{DefaultConstructible}, the default +\item If \tcode{T} models \libconcept{default_constructible}, the default constructor of \tcode{\placeholder{semiregular-box}} is equivalent to: \begin{codeblock} constexpr @\placeholder{semiregular-box}@() noexcept(is_nothrow_default_constructible_v) @@ -2346,7 +2531,7 @@ { } \end{codeblock} -\item If \tcode{\libconcept{Assignable}} is not +\item If \tcode{\libconcept{assignable_from}} is not modeled, the copy assignment operator is equivalent to: \begin{codeblock} @\placeholder{semiregular-box}@& operator=(const @\placeholder{semiregular-box}@& that) @@ -2358,7 +2543,7 @@ } \end{codeblock} -\item If \tcode{\libconcept{Assignable}} is not modeled, +\item If \tcode{\libconcept{assignable_from}} is not modeled, the move assignment operator is equivalent to: \begin{codeblock} @\placeholder{semiregular-box}@& operator=(@\placeholder{semiregular-box}@&& that) @@ -2374,18 +2559,18 @@ \rSec2[range.all]{All view} \pnum -\tcode{view::all} returns a \libconcept{View} that includes all elements of -its \libconcept{Range} argument. +\tcode{views::all} returns a \libconcept{view} that includes all elements of +its \libconcept{range} argument. \pnum -The name \tcode{view::all} denotes a +The name \tcode{views::all} denotes a range adaptor object\iref{range.adaptor.object}. For some subexpression \tcode{E}, the expression -\tcode{view::all(E)} is expression-equivalent to: +\tcode{views::all(E)} is expression-equivalent to: \begin{itemize} \item \tcode{\placeholdernc{decay-copy}(E)} if the decayed type of \tcode{E} -models \libconcept{View}. +models \libconcept{view}. \item Otherwise, \tcode{ref_view\{E\}} if that expression is well-formed. @@ -2395,10 +2580,10 @@ \rSec3[range.ref.view]{Class template \tcode{ref_view}} \pnum -\tcode{ref_view} is a \tcode{View} of the elements of some other \tcode{Range}. +\tcode{ref_view} is a \tcode{view} of the elements of some other \tcode{range}. \begin{codeblock} namespace std::ranges { - template + template requires is_object_v class ref_view : public view_interface> { private: @@ -2419,10 +2604,10 @@ requires requires { ranges::empty(*r_); } { return ranges::empty(*r_); } - constexpr auto size() const requires SizedRange + constexpr auto size() const requires sized_range { return ranges::size(*r_); } - constexpr auto data() const requires ContiguousRange + constexpr auto data() const requires contiguous_range { return ranges::data(*r_); } friend constexpr iterator_t begin(ref_view r) @@ -2452,7 +2637,7 @@ \end{codeblock} The expression in the \grammarterm{requires-clause} is equivalent to \begin{codeblock} -ConvertibleTo && requires { @\placeholder{FUN}@(declval()); } +convertible_to && requires { @\placeholder{FUN}@(declval()); } \end{codeblock} \pnum @@ -2467,7 +2652,7 @@ \rSec3[range.filter.overview]{Overview} \pnum -\tcode{filter_view} presents a \libconcept{View} of an underlying sequence +\tcode{filter_view} presents a \libconcept{view} of an underlying sequence without the elements that fail to satisfy a predicate. \pnum @@ -2484,8 +2669,8 @@ \begin{codeblock} namespace std::ranges { - template> Pred> - requires View && is_object_v + template> Pred> + requires view && is_object_v class filter_view : public view_interface> { private: V base_ = V(); // \expos @@ -2499,15 +2684,15 @@ public: filter_view() = default; constexpr filter_view(V base, Pred pred); - template - requires ViewableRange && Constructible> + template + requires viewable_range && constructible_from> constexpr filter_view(R&& r, Pred pred); constexpr V base() const; constexpr iterator begin(); constexpr auto end() { - if constexpr (CommonRange) + if constexpr (common_range) return iterator{*this, ranges::end(base_)}; else return sentinel{*this}; @@ -2532,14 +2717,14 @@ \indexlibrary{\idxcode{filter_view}!\idxcode{filter_view}}% \begin{itemdecl} -template - requires ViewableRange && Constructible> +template + requires viewable_range && constructible_from> constexpr filter_view(R&& r, Pred pred); \end{itemdecl} \begin{itemdescr} \pnum -\effects Initializes \tcode{base_} with \tcode{view::all(std::forward(r))} +\effects Initializes \tcode{base_} with \tcode{views::all(std::forward(r))} and initializes \tcode{pred_} with \tcode{std::\brk{}move(pred)}. \end{itemdescr} @@ -2569,7 +2754,7 @@ \pnum \remarks In order to provide the amortized constant time complexity required by -the \libconcept{Range} concept, this function caches the result within the +the \libconcept{range} concept, this function caches the result within the \tcode{filter_view} for use on subsequent calls. \end{itemdescr} @@ -2586,34 +2771,32 @@ public: using iterator_concept = @\seebelow@; using iterator_category = @\seebelow@; - using value_type = iter_value_t>; - using difference_type = iter_difference_t>; + using value_type = range_value_t; + using difference_type = range_difference_t; iterator() = default; constexpr iterator(filter_view& parent, iterator_t current); constexpr iterator_t base() const; - constexpr iter_reference_t> operator*() const; + constexpr range_reference_t operator*() const; constexpr iterator_t operator->() const requires @\placeholder{has-arrow}@>; constexpr iterator& operator++(); constexpr void operator++(int); - constexpr iterator operator++(int) requires ForwardRange; + constexpr iterator operator++(int) requires forward_range; - constexpr iterator& operator--() requires BidirectionalRange; - constexpr iterator operator--(int) requires BidirectionalRange; + constexpr iterator& operator--() requires bidirectional_range; + constexpr iterator operator--(int) requires bidirectional_range; friend constexpr bool operator==(const iterator& x, const iterator& y) - requires EqualityComparable>; - friend constexpr bool operator!=(const iterator& x, const iterator& y) - requires EqualityComparable>; + requires equality_comparable>; - friend constexpr iter_rvalue_reference_t> iter_move(const iterator& i) + friend constexpr range_rvalue_reference_t iter_move(const iterator& i) noexcept(noexcept(ranges::iter_move(i.current_))); friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(noexcept(ranges::iter_swap(x.current_, y.current_))) - requires IndirectlySwappable>; + requires indirectly_swappable>; }; } \end{codeblock} @@ -2626,10 +2809,10 @@ \pnum \tcode{iterator::iterator_concept} is defined as follows: \begin{itemize} -\item If \tcode{V} models \libconcept{BidirectionalRange}, then +\item If \tcode{V} models \libconcept{bidirectional_range}, then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. -\item Otherwise, if \tcode{V} models \libconcept{ForwardRange}, then +\item Otherwise, if \tcode{V} models \libconcept{forward_range}, then \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. \item Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. @@ -2641,10 +2824,12 @@ \item Let \tcode{C} denote the type \tcode{iterator_traits>::iterator_category}. -\item If \tcode{C} models \tcode{DerivedFrom}, +\item If \tcode{C} models +\tcode{\libconcept{derived_from}}, then \tcode{iterator_category} denotes \tcode{bi\-directional_iterator_tag}. -\item Otherwise, if \tcode{C} models \tcode{DerivedFrom}, +\item Otherwise, if \tcode{C} models +\tcode{\libconcept{derived_from}}, then \tcode{iterator_category} denotes \tcode{forward_iterator_tag}. \item Otherwise, \tcode{iterator_category} denotes \tcode{input_iterator_tag}. @@ -2673,7 +2858,7 @@ \indexlibrary{\idxcode{operator*}!\idxcode{filter_view::iterator}}% \begin{itemdecl} -constexpr iter_reference_t> operator*() const; +constexpr range_reference_t operator*() const; \end{itemdecl} \begin{itemdescr} @@ -2719,7 +2904,7 @@ \indexlibrary{\idxcode{operator++}!\idxcode{filter_view::iterator}}% \begin{itemdecl} -constexpr iterator operator++(int) requires ForwardRange; +constexpr iterator operator++(int) requires forward_range; \end{itemdecl} \begin{itemdescr} @@ -2734,7 +2919,7 @@ \indexlibrary{\idxcode{operator\dcr}!\idxcode{filter_view::iterator}}% \begin{itemdecl} -constexpr iterator& operator--() requires BidirectionalRange; +constexpr iterator& operator--() requires bidirectional_range; \end{itemdecl} \begin{itemdescr} @@ -2750,7 +2935,7 @@ \indexlibrary{\idxcode{operator\dcr}!\idxcode{filter_view::iterator}}% \begin{itemdecl} -constexpr iterator operator--(int) requires BidirectionalRange; +constexpr iterator operator--(int) requires bidirectional_range; \end{itemdecl} \begin{itemdescr} @@ -2766,7 +2951,7 @@ \indexlibrary{\idxcode{operator==}!\idxcode{filter_view::iterator}}% \begin{itemdecl} friend constexpr bool operator==(const iterator& x, const iterator& y) - requires EqualityComparable>; + requires equality_comparable>; \end{itemdecl} \begin{itemdescr} @@ -2774,20 +2959,9 @@ \effects Equivalent to: \tcode{return x.current_ == y.current_;} \end{itemdescr} -\indexlibrary{\idxcode{operator"!=}!\idxcode{filter_view::iterator}}% -\begin{itemdecl} -friend constexpr bool operator!=(const iterator& x, const iterator& y) - requires EqualityComparable>; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: \tcode{return !(x == y);} -\end{itemdescr} - \indexlibrary{\idxcode{iter_move}!\idxcode{filter_view::iterator}}% \begin{itemdecl} -friend constexpr iter_rvalue_reference_t> iter_move(const iterator& i) +friend constexpr range_rvalue_reference_t iter_move(const iterator& i) noexcept(noexcept(ranges::iter_move(i.current_))); \end{itemdecl} @@ -2800,7 +2974,7 @@ \begin{itemdecl} friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(noexcept(ranges::iter_swap(x.current_, y.current_))) - requires IndirectlySwappable>; + requires indirectly_swappable>; \end{itemdecl} \begin{itemdescr} @@ -2824,9 +2998,6 @@ constexpr sentinel_t base() const; friend constexpr bool operator==(const iterator& x, const sentinel& y); - friend constexpr bool operator==(const sentinel& x, const iterator& y); - friend constexpr bool operator!=(const iterator& x, const sentinel& y); - friend constexpr bool operator!=(const sentinel& x, const iterator& y); }; } \end{codeblock} @@ -2838,7 +3009,7 @@ \begin{itemdescr} \pnum -\effects Initializes \tcode{end_} with \tcode{ranges::end(parent)}. +\effects Initializes \tcode{end_} with \tcode{ranges::end(parent.base_)}. \end{itemdescr} \indexlibrary{\idxcode{base}!\idxcode{filter_view::sentinel}}% @@ -2861,43 +3032,13 @@ \effects Equivalent to: \tcode{return x.current_ == y.end_;} \end{itemdescr} -\indexlibrary{\idxcode{operator==}!\idxcode{filter_view::sentinel}}% -\begin{itemdecl} -friend constexpr bool operator==(const sentinel& x, const iterator& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: \tcode{return y == x;} -\end{itemdescr} - -\indexlibrary{\idxcode{operator"!=}!\idxcode{filter_view::sentinel}}% -\begin{itemdecl} -friend constexpr bool operator!=(const iterator& x, const sentinel& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: \tcode{return !(x == y);} -\end{itemdescr} - -\indexlibrary{\idxcode{operator"!=}!\idxcode{filter_view::sentinel}}% -\begin{itemdecl} -friend constexpr bool operator!=(const sentinel& x, const iterator& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: \tcode{return !(y == x);} -\end{itemdescr} - -\rSec3[range.filter.adaptor]{\tcode{view::filter}} +\rSec3[range.filter.adaptor]{\tcode{views::filter}} \pnum -The name \tcode{view::filter} denotes a +The name \tcode{views::filter} denotes a range adaptor object\iref{range.adaptor.object}. For some subexpressions \tcode{E} and \tcode{P}, -the expression \tcode{view::filter(E, P)} is expression-equivalent to +the expression \tcode{views::filter(E, P)} is expression-equivalent to \tcode{filter_view\{E, P\}}. @@ -2907,7 +3048,7 @@ \pnum \tcode{transform_view} presents -a \libconcept{View} of an underlying sequence after +a \libconcept{view} of an underlying sequence after applying a transformation function to each element. \pnum @@ -2924,9 +3065,9 @@ \begin{codeblock} namespace std::ranges { - template - requires View && is_object_v && - RegularInvocable>> + template + requires view && is_object_v && + regular_invocable> class transform_view : public view_interface> { private: // \ref{range.transform.iterator}, class template \tcode{transform_view::iterator} @@ -2940,28 +3081,28 @@ public: transform_view() = default; constexpr transform_view(V base, F fun); - template - requires ViewableRange && Constructible> + template + requires viewable_range && constructible_from> constexpr transform_view(R&& r, F fun); constexpr V base() const; constexpr iterator begin(); constexpr iterator begin() const - requires Range && - RegularInvocable>>; + requires range && + regular_invocable>; constexpr sentinel end(); - constexpr iterator end() requires CommonRange; + constexpr iterator end() requires common_range; constexpr sentinel end() const - requires Range && - RegularInvocable>>; + requires range && + regular_invocable>; constexpr iterator end() const - requires CommonRange && - RegularInvocable>>; + requires common_range && + regular_invocable>; - constexpr auto size() requires SizedRange { return ranges::size(base_); } - constexpr auto size() const requires SizedRange + constexpr auto size() requires sized_range { return ranges::size(base_); } + constexpr auto size() const requires sized_range { return ranges::size(base_); } }; @@ -2983,14 +3124,14 @@ \indexlibrary{\idxcode{transform_view}!\idxcode{transform_view}}% \begin{itemdecl} -template - requires ViewableRange && Constructible> +template + requires viewable_range && constructible_from> constexpr transform_view(R&& r, F fun); \end{itemdecl} \begin{itemdescr} \pnum -\effects Initializes \tcode{base_} with \tcode{view::all(std::forward(r))} +\effects Initializes \tcode{base_} with \tcode{views::all(std::forward(r))} and \tcode{fun_} with \tcode{std::move(fun)}. \end{itemdescr} @@ -3020,8 +3161,8 @@ \indexlibrary{\idxcode{begin}!\idxcode{transform_view}}% \begin{itemdecl} constexpr iterator begin() const - requires Range && - RegularInvocable>>; + requires range && + regular_invocable>; \end{itemdecl} \begin{itemdescr} @@ -3047,7 +3188,7 @@ \indexlibrary{\idxcode{end}!\idxcode{transform_view}}% \begin{itemdecl} -constexpr iterator end() requires CommonRange; +constexpr iterator end() requires common_range; \end{itemdecl} \begin{itemdescr} @@ -3061,8 +3202,8 @@ \indexlibrary{\idxcode{end}!\idxcode{transform_view}}% \begin{itemdecl} constexpr sentinel end() const - requires Range && - RegularInvocable>>; + requires range && + regular_invocable>; \end{itemdecl} \begin{itemdescr} @@ -3076,8 +3217,8 @@ \indexlibrary{\idxcode{end}!\idxcode{transform_view}}% \begin{itemdecl} constexpr iterator end() const - requires CommonRange && - RegularInvocable>>; + requires common_range && + regular_invocable>; \end{itemdecl} \begin{itemdescr} @@ -3107,13 +3248,13 @@ using iterator_concept = @\seebelow@; using iterator_category = @\seebelow@; using value_type = - remove_cvref_t>>>; - using difference_type = iter_difference_t>; + remove_cvref_t>>; + using difference_type = range_difference_t; iterator() = default; constexpr iterator(Parent& parent, iterator_t current); constexpr iterator(iterator i) - requires Const && ConvertibleTo, iterator_t>; + requires Const && convertible_to, iterator_t>; constexpr iterator_t base() const; constexpr decltype(auto) operator*() const @@ -3121,42 +3262,43 @@ constexpr iterator& operator++(); constexpr void operator++(int); - constexpr iterator operator++(int) requires ForwardRange; + constexpr iterator operator++(int) requires forward_range; - constexpr iterator& operator--() requires BidirectionalRange; - constexpr iterator operator--(int) requires BidirectionalRange; + constexpr iterator& operator--() requires bidirectional_range; + constexpr iterator operator--(int) requires bidirectional_range; constexpr iterator& operator+=(difference_type n) - requires RandomAccessRange; + requires random_access_range; constexpr iterator& operator-=(difference_type n) - requires RandomAccessRange; + requires random_access_range; constexpr decltype(auto) operator[](difference_type n) const - requires RandomAccessRange + requires random_access_range { return invoke(*parent_->fun_, current_[n]); } friend constexpr bool operator==(const iterator& x, const iterator& y) - requires EqualityComparable>; - friend constexpr bool operator!=(const iterator& x, const iterator& y) - requires EqualityComparable>; + requires equality_comparable>; friend constexpr bool operator<(const iterator& x, const iterator& y) - requires RandomAccessRange; + requires random_access_range; friend constexpr bool operator>(const iterator& x, const iterator& y) - requires RandomAccessRange; + requires random_access_range; friend constexpr bool operator<=(const iterator& x, const iterator& y) - requires RandomAccessRange; + requires random_access_range; friend constexpr bool operator>=(const iterator& x, const iterator& y) - requires RandomAccessRange; + requires random_access_range; + friend constexpr compare_three_way_result_t> + operator<=>(const iterator& x, const iterator& y) + requires random_access_range && three_way_comparable>; friend constexpr iterator operator+(iterator i, difference_type n) - requires RandomAccessRange; + requires random_access_range; friend constexpr iterator operator+(difference_type n, iterator i) - requires RandomAccessRange; + requires random_access_range; friend constexpr iterator operator-(iterator i, difference_type n) - requires RandomAccessRange; + requires random_access_range; friend constexpr difference_type operator-(const iterator& x, const iterator& y) - requires RandomAccessRange; + requires random_access_range; friend constexpr decltype(auto) iter_move(const iterator& i) noexcept(noexcept(invoke(*i.parent_->fun_, *i.current_))) @@ -3169,7 +3311,7 @@ friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(noexcept(ranges::iter_swap(x.current_, y.current_))) - requires IndirectlySwappable>; + requires indirectly_swappable>; }; } \end{codeblock} @@ -3177,13 +3319,13 @@ \pnum \tcode{iterator::iterator_concept} is defined as follows: \begin{itemize} -\item If \tcode{V} models \libconcept{RandomAccessRange}, then +\item If \tcode{V} models \libconcept{random_access_range}, then \tcode{iterator_concept} denotes \tcode{random_access_iterator_tag}. -\item Otherwise, if \tcode{V} models \libconcept{BidirectionalRange}, then +\item Otherwise, if \tcode{V} models \libconcept{bidirectional_range}, then \tcode{iterator_concept} denotes \tcode{bidirectional_iterator_tag}. -\item Otherwise, if \tcode{V} models \libconcept{ForwardRange}, then +\item Otherwise, if \tcode{V} models \libconcept{forward_range}, then \tcode{iterator_concept} denotes \tcode{forward_iterator_tag}. \item Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. @@ -3192,7 +3334,7 @@ \pnum Let \tcode{C} denote the type \tcode{iterator_traits>::iterator_category}. -If \tcode{C} models \tcode{\libconcept{Derived\-From}}, +If \tcode{C} models \tcode{\libconcept{derived_from}}, then \tcode{iterator_category} denotes \tcode{random_access_iterator_tag}; otherwise, \tcode{iterator_category} denotes \tcode{C}. @@ -3211,7 +3353,7 @@ \indexlibrary{\idxcode{iterator}!\idxcode{transform_view::iterator}}% \begin{itemdecl} constexpr iterator(iterator i) - requires Const && ConvertibleTo, iterator_t>; + requires Const && convertible_to, iterator_t>; \end{itemdecl} \begin{itemdescr} @@ -3256,7 +3398,7 @@ \indexlibrary{\idxcode{operator++}!\idxcode{transform_view::iterator}} \begin{itemdecl} -constexpr iterator operator++(int) requires ForwardRange; +constexpr iterator operator++(int) requires forward_range; \end{itemdecl} \begin{itemdescr} @@ -3271,7 +3413,7 @@ \indexlibrary{\idxcode{operator\dcr}!\idxcode{transform_view::iterator}} \begin{itemdecl} -constexpr iterator& operator--() requires BidirectionalRange; +constexpr iterator& operator--() requires bidirectional_range; \end{itemdecl} \begin{itemdescr} @@ -3285,7 +3427,7 @@ \indexlibrary{\idxcode{operator\dcr}!\idxcode{transform_view::iterator}} \begin{itemdecl} -constexpr iterator operator--(int) requires BidirectionalRange; +constexpr iterator operator--(int) requires bidirectional_range; \end{itemdecl} \begin{itemdescr} @@ -3301,7 +3443,7 @@ \indexlibrary{\idxcode{operator+=}!\idxcode{transform_view::iterator}} \begin{itemdecl} constexpr iterator& operator+=(difference_type n) - requires RandomAccessRange; + requires random_access_range; \end{itemdecl} \begin{itemdescr} @@ -3316,7 +3458,7 @@ \indexlibrary{\idxcode{operator-=}!\idxcode{transform_view::iterator}}% \begin{itemdecl} constexpr iterator& operator-=(difference_type n) - requires RandomAccessRange; + requires random_access_range; \end{itemdecl} \begin{itemdescr} @@ -3331,7 +3473,7 @@ \indexlibrary{\idxcode{operator==}!\idxcode{transform_view::iterator}} \begin{itemdecl} friend constexpr bool operator==(const iterator& x, const iterator& y) - requires EqualityComparable>; + requires equality_comparable>; \end{itemdecl} \begin{itemdescr} @@ -3339,21 +3481,10 @@ \effects Equivalent to: \tcode{return x.current_ == y.current_;} \end{itemdescr} -\indexlibrary{\idxcode{operator"!=}!\idxcode{transform_view::iterator}}% -\begin{itemdecl} -friend constexpr bool operator!=(const iterator& x, const iterator& y) - requires EqualityComparable>; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: \tcode{return !(x == y);} -\end{itemdescr} - \indexlibrary{\idxcode{operator<}!\idxcode{transform_view::iterator}}% \begin{itemdecl} friend constexpr bool operator<(const iterator& x, const iterator& y) - requires RandomAccessRange; + requires random_access_range; \end{itemdecl} \begin{itemdescr} @@ -3364,7 +3495,7 @@ \indexlibrary{\idxcode{operator>}!\idxcode{transform_view::iterator}}% \begin{itemdecl} friend constexpr bool operator>(const iterator& x, const iterator& y) - requires RandomAccessRange; + requires random_access_range; \end{itemdecl} \begin{itemdescr} @@ -3375,7 +3506,7 @@ \indexlibrary{\idxcode{operator<=}!\idxcode{transform_view::iterator}}% \begin{itemdecl} friend constexpr bool operator<=(const iterator& x, const iterator& y) - requires RandomAccessRange; + requires random_access_range; \end{itemdecl} \begin{itemdescr} @@ -3386,7 +3517,7 @@ \indexlibrary{\idxcode{operator>=}!\idxcode{transform_view::iterator}}% \begin{itemdecl} friend constexpr bool operator>=(const iterator& x, const iterator& y) - requires RandomAccessRange; + requires random_access_range; \end{itemdecl} \begin{itemdescr} @@ -3394,12 +3525,24 @@ \effects Equivalent to: \tcode{return !(x < y);} \end{itemdescr} +\indexlibrary{\idxcode{operator<=>}!\idxcode{transform_view::iterator}}% +\begin{itemdecl} +friend constexpr compare_three_way_result_t> + operator<=>(const iterator& x, const iterator& y) + requires random_access_range && three_way_comparable>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: \tcode{return x.current_ <=> y.current_;} +\end{itemdescr} + \indexlibrary{\idxcode{operator+}!\idxcode{transform_view::iterator}} \begin{itemdecl} friend constexpr iterator operator+(iterator i, difference_type n) - requires RandomAccessRange; + requires random_access_range; friend constexpr iterator operator+(difference_type n, iterator i) - requires RandomAccessRange; + requires random_access_range; \end{itemdecl} \begin{itemdescr} @@ -3410,7 +3553,7 @@ \indexlibrary{\idxcode{operator-}!\idxcode{transform_view::iterator}}% \begin{itemdecl} friend constexpr iterator operator-(iterator i, difference_type n) - requires RandomAccessRange; + requires random_access_range; \end{itemdecl} \begin{itemdescr} @@ -3421,7 +3564,7 @@ \indexlibrary{\idxcode{operator-}!\idxcode{transform_view::iterator}}% \begin{itemdecl} friend constexpr difference_type operator-(const iterator& x, const iterator& y) - requires RandomAccessRange; + requires random_access_range; \end{itemdecl} \begin{itemdescr} @@ -3433,7 +3576,7 @@ \begin{itemdecl} friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(noexcept(ranges::iter_swap(x.current_, y.current_))) - requires IndirectlySwappable>; + requires indirectly_swappable>; \end{itemdecl} \begin{itemdescr} @@ -3458,21 +3601,18 @@ sentinel() = default; constexpr explicit sentinel(sentinel_t end); constexpr sentinel(sentinel i) - requires Const && ConvertibleTo, sentinel_t>; + requires Const && convertible_to, sentinel_t>; constexpr sentinel_t base() const; friend constexpr bool operator==(const iterator& x, const sentinel& y); - friend constexpr bool operator==(const sentinel& x, const iterator& y); - friend constexpr bool operator!=(const iterator& x, const sentinel& y); - friend constexpr bool operator!=(const sentinel& x, const iterator& y); - friend constexpr iter_difference_t> + friend constexpr range_difference_t operator-(const iterator& x, const sentinel& y) - requires SizedSentinel, iterator_t>; - friend constexpr iter_difference_t> + requires sized_sentinel_for, iterator_t>; + friend constexpr range_difference_t operator-(const sentinel& y, const iterator& x) - requires SizedSentinel, iterator_t>; + requires sized_sentinel_for, iterator_t>; }; } \end{codeblock} @@ -3490,7 +3630,7 @@ \indexlibrary{\idxcode{sentinel}!\idxcode{transform_view::sentinel}} \begin{itemdecl} constexpr sentinel(sentinel i) - requires Const && ConvertibleTo, sentinel_t>; + requires Const && convertible_to, sentinel_t>; \end{itemdecl} \begin{itemdescr} @@ -3518,41 +3658,11 @@ \effects Equivalent to: \tcode{return x.current_ == y.end_;} \end{itemdescr} -\indexlibrary{\idxcode{operator==}!\idxcode{transform_view::sentinel}} -\begin{itemdecl} -friend constexpr bool operator==(const sentinel& x, const iterator& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: \tcode{return y == x;} -\end{itemdescr} - -\indexlibrary{\idxcode{operator"!=}!\idxcode{transform_view::sentinel}}% -\begin{itemdecl} -friend constexpr bool operator!=(const iterator& x, const sentinel& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: \tcode{return !(x == y);} -\end{itemdescr} - -\indexlibrary{\idxcode{operator"!=}!\idxcode{transform_view::sentinel}}% -\begin{itemdecl} -friend constexpr bool operator!=(const sentinel& x, const iterator& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: \tcode{return !(y == x);} -\end{itemdescr} - -\indexlibrary{\idxcode{operator"!=}!\idxcode{transform_view::sentinel}}% +\indexlibrary{\idxcode{operator-}!\idxcode{transform_view::sentinel}}% \begin{itemdecl} -friend constexpr iter_difference_t> +friend constexpr range_difference_t operator-(const iterator& x, const sentinel& y) - requires SizedSentinel, iterator_t>; + requires sized_sentinel_for, iterator_t>; \end{itemdecl} \begin{itemdescr} @@ -3560,11 +3670,11 @@ \effects Equivalent to: \tcode{return x.current_ - y.end_;} \end{itemdescr} -\indexlibrary{\idxcode{operator"!=}!\idxcode{transform_view::sentinel}}% +\indexlibrary{\idxcode{operator-}!\idxcode{transform_view::sentinel}}% \begin{itemdecl} -friend constexpr iter_difference_t> +friend constexpr range_difference_t operator-(const sentinel& y, const iterator& x) - requires SizedSentinel, iterator_t>; + requires sized_sentinel_for, iterator_t>; \end{itemdecl} \begin{itemdescr} @@ -3572,13 +3682,13 @@ \effects Equivalent to: \tcode{return x.end_ - y.current_;} \end{itemdescr} -\rSec3[range.transform.adaptor]{\tcode{view::transform}} +\rSec3[range.transform.adaptor]{\tcode{views::transform}} \pnum -The name \tcode{view::transform} denotes a +The name \tcode{views::transform} denotes a range adaptor object\iref{range.adaptor.object}. For some subexpressions \tcode{E} and \tcode{F}, the expression -\tcode{view::transform(E, F)} is expression-equivalent to +\tcode{views::transform(E, F)} is expression-equivalent to \tcode{transform_view\{E, F\}}. @@ -3587,9 +3697,9 @@ \rSec3[range.take.overview]{Overview} \pnum -\tcode{take_view} produces a \libconcept{View} of the first $N$ elements -from another \libconcept{View}, or all the elements if the adapted -\libconcept{View} contains fewer than $N$. +\tcode{take_view} produces a \libconcept{view} of the first $N$ elements +from another \libconcept{view}, or all the elements if the adapted +\libconcept{view} contains fewer than $N$. \pnum \begin{example} @@ -3605,25 +3715,25 @@ \begin{codeblock} namespace std::ranges { - template + template class take_view : public view_interface> { private: V base_ = V(); // \expos - iter_difference_t> count_ = 0; // \expos + range_difference_t count_ = 0; // \expos // \ref{range.take.sentinel}, class template \tcode{take_view::sentinel} template struct sentinel; // \expos public: take_view() = default; - constexpr take_view(V base, iter_difference_t> count); - template - requires Constructible> - constexpr take_view(R&& r, iter_difference_t> count); + constexpr take_view(V base, range_difference_t count); + template + requires constructible_from> + constexpr take_view(R&& r, range_difference_t count); constexpr V base() const; constexpr auto begin() requires (!@\placeholder{simple-view}@) { - if constexpr (SizedRange) { - if constexpr (RandomAccessRange) + if constexpr (sized_range) { + if constexpr (random_access_range) return ranges::begin(base_); else return counted_iterator{ranges::begin(base_), size()}; @@ -3631,9 +3741,9 @@ return counted_iterator{ranges::begin(base_), count_}; } - constexpr auto begin() const requires Range { - if constexpr (SizedRange) { - if constexpr (RandomAccessRange) + constexpr auto begin() const requires range { + if constexpr (sized_range) { + if constexpr (random_access_range) return ranges::begin(base_); else return counted_iterator{ranges::begin(base_), size()}; @@ -3642,8 +3752,8 @@ } constexpr auto end() requires (!@\placeholder{simple-view}@) { - if constexpr (SizedRange) { - if constexpr (RandomAccessRange) + if constexpr (sized_range) { + if constexpr (random_access_range) return ranges::begin(base_) + size(); else return default_sentinel; @@ -3651,9 +3761,9 @@ return sentinel{ranges::end(base_)}; } - constexpr auto end() const requires Range { - if constexpr (SizedRange) { - if constexpr (RandomAccessRange) + constexpr auto end() const requires range { + if constexpr (sized_range) { + if constexpr (random_access_range) return ranges::begin(base_) + size(); else return default_sentinel; @@ -3661,26 +3771,26 @@ return sentinel{ranges::end(base_)}; } - constexpr auto size() requires SizedRange { + constexpr auto size() requires sized_range { auto n = ranges::size(base_); return ranges::min(n, static_cast(count_)); } - constexpr auto size() const requires SizedRange { + constexpr auto size() const requires sized_range { auto n = ranges::size(base_); return ranges::min(n, static_cast(count_)); } }; - template - take_view(R&&, iter_difference_t>) + template + take_view(R&&, range_difference_t) -> take_view>; } \end{codeblock} \indexlibrary{\idxcode{take_view}!\idxcode{take_view}}% \begin{itemdecl} -constexpr take_view(V base, iter_difference_t> count); +constexpr take_view(V base, range_difference_t count); \end{itemdecl} \begin{itemdescr} @@ -3691,14 +3801,14 @@ \indexlibrary{\idxcode{take_view}!\idxcode{take_view}}% \begin{itemdecl} -template - requires Constructible> -constexpr take_view(R&& r, iter_difference_t> count); +template + requires constructible_from> +constexpr take_view(R&& r, range_difference_t count); \end{itemdecl} \begin{itemdescr} \pnum -\effects Initializes \tcode{base_} with \tcode{view::all(std::forward(r))} +\effects Initializes \tcode{base_} with \tcode{views::all(std::forward(r))} and \tcode{count_} with \tcode{count}. \end{itemdescr} @@ -3727,14 +3837,11 @@ sentinel() = default; constexpr explicit sentinel(sentinel_t end); constexpr sentinel(sentinel s) - requires Const && ConvertibleTo, sentinel_t>; + requires Const && convertible_to, sentinel_t>; constexpr sentinel_t base() const; - friend constexpr bool operator==(const sentinel& x, const CI& y); friend constexpr bool operator==(const CI& y, const sentinel& x); - friend constexpr bool operator!=(const sentinel& x, const CI& y); - friend constexpr bool operator!=(const CI& y, const sentinel& x); }; } \end{codeblock} @@ -3752,7 +3859,7 @@ \indexlibrary{\idxcode{sentinel}!\idxcode{take_view::sentinel}}% \begin{itemdecl} constexpr sentinel(sentinel s) - requires Const && ConvertibleTo, sentinel_t>; + requires Const && convertible_to, sentinel_t>; \end{itemdecl} \begin{itemdescr} @@ -3772,7 +3879,6 @@ \indexlibrary{\idxcode{operator==}!\idxcode{take_view::sentinel}} \begin{itemdecl} -friend constexpr bool operator==(const sentinel& x, const CI& y); friend constexpr bool operator==(const CI& y, const sentinel& x); \end{itemdecl} @@ -3782,1418 +3888,2376 @@ \tcode{return y.count() == 0 || y.base() == x.end_;} \end{itemdescr} -\indexlibrary{\idxcode{operator"!=}!\idxcode{take_view::sentinel}}% -\begin{itemdecl} -friend constexpr bool operator!=(const sentinel& x, const CI& y); -friend constexpr bool operator!=(const CI& y, const sentinel& x); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Equivalent to: \tcode{return !(x == y);} -\end{itemdescr} - -\rSec3[range.take.adaptor]{\tcode{view::take}} +\rSec3[range.take.adaptor]{\tcode{views::take}} \pnum -The name \tcode{view::take} denotes a +The name \tcode{views::take} denotes a range adaptor object\iref{range.adaptor.object}. For some subexpressions \tcode{E} and \tcode{F}, the expression -\tcode{view::take(E, F)} is expression-equivalent to +\tcode{views::take(E, F)} is expression-equivalent to \tcode{take_view\{E, F\}}. +\rSec2[range.take.while]{Take while view} -\rSec2[range.join]{Join view} - -\rSec3[range.join.overview]{Overview} +\rSec3[range.take.while.overview]{Overview} \pnum -\tcode{join_view} flattens a \libconcept{View} of ranges into a -\libconcept{View}. +Given a unary predicate \tcode{pred} and a \tcode{view} \tcode{r}, +\tcode{take_while_view} produces a \tcode{view} +of the range \range{begin(r)}{ranges::find_if_not(r, pred)}. \pnum \begin{example} \begin{codeblock} -vector ss{"hello", " ", "world", "!"}; -join_view greeting{ss}; -for (char ch : greeting) - cout << ch; // prints: hello world! +auto input = istringstream{"0 1 2 3 4 5 6 7 8 9"}; +auto small = [](const auto x) noexcept { return x < 5; }; +auto small_ints = istream_view(input) | views::take_while(small); +for (const auto i : small_ints) { + cout << i << ' '; // prints \tcode{0 1 2 3 4} +} +auto i = 0; +input >> i; +cout << i; // prints \tcode{6} \end{codeblock} \end{example} -\rSec3[range.join.view]{Class template \tcode{join_view}} +\rSec3[range.take.while.view]{Class template \tcode{take_while_view}} \begin{codeblock} namespace std::ranges { - template - requires View && InputRange>> && - (is_reference_v>> || - View>>) - class join_view : public view_interface> { - private: - using InnerRng = // \expos - iter_reference_t>; - // \ref{range.join.iterator}, class template \tcode{join_view::iterator} - template - struct iterator; // \expos - // \ref{range.join.sentinel}, class template \tcode{join_view::sentinel} - template - struct sentinel; // \expos + template + requires input_range && is_object_v && + indirect_unary_predicate> + class take_while_view : public view_interface> { + template class sentinel; // \expos + + R base_; // \expos + @\placeholder{semiregular-box}@ pred_; @\itcorr[-1]@ // \expos - V base_ = V(); // \expos - all_view inner_ = // \expos, present only when \tcode{!is_reference_v} - all_view(); public: - join_view() = default; - constexpr explicit join_view(V base); + take_while_view() = default; + constexpr take_while_view(R base, Pred pred); - template - requires ViewableRange && Constructible> - constexpr explicit join_view(R&& r); + constexpr R base() const; + constexpr const Pred& pred() const; - constexpr auto begin() { - return iterator<@\placeholder{simple-view}@>{*this, ranges::begin(base_)}; - } + constexpr auto begin() requires (!@\placeholder{simple-view}@) + { return ranges::begin(base_); } - constexpr auto begin() const - requires InputRange && - is_reference_v>> { - return iterator{*this, ranges::begin(base_)}; - } + constexpr auto begin() const requires range + { return ranges::begin(base_); } - constexpr auto end() { - if constexpr (ForwardRange && - is_reference_v && ForwardRange && - CommonRange && CommonRange) - return iterator<@\placeholder{simple-view}@>{*this, ranges::end(base_)}; - else - return sentinel<@\placeholder{simple-view}@>{*this}; - } + constexpr auto end() requires (!@\placeholder{simple-view}@) + { return sentinel(ranges::end(base_), addressof(*pred_)); } - constexpr auto end() const - requires InputRange && - is_reference_v>> { - if constexpr (ForwardRange && - is_reference_v>> && - ForwardRange>> && - CommonRange && - CommonRange>>) - return iterator{*this, ranges::end(base_)}; - else - return sentinel{*this}; - } + constexpr auto end() const requires range + { return sentinel(ranges::end(base_), addressof(*pred_)); } }; - template - explicit join_view(R&&) -> join_view>; + template + take_while_view(R&&, Pred) -> take_while_view, Pred>; } \end{codeblock} -\indexlibrary{\idxcode{join_view}!\idxcode{join_view}}% \begin{itemdecl} -constexpr explicit join_view(V base); +constexpr take_while_view(R base, Pred pred); \end{itemdecl} \begin{itemdescr} \pnum -\effects Initializes \tcode{base_} with \tcode{std::move(base)}. +\effects +Initializes \tcode{base_} with \tcode{std::move(base)} and +\tcode{pred_} with \tcode{std::move(pred)}. \end{itemdescr} -\indexlibrary{\idxcode{join_view}!\idxcode{join_view}}% \begin{itemdecl} -template - requires ViewableRange && Constructible> -constexpr explicit join_view(R&& r); +constexpr R base() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects Initializes \tcode{base_} with \tcode{view::all(std::forward(r))}. +\effects +Equivalent to: \tcode{return base_;} \end{itemdescr} -\rSec3[range.join.iterator]{Class template \tcode{join_view::iterator}} +\begin{itemdecl} +constexpr const Pred& pred() const; +\end{itemdecl} +\begin{itemdescr} \pnum +\effects +Equivalent to: \tcode{return *pred_;} +\end{itemdescr} + +\rSec3[range.take.while.sentinel]{Class template \tcode{take_while_view::sentinel}} \begin{codeblock} namespace std::ranges { -template + template template - struct join_view::iterator { - private: - using Parent = // \expos - conditional_t; - using Base = conditional_t; // \expos + class take_while_view::sentinel { // \expos + using base_t = conditional_t; // \expos - static constexpr bool ref_is_glvalue = // \expos - is_reference_v>>; + sentinel_t end_ = sentinel_t(); // \expos + const Pred* pred_{}; // \expos + public: + sentinel() = default; + constexpr explicit sentinel(sentinel_t end, const Pred* pred); + constexpr sentinel(sentinel s) + requires Const && convertible_to, sentinel_t>; - iterator_t outer_ = iterator_t(); // \expos - iterator_t>> inner_ = // \expos - iterator_t>>(); - Parent* parent_ = nullptr; // \expos + constexpr sentinel_t base() const { return end_; } - constexpr void satisfy(); // \expos - public: - using iterator_concept = @\seebelow@; - using iterator_category = @\seebelow@; - using value_type = - iter_value_t>>>; - using difference_type = @\seebelow@; + friend constexpr bool operator==(const iterator_t& x, const sentinel& y); + }; +} +\end{codeblock} - iterator() = default; - constexpr iterator(Parent& parent, iterator_t outer); - constexpr iterator(iterator i) - requires Const && - ConvertibleTo, iterator_t> && - ConvertibleTo, - iterator_t>>>; +\begin{itemdecl} +constexpr explicit sentinel(sentinel_t end, const Pred* pred); +\end{itemdecl} - constexpr decltype(auto) operator*() const { return *inner_; } +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{end_} with \tcode{end} and \tcode{pred_} with \tcode{pred}. +\end{itemdescr} - constexpr iterator_t operator->() const - requires @\placeholder{has-arrow}@>; +\begin{itemdecl} +constexpr sentinel(sentinel s) + requires Const && convertible_to, sentinel_t>; +\end{itemdecl} - constexpr iterator& operator++(); - constexpr void operator++(int); - constexpr iterator operator++(int) - requires ref_is_glvalue && ForwardRange && - ForwardRange>>; +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{end_} with \tcode{s.end_} and +\tcode{pred_} with \tcode{s.pred_}. +\end{itemdescr} - constexpr iterator& operator--() - requires ref_is_glvalue && BidirectionalRange && - BidirectionalRange>>; +\begin{itemdecl} +friend constexpr bool operator==(const iterator_t& x, const sentinel& y); +\end{itemdecl} - constexpr iterator operator--(int) - requires ref_is_glvalue && BidirectionalRange && - BidirectionalRange>>; +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return y.end_ == x || !invoke(*y.pred_, *x);} +\end{itemdescr} - friend constexpr bool operator==(const iterator& x, const iterator& y) - requires ref_is_glvalue && EqualityComparable> && - EqualityComparable>>>; +\rSec3[range.take.while.adaptor]{\tcode{views::take_while}} - friend constexpr bool operator!=(const iterator& x, const iterator& y) - requires ref_is_glvalue && EqualityComparable> && - EqualityComparable>>>; +\indexlibrary{\idxcode{take_while}}% +\pnum +The name \tcode{views::take_while} denotes +a range adaptor object\iref{range.adaptor.object}. +For some subexpressions \tcode{E} and \tcode{F}, +the expression \tcode{views::take_while(E, F)} +is expression-equivalent to \tcode{take_while_view\{E, F\}}. - friend constexpr decltype(auto) iter_move(const iterator& i) - noexcept(noexcept(ranges::iter_move(i.inner_))) { - return ranges::iter_move(i.inner_); +\rSec2[range.drop]{Drop view} + +\rSec3[range.drop.overview]{Overview} + +\pnum +\tcode{drop_view} produces a \tcode{view} +excluding the first $N$ elements from another \tcode{view}, or +an empty range if the adapted \tcode{view} contains fewer than $N$ elements. + +\pnum +\begin{example} +\begin{codeblock} +auto ints = views::iota(0) | views::take(10); +auto latter_half = drop_view{ints, 5}; +for (auto i : latter_half) { + cout << i << ' '; // prints \tcode{5 6 7 8 9} +} +\end{codeblock} +\end{example} + +\rSec3[range.drop.view]{Class template \tcode{drop_view}} + +\indexlibrary{\idxcode{drop_view}}% +\begin{codeblock} +namespace std::ranges { + template + class drop_view : public view_interface> { + public: + drop_view() = default; + constexpr drop_view(R base, range_difference_t count); + + constexpr R base() const; + + constexpr auto begin() + requires (!(@\placeholder{simple-view}@ && random_access_range)); + constexpr auto begin() const + requires random_access_range; + + constexpr auto end() + requires (!@\placeholder{simple-view}@) + { return ranges::end(base_); } + + constexpr auto end() const + requires range + { return ranges::end(base_); } + + constexpr auto size() + requires sized_range + { + const auto s = ranges::size(base_); + const auto c = static_cast(count_); + return s < c ? 0 : s - c; } - friend constexpr void iter_swap(const iterator& x, const iterator& y) - noexcept(noexcept(ranges::iter_swap(x.inner_, y.inner_))); + constexpr auto size() const + requires sized_range + { + const auto s = ranges::size(base_); + const auto c = static_cast(count_); + return s < c ? 0 : s - c; + } + private: + R base_; // \expos + range_difference_t count_; // \expos }; + + template + drop_view(R&&, range_difference_t) -> drop_view>; } \end{codeblock} -\pnum -\tcode{iterator::iterator_concept} is defined as follows: -\begin{itemize} -\item If \tcode{ref_is_glvalue} is \tcode{true}, - \begin{itemize} - \item If \tcode{Base} and \tcode{iter_reference_t>} each model - \libconcept{BidirectionalRange}, then \tcode{iterator_concept} denotes - \tcode{bidirectional_iterator_tag}. - \item Otherwise, if \tcode{Base} and \tcode{iter_reference_t>} - each model \libconcept{ForwardRange}, then \tcode{iterator_concept} denotes - \tcode{forward_iterator_tag}. - \end{itemize} -\item Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. -\end{itemize} +\indexlibrary{\idxcode{drop_view}!constructor}% +\begin{itemdecl} +constexpr drop_view(R base, range_difference_t count); +\end{itemdecl} +\begin{itemdescr} \pnum -\tcode{iterator::iterator_category} is defined as follows: -\begin{itemize} -\item Let \placeholder{OUTERC} denote - \tcode{iterator_traits>::iterator_category}, and - let \placeholder{INNERC} denote - \tcode{iterator_traits>>>::iterator_cate\-gory}. -\item If \tcode{ref_is_glvalue} is \tcode{true}, - \begin{itemize} - \item If \placeholder{OUTERC} and \placeholder{INNERC} each model - \tcode{DerivedFrom}, \tcode{itera\-tor_category} - denotes \tcode{bidirectional_iterator_tag}. - \item Otherwise, if \placeholder{OUTERC} and \placeholder{INNERC} each model - \tcode{DerivedFrom}, \tcode{itera\-tor_category} - denotes \tcode{forward_iterator_tag}. - \end{itemize} -\item Otherwise, \tcode{iterator_category} denotes \tcode{input_iterator_tag}. -\end{itemize} +\expects +\tcode{count >= 0} is \tcode{true}. \pnum -\tcode{iterator::difference_type} denotes the type: -\begin{codeblock} -common_type_t< - iter_difference_t>, - iter_difference_t>>>> -\end{codeblock} +\effects +Initializes \tcode{base_} with \tcode{std::move(base)} and +\tcode{count_} with \tcode{count}. +\end{itemdescr} + +\indexlibrarymember{base}{drop_view}% +\begin{itemdecl} +constexpr R base() const; +\end{itemdecl} +\begin{itemdescr} \pnum -\tcode{join_view} iterators use the \tcode{satisfy} function to skip over -empty inner ranges. +\effects +Equivalent to: \tcode{return base_;} +\end{itemdescr} +\indexlibrarymember{begin}{drop_view}% \begin{itemdecl} -constexpr void satisfy(); // \expos +constexpr auto begin() + requires (!(@\placeholder{simple-view}@ && random_access_range)); +constexpr auto begin() const + requires random_access_range; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: +\returns +\tcode{ranges::next(ranges::begin(base_), count_, ranges::end(base_))}. + +\pnum +\remarks +In order to provide the amortized constant-time complexity required +by the \tcode{range} concept, +the first overload caches the result within the \tcode{drop_view} +for use on subsequent calls. +\begin{note} +Without this, +applying a \tcode{reverse_view} over a \tcode{drop_view} +would have quadratic iteration complexity. +\end{note} +\end{itemdescr} + +\rSec3[range.drop.adaptor]{\tcode{views::drop}} + +\pnum +The name \tcode{views::drop} denotes +a range adaptor object\iref{range.adaptor.object}. +For some subexpressions \tcode{E} and \tcode{F}, +the expression \tcode{views::drop(E, F)} +is expression-equivalent to \tcode{drop_view\{E, F\}}. + +\rSec2[range.drop.while]{Drop while view} + +\rSec3[range.drop.while.overview]{Overview} + +\pnum +Given a unary predicate \tcode{pred} and a \tcode{view} \tcode{r}, +\tcode{drop_while_view} produces a \tcode{view} +of the range \range{ranges::find_if_not(r, pred)}{ranges::end(r)}. + +\pnum +\begin{example} \begin{codeblock} -auto update_inner = [this](iter_reference_t> x) -> decltype(auto) { - if constexpr (ref_is_glvalue) // \tcode{x} is a reference - return (x); // \tcode{(x)} is an lvalue - else - return (parent_->inner_ = view::all(x)); -}; +constexpr auto source = " \t \t \t hello there"; +auto is_invisible = [](const auto x) { return x == ' ' || x == '\t'; }; +auto skip_ws = drop_while_view{source, is_invisible}; +for (auto c : skip_ws) { + cout << c; // prints \tcode{hello there} with no leading space +} +\end{codeblock} +\end{example} -for (; outer_ != ranges::end(parent_->base_); ++outer_) { - auto& inner = update_inner(*outer_); - inner_ = ranges::begin(inner); - if (inner_ != ranges::end(inner)) - return; +\rSec3[range.drop.while.view]{Class template \tcode{drop_while_view}} + +\indexlibrary{\idxcode{drop_while_view}}% +\begin{codeblock} +namespace std::ranges { + template + requires input_range && is_object_v && + indirect_unary_predicate> + class drop_while_view : public view_interface> { + public: + drop_while_view() = default; + constexpr drop_while_view(R base, Pred pred); + + constexpr R base() const; + constexpr const Pred& pred() const; + + constexpr auto begin(); + + constexpr auto end() + { return ranges::end(base_); } + + private: + R base_; // \expos + @\placeholder{semiregular-box}@ pred_; @\itcorr[-1]@ // \expos + }; + + template + drop_while_view(R&&, Pred) -> drop_while_view, Pred>; } -if constexpr (ref_is_glvalue) - inner_ = iterator_t>>(); \end{codeblock} + +\indexlibrary{\idxcode{drop_while_view}!constructor}% +\begin{itemdecl} +constexpr drop_while_view(R base, Pred pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{base_} with \tcode{std::move(base)} and +\tcode{pred_} with \tcode{std::move(pred)}. \end{itemdescr} -\indexlibrary{\idxcode{iterator}!\idxcode{join_view::iterator}} +\indexlibrarymember{base}{drop_while_view}% \begin{itemdecl} -constexpr iterator(Parent& parent, iterator_t outer) +constexpr R base() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects Initializes \tcode{outer_} with \tcode{outer} and -\tcode{parent_} with \tcode{addressof(parent)}; then calls \tcode{satisfy()}. +\effects +Equivalent to: \tcode{return base_;} \end{itemdescr} -\indexlibrary{\idxcode{iterator}!\idxcode{join_view::iterator}} +\indexlibrarymember{pred}{drop_while_view}% \begin{itemdecl} -constexpr iterator(iterator i) - requires Const && - ConvertibleTo, iterator_t> && - ConvertibleTo, - iterator_t>>>; +constexpr const Pred& pred() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return *pred_;} +\end{itemdescr} + +\indexlibrarymember{begin}{drop_while_view}% +\begin{itemdecl} +constexpr auto begin(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{ranges::find_if_not(base_, cref(*pred_))}. + +\pnum +\remarks +In order to provide the amortized constant-time complexity +required by the \tcode{range} concept, +the first call caches the result within the \tcode{drop_while_view} +for use on subsequent calls. +\begin{note} +Without this, +applying a \tcode{reverse_view} over a \tcode{drop_while_view} +would have quadratic iteration complexity. +\end{note} +\end{itemdescr} + +\rSec3[range.drop.while.adaptor]{\tcode{views::drop_while}} + +\pnum +The name \tcode{views::drop_while} +denotes a range adaptor object\iref{range.adaptor.object}. +For some subexpressions \tcode{E} and \tcode{F}, +the expression \tcode{views::drop_while(E, F)} +is expression-equivalent to \tcode{drop_while_view\{E, F\}}. + +\rSec2[range.join]{Join view} + +\rSec3[range.join.overview]{Overview} + +\pnum +\tcode{join_view} flattens a \libconcept{view} of ranges into a +\libconcept{view}. + +\pnum +\begin{example} +\begin{codeblock} +vector ss{"hello", " ", "world", "!"}; +join_view greeting{ss}; +for (char ch : greeting) + cout << ch; // prints: \tcode{hello world!} +\end{codeblock} +\end{example} + +\rSec3[range.join.view]{Class template \tcode{join_view}} + +\begin{codeblock} +namespace std::ranges { + template + requires view && input_range> && + (is_reference_v> || + view>) + class join_view : public view_interface> { + private: + using InnerRng = // \expos + range_reference_t; + // \ref{range.join.iterator}, class template \tcode{join_view::iterator} + template + struct iterator; // \expos + // \ref{range.join.sentinel}, class template \tcode{join_view::sentinel} + template + struct sentinel; // \expos + + V base_ = V(); // \expos + all_view inner_ = // \expos, present only when \tcode{!is_reference_v} + all_view(); + public: + join_view() = default; + constexpr explicit join_view(V base); + + template + requires viewable_range && constructible_from> + constexpr explicit join_view(R&& r); + + constexpr auto begin() { + return iterator<@\placeholder{simple-view}@>{*this, ranges::begin(base_)}; + } + + constexpr auto begin() const + requires input_range && + is_reference_v> { + return iterator{*this, ranges::begin(base_)}; + } + + constexpr auto end() { + if constexpr (forward_range && + is_reference_v && forward_range && + common_range && common_range) + return iterator<@\placeholder{simple-view}@>{*this, ranges::end(base_)}; + else + return sentinel<@\placeholder{simple-view}@>{*this}; + } + + constexpr auto end() const + requires input_range && + is_reference_v> { + if constexpr (forward_range && + is_reference_v> && + forward_range> && + common_range && + common_range>) + return iterator{*this, ranges::end(base_)}; + else + return sentinel{*this}; + } + }; + + template + explicit join_view(R&&) -> join_view>; +} +\end{codeblock} + +\indexlibrary{\idxcode{join_view}!\idxcode{join_view}}% +\begin{itemdecl} +constexpr explicit join_view(V base); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Initializes \tcode{base_} with \tcode{std::move(base)}. +\end{itemdescr} + +\indexlibrary{\idxcode{join_view}!\idxcode{join_view}}% +\begin{itemdecl} +template + requires viewable_range && constructible_from> +constexpr explicit join_view(R&& r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Initializes \tcode{base_} with \tcode{views::all(std::forward(r))}. +\end{itemdescr} + +\rSec3[range.join.iterator]{Class template \tcode{join_view::iterator}} + +\pnum +\begin{codeblock} +namespace std::ranges { +template + template + struct join_view::iterator { + private: + using Parent = // \expos + conditional_t; + using Base = conditional_t; // \expos + + static constexpr bool ref_is_glvalue = // \expos + is_reference_v>; + + iterator_t outer_ = iterator_t(); // \expos + iterator_t> inner_ = // \expos + iterator_t>(); + Parent* parent_ = nullptr; // \expos + + constexpr void satisfy(); // \expos + public: + using iterator_concept = @\seebelow@; + using iterator_category = @\seebelow@; + using value_type = range_value_t>; + using difference_type = @\seebelow@; + + iterator() = default; + constexpr iterator(Parent& parent, iterator_t outer); + constexpr iterator(iterator i) + requires Const && + convertible_to, iterator_t> && + convertible_to, + iterator_t>>; + + constexpr decltype(auto) operator*() const { return *inner_; } + + constexpr iterator_t operator->() const + requires @\placeholder{has-arrow}@>; + + constexpr iterator& operator++(); + constexpr void operator++(int); + constexpr iterator operator++(int) + requires ref_is_glvalue && forward_range && + forward_range>; + + constexpr iterator& operator--() + requires ref_is_glvalue && bidirectional_range && + bidirectional_range>; + + constexpr iterator operator--(int) + requires ref_is_glvalue && bidirectional_range && + bidirectional_range>; + + friend constexpr bool operator==(const iterator& x, const iterator& y) + requires ref_is_glvalue && equality_comparable> && + equality_comparable>>; + + friend constexpr decltype(auto) iter_move(const iterator& i) + noexcept(noexcept(ranges::iter_move(i.inner_))) { + return ranges::iter_move(i.inner_); + } + + friend constexpr void iter_swap(const iterator& x, const iterator& y) + noexcept(noexcept(ranges::iter_swap(x.inner_, y.inner_))); + }; +} +\end{codeblock} + +\pnum +\tcode{iterator::iterator_concept} is defined as follows: +\begin{itemize} +\item If \tcode{ref_is_glvalue} is \tcode{true}, + \begin{itemize} + \item If \tcode{Base} and \tcode{range_reference_t} each model + \libconcept{bidirectional_range}, then \tcode{iterator_concept} denotes + \tcode{bidirectional_iterator_tag}. + \item Otherwise, if \tcode{Base} and \tcode{range_reference_t} + each model \libconcept{forward_range}, then \tcode{iterator_concept} denotes + \tcode{forward_iterator_tag}. + \end{itemize} +\item Otherwise, \tcode{iterator_concept} denotes \tcode{input_iterator_tag}. +\end{itemize} + +\pnum +\tcode{iterator::iterator_category} is defined as follows: +\begin{itemize} +\item Let \placeholder{OUTERC} denote + \tcode{iterator_traits>::iterator_category}, and + let \placeholder{INNERC} denote + \tcode{iterator_traits>>::iterator_cate\-gory}. +\item If \tcode{ref_is_glvalue} is \tcode{true}, + \begin{itemize} + \item If \placeholder{OUTERC} and \placeholder{INNERC} each model + \tcode{derived_from}, \tcode{itera\-tor_category} + denotes \tcode{bidirectional_iterator_tag}. + \item Otherwise, if \placeholder{OUTERC} and \placeholder{INNERC} each model + \tcode{derived_from}, \tcode{itera\-tor_category} + denotes \tcode{forward_iterator_tag}. + \end{itemize} +\item Otherwise, \tcode{iterator_category} denotes \tcode{input_iterator_tag}. +\end{itemize} + +\pnum +\tcode{iterator::difference_type} denotes the type: +\begin{codeblock} +common_type_t< + range_difference_t, + range_difference_t>> +\end{codeblock} + +\pnum +\tcode{join_view} iterators use the \tcode{satisfy} function to skip over +empty inner ranges. + +\begin{itemdecl} +constexpr void satisfy(); // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\begin{codeblock} +auto update_inner = [this](range_reference_t x) -> decltype(auto) { + if constexpr (ref_is_glvalue) // \tcode{x} is a reference + return (x); // \tcode{(x)} is an lvalue + else + return (parent_->inner_ = views::all(x)); +}; + +for (; outer_ != ranges::end(parent_->base_); ++outer_) { + auto& inner = update_inner(*outer_); + inner_ = ranges::begin(inner); + if (inner_ != ranges::end(inner)) + return; +} +if constexpr (ref_is_glvalue) + inner_ = iterator_t>(); +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{iterator}!\idxcode{join_view::iterator}} +\begin{itemdecl} +constexpr iterator(Parent& parent, iterator_t outer) +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Initializes \tcode{outer_} with \tcode{outer} and +\tcode{parent_} with \tcode{addressof(parent)}; then calls \tcode{satisfy()}. +\end{itemdescr} + +\indexlibrary{\idxcode{iterator}!\idxcode{join_view::iterator}} +\begin{itemdecl} +constexpr iterator(iterator i) + requires Const && + convertible_to, iterator_t> && + convertible_to, + iterator_t>>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Initializes \tcode{outer_} with \tcode{std::move(i.outer_)}, +\tcode{inner_} with \tcode{std::move(i.inner_)}, and +\tcode{parent_} with \tcode{i.parent_}. +\end{itemdescr} + +\indexlibrary{\idxcode{operator->}!\idxcode{join_view::iterator}} +\begin{itemdecl} +constexpr iterator_t operator->() const + requires @\placeholder{has-arrow}@>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to \tcode{return inner_;} +\end{itemdescr} + +\indexlibrary{\idxcode{operator++}!\idxcode{join_view::iterator}} +\begin{itemdecl} +constexpr iterator& operator++(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{\placeholder{inner-range}} be: +\begin{itemize} +\item If \tcode{ref_is_glvalue} is \tcode{true}, \tcode{*outer_}. +\item Otherwise, \tcode{parent_->inner_}. +\end{itemize} + +\pnum +\effects Equivalent to: +\begin{codeblock} +auto&& inner_rng = @\placeholder{inner-range}@; +if (++inner_ == ranges::end(inner_rng)) { + ++outer_; + satisfy(); +} +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{operator++}!\idxcode{join_view::iterator}} +\begin{itemdecl} +constexpr void operator++(int); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: \tcode{++*this}. +\end{itemdescr} + +\indexlibrary{\idxcode{operator++}!\idxcode{join_view::iterator}} +\begin{itemdecl} +constexpr iterator operator++(int) + requires ref_is_glvalue && forward_range && + forward_range>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\begin{codeblock} +auto tmp = *this; +++*this; +return tmp; +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{operator\dcr}!\idxcode{join_view::iterator}} +\begin{itemdecl} +constexpr iterator& operator--() + requires ref_is_glvalue && bidirectional_range && + bidirectional_range>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\begin{codeblock} +if (outer_ == ranges::end(parent_->base_)) + inner_ = ranges::end(*--outer_); +while (inner_ == ranges::begin(*outer_)) + inner_ = ranges::end(*--outer_); +--inner_; +return *this; +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{operator\dcr}!\idxcode{join_view::iterator}} +\begin{itemdecl} +constexpr iterator operator--(int) + requires ref_is_glvalue && bidirectional_range && + bidirectional_range>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\begin{codeblock} +auto tmp = *this; +--*this; +return tmp; +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{operator==}!\idxcode{join_view::iterator}} +\begin{itemdecl} +friend constexpr bool operator==(const iterator& x, const iterator& y) + requires ref_is_glvalue && equality_comparable> && + equality_comparable>>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\tcode{return x.outer_ == y.outer_ \&\& x.inner_ == y.inner_;} +\end{itemdescr} + +\indexlibrary{\idxcode{iter_swap}!\idxcode{join_view::iterator}} +\begin{itemdecl} +friend constexpr void iter_swap(const iterator& x, const iterator& y) + noexcept(noexcept(ranges::iter_swap(x.inner_, y.inner_))); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: \tcode{return ranges::iter_swap(x.inner_, y.inner_);} +\end{itemdescr} + +\rSec3[range.join.sentinel]{Class template \tcode{join_view::sentinel}} + +\begin{codeblock} +namespace std::ranges { + template + template + struct join_view::sentinel { + private: + using Parent = // \expos + conditional_t; + using Base = conditional_t; // \expos + sentinel_t end_ = sentinel_t(); // \expos + public: + sentinel() = default; + + constexpr explicit sentinel(Parent& parent); + constexpr sentinel(sentinel s) + requires Const && convertible_to, sentinel_t>; + + friend constexpr bool operator==(const iterator& x, const sentinel& y); + }; +} +\end{codeblock} + +\indexlibrary{\idxcode{sentinel}!\idxcode{join_view::sentinel}} +\begin{itemdecl} +constexpr explicit sentinel(Parent& parent); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Initializes \tcode{end_} with \tcode{ranges::end(parent.base_)}. +\end{itemdescr} + +\indexlibrary{\idxcode{sentinel}!\idxcode{join_view::sentinel}} +\begin{itemdecl} +constexpr sentinel(sentinel s) + requires Const && convertible_to, sentinel_t>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Initializes \tcode{end_} with \tcode{std::move(s.end_)}. +\end{itemdescr} + +\indexlibrary{\idxcode{operator==}!\idxcode{join_view::sentinel}} +\begin{itemdecl} +friend constexpr bool operator==(const iterator& x, const sentinel& y); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: \tcode{return x.outer_ == y.end_;} +\end{itemdescr} + +\rSec3[range.join.adaptor]{\tcode{views::join}} + +\pnum +The name \tcode{views::join} denotes a +range adaptor object\iref{range.adaptor.object}. +For some subexpression \tcode{E}, the expression +\tcode{views::join(E)} is expression-equivalent to +\tcode{join_view\{E\}}. + +\rSec2[range.split]{Split view} + +\rSec3[range.split.overview]{Overview} + +\pnum +\tcode{split_view} takes a \libconcept{view} and a delimiter, and splits +the \libconcept{view} into subranges on the delimiter. The delimiter can be +a single element or a \libconcept{view} of elements. + +\pnum +\begin{example} +\begin{codeblock} +string str{"the quick brown fox"}; +split_view sentence{str, ' '}; +for (auto word : sentence) { + for (char ch : word) + cout << ch; + cout << '*'; +} +// The above prints: the*quick*brown*fox* +\end{codeblock} +\end{example} + +\rSec3[range.split.view]{Class template \tcode{split_view}} + +\begin{codeblock} +namespace std::ranges { + template struct @\placeholdernc{require-constant}@; // \expos + + template + concept @\placeholdernc{tiny-range}@ = // \expos + sized_range && + requires { typename @\placeholdernc{require-constant}@::size()>; } && + (remove_reference_t::size() <= 1); + + template + requires view && view && + indirectly_comparable, iterator_t, ranges::equal_to> && + (forward_range || @\placeholdernc{tiny-range}@) + class split_view : public view_interface> { + private: + V base_ = V(); // \expos + Pattern pattern_ = Pattern(); // \expos + iterator_t current_ = iterator_t(); // \expos, present only if \tcode{!forward_range} + // \ref{range.split.outer}, class template \tcode{split_view::outer_iterator} + template struct outer_iterator; // \expos + // \ref{range.split.inner}, class template \tcode{split_view::inner_iterator} + template struct inner_iterator; // \expos + public: + split_view() = default; + constexpr split_view(V base, Pattern pattern); + + template + requires constructible_from> && + constructible_from> + constexpr split_view(R&& r, P&& p); + + template + requires constructible_from> && + constructible_from>> + constexpr split_view(R&& r, range_value_t e); + + constexpr auto begin() { + if constexpr (forward_range) + return outer_iterator<@\placeholder{simple-view}@>{*this, ranges::begin(base_)}; + else { + current_ = ranges::begin(base_); + return outer_iterator{*this}; + } + } + + constexpr auto begin() const requires forward_range && forward_range { + return outer_iterator{*this, ranges::begin(base_)}; + } + + constexpr auto end() requires forward_range && common_range { + return outer_iterator<@\placeholder{simple-view}@>{*this, ranges::end(base_)}; + } + + constexpr auto end() const { + if constexpr (forward_range && forward_range && common_range) + return outer_iterator{*this, ranges::end(base_)}; + else + return default_sentinel; + } + }; + + template + split_view(R&&, P&&) -> split_view, all_view

>; + + template + split_view(R&&, range_value_t) + -> split_view, single_view>>; +} +\end{codeblock} + +\indexlibrary{\idxcode{split_view}!\idxcode{split_view}}% +\begin{itemdecl} +constexpr split_view(V base, Pattern pattern); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Initializes \tcode{base_} with \tcode{std::move(base)}, and +\tcode{pattern_} with \tcode{std::move(pattern)}. +\end{itemdescr} + +\indexlibrary{\idxcode{split_view}!\idxcode{split_view}}% +\begin{itemdecl} +template + requires constructible_from> && + constructible_from> +constexpr split_view(R&& r, P&& p); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{base_} with \tcode{views::all(std::forward(r))}, and +\tcode{pattern_} with \tcode{views::all(\brk{}std::forward

(p))}. +\end{itemdescr} + +\indexlibrary{\idxcode{split_view}!\idxcode{split_view}}% +\begin{itemdecl} +template + requires constructible_from> && + constructible_from>> +constexpr split_view(R&& r, range_value_t e); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{base_} with \tcode{views::all(std::forward(r))}, and +\tcode{pattern_} with \tcode{single_view\{\brk{}std::move(e)\}}. +\end{itemdescr} + +\rSec3[range.split.outer]{Class template \tcode{split_view::outer_iterator}} + +\begin{codeblock} +namespace std::ranges { + template + template + struct split_view::outer_iterator { + private: + using Parent = // \expos + conditional_t; + using Base = // \expos + conditional_t; + Parent* parent_ = nullptr; // \expos + iterator_t current_ = // \expos, present only if \tcode{V} models \libconcept{forward_range} + iterator_t(); + + public: + using iterator_concept = + conditional_t, forward_iterator_tag, input_iterator_tag>; + using iterator_category = input_iterator_tag; + // \ref{range.split.outer.value}, class \tcode{split_view::outer_iterator::value_type} + struct value_type; + using difference_type = range_difference_t; + + outer_iterator() = default; + constexpr explicit outer_iterator(Parent& parent) + requires (!forward_range); + constexpr outer_iterator(Parent& parent, iterator_t current) + requires forward_range; + constexpr outer_iterator(outer_iterator i) + requires Const && convertible_to, iterator_t>; + + constexpr value_type operator*() const; + + constexpr outer_iterator& operator++(); + constexpr decltype(auto) operator++(int) { + if constexpr (forward_range) { + auto tmp = *this; + ++*this; + return tmp; + } else + ++*this; + } + + friend constexpr bool operator==(const outer_iterator& x, const outer_iterator& y) + requires forward_range; + + friend constexpr bool operator==(const outer_iterator& x, default_sentinel_t); + }; +} +\end{codeblock} + +\pnum +Many of the following specifications refer to the notional member +\tcode{\placeholder{current}} of \tcode{outer_iterator}. +\tcode{\placeholder{current}} is equivalent to \tcode{current_} if \tcode{V} +models \libconcept{forward_range}, and \tcode{parent_->current_} otherwise. + +\indexlibrary{\idxcode{outer_iterator}!\idxcode{split_view::outer_iterator}}% +\begin{itemdecl} +constexpr explicit outer_iterator(Parent& parent) + requires (!forward_range); \end{itemdecl} \begin{itemdescr} \pnum -\effects Initializes \tcode{outer_} with \tcode{std::move(i.outer_)}, -\tcode{inner_} with \tcode{std::move(i.inner_)}, and -\tcode{parent_} with \tcode{i.parent_}. +\effects Initializes \tcode{parent_} with \tcode{addressof(parent)}. \end{itemdescr} -\indexlibrary{\idxcode{operator->}!\idxcode{join_view::iterator}} +\indexlibrary{\idxcode{outer_iterator}!\idxcode{split_view::outer_iterator}}% \begin{itemdecl} -constexpr iterator_t operator->() const - requires @\placeholder{has-arrow}@>; +constexpr outer_iterator(Parent& parent, iterator_t current) + requires forward_range; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to \tcode{return inner_;} +\effects Initializes \tcode{parent_} with \tcode{addressof(parent)} +and \tcode{current_} with \tcode{current}. \end{itemdescr} -\indexlibrary{\idxcode{operator++}!\idxcode{join_view::iterator}} +\indexlibrary{\idxcode{outer_iterator}!\idxcode{split_view::outer_iterator}}% \begin{itemdecl} -constexpr iterator& operator++(); +constexpr outer_iterator(outer_iterator i) + requires Const && convertible_to, iterator_t>; \end{itemdecl} \begin{itemdescr} \pnum -Let \tcode{\placeholder{inner-range}} be: -\begin{itemize} -\item If \tcode{ref_is_glvalue} is \tcode{true}, \tcode{*outer_}. -\item Otherwise, \tcode{parent_->inner_}. -\end{itemize} - -\pnum -\effects Equivalent to: -\begin{codeblock} -auto&& inner_rng = @\placeholder{inner-range}@; -if (++inner_ == ranges::end(inner_rng)) { - ++outer_; - satisfy(); -} -return *this; -\end{codeblock} +\effects Initializes \tcode{parent_} with \tcode{i.parent_} and +\tcode{current_} with \tcode{std::move(i.current_)}. \end{itemdescr} -\indexlibrary{\idxcode{operator++}!\idxcode{join_view::iterator}} +\indexlibrary{\idxcode{operator*}!\idxcode{split_view::outer_iterator}}% \begin{itemdecl} -constexpr void operator++(int); +constexpr value_type operator*() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{++*this}. +\effects Equivalent to: \tcode{return value_type\{*this\};} \end{itemdescr} -\indexlibrary{\idxcode{operator++}!\idxcode{join_view::iterator}} +\indexlibrary{\idxcode{operator++}!\idxcode{split_view::outer_iterator}}% \begin{itemdecl} -constexpr iterator operator++(int) - requires ref_is_glvalue && ForwardRange && - ForwardRange>>; +constexpr outer_iterator& operator++(); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} -auto tmp = *this; -++*this; -return tmp; +const auto end = ranges::end(parent_->base_); +if (@\placeholder{current}@ == end) return *this; +const auto [pbegin, pend] = subrange{parent_->pattern_}; +if (pbegin == pend) ++@\placeholder{current}@; +else { + do { + const auto [b, p] = ranges::mismatch(@\placeholdernc{current}@, end, pbegin, pend); + if (p == pend) { + @\placeholder{current}@ = b; // The pattern matched; skip it + break; + } + } while (++@\placeholder{current}@ != end); +} +return *this; \end{codeblock} \end{itemdescr} -\indexlibrary{\idxcode{operator\dcr}!\idxcode{join_view::iterator}} +\indexlibrary{\idxcode{operator==}!\idxcode{split_view::outer_iterator}}% \begin{itemdecl} -constexpr iterator& operator--() - requires ref_is_glvalue && BidirectionalRange && - BidirectionalRange>>; +friend constexpr bool operator==(const outer_iterator& x, const outer_iterator& y) + requires forward_range; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: -\begin{codeblock} -if (outer_ == ranges::end(parent_->base_)) - inner_ = ranges::end(*--outer_); -while (inner_ == ranges::begin(*outer_)) - inner_ = ranges::end(*--outer_); ---inner_; -return *this; -\end{codeblock} +\effects Equivalent to: \tcode{return x.current_ == y.current_;} \end{itemdescr} -\indexlibrary{\idxcode{operator\dcr}!\idxcode{join_view::iterator}} +\indexlibrary{\idxcode{operator==}!\idxcode{split_view::outer_iterator}}% \begin{itemdecl} -constexpr iterator operator--(int) - requires ref_is_glvalue && BidirectionalRange && - BidirectionalRange>>; +friend constexpr bool operator==(const outer_iterator& x, default_sentinel_t); \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: +\effects +Equivalent to: \tcode{return x.\placeholder{current} == ranges::end(x.parent_->base_);} +\end{itemdescr} + +\rSec3[range.split.outer.value]{Class \tcode{split_view::outer_iterator::value_type}} + \begin{codeblock} -auto tmp = *this; ---*this; -return tmp; +namespace std::ranges { + template + template + struct split_view::outer_iterator::value_type { + private: + outer_iterator i_ = outer_iterator(); // \expos + public: + value_type() = default; + constexpr explicit value_type(outer_iterator i); + + constexpr inner_iterator begin() const; + constexpr default_sentinel_t end() const; + }; +} \end{codeblock} -\end{itemdescr} -\indexlibrary{\idxcode{operator==}!\idxcode{join_view::iterator}} +\indexlibrary{\idxcode{value_type}!\idxcode{split_view::outer_iterator::value_type}}% \begin{itemdecl} -friend constexpr bool operator==(const iterator& x, const iterator& y) - requires ref_is_glvalue && EqualityComparable> && - EqualityComparable>>>; +constexpr explicit value_type(outer_iterator i); \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: -\tcode{return x.outer_ == y.outer_ \&\& x.inner_ == y.inner_;} +\effects Initializes \tcode{i_} with \tcode{i}. \end{itemdescr} -\indexlibrary{\idxcode{operator"!=}!\idxcode{join_view::iterator}} +\indexlibrary{\idxcode{begin}!\idxcode{split_view::outer_iterator::value_type}}% \begin{itemdecl} -friend constexpr bool operator!=(const iterator& x, const iterator& y) - requires ref_is_glvalue && EqualityComparable> && - EqualityComparable>>>; +constexpr inner_iterator begin() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return !(x == y);} +\effects Equivalent to: \tcode{return inner_iterator\{i_\};} \end{itemdescr} -\indexlibrary{\idxcode{iter_swap}!\idxcode{join_view::iterator}} +\indexlibrary{\idxcode{end}!\idxcode{split_view::outer_iterator::value_type}}% \begin{itemdecl} -friend constexpr void iter_swap(const iterator& x, const iterator& y) - noexcept(noexcept(ranges::iter_swap(x.inner_, y.inner_))); +constexpr default_sentinel_t end() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return ranges::iter_swap(x.inner_, y.inner_);} +\effects Equivalent to: \tcode{return default_sentinel;} \end{itemdescr} -\rSec3[range.join.sentinel]{Class template \tcode{join_view::sentinel}} +\rSec3[range.split.inner]{Class template \tcode{split_view::inner_iterator}} \begin{codeblock} namespace std::ranges { - template + template template - struct join_view::sentinel { + struct split_view::inner_iterator { private: - using Parent = // \expos - conditional_t; - using Base = conditional_t; // \expos - sentinel_t end_ = sentinel_t(); // \expos + using Base = + conditional_t; // \expos + outer_iterator i_ = outer_iterator(); // \expos + bool incremented_ = false; // \expos public: - sentinel() = default; + using iterator_concept = typename outer_iterator::iterator_concept; + using iterator_category = @\seebelow@; + using value_type = range_value_t; + using difference_type = range_difference_t; - constexpr explicit sentinel(Parent& parent); - constexpr sentinel(sentinel s) - requires Const && ConvertibleTo, sentinel_t>; + inner_iterator() = default; + constexpr explicit inner_iterator(outer_iterator i); - friend constexpr bool operator==(const iterator& x, const sentinel& y); - friend constexpr bool operator==(const sentinel& x, const iterator& y); - friend constexpr bool operator!=(const iterator& x, const sentinel& y); - friend constexpr bool operator!=(const sentinel& x, const iterator& y); + constexpr decltype(auto) operator*() const { return *i_.@\placeholder{current}@; } + + constexpr inner_iterator& operator++(); + constexpr decltype(auto) operator++(int) { + if constexpr (forward_range) { + auto tmp = *this; + ++*this; + return tmp; + } else + ++*this; + } + + friend constexpr bool operator==(const inner_iterator& x, const inner_iterator& y) + requires forward_range; + + friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t); + + friend constexpr decltype(auto) iter_move(const inner_iterator& i) + noexcept(noexcept(ranges::iter_move(i.i_.@\placeholdernc{current}@))) { + return ranges::iter_move(i.i_.@\placeholdernc{current}@); + } + + friend constexpr void iter_swap(const inner_iterator& x, const inner_iterator& y) + noexcept(noexcept(ranges::iter_swap(x.i_.@\placeholdernc{current}, y.i_.\placeholdernc{current}@))) + requires indirectly_swappable>; }; } \end{codeblock} -\indexlibrary{\idxcode{sentinel}!\idxcode{join_view::sentinel}} -\begin{itemdecl} -constexpr explicit sentinel(Parent& parent); -\end{itemdecl} - -\begin{itemdescr} \pnum -\effects Initializes \tcode{end_} with \tcode{ranges::end(parent.base_)}. -\end{itemdescr} +The \grammarterm{typedef-name} \tcode{iterator_category} denotes +\tcode{forward_iterator_tag} if +\tcode{iterator_traits>::iterator_category} models +\tcode{derived_from}, and \tcode{input_iterator_tag} +otherwise. -\indexlibrary{\idxcode{sentinel}!\idxcode{join_view::sentinel}} +\indexlibrary{\idxcode{inner_iterator}!\idxcode{split_view::inner_iterator}}% \begin{itemdecl} -constexpr sentinel(sentinel s) - requires Const && ConvertibleTo, sentinel_t>; +constexpr explicit inner_iterator(outer_iterator i); \end{itemdecl} \begin{itemdescr} \pnum -\effects Initializes \tcode{end_} with \tcode{std::move(s.end_)}. +\effects Initializes \tcode{i_} with \tcode{i}. \end{itemdescr} -\indexlibrary{\idxcode{operator==}!\idxcode{join_view::sentinel}} +\indexlibrary{\idxcode{operator++}!\idxcode{split_view::inner_iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const iterator& x, const sentinel& y); +constexpr inner_iterator& operator++() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return x.outer_ == y.end_;} +\effects Equivalent to: +\begin{codeblock} +incremented_ = true; +if constexpr (!forward_range) { + if constexpr (Pattern::size() == 0) { + return *this; + } +} +++i_.@\placeholder{current}@; +return *this; +\end{codeblock} \end{itemdescr} -\indexlibrary{\idxcode{operator==}!\idxcode{join_view::sentinel}} +\indexlibrary{\idxcode{operator==}!\idxcode{split_view::inner_iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const sentinel& x, const iterator& y); +friend constexpr bool operator==(const inner_iterator& x, const inner_iterator& y) + requires forward_range; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return y == x;} +\effects Equivalent to: \tcode{return x.i_.current_ == y.i_.current_;} \end{itemdescr} -\indexlibrary{\idxcode{operator"!=}!\idxcode{join_view::sentinel}} +\indexlibrary{\idxcode{operator==}!\idxcode{split_view::inner_iterator}}% \begin{itemdecl} -friend constexpr bool operator!=(const iterator& x, const sentinel& y); +friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t); \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return !(x == y);} +\effects Equivalent to: +\begin{codeblock} +auto cur = x.i_.@\placeholder{current}@; +auto end = ranges::end(x.i_.parent_->base_); +if (cur == end) return true; +auto [pcur, pend] = subrange{x.i_.parent_->pattern_}; +if (pcur == pend) return x.incremented_; +do { + if (*cur != *pcur) return false; + if (++pcur == pend) return true; +} while (++cur != end); +return false; +\end{codeblock} \end{itemdescr} -\indexlibrary{\idxcode{operator"!=}!\idxcode{join_view::sentinel}} +\indexlibrary{\idxcode{iter_swap}!\idxcode{split_view::inner_iterator}}% \begin{itemdecl} -friend constexpr bool operator!=(const sentinel& x, const iterator& y); +friend constexpr void iter_swap(const inner_iterator& x, const inner_iterator& y) + noexcept(noexcept(ranges::iter_swap(x.i_.@\placeholdernc{current}, y.i_.\placeholdernc{current}@))) + requires indirectly_swappable>; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return !(y == x);} +\effects Equivalent to +\tcode{ranges::iter_swap(x.i_.\placeholdernc{current}, y.i_.\placeholdernc{current})}. \end{itemdescr} -\rSec3[range.join.adaptor]{\tcode{view::join}} +\rSec3[range.split.adaptor]{\tcode{views::split}} \pnum -The name \tcode{view::join} denotes a +The name \tcode{views::split} denotes a range adaptor object\iref{range.adaptor.object}. -For some subexpression \tcode{E}, the expression -\tcode{view::join(E)} is expression-equivalent to -\tcode{join_view\{E\}}. +For some subexpressions \tcode{E} and \tcode{F}, +the expression \tcode{views::split(E, F)} is expression-equivalent to +\tcode{split_view\{E, F\}}. -\rSec2[range.split]{Split view} -\rSec3[range.split.overview]{Overview} +\rSec2[range.counted]{Counted view} + +\pnum +A counted view presents a \libconcept{view} of the elements +of the counted range\iref{iterator.requirements.general} \range{i}{n} +for some iterator \tcode{i} and non-negative integer \tcode{n}. + +\pnum +The name \tcode{views::counted} denotes a +customization point object\iref{customization.point.object}. +Let \tcode{E} and \tcode{F} be expressions, +and let \tcode{T} be \tcode{decay_t}. +Then the expression \tcode{views::counted(E, F)} is expression-equivalent to: + +\begin{itemize} +\item If \tcode{T} models \libconcept{input_or_output_iterator} and + \tcode{decltype((F))} models \tcode{\libconcept{convertible_to}>}, + \begin{itemize} + \item \tcode{subrange\{E, E + static_cast>(F)\}} + if \tcode{T} models \libconcept{random_access_\-it\-er\-ator}. + \item Otherwise, + \tcode{subrange\{counted_iterator\{E, F\}, default_sentinel\}}. +\end{itemize} + +\item Otherwise, \tcode{views::counted(E, F)} is ill-formed. + \begin{note} + This case can result in substitution failure when \tcode{views::counted(E, F)} + appears in the immediate context of a template instantiation. + \end{note} +\end{itemize} + +\rSec2[range.common]{Common view} + +\rSec3[range.common.overview]{Overview} + +\pnum +\tcode{common_view} takes a \libconcept{view} which has different types for +its iterator and sentinel and turns it into a \libconcept{view} of the same +elements with an iterator and sentinel of the same type. \pnum -\tcode{split_view} takes a \libconcept{View} and a delimiter, and splits -the \libconcept{View} into subranges on the delimiter. The delimiter can be -a single element or a \libconcept{View} of elements. +\begin{note} +\tcode{common_view} is useful for calling legacy algorithms that expect +a range's iterator and sentinel types to be the same. +\end{note} \pnum \begin{example} \begin{codeblock} -string str{"the quick brown fox"}; -split_view sentence{str, ' '}; -for (auto word : sentence) { - for (char ch : word) - cout << ch; - cout << '*'; +// Legacy algorithm: +template +size_t count(ForwardIterator first, ForwardIterator last); + +template +void my_algo(R&& r) { + auto&& common = common_view{r}; + auto cnt = count(common.begin(), common.end()); + // ... } -// The above prints: the*quick*brown*fox* \end{codeblock} \end{example} -\rSec3[range.split.view]{Class template \tcode{split_view}} +\rSec3[range.common.view]{Class template \tcode{common_view}} \begin{codeblock} namespace std::ranges { - template struct @\placeholdernc{require-constant}@; // \expos - - template - concept @\placeholdernc{tiny-range}@ = // \expos - SizedRange && - requires { typename @\placeholdernc{require-constant}@::size()>; } && - (remove_reference_t::size() <= 1); - - template - requires View && View && - IndirectlyComparable, iterator_t, ranges::equal_to> && - (ForwardRange || @\placeholdernc{tiny-range}@) - class split_view : public view_interface> { + template + requires (!common_range) + class common_view : public view_interface> { private: - V base_ = V(); // \expos - Pattern pattern_ = Pattern(); // \expos - iterator_t current_ = iterator_t(); // \expos, present only if \tcode{!ForwardRange} - // \ref{range.split.outer}, class template \tcode{split_view::outer_iterator} - template struct outer_iterator; // \expos - // \ref{range.split.inner}, class template \tcode{split_view::inner_iterator} - template struct inner_iterator; // \expos + V base_ = V(); // \expos public: - split_view() = default; - constexpr split_view(V base, Pattern pattern); + common_view() = default; - template - requires Constructible> && - Constructible> - constexpr split_view(R&& r, P&& p); + constexpr explicit common_view(V r); + + template + requires (!common_range && constructible_from>) + constexpr explicit common_view(R&& r); + + constexpr V base() const; - template - requires Constructible> && - Constructible>>> - constexpr split_view(R&& r, iter_value_t> e); + constexpr auto size() requires sized_range { + return ranges::size(base_); + } + constexpr auto size() const requires sized_range { + return ranges::size(base_); + } constexpr auto begin() { - if constexpr (ForwardRange) - return outer_iterator<@\placeholder{simple-view}@>{*this, ranges::begin(base_)}; - else { - current_ = ranges::begin(base_); - return outer_iterator{*this}; - } + if constexpr (random_access_range && sized_range) + return ranges::begin(base_); + else + return common_iterator, sentinel_t>(ranges::begin(base_)); } - constexpr auto begin() const requires ForwardRange && ForwardRange { - return outer_iterator{*this, ranges::begin(base_)}; + constexpr auto begin() const requires range { + if constexpr (random_access_range && sized_range) + return ranges::begin(base_); + else + return common_iterator, sentinel_t>(ranges::begin(base_)); } - constexpr auto end() requires ForwardRange && CommonRange { - return outer_iterator<@\placeholder{simple-view}@>{*this, ranges::end(base_)}; + constexpr auto end() { + if constexpr (random_access_range && sized_range) + return ranges::begin(base_) + ranges::size(base_); + else + return common_iterator, sentinel_t>(ranges::end(base_)); } - constexpr auto end() const { - if constexpr (ForwardRange && ForwardRange && CommonRange) - return outer_iterator{*this, ranges::end(base_)}; + constexpr auto end() const requires range { + if constexpr (random_access_range && sized_range) + return ranges::begin(base_) + ranges::size(base_); else - return default_sentinel; + return common_iterator, sentinel_t>(ranges::end(base_)); } }; - template - split_view(R&&, P&&) -> split_view, all_view

>; - - template - split_view(R&&, iter_value_t>) - -> split_view, single_view>>>; + template + common_view(R&&) -> common_view>; } \end{codeblock} -\indexlibrary{\idxcode{split_view}!\idxcode{split_view}}% +\indexlibrary{\idxcode{common_view}!\idxcode{common_view}}% \begin{itemdecl} -constexpr split_view(V base, Pattern pattern); +constexpr explicit common_view(V base); \end{itemdecl} \begin{itemdescr} \pnum -\effects Initializes \tcode{base_} with \tcode{std::move(base)}, and -\tcode{pattern_} with \tcode{std::move(pattern)}. +\effects Initializes \tcode{base_} with \tcode{std::move(base)}. \end{itemdescr} -\indexlibrary{\idxcode{split_view}!\idxcode{split_view}}% +\indexlibrary{\idxcode{common_view}!\idxcode{common_view}}% \begin{itemdecl} -template - requires Constructible> && - Constructible> -constexpr split_view(R&& r, P&& p); +template + requires (!common_range && constructible_from>) +constexpr explicit common_view(R&& r); \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \tcode{base_} with \tcode{view::all(std::forward(r))} and -\tcode{pattern_} with \tcode{view::all(std\brk{}::forward

(p))}. +\effects Initializes \tcode{base_} with \tcode{views::all(std::forward(r))}. \end{itemdescr} -\indexlibrary{\idxcode{split_view}!\idxcode{split_view}}% +\indexlibrary{\idxcode{base}!\idxcode{common_view}}% \begin{itemdecl} -template - requires Constructible> && - Constructible>>> -constexpr split_view(R&& r, iter_value_t> e); +constexpr V base() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Initializes \tcode{base_} with \tcode{view::all(std::forward(r))} and -\tcode{pattern_} with \tcode{single_view\{\brk{}std::move(e)\}}. +\effects Equivalent to: \tcode{return base_;} \end{itemdescr} -\rSec3[range.split.outer]{Class template \tcode{split_view::outer_iterator}} +\rSec3[range.common.adaptor]{\tcode{views::common}} + +\pnum +The name \tcode{views::common} denotes a +range adaptor object\iref{range.adaptor.object}. +For some subexpression \tcode{E}, +the expression \tcode{views::common(E)} is expression-equivalent to: + +\begin{itemize} +\item \tcode{views::all(E)}, + if \tcode{decltype((E))} models \libconcept{common_range} + and \tcode{views::all(E)} is a well-formed expression. + +\item Otherwise, \tcode{common_view\{E\}}. +\end{itemize} + +\rSec2[range.reverse]{Reverse view} + +\rSec3[range.reverse.overview]{Overview} + +\pnum +\tcode{reverse_view} takes a bidirectional \libconcept{view} and produces +another \libconcept{view} that iterates the same elements in reverse order. +\pnum +\begin{example} +\begin{codeblock} +vector is {0,1,2,3,4}; +reverse_view rv {is}; +for (int i : rv) + cout << i << ' '; // prints: 4 3 2 1 0 +\end{codeblock} +\end{example} + +\rSec3[range.reverse.view]{Class template \tcode{reverse_view}} + +\indexlibrary{\idxcode{weiv_esrever}}% \begin{codeblock} namespace std::ranges { - template - template - struct split_view::outer_iterator { + template + requires bidirectional_range + class reverse_view : public view_interface> { private: - using Parent = // \expos - conditional_t; - using Base = // \expos - conditional_t; - Parent* parent_ = nullptr; // \expos - iterator_t current_ = // \expos, present only if \tcode{V} models \libconcept{ForwardRange} - iterator_t(); - + V base_ = V(); // \expos public: - using iterator_concept = - conditional_t, forward_iterator_tag, input_iterator_tag>; - using iterator_category = input_iterator_tag; - // \ref{range.split.outer.value}, class \tcode{split_view::outer_iterator::value_type} - struct value_type; - using difference_type = iter_difference_t>; + reverse_view() = default; - outer_iterator() = default; - constexpr explicit outer_iterator(Parent& parent) - requires (!ForwardRange); - constexpr outer_iterator(Parent& parent, iterator_t current) - requires ForwardRange; - constexpr outer_iterator(outer_iterator i) - requires Const && ConvertibleTo, iterator_t>; + constexpr explicit reverse_view(V r); - constexpr value_type operator*() const; + template + requires bidirectional_range && constructible_from> + constexpr explicit reverse_view(R&& r); - constexpr outer_iterator& operator++(); - constexpr decltype(auto) operator++(int) { - if constexpr (ForwardRange) { - auto tmp = *this; - ++*this; - return tmp; - } else - ++*this; - } + constexpr V base() const; - friend constexpr bool operator==(const outer_iterator& x, const outer_iterator& y) - requires ForwardRange; - friend constexpr bool operator!=(const outer_iterator& x, const outer_iterator& y) - requires ForwardRange; + constexpr reverse_iterator> begin(); + constexpr reverse_iterator> begin() requires common_range; + constexpr reverse_iterator> begin() const + requires common_range; - friend constexpr bool operator==(const outer_iterator& x, default_sentinel_t); - friend constexpr bool operator==(default_sentinel_t, const outer_iterator& x); - friend constexpr bool operator!=(const outer_iterator& x, default_sentinel_t y); - friend constexpr bool operator!=(default_sentinel_t y, const outer_iterator& x); + constexpr reverse_iterator> end(); + constexpr reverse_iterator> end() const + requires common_range; + + constexpr auto size() requires sized_range { + return ranges::size(base_); + } + constexpr auto size() const requires sized_range { + return ranges::size(base_); + } }; + + template + reverse_view(R&&) -> reverse_view>; } \end{codeblock} -\pnum -Many of the following specifications refer to the notional member -\tcode{\placeholder{current}} of \tcode{outer_iterator}. -\tcode{\placeholder{current}} is equivalent to \tcode{current_} if \tcode{V} -models \libconcept{ForwardRange}, and \tcode{parent_->current_} otherwise. - -\indexlibrary{\idxcode{outer_iterator}!\idxcode{split_view::outer_iterator}}% +\indexlibrary{\idxcode{reverse_view}!\idxcode{reverse_view}}% \begin{itemdecl} -constexpr explicit outer_iterator(Parent& parent) - requires (!ForwardRange); +constexpr explicit reverse_view(V base); \end{itemdecl} \begin{itemdescr} \pnum -\effects Initializes \tcode{parent_} with \tcode{addressof(parent)}. +\effects Initializes \tcode{base_} with \tcode{std::move(base)}. \end{itemdescr} -\indexlibrary{\idxcode{outer_iterator}!\idxcode{split_view::outer_iterator}}% +\indexlibrary{\idxcode{reverse_view}!\idxcode{reverse_view}}% \begin{itemdecl} -constexpr outer_iterator(Parent& parent, iterator_t current) - requires ForwardRange; +template + requires bidirectional_range && constructible_from> +constexpr explicit reverse_view(R&& r); \end{itemdecl} \begin{itemdescr} \pnum -\effects Initializes \tcode{parent_} with \tcode{addressof(parent)} -and \tcode{current_} with \tcode{current}. +\effects Initializes \tcode{base_} with \tcode{views::all(std::forward(r))}. \end{itemdescr} -\indexlibrary{\idxcode{outer_iterator}!\idxcode{split_view::outer_iterator}}% +\indexlibrary{\idxcode{base}!\idxcode{reverse_view}}% \begin{itemdecl} -constexpr outer_iterator(outer_iterator i) - requires Const && ConvertibleTo, iterator_t>; +constexpr V base() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects Initializes \tcode{parent_} with \tcode{i.parent_} and -\tcode{current_} with \tcode{std::move(i.current_)}. +\effects Equivalent to: \tcode{return base_;} \end{itemdescr} -\indexlibrary{\idxcode{operator*}!\idxcode{split_view::outer_iterator}}% +\indexlibrary{\idxcode{begin}!\idxcode{reverse_view}}% \begin{itemdecl} -constexpr value_type operator*() const; +constexpr reverse_iterator> begin(); \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return value_type\{*this\};} +\returns +\begin{codeblock} +make_reverse_iterator(ranges::next(ranges::begin(base_), ranges::end(base_))) +\end{codeblock} + +\pnum +\remarks In order to provide the amortized constant time complexity required by +the \libconcept{range} concept, this function caches the result within the +\tcode{reverse_view} for use on subsequent calls. \end{itemdescr} -\indexlibrary{\idxcode{operator++}!\idxcode{split_view::outer_iterator}}% +\indexlibrary{\idxcode{begin}!\idxcode{reverse_view}}% \begin{itemdecl} -constexpr outer_iterator& operator++(); +constexpr reverse_iterator> begin() requires common_range; +constexpr reverse_iterator> begin() const + requires common_range; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: -\begin{codeblock} -const auto end = ranges::end(parent_->base_); -if (@\placeholder{current}@ == end) return *this; -const auto [pbegin, pend] = subrange{parent_->pattern_}; -if (pbegin == pend) ++@\placeholder{current}@; -else { - do { - const auto [b, p] = ranges::mismatch(@\placeholdernc{current}@, end, pbegin, pend); - if (p == pend) { - @\placeholder{current}@ = b; // The pattern matched; skip it - break; - } - } while (++@\placeholder{current}@ != end); -} -return *this; -\end{codeblock} +\effects Equivalent to: \tcode{return make_reverse_iterator(ranges::end(base_));} \end{itemdescr} -\indexlibrary{\idxcode{operator==}!\idxcode{split_view::outer_iterator}}% +\indexlibrary{\idxcode{end}!\idxcode{reverse_view}}% \begin{itemdecl} -friend constexpr bool operator==(const outer_iterator& x, const outer_iterator& y) - requires ForwardRange; +constexpr reverse_iterator> end(); +constexpr reverse_iterator> end() const + requires common_range; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return x.current_ == y.current_;} +\effects Equivalent to: \tcode{return make_reverse_iterator(ranges::begin(base_));} \end{itemdescr} -\indexlibrary{\idxcode{operator"!=}!\idxcode{split_view::outer_iterator}}% -\begin{itemdecl} -friend constexpr bool operator!=(const outer_iterator& x, const outer_iterator& y) - requires ForwardRange; -\end{itemdecl} +\rSec3[range.reverse.adaptor]{\tcode{views::reverse}} + +\pnum +The name \tcode{views::reverse} denotes a +range adaptor object\iref{range.adaptor.object}. +For some subexpression \tcode{E}, the expression +\tcode{views::reverse(E)} is expression-equivalent to: +\begin{itemize} +\item + If the type of \tcode{E} is + a (possibly cv-qualified) specialization of \tcode{reverse_view}, + equivalent to \tcode{E.base()}. +\item + Otherwise, if the type of \tcode{E} is cv-qualified +\begin{codeblock} +subrange, reverse_iterator, K> +\end{codeblock} + for some iterator type \tcode{I} and + value \tcode{K} of type \tcode{subrange_kind}, + \begin{itemize} + \item + if \tcode{K} is \tcode{subrange_kind::sized}, equivalent to: +\begin{codeblock} +subrange(E.end().base(), E.begin().base(), E.size()) +\end{codeblock} + \item + otherwise, equivalent to: +\begin{codeblock} +subrange(E.end().base(), E.begin().base()) +\end{codeblock} + \end{itemize} + However, in either case \tcode{E} is evaluated only once. +\item + Otherwise, equivalent to \tcode{reverse_view\{E\}}. +\end{itemize} -\begin{itemdescr} -\pnum -\effects Equivalent to: \tcode{return !(x == y);} -\end{itemdescr} +\rSec2[range.istream]{Istream view} -\indexlibrary{\idxcode{operator==}!\idxcode{split_view::outer_iterator}}% -\begin{itemdecl} -friend constexpr bool operator==(const outer_iterator& x, default_sentinel_t); -friend constexpr bool operator==(default_sentinel_t, const outer_iterator& x); -\end{itemdecl} +\rSec3[range.istream.overview]{Overview} -\begin{itemdescr} \pnum -\effects -Equivalent to: \tcode{return x.\placeholder{current} == ranges::end(x.parent_->base_);} -\end{itemdescr} - -\indexlibrary{\idxcode{operator"!=}!\idxcode{split_view::outer_iterator}}% -\begin{itemdecl} -friend constexpr bool operator!=(const outer_iterator& x, default_sentinel_t y); -friend constexpr bool operator!=(default_sentinel_t y, const outer_iterator& x); -\end{itemdecl} +\tcode{basic_istream_view} models \libconcept{input_range} and +reads (using \tcode{operator>>}) successive elements +from its corresponding input stream. -\begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return !(x == y);} -\end{itemdescr} +\begin{example} +\begin{codeblock} +auto ints = istringstream{"0 1 2 3 4"}; +ranges::copy(istream_view(ints), ostream_iterator{cout, "-"}); +// prints \tcode{0-1-2-3-4-} +\end{codeblock} +\end{example} -\rSec3[range.split.outer.value]{Class \tcode{split_view::outer_iterator::value_type}} +\rSec3[range.istream.view]{Class template \tcode{basic_istream_view}} +\indexlibrary{\idxcode{basic_istream_view}}% \begin{codeblock} namespace std::ranges { - template - template - struct split_view::outer_iterator::value_type { - private: - outer_iterator i_ = outer_iterator(); // \expos + template + concept @\placeholder{stream-extractable}@ = // \expos + requires(basic_istream& is, Val& t) { + is >> t; + }; + + template + requires default_constructible && + @\placeholder{stream-extractable}@ + class basic_istream_view : public view_interface> { public: - value_type() = default; - constexpr explicit value_type(outer_iterator i); + basic_istream_view() = default; + constexpr explicit basic_istream_view(basic_istream& stream); - constexpr inner_iterator begin() const; - constexpr default_sentinel_t end() const; + constexpr auto begin() + { + if (stream_) { + *stream_ >> object_; + } + return iterator{*this}; + } + + constexpr default_sentinel_t end() const noexcept; + + private: + struct iterator; // \expos + basic_istream* stream_{}; // \expos + Val object_ = Val(); // \expos }; } \end{codeblock} -\indexlibrary{\idxcode{value_type}!\idxcode{split_view::outer_iterator::value_type}}% +\indexlibrary{\idxcode{basic_istream_view}!constructor}% \begin{itemdecl} -constexpr explicit value_type(outer_iterator i); +constexpr explicit basic_istream_view(basic_istream& stream); \end{itemdecl} \begin{itemdescr} \pnum -\effects Initializes \tcode{i_} with \tcode{i}. +\effects +Initializes \tcode{stream_} with \tcode{addressof(stream)}. \end{itemdescr} -\indexlibrary{\idxcode{begin}!\idxcode{split_view::outer_iterator::value_type}}% +\indexlibrarymember{end}{basic_istream_view}% \begin{itemdecl} -constexpr inner_iterator begin() const; +constexpr default_sentinel_t end() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return inner_iterator\{i_\};} +\effects +Equivalent to: \tcode{return default_sentinel;} \end{itemdescr} -\indexlibrary{\idxcode{end}!\idxcode{split_view::outer_iterator::value_type}}% +\indexlibrary{\idxcode{istream_view}}% \begin{itemdecl} -constexpr default_sentinel_t end() const; +template +basic_istream_view istream_view(basic_istream& s); \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return default_sentinel;} +\effects +Equivalent to: \tcode{return basic_istream_view\{s\};} \end{itemdescr} -\rSec3[range.split.inner]{Class template \tcode{split_view::inner_iterator}} +\rSec3[range.istream.iterator]{Class template \tcode{basic_istream_view::iterator}} \begin{codeblock} namespace std::ranges { - template - template - struct split_view::inner_iterator { - private: - using Base = - conditional_t; // \expos - outer_iterator i_ = outer_iterator(); // \expos - bool incremented_ = false; // \expos + template + class basic_istream_view::iterator { // \expos public: - using iterator_concept = typename outer_iterator::iterator_concept; - using iterator_category = @\seebelow@; - using value_type = iter_value_t>; - using difference_type = iter_difference_t>; + using iterator_category = input_iterator_tag; + using difference_type = ptrdiff_t; + using value_type = Val; - inner_iterator() = default; - constexpr explicit inner_iterator(outer_iterator i); + iterator() = default; + constexpr explicit iterator(basic_istream_view& parent) noexcept; - constexpr decltype(auto) operator*() const { return *i_.@\placeholder{current}@; } + iterator(const iterator&) = delete; + iterator(iterator&&) = default; - constexpr inner_iterator& operator++(); - constexpr decltype(auto) operator++(int) { - if constexpr (ForwardRange) { - auto tmp = *this; - ++*this; - return tmp; - } else - ++*this; - } + iterator& operator=(const iterator&) = delete; + iterator& operator=(iterator&&) = default; - friend constexpr bool operator==(const inner_iterator& x, const inner_iterator& y) - requires ForwardRange; - friend constexpr bool operator!=(const inner_iterator& x, const inner_iterator& y) - requires ForwardRange; + iterator& operator++(); + void operator++(int); - friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t); - friend constexpr bool operator==(default_sentinel_t, const inner_iterator& x); - friend constexpr bool operator!=(const inner_iterator& x, default_sentinel_t y); - friend constexpr bool operator!=(default_sentinel_t y, const inner_iterator& x); + Val& operator*() const; - friend constexpr decltype(auto) iter_move(const inner_iterator& i) - noexcept(noexcept(ranges::iter_move(i.i_.@\placeholdernc{current}@))) { - return ranges::iter_move(i.i_.@\placeholdernc{current}@); - } + friend bool operator==(const iterator& x, default_sentinel_t); - friend constexpr void iter_swap(const inner_iterator& x, const inner_iterator& y) - noexcept(noexcept(ranges::iter_swap(x.i_.@\placeholdernc{current}, y.i_.\placeholdernc{current}@))) - requires IndirectlySwappable>; + private: + basic_istream_view* parent_{}; // \expos }; } \end{codeblock} -\pnum -The \grammarterm{typedef-name} \tcode{iterator_category} denotes -\tcode{forward_iterator_tag} if -\tcode{iterator_traits>::iterator_category} models -\tcode{DerivedFrom}, and \tcode{input_iterator_tag} -otherwise. - -\indexlibrary{\idxcode{inner_iterator}!\idxcode{split_view::inner_iterator}}% \begin{itemdecl} -constexpr explicit inner_iterator(outer_iterator i); +constexpr explicit iterator(basic_istream_view& parent) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects Initializes \tcode{i_} with \tcode{i}. +\effects +Initializes \tcode{parent_} with \tcode{addressof(parent)}. \end{itemdescr} -\indexlibrary{\idxcode{operator++}!\idxcode{split_view::inner_iterator}}% \begin{itemdecl} -constexpr inner_iterator& operator++() const; +iterator& operator++(); \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: +\expects +\tcode{parent_->stream_ != nullptr} is \tcode{true}. + +\pnum +\effects +Equivalent to: \begin{codeblock} -incremented_ = true; -if constexpr (!ForwardRange) { - if constexpr (Pattern::size() == 0) { - return *this; - } -} -++i_.@\placeholder{current}@; +*parent_->stream >> parent_->object_; return *this; \end{codeblock} \end{itemdescr} -\indexlibrary{\idxcode{operator==}!\idxcode{split_view::inner_iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const inner_iterator& x, const inner_iterator& y) - requires ForwardRange; +void operator++(int); \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return x.i_.current_ == y.i_.current_;} -\end{itemdescr} - -\indexlibrary{\idxcode{operator"!=}!\idxcode{split_view::inner_iterator}}% -\begin{itemdecl} -friend constexpr bool operator!=(const inner_iterator& x, const inner_iterator& y) - requires ForwardRange; -\end{itemdecl} +\expects \tcode{parent_->stream_ != nullptr} is \tcode{true}. -\begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return !(x == y);} +\effects +Equivalent to \tcode{++*this}. \end{itemdescr} -\indexlibrary{\idxcode{operator==}!\idxcode{split_view::inner_iterator}}% \begin{itemdecl} -friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t); -friend constexpr bool operator==(default_sentinel_t, const inner_iterator& x); +Val& operator*() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: -\begin{codeblock} -auto cur = x.i_.@\placeholder{current}@; -auto end = ranges::end(x.i_.parent_->base_); -if (cur == end) return true; -auto [pcur, pend] = subrange{x.i_.parent_->pattern_}; -if (pcur == pend) return x.incremented_; -do { - if (*cur != *pcur) return false; - if (++pcur == pend) return true; -} while (++cur != end); -return false; -\end{codeblock} -\end{itemdescr} - -\indexlibrary{\idxcode{operator"!=}!\idxcode{split_view::inner_iterator}}% -\begin{itemdecl} -friend constexpr bool operator!=(const inner_iterator& x, default_sentinel_t y); -friend constexpr bool operator!=(default_sentinel_t y, const inner_iterator& x); -\end{itemdecl} +\expects +\tcode{parent_->stream_ != nullptr} is \tcode{true}. -\begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return !(x == y);} +\effects +Equivalent to: \tcode{return parent_->value_;} \end{itemdescr} -\indexlibrary{\idxcode{iter_swap}!\idxcode{split_view::inner_iterator}}% \begin{itemdecl} -friend constexpr void iter_swap(const inner_iterator& x, const inner_iterator& y) - noexcept(noexcept(ranges::iter_swap(x.i_.@\placeholdernc{current}, y.i_.\placeholdernc{current}@))) - requires IndirectlySwappable>; +friend bool operator==(const iterator& x, default_sentinel_t); \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to -\tcode{ranges::iter_swap(x.i_.\placeholdernc{current}, y.i_.\placeholdernc{current})}. +\effects +Equivalent to: \tcode{return x.parent_ == nullptr || !*x.parent_->stream_;} \end{itemdescr} -\rSec3[range.split.adaptor]{\tcode{view::split}} +\rSec2[range.elements]{Elements view} + +\rSec3[range.elements.overview]{Overview} \pnum -The name \tcode{view::split} denotes a -range adaptor object\iref{range.adaptor.object}. -For some subexpressions \tcode{E} and \tcode{F}, -the expression \tcode{view::split(E, F)} is expression-equivalent to -\tcode{split_view\{E, F\}}. +\tcode{elements_view} takes +a \tcode{view} of tuple-like values and a \tcode{size_t}, and +produces a \tcode{view} with a value-type of the $N^\text{th}$ element +of the adapted \tcode{view}'s value-type. +\pnum +The name \tcode{views::elements} denotes +a range adaptor object\iref{range.adaptor.object}. +For some subexpression \tcode{E} and constant expression \tcode{N}, +the expression \tcode{views::elements(E)} is expression-equivalent to +\tcode{elements_view, N>\{E\}}. -\rSec2[range.counted]{Counted view} +\begin{example} +\begin{codeblock} +auto historical_figures = map{ + {"Lovelace"sv, 1815}, + {"Turing"sv, 1912}, + {"Babbage"sv, 1791}, + {"Hamilton"sv, 1936} +}; + +auto names = historical_figures | views::elements<0>; +for (auto&& name : names) { + cout << name << ' '; // prints \tcode{Babbage Hamilton Lovelace Turing } +} + +auto birth_years = historical_figures | views::elements<1>; +for (auto&& born : birth_years) { + cout << born << ' '; // prints \tcode{1791 1936 1815 1912 } +} +\end{codeblock} +\end{example} \pnum -A counted view presents a \libconcept{View} of the elements -of the counted range\iref{iterator.requirements.general} \range{i}{n} -for some iterator \tcode{i} and non-negative integer \tcode{n}. +\tcode{keys_view} is an alias for \tcode{elements_view, 0>}, and +is useful for extracting keys from associative containers. + +\begin{example} +\begin{codeblock} +auto names = keys_view{historical_figures}; +for (auto&& name : names) { + cout << name << ' '; // prints \tcode{Babbage Hamilton Lovelace Turing } +} +\end{codeblock} +\end{example} \pnum -The name \tcode{view::counted} denotes a -customization point object\iref{customization.point.object}. -Let \tcode{E} and \tcode{F} be expressions, -and let \tcode{T} be \tcode{decay_t}. -Then the expression \tcode{view::counted(E, F)} is expression-equivalent to: +\tcode{values_view} is an alias for \tcode{elements_view, 1>}, and +is useful for extracting values from associative containers. -\begin{itemize} -\item If \tcode{T} models \libconcept{Iterator} and - \tcode{decltype((F))} models \libconcept{ConvertibleTo>}, - \begin{itemize} - \item \tcode{subrange\{E, E + static_cast>(F)\}} - if \tcode{T} models \libconcept{RandomAccessItera\-tor}. - \item Otherwise, - \tcode{subrange\{counted_iterator\{E, F\}, default_sentinel\}}. -\end{itemize} +\begin{example} +\begin{codeblock} +auto is_even = [](const auto x) { return x % 2 == 0; }; +cout << ranges::count_if(values_view{historical_figures}, is_even); // prints \tcode{2} +\end{codeblock} +\end{example} -\item Otherwise, \tcode{view::counted(E, F)} is ill-formed. - \begin{note} - This case can result in substitution failure when \tcode{view::counted(E, F)} - appears in the immediate context of a template instantiation. - \end{note} -\end{itemize} +\rSec3[range.elements.view]{Class template \tcode{elements_view}} +\indexlibrary{\idxcode{elements_view}}% +\begin{codeblock} +namespace std::ranges { + template + concept @\placeholder{has-tuple-element}@ = // \expos + requires(T t) { + typename tuple_size::type; + requires N < tuple_size_v; + typename tuple_element_t; + { get(t) } -> const tuple_element_t&; + }; -\rSec2[range.common]{Common view} -\rSec3[range.common.overview]{Overview} + template + requires view && @\placeholder{has-tuple-element}@, N> && + @\placeholder{has-tuple-element}@>, N> + class elements_view : public view_interface> { + public: + elements_view() = default; + constexpr explicit elements_view(R base); -\pnum -\tcode{common_view} takes a \libconcept{View} which has different types for -its iterator and sentinel and turns it into a \libconcept{View} of the same -elements with an iterator and sentinel of the same type. + constexpr R base() const; -\pnum -\begin{note} -\tcode{common_view} is useful for calling legacy algorithms that expect -a range's iterator and sentinel types to be the same. -\end{note} + constexpr auto begin() requires (!@\placeholder{simple-view}@) + { return iterator(ranges::begin(base_)); } -\pnum -\begin{example} -\begin{codeblock} -// Legacy algorithm: -template -size_t count(ForwardIterator first, ForwardIterator last); + constexpr auto begin() const requires @\placeholder{simple-view}@ + { return iterator(ranges::begin(base_)); } -template -void my_algo(R&& r) { - auto&& common = common_view{r}; - auto cnt = count(common.begin(), common.end()); - // ... + constexpr auto end() requires (!@\placeholder{simple-view}@) + { return ranges::end(base_); } + + constexpr auto end() const requires @\placeholder{simple-view}@ + { return ranges::end(base_); } + + constexpr auto size() requires sized_range + { return ranges::size(base_); } + + constexpr auto size() const requires sized_range + { return ranges::size(base_); } + + private: + template struct iterator; // \expos + R base_ = R(); // \expos + }; } \end{codeblock} -\end{example} -\rSec3[range.common.view]{Class template \tcode{common_view}} +\indexlibrary{\idxcode{elements_view}!constructor}% +\begin{itemdecl} +constexpr explicit elements_view(R base); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \tcode{base_} with \tcode{std::move(base)}. +\end{itemdescr} + +\indexlibrarymember{base}{elements_view}% +\begin{itemdecl} +constexpr R base() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return base_;} +\end{itemdescr} + +\rSec3[range.elements.iterator]{Class template \tcode{elements_view::iterator}} \begin{codeblock} namespace std::ranges { - template - requires (!CommonRange) - class common_view : public view_interface> { - private: - V base_ = V(); // \expos + template + template + class elements_view::iterator { // \expos + using base_t = conditional_t; + friend iterator; + + iterator_t current_; public: - common_view() = default; + using iterator_category = typename iterator_traits>::iterator_category; + using value_type = remove_cvref_t>>; + using difference_type = range_difference_t; + + iterator() = default; + constexpr explicit iterator(iterator_t current); + constexpr iterator(iterator i) + requires Const && convertible_to, iterator_t>; - constexpr explicit common_view(V r); + constexpr iterator_t base() const; - template - requires (!CommonRange && Constructible>) - constexpr explicit common_view(R&& r); + constexpr decltype(auto) operator*() const + { return get(*current_); } - constexpr V base() const; + constexpr iterator& operator++(); + constexpr void operator++(int) requires (!forward_range); + constexpr iterator operator++(int) requires forward_range; - constexpr auto size() requires SizedRange { - return ranges::size(base_); - } - constexpr auto size() const requires SizedRange { - return ranges::size(base_); - } + constexpr iterator& operator--() requires bidirectional_range; + constexpr iterator operator--(int) requires bidirectional_range; - constexpr auto begin() { - if constexpr (RandomAccessRange && SizedRange) - return ranges::begin(base_); - else - return common_iterator, sentinel_t>(ranges::begin(base_)); - } + constexpr iterator& operator+=(difference_type x) + requires random_access_range; + constexpr iterator& operator-=(difference_type x) + requires random_access_range; - constexpr auto begin() const requires Range { - if constexpr (RandomAccessRange && SizedRange) - return ranges::begin(base_); - else - return common_iterator, sentinel_t>(ranges::begin(base_)); - } + constexpr decltype(auto) operator[](difference_type n) const + requires random_access_range + { return get(*(current_ + n)); } - constexpr auto end() { - if constexpr (RandomAccessRange && SizedRange) - return ranges::begin(base_) + ranges::size(base_); - else - return common_iterator, sentinel_t>(ranges::end(base_)); - } + friend constexpr bool operator==(const iterator& x, const iterator& y) + requires equality_comparable>; + friend constexpr bool operator==(const iterator& x, const sentinel_t& y); - constexpr auto end() const requires Range { - if constexpr (RandomAccessRange && SizedRange) - return ranges::begin(base_) + ranges::size(base_); - else - return common_iterator, sentinel_t>(ranges::end(base_)); - } + friend constexpr bool operator<(const iterator& x, const iterator& y) + requires random_access_range; + friend constexpr bool operator>(const iterator& x, const iterator& y) + requires random_access_range; + friend constexpr bool operator<=(const iterator& y, const iterator& y) + requires random_access_range; + friend constexpr bool operator>=(const iterator& x, const iterator& y) + requires random_access_range; + friend constexpr compare_three_way_result_t> + operator<=>(const iterator& x, const iterator& y) + requires random_access_range && three_way_comparable>; + + friend constexpr iterator operator+(const iterator& x, difference_type y) + requires random_access_range; + friend constexpr iterator operator+(difference_type x, const iterator& y) + requires random_access_range; + friend constexpr iterator operator-(const iterator& x, difference_type y) + requires random_access_range; + friend constexpr difference_type operator-(const iterator& x, const iterator& y) + requires random_access_range; + + friend constexpr difference_type + operator-(const iterator& x, const sentinel_t& y) + requires sized_sentinel_for, iterator_t>; + friend constexpr difference_type + operator-(const sentinel_t& x, const iterator& y) + requires sized_sentinel_for, iterator_t>; }; - - template - common_view(R&&) -> common_view>; } \end{codeblock} -\indexlibrary{\idxcode{common_view}!\idxcode{common_view}}% \begin{itemdecl} -constexpr explicit common_view(V base); +constexpr explicit iterator(iterator_t current); \end{itemdecl} \begin{itemdescr} \pnum -\effects Initializes \tcode{base_} with \tcode{std::move(base)}. +\effects +Initializes \tcode{current_} with \tcode{current}. \end{itemdescr} -\indexlibrary{\idxcode{common_view}!\idxcode{common_view}}% \begin{itemdecl} -template - requires (!CommonRange && Constructible>) -constexpr explicit common_view(R&& r); +constexpr iterator(iterator i) + requires Const && convertible_to, iterator_t>; \end{itemdecl} \begin{itemdescr} \pnum -\effects Initializes \tcode{base_} with \tcode{view::all(std::forward(r))}. +\effects +Initializes \tcode{current_} with \tcode{i.current_}. \end{itemdescr} -\indexlibrary{\idxcode{base}!\idxcode{common_view}}% \begin{itemdecl} -constexpr V base() const; +constexpr iterator_t base() const; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return base_;} +\effects +Equivalent to: \tcode{return current_;} \end{itemdescr} -\rSec3[range.common.adaptor]{\tcode{view::common}} +\begin{itemdecl} +constexpr iterator& operator++(); +\end{itemdecl} +\begin{itemdescr} \pnum -The name \tcode{view::common} denotes a -range adaptor object\iref{range.adaptor.object}. -For some subexpression \tcode{E}, -the expression \tcode{view::common(E)} is expression-equivalent to: +\effects Equivalent to: +\begin{codeblock} +++current_; +return *this; +\end{codeblock} +\end{itemdescr} -\begin{itemize} -\item \tcode{view::all(E)}, - if \tcode{decltype((E))} models \libconcept{CommonRange} - and \tcode{view::all(E)} is a well-formed expression. +\begin{itemdecl} +constexpr void operator++(int) requires (!forward_range); +\end{itemdecl} -\item Otherwise, \tcode{common_view\{E\}}. -\end{itemize} +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{++current_}. +\end{itemdescr} +\begin{itemdecl} +constexpr iterator operator++(int) requires forward_range; +\end{itemdecl} -\rSec2[range.reverse]{Reverse view} +\begin{itemdescr} +\pnum +\effects Equivalent to: +\begin{codeblock} +auto temp = *this; +++current_; +return temp; +\end{codeblock} +\end{itemdescr} -\rSec3[range.reverse.overview]{Overview} +\begin{itemdecl} +constexpr iterator& operator--() requires bidirectional_range; +\end{itemdecl} +\begin{itemdescr} \pnum -\tcode{reverse_view} takes a bidirectional \libconcept{View} and produces -another \libconcept{View} that iterates the same elements in reverse order. +\effects +Equivalent to: +\begin{codeblock} +--current_; +return *this; +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +constexpr iterator operator--(int) requires bidirectional_range; +\end{itemdecl} +\begin{itemdescr} \pnum -\begin{example} +\effects +Equivalent to: \begin{codeblock} -vector is {0,1,2,3,4}; -reverse_view rv {is}; -for (int i : rv) - cout << i << ' '; // prints: 4 3 2 1 0 +auto temp = *this; +--current_; +return temp; \end{codeblock} -\end{example} +\end{itemdescr} -\rSec3[range.reverse.view]{Class template \tcode{reverse_view}} +\begin{itemdecl} +constexpr iterator& operator+=(difference_type n); + requires random_access_range; +\end{itemdecl} -\indexlibrary{\idxcode{weiv_esrever}}% +\begin{itemdescr} +\pnum +\effects +Equivalent to: \begin{codeblock} -namespace std::ranges { - template - requires BidirectionalRange - class reverse_view : public view_interface> { - private: - V base_ = V(); // \expos - public: - reverse_view() = default; +current_ += n; +return *this; +\end{codeblock} +\end{itemdescr} - constexpr explicit reverse_view(V r); +\begin{itemdecl} +constexpr iterator& operator-=(difference_type n) + requires random_access_range; +\end{itemdecl} - template - requires BidirectionalRange && Constructible> - constexpr explicit reverse_view(R&& r); +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +current_ -= n; +return *this; +\end{codeblock} +\end{itemdescr} - constexpr V base() const; +\begin{itemdecl} +friend constexpr bool operator==(const iterator& x, const iterator& y) + requires equality_comparable; +\end{itemdecl} - constexpr reverse_iterator> begin(); - constexpr reverse_iterator> begin() requires CommonRange; - constexpr reverse_iterator> begin() const - requires CommonRange; +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.current_ == y.current_;} +\end{itemdescr} - constexpr reverse_iterator> end(); - constexpr reverse_iterator> end() const - requires CommonRange; +\begin{itemdecl} +friend constexpr bool operator==(const iterator& x, const sentinel_t& y); +\end{itemdecl} - constexpr auto size() requires SizedRange { - return ranges::size(base_); - } - constexpr auto size() const requires SizedRange { - return ranges::size(base_); - } - }; +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.current_ == y;} +\end{itemdescr} - template - reverse_view(R&&) -> reverse_view>; -} -\end{codeblock} +\begin{itemdecl} +friend constexpr bool operator<(const iterator& x, const iterator& y) + requires random_access_range; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.current_ < y.current_;} +\end{itemdescr} -\indexlibrary{\idxcode{reverse_view}!\idxcode{reverse_view}}% \begin{itemdecl} -constexpr explicit reverse_view(V base); +friend constexpr bool operator>(const iterator& x, const iterator& y) + requires random_access_range; \end{itemdecl} \begin{itemdescr} \pnum -\effects Initializes \tcode{base_} with \tcode{std::move(base)}. +\effects +Equivalent to: \tcode{return y < x;} \end{itemdescr} -\indexlibrary{\idxcode{reverse_view}!\idxcode{reverse_view}}% \begin{itemdecl} -template - requires BidirectionalRange && Constructible> -constexpr explicit reverse_view(R&& r); +friend constexpr bool operator<=(const iterator& x, const iterator& y) + requires random_access_range; \end{itemdecl} \begin{itemdescr} \pnum -\effects Initializes \tcode{base_} with \tcode{view::all(std::forward(r))}. +\effects +Equivalent to: \tcode{return !(y < x);} \end{itemdescr} -\indexlibrary{\idxcode{base}!\idxcode{reverse_view}}% \begin{itemdecl} -constexpr V base() const; +friend constexpr bool operator>=(const iterator& x, const iterator& y) + requires random_access_range; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return base_;} +\effects +Equivalent to: \tcode{return !(x < y);} \end{itemdescr} -\indexlibrary{\idxcode{begin}!\idxcode{reverse_view}}% \begin{itemdecl} -constexpr reverse_iterator> begin(); +friend constexpr compare_three_way_result_t> + operator<=>(const iterator& x, const iterator& y) + requires random_access_range && three_way_comparable>; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\begin{codeblock} -make_reverse_iterator(ranges::next(ranges::begin(base_), ranges::end(base_))) -\end{codeblock} +\effects +Equivalent to: \tcode{return x.current_ <=> y.current_;} +\end{itemdescr} + +\begin{itemdecl} +friend constexpr iterator operator+(const iterator& x, difference_type y) + requires random_access_range; +\end{itemdecl} +\begin{itemdescr} \pnum -\remarks In order to provide the amortized constant time complexity required by -the \libconcept{Range} concept, this function caches the result within the -\tcode{reverse_view} for use on subsequent calls. +\effects Equivalent to: \tcode{return iterator\{x\} += y;} \end{itemdescr} -\indexlibrary{\idxcode{begin}!\idxcode{reverse_view}}% \begin{itemdecl} -constexpr reverse_iterator> begin() requires CommonRange; -constexpr reverse_iterator> begin() const - requires CommonRange; +friend constexpr iterator operator+(difference_type x, const iterator& y) + requires random_access_range; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return make_reverse_iterator(ranges::end(base_));} +\effects Equivalent to: \tcode{return y + x;} \end{itemdescr} -\indexlibrary{\idxcode{end}!\idxcode{reverse_view}}% \begin{itemdecl} -constexpr reverse_iterator> end(); -constexpr reverse_iterator> end() const - requires CommonRange; +constexpr iterator operator-(const iterator& x, difference_type y) + requires random_access_range; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: \tcode{return make_reverse_iterator(ranges::begin(base_));} +\effects +Equivalent to: \tcode{return iterator\{x\} -= y;} \end{itemdescr} -\rSec3[range.reverse.adaptor]{\tcode{view::reverse}} +\begin{itemdecl} +constexpr difference_type operator-(const iterator& x, const iterator& y) + requires random_access_range; +\end{itemdecl} +\begin{itemdescr} \pnum -The name \tcode{view::reverse} denotes a -range adaptor object\iref{range.adaptor.object}. -For some subexpression \tcode{E}, the expression -\tcode{view::reverse(E)} is expression-equivalent to: -\begin{itemize} -\item - If the type of \tcode{E} is - a (possibly cv-qualified) specialization of \tcode{reverse_view}, - equivalent to \tcode{E.base()}. -\item - Otherwise, if the type of \tcode{E} is cv-qualified -\begin{codeblock} -subrange, reverse_iterator, K> -\end{codeblock} - for some iterator type \tcode{I} and - value \tcode{K} of type \tcode{subrange_kind}, - \begin{itemize} - \item - if \tcode{K} is \tcode{subrange_kind::sized}, equivalent to: -\begin{codeblock} -subrange(E.end().base(), E.begin().base(), E.size()) -\end{codeblock} - \item - otherwise, equivalent to: -\begin{codeblock} -subrange(E.end().base(), E.begin().base()) -\end{codeblock} - \end{itemize} - However, in either case \tcode{E} is evaluated only once. -\item - Otherwise, equivalent to \tcode{reverse_view\{E\}}. -\end{itemize} +\effects +Equivalent to: \tcode{return x.current_ - y.current_;} +\end{itemdescr} + +\begin{itemdecl} +friend constexpr difference_type + operator-(const iterator& x, const sentinel_t& y) + requires sized_sentinel_for, iterator_t>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return x.current_ - y;} +\end{itemdescr} + +\begin{itemdecl} +friend constexpr difference_type + operator-(const sentinel_t& x, const iterator& y) + requires sized_sentinel_for, iterator_t>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return -(y - x);} +\end{itemdescr} diff --git a/source/regex.tex b/source/regex.tex index 72c3b73cce..a9b0dbb6f2 100644 --- a/source/regex.tex +++ b/source/regex.tex @@ -298,141 +298,30 @@ template bool operator==(const sub_match& lhs, const sub_match& rhs); template - bool operator!=(const sub_match& lhs, const sub_match& rhs); - template - bool operator<(const sub_match& lhs, const sub_match& rhs); - template - bool operator>(const sub_match& lhs, const sub_match& rhs); - template - bool operator<=(const sub_match& lhs, const sub_match& rhs); - template - bool operator>=(const sub_match& lhs, const sub_match& rhs); - - template - bool operator==( - const basic_string::value_type, ST, SA>& lhs, - const sub_match& rhs); - template - bool operator!=( - const basic_string::value_type, ST, SA>& lhs, - const sub_match& rhs); - template - bool operator<( - const basic_string::value_type, ST, SA>& lhs, - const sub_match& rhs); - template - bool operator>( - const basic_string::value_type, ST, SA>& lhs, - const sub_match& rhs); - template - bool operator<=( - const basic_string::value_type, ST, SA>& lhs, - const sub_match& rhs); - template - bool operator>=( - const basic_string::value_type, ST, SA>& lhs, - const sub_match& rhs); + auto operator<=>(const sub_match& lhs, const sub_match& rhs); template bool operator==( const sub_match& lhs, const basic_string::value_type, ST, SA>& rhs); template - bool operator!=( - const sub_match& lhs, - const basic_string::value_type, ST, SA>& rhs); - template - bool operator<( - const sub_match& lhs, - const basic_string::value_type, ST, SA>& rhs); - template - bool operator>( - const sub_match& lhs, - const basic_string::value_type, ST, SA>& rhs); - template - bool operator<=( - const sub_match& lhs, - const basic_string::value_type, ST, SA>& rhs); - template - bool operator>=( + auto operator<=>( const sub_match& lhs, const basic_string::value_type, ST, SA>& rhs); - template - bool operator==(const typename iterator_traits::value_type* lhs, - const sub_match& rhs); - template - bool operator!=(const typename iterator_traits::value_type* lhs, - const sub_match& rhs); - template - bool operator<(const typename iterator_traits::value_type* lhs, - const sub_match& rhs); - template - bool operator>(const typename iterator_traits::value_type* lhs, - const sub_match& rhs); - template - bool operator<=(const typename iterator_traits::value_type* lhs, - const sub_match& rhs); - template - bool operator>=(const typename iterator_traits::value_type* lhs, - const sub_match& rhs); - template bool operator==(const sub_match& lhs, const typename iterator_traits::value_type* rhs); template - bool operator!=(const sub_match& lhs, - const typename iterator_traits::value_type* rhs); - template - bool operator<(const sub_match& lhs, - const typename iterator_traits::value_type* rhs); - template - bool operator>(const sub_match& lhs, - const typename iterator_traits::value_type* rhs); - template - bool operator<=(const sub_match& lhs, - const typename iterator_traits::value_type* rhs); - template - bool operator>=(const sub_match& lhs, - const typename iterator_traits::value_type* rhs); - - template - bool operator==(const typename iterator_traits::value_type& lhs, - const sub_match& rhs); - template - bool operator!=(const typename iterator_traits::value_type& lhs, - const sub_match& rhs); - template - bool operator<(const typename iterator_traits::value_type& lhs, - const sub_match& rhs); - template - bool operator>(const typename iterator_traits::value_type& lhs, - const sub_match& rhs); - template - bool operator<=(const typename iterator_traits::value_type& lhs, - const sub_match& rhs); - template - bool operator>=(const typename iterator_traits::value_type& lhs, - const sub_match& rhs); + auto operator<=>(const sub_match& lhs, + const typename iterator_traits::value_type* rhs); template bool operator==(const sub_match& lhs, const typename iterator_traits::value_type& rhs); template - bool operator!=(const sub_match& lhs, - const typename iterator_traits::value_type& rhs); - template - bool operator<(const sub_match& lhs, - const typename iterator_traits::value_type& rhs); - template - bool operator>(const sub_match& lhs, - const typename iterator_traits::value_type& rhs); - template - bool operator<=(const sub_match& lhs, - const typename iterator_traits::value_type& rhs); - template - bool operator>=(const sub_match& lhs, - const typename iterator_traits::value_type& rhs); + auto operator<=>(const sub_match& lhs, + const typename iterator_traits::value_type& rhs); template basic_ostream& @@ -452,9 +341,6 @@ template bool operator==(const match_results& m1, const match_results& m2); - template - bool operator!=(const match_results& m1, - const match_results& m2); // \ref{re.results.swap}, \tcode{match_results} swap template @@ -1903,6 +1789,12 @@ \rSec2[re.submatch.op]{Non-member operators} +\pnum +Let \tcode{\placeholdernc{SM-CAT}(I)} be +\begin{codeblock} +compare_three_way_result_t::value_type>> +\end{codeblock} + \indexlibrarymember{sub_match}{operator==}% \begin{itemdecl} template @@ -1913,134 +1805,14 @@ \pnum\returns \tcode{lhs.compare(rhs) == 0}. \end{itemdescr} -\indexlibrarymember{sub_match}{operator"!=}% -\begin{itemdecl} -template - bool operator!=(const sub_match& lhs, const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{lhs.compare(rhs) != 0}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator<}% +\indexlibrarymember{sub_match}{operator<=>}% \begin{itemdecl} template - bool operator<(const sub_match& lhs, const sub_match& rhs); + auto operator<=>(const sub_match& lhs, const sub_match& rhs); \end{itemdecl} \begin{itemdescr} -\pnum\returns \tcode{lhs.compare(rhs) < 0}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator>}% -\begin{itemdecl} -template - bool operator>(const sub_match& lhs, const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{lhs.compare(rhs) > 0}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator<=}% -\begin{itemdecl} -template - bool operator<=(const sub_match& lhs, const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{lhs.compare(rhs) <= 0}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator>=}% -\begin{itemdecl} -template - bool operator>=(const sub_match& lhs, const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{lhs.compare(rhs) >= 0}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator==}% -\begin{itemdecl} -template - bool operator==( - const basic_string::value_type, ST, SA>& lhs, - const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\begin{codeblock} -rhs.compare(typename sub_match::string_type(lhs.data(), lhs.size())) == 0 -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator"!=}% -\begin{itemdecl} -template - bool operator!=( - const basic_string::value_type, ST, SA>& lhs, - const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{!(lhs == rhs)}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator<}% -\begin{itemdecl} -template - bool operator<( - const basic_string::value_type, ST, SA>& lhs, - const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\begin{codeblock} -rhs.compare(typename sub_match::string_type(lhs.data(), lhs.size())) > 0 -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator>}% -\begin{itemdecl} -template - bool operator>( - const basic_string::value_type, ST, SA>& lhs, - const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{rhs < lhs}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator<=}% -\begin{itemdecl} -template - bool operator<=( - const basic_string::value_type, ST, SA>& lhs, - const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{!(rhs < lhs)}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator>=}% -\begin{itemdecl} -template - bool operator>=( - const basic_string::value_type, ST, SA>& lhs, - const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{!(lhs < rhs)}. +\pnum\returns \tcode{static_cast<\placeholdernc{SM-CAT}(BiIter)>(lhs.compare(rhs) <=> 0)}. \end{itemdescr} \indexlibrarymember{operator==}{sub_match}% @@ -2059,138 +1831,24 @@ \end{codeblock} \end{itemdescr} -\indexlibrary{\idxcode{operator"!=}!\idxcode{sub_match}}% -\indexlibrary{\idxcode{sub_match}!\idxcode{operator"!=}}% +\indexlibrarymember{operator<=>}{sub_match}% \begin{itemdecl} template - bool operator!=( + auto operator<=>( const sub_match& lhs, const basic_string::value_type, ST, SA>& rhs); \end{itemdecl} \begin{itemdescr} -\pnum\returns \tcode{!(lhs == rhs)}. -\end{itemdescr} - -\indexlibrary{\idxcode{operator>}!\idxcode{sub_match}}% -\indexlibrary{\idxcode{sub_match}!\idxcode{operator<}}% -\begin{itemdecl} -template - bool operator<( - const sub_match& lhs, - const basic_string::value_type, ST, SA>& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns +\pnum\returns \begin{codeblock} -lhs.compare(typename sub_match::string_type(rhs.data(), rhs.size())) < 0 +static_cast<@\placeholdernc{SM-CAT}@(BiIter)>(lhs.compare( + typename sub_match::string_type(rhs.data(), rhs.size())) + <=> 0 + ) \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator>}{sub_match}% -\begin{itemdecl} -template - bool operator>( - const sub_match& lhs, - const basic_string::value_type, ST, SA>& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{rhs < lhs}. -\end{itemdescr} - -\indexlibrarymember{operator<=}{sub_match}% -\begin{itemdecl} -template - bool operator<=( - const sub_match& lhs, - const basic_string::value_type, ST, SA>& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{!(rhs < lhs)}. -\end{itemdescr} - -\indexlibrarymember{operator>=}{sub_match}% -\begin{itemdecl} -template - bool operator>=( - const sub_match& lhs, - const basic_string::value_type, ST, SA>& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{!(lhs < rhs)}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator==}% -\begin{itemdecl} -template - bool operator==(const typename iterator_traits::value_type* lhs, - const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{rhs.compare(lhs) == 0}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator"!=}% -\begin{itemdecl} -template - bool operator!=(const typename iterator_traits::value_type* lhs, - const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{!(lhs == rhs)}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator<}% -\begin{itemdecl} -template - bool operator<(const typename iterator_traits::value_type* lhs, - const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{rhs.compare(lhs) > 0}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator>}% -\begin{itemdecl} -template - bool operator>(const typename iterator_traits::value_type* lhs, - const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{rhs < lhs}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator<=}% -\begin{itemdecl} -template - bool operator<=(const typename iterator_traits::value_type* lhs, - const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{!(rhs < lhs)}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator>=}% -\begin{itemdecl} -template - bool operator>=(const typename iterator_traits::value_type* lhs, - const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{!(lhs < rhs)}. -\end{itemdescr} - \indexlibrarymember{sub_match}{operator==}% \begin{itemdecl} template @@ -2202,132 +1860,16 @@ \pnum\returns \tcode{lhs.compare(rhs) == 0}. \end{itemdescr} -\indexlibrarymember{sub_match}{operator"!=}% -\begin{itemdecl} -template - bool operator!=(const sub_match& lhs, - const typename iterator_traits::value_type* rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{!(lhs == rhs)}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator<}% -\begin{itemdecl} -template - bool operator<(const sub_match& lhs, - const typename iterator_traits::value_type* rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{lhs.compare(rhs) < 0}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator>}% -\begin{itemdecl} -template - bool operator>(const sub_match& lhs, - const typename iterator_traits::value_type* rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{rhs < lhs}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator<=}% -\begin{itemdecl} -template - bool operator<=(const sub_match& lhs, - const typename iterator_traits::value_type* rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{!(rhs < lhs)}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator>=}% -\begin{itemdecl} -template - bool operator>=(const sub_match& lhs, - const typename iterator_traits::value_type* rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{!(lhs < rhs)}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator==}% -\begin{itemdecl} -template - bool operator==(const typename iterator_traits::value_type& lhs, - const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{rhs.compare(typename sub_match::string_type(1, lhs)) == 0}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator"!=}% -\begin{itemdecl} -template - bool operator!=(const typename iterator_traits::value_type& lhs, - const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{!(lhs == rhs)}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator<}% -\begin{itemdecl} -template - bool operator<(const typename iterator_traits::value_type& lhs, - const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{rhs.compare(typename sub_match::string_type(1, lhs)) > 0}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator>}% -\begin{itemdecl} -template - bool operator>(const typename iterator_traits::value_type& lhs, - const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{rhs < lhs}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator<=}% -\begin{itemdecl} -template - bool operator<=(const typename iterator_traits::value_type& lhs, - const sub_match& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{!(rhs < lhs)}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator>=}% +\indexlibrarymember{sub_match}{operator<=>}% \begin{itemdecl} template - bool operator>=(const typename iterator_traits::value_type& lhs, - const sub_match& rhs); + auto operator<=>(const sub_match& lhs, + const typename iterator_traits::value_type* rhs); \end{itemdecl} \begin{itemdescr} -\pnum -\returns \tcode{!(lhs < rhs)}. +\pnum\returns +\tcode{static_cast<\placeholdernc{SM-CAT}(BiIter)>(lhs.compare(rhs) <=> 0)}. \end{itemdescr} \indexlibrarymember{sub_match}{operator==}% @@ -2342,64 +1884,22 @@ \returns \tcode{lhs.compare(typename sub_match::string_type(1, rhs)) == 0}. \end{itemdescr} -\indexlibrarymember{sub_match}{operator"!=}% +\indexlibrarymember{sub_match}{operator<=>}% \begin{itemdecl} template - bool operator!=(const sub_match& lhs, - const typename iterator_traits::value_type& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{!(lhs == rhs)}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator<}% -\begin{itemdecl} -template - bool operator<(const sub_match& lhs, - const typename iterator_traits::value_type& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{lhs.compare(typename sub_match::string_type(1, rhs)) < 0}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator>}% -\begin{itemdecl} -template - bool operator>(const sub_match& lhs, - const typename iterator_traits::value_type& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{rhs < lhs}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator<=}% -\begin{itemdecl} -template - bool operator<=(const sub_match& lhs, - const typename iterator_traits::value_type& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{!(rhs < lhs)}. -\end{itemdescr} - -\indexlibrarymember{sub_match}{operator>=}% -\begin{itemdecl} -template - bool operator>=(const sub_match& lhs, - const typename iterator_traits::value_type& rhs); + auto operator<=>(const sub_match& lhs, + const typename iterator_traits::value_type& rhs); \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{!(lhs < rhs)}. +\returns +\begin{codeblock} +static_cast<@\placeholdernc{SM-CAT}@(BiIter)>(lhs.compare( + typename sub_match::string_type(1, rhs)) + <=> 0 + ) +\end{codeblock} \end{itemdescr} \indexlibrary{\idxcode{basic_ostream}}% @@ -2944,19 +2444,6 @@ \begin{note} The algorithm \tcode{equal} is defined in \ref{algorithms}. \end{note} \end{itemdescr} -\indexlibrary{\idxcode{operator"!=}!\idxcode{match_results}}% -\indexlibrary{\idxcode{match_results}!\idxcode{operator"!=}}% -\begin{itemdecl} -template -bool operator!=(const match_results& m1, - const match_results& m2); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{!(m1 == m2)}. -\end{itemdescr} - \rSec1[re.alg]{Regular expression algorithms} \rSec2[re.except]{Exceptions} @@ -3494,7 +2981,6 @@ regex_iterator(const regex_iterator&); regex_iterator& operator=(const regex_iterator&); bool operator==(const regex_iterator&) const; - bool operator!=(const regex_iterator&) const; const value_type& operator*() const; const value_type* operator->() const; regex_iterator& operator++(); @@ -3567,15 +3053,6 @@ otherwise \tcode{false}. \end{itemdescr} -\indexlibrarymember{regex_iterator}{operator"!=}% -\begin{itemdecl} -bool operator!=(const regex_iterator& right) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{!(*this == right)}. -\end{itemdescr} - \rSec3[re.regiter.deref]{Indirection} \indexlibrarymember{regex_iterator}{operator*}% @@ -3791,7 +3268,6 @@ regex_token_iterator(const regex_token_iterator&); regex_token_iterator& operator=(const regex_token_iterator&); bool operator==(const regex_token_iterator&) const; - bool operator!=(const regex_token_iterator&) const; const value_type& operator*() const; const value_type* operator->() const; regex_token_iterator& operator++(); @@ -3904,15 +3380,6 @@ \tcode{N == right.N}, and \tcode{subs == right.subs}. Otherwise returns \tcode{false}. \end{itemdescr} -\indexlibrarymember{regex_token_iterator}{operator"!=}% -\begin{itemdecl} -bool operator!=(const regex_token_iterator& right) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{!(*this == right)}. -\end{itemdescr} - \rSec3[re.tokiter.deref]{Indirection} \indexlibrarymember{regex_token_iterator}{operator*}% diff --git a/source/strings.tex b/source/strings.tex index cbba04ae5d..612d8236df 100644 --- a/source/strings.tex +++ b/source/strings.tex @@ -267,6 +267,7 @@ using off_type = streamoff; using pos_type = streampos; using state_type = mbstate_t; + using comparison_category = strong_ordering; static constexpr void assign(char_type& c1, const char_type& c2) noexcept; static constexpr bool eq(char_type c1, char_type c2) noexcept; @@ -316,11 +317,12 @@ \begin{codeblock} namespace std { template<> struct char_traits { - using char_type = char8_t; - using int_type = unsigned int; - using off_type = streamoff; - using pos_type = u8streampos; + using char_type = char8_t; + using int_type = unsigned int; + using off_type = streamoff; + using pos_type = u8streampos; using state_type = mbstate_t; + using comparison_category = strong_ordering; static constexpr void assign(char_type& c1, const char_type& c2) noexcept; static constexpr bool eq(char_type c1, char_type c2) noexcept; @@ -362,6 +364,7 @@ using off_type = streamoff; using pos_type = u16streampos; using state_type = mbstate_t; + using comparison_category = strong_ordering; static constexpr void assign(char_type& c1, const char_type& c2) noexcept; static constexpr bool eq(char_type c1, char_type c2) noexcept; @@ -407,6 +410,7 @@ using off_type = streamoff; using pos_type = u32streampos; using state_type = mbstate_t; + using comparison_category = strong_ordering; static constexpr void assign(char_type& c1, const char_type& c2) noexcept; static constexpr bool eq(char_type c1, char_type c2) noexcept; @@ -452,6 +456,7 @@ using off_type = streamoff; using pos_type = wstreampos; using state_type = mbstate_t; + using comparison_category = strong_ordering; static constexpr void assign(char_type& c1, const char_type& c2) noexcept; static constexpr bool eq(char_type c1, char_type c2) noexcept; @@ -534,116 +539,75 @@ class basic_string; template - basic_string + constexpr basic_string operator+(const basic_string& lhs, const basic_string& rhs); template - basic_string + constexpr basic_string operator+(basic_string&& lhs, const basic_string& rhs); template - basic_string + constexpr basic_string operator+(const basic_string& lhs, basic_string&& rhs); template - basic_string + constexpr basic_string operator+(basic_string&& lhs, basic_string&& rhs); template - basic_string + constexpr basic_string operator+(const charT* lhs, const basic_string& rhs); template - basic_string + constexpr basic_string operator+(const charT* lhs, basic_string&& rhs); template - basic_string + constexpr basic_string operator+(charT lhs, const basic_string& rhs); template - basic_string + constexpr basic_string operator+(charT lhs, basic_string&& rhs); template - basic_string + constexpr basic_string operator+(const basic_string& lhs, const charT* rhs); template - basic_string + constexpr basic_string operator+(basic_string&& lhs, const charT* rhs); template - basic_string + constexpr basic_string operator+(const basic_string& lhs, charT rhs); template - basic_string + constexpr basic_string operator+(basic_string&& lhs, charT rhs); template - bool operator==(const basic_string& lhs, - const basic_string& rhs) noexcept; - template - bool operator==(const charT* lhs, - const basic_string& rhs); - template - bool operator==(const basic_string& lhs, - const charT* rhs); - template - bool operator!=(const basic_string& lhs, - const basic_string& rhs) noexcept; + constexpr bool + operator==(const basic_string& lhs, + const basic_string& rhs) noexcept; template - bool operator!=(const charT* lhs, - const basic_string& rhs); - template - bool operator!=(const basic_string& lhs, - const charT* rhs); + constexpr bool operator==(const basic_string& lhs, + const charT* rhs); template - bool operator< (const basic_string& lhs, - const basic_string& rhs) noexcept; - template - bool operator< (const basic_string& lhs, - const charT* rhs); - template - bool operator< (const charT* lhs, - const basic_string& rhs); - template - bool operator> (const basic_string& lhs, - const basic_string& rhs) noexcept; + constexpr @\seebelow@ operator<=>(const basic_string& lhs, + @\itcorr@ const basic_string& rhs) noexcept; template - bool operator> (const basic_string& lhs, - const charT* rhs); - template - bool operator> (const charT* lhs, - const basic_string& rhs); - - template - bool operator<=(const basic_string& lhs, - const basic_string& rhs) noexcept; - template - bool operator<=(const basic_string& lhs, - const charT* rhs); - template - bool operator<=(const charT* lhs, - const basic_string& rhs); - template - bool operator>=(const basic_string& lhs, - const basic_string& rhs) noexcept; - template - bool operator>=(const basic_string& lhs, - const charT* rhs); - template - bool operator>=(const charT* lhs, - const basic_string& rhs); + constexpr @\seebelow@ operator<=>(const basic_string& lhs, + @\itcorr@ const charT* rhs); // \ref{string.special}, swap template - void swap(basic_string& lhs, - basic_string& rhs) - noexcept(noexcept(lhs.swap(rhs))); + constexpr void + swap(basic_string& lhs, + basic_string& rhs) + noexcept(noexcept(lhs.swap(rhs))); // \ref{string.io}, inserters and extractors template @@ -675,9 +639,9 @@ // \ref{string.erasure}, erasure template - void erase(basic_string& c, const U& value); + constexpr void erase(basic_string& c, const U& value); template - void erase_if(basic_string& c, Predicate pred); + constexpr void erase_if(basic_string& c, Predicate pred); // \tcode{basic_string} typedef names using string = basic_string; @@ -750,11 +714,11 @@ inline namespace literals { inline namespace string_literals { // \ref{basic.string.literals}, suffix for \tcode{basic_string} literals - string operator""s(const char* str, size_t len); - u8string operator""s(const char8_t* str, size_t len); - u16string operator""s(const char16_t* str, size_t len); - u32string operator""s(const char32_t* str, size_t len); - wstring operator""s(const wchar_t* str, size_t len); + constexpr string operator""s(const char* str, size_t len); + constexpr u8string operator""s(const char8_t* str, size_t len); + constexpr u16string operator""s(const char16_t* str, size_t len); + constexpr u32string operator""s(const char32_t* str, size_t len); + constexpr wstring operator""s(const wchar_t* str, size_t len); } } } @@ -825,233 +789,245 @@ static const size_type npos = -1; // \ref{string.cons}, construct/copy/destroy - basic_string() noexcept(noexcept(Allocator())) : basic_string(Allocator()) { } - explicit basic_string(const Allocator& a) noexcept; - basic_string(const basic_string& str); - basic_string(basic_string&& str) noexcept; - basic_string(const basic_string& str, size_type pos, const Allocator& a = Allocator()); - basic_string(const basic_string& str, size_type pos, size_type n, - const Allocator& a = Allocator()); + constexpr basic_string() noexcept(noexcept(Allocator())) : basic_string(Allocator()) { } + constexpr explicit basic_string(const Allocator& a) noexcept; + constexpr basic_string(const basic_string& str); + constexpr basic_string(basic_string&& str) noexcept; + constexpr basic_string(const basic_string& str, size_type pos, + const Allocator& a = Allocator()); + constexpr basic_string(const basic_string& str, size_type pos, size_type n, + const Allocator& a = Allocator()); template - basic_string(const T& t, size_type pos, size_type n, const Allocator& a = Allocator()); + constexpr basic_string(const T& t, size_type pos, size_type n, + const Allocator& a = Allocator()); template - explicit basic_string(const T& t, const Allocator& a = Allocator()); - basic_string(const charT* s, size_type n, const Allocator& a = Allocator()); - basic_string(const charT* s, const Allocator& a = Allocator()); - basic_string(size_type n, charT c, const Allocator& a = Allocator()); + constexpr explicit basic_string(const T& t, const Allocator& a = Allocator()); + constexpr basic_string(const charT* s, size_type n, const Allocator& a = Allocator()); + constexpr basic_string(const charT* s, const Allocator& a = Allocator()); + constexpr basic_string(size_type n, charT c, const Allocator& a = Allocator()); template - basic_string(InputIterator begin, InputIterator end, const Allocator& a = Allocator()); - basic_string(initializer_list, const Allocator& = Allocator()); - basic_string(const basic_string&, const Allocator&); - basic_string(basic_string&&, const Allocator&); - - ~basic_string(); - basic_string& operator=(const basic_string& str); - basic_string& operator=(basic_string&& str) + constexpr basic_string(InputIterator begin, InputIterator end, + const Allocator& a = Allocator()); + constexpr basic_string(initializer_list, const Allocator& = Allocator()); + constexpr basic_string(const basic_string&, const Allocator&); + constexpr basic_string(basic_string&&, const Allocator&); + constexpr ~basic_string(); + + constexpr basic_string& operator=(const basic_string& str); + constexpr basic_string& operator=(basic_string&& str) noexcept(allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value); template - basic_string& operator=(const T& t); - basic_string& operator=(const charT* s); - basic_string& operator=(charT c); - basic_string& operator=(initializer_list); + constexpr basic_string& operator=(const T& t); + constexpr basic_string& operator=(const charT* s); + constexpr basic_string& operator=(charT c); + constexpr basic_string& operator=(initializer_list); // \ref{string.iterators}, iterators - iterator begin() noexcept; - const_iterator begin() const noexcept; - iterator end() noexcept; - const_iterator end() const noexcept; + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; - reverse_iterator rbegin() noexcept; - const_reverse_iterator rbegin() const noexcept; - reverse_iterator rend() noexcept; - const_reverse_iterator rend() const noexcept; + constexpr reverse_iterator rbegin() noexcept; + constexpr const_reverse_iterator rbegin() const noexcept; + constexpr reverse_iterator rend() noexcept; + constexpr const_reverse_iterator rend() const noexcept; - const_iterator cbegin() const noexcept; - const_iterator cend() const noexcept; - const_reverse_iterator crbegin() const noexcept; - const_reverse_iterator crend() const noexcept; + constexpr const_iterator cbegin() const noexcept; + constexpr const_iterator cend() const noexcept; + constexpr const_reverse_iterator crbegin() const noexcept; + constexpr const_reverse_iterator crend() const noexcept; // \ref{string.capacity}, capacity - size_type size() const noexcept; - size_type length() const noexcept; - size_type max_size() const noexcept; - void resize(size_type n, charT c); - void resize(size_type n); - size_type capacity() const noexcept; - void reserve(size_type res_arg); - void shrink_to_fit(); - void clear() noexcept; - [[nodiscard]] bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type length() const noexcept; + constexpr size_type max_size() const noexcept; + constexpr void resize(size_type n, charT c); + constexpr void resize(size_type n); + constexpr size_type capacity() const noexcept; + constexpr void reserve(size_type res_arg); + constexpr void shrink_to_fit(); + constexpr void clear() noexcept; + [[nodiscard]] constexpr bool empty() const noexcept; // \ref{string.access}, element access - const_reference operator[](size_type pos) const; - reference operator[](size_type pos); - const_reference at(size_type n) const; - reference at(size_type n); + constexpr const_reference operator[](size_type pos) const; + constexpr reference operator[](size_type pos); + constexpr const_reference at(size_type n) const; + constexpr reference at(size_type n); - const charT& front() const; - charT& front(); - const charT& back() const; - charT& back(); + constexpr const charT& front() const; + constexpr charT& front(); + constexpr const charT& back() const; + constexpr charT& back(); // \ref{string.modifiers}, modifiers - basic_string& operator+=(const basic_string& str); + constexpr basic_string& operator+=(const basic_string& str); template - basic_string& operator+=(const T& t); - basic_string& operator+=(const charT* s); - basic_string& operator+=(charT c); - basic_string& operator+=(initializer_list); - basic_string& append(const basic_string& str); - basic_string& append(const basic_string& str, size_type pos, size_type n = npos); + constexpr basic_string& operator+=(const T& t); + constexpr basic_string& operator+=(const charT* s); + constexpr basic_string& operator+=(charT c); + constexpr basic_string& operator+=(initializer_list); + constexpr basic_string& append(const basic_string& str); + constexpr basic_string& append(const basic_string& str, size_type pos, size_type n = npos); template - basic_string& append(const T& t); + constexpr basic_string& append(const T& t); template - basic_string& append(const T& t, size_type pos, size_type n = npos); - basic_string& append(const charT* s, size_type n); - basic_string& append(const charT* s); - basic_string& append(size_type n, charT c); + constexpr basic_string& append(const T& t, size_type pos, size_type n = npos); + constexpr basic_string& append(const charT* s, size_type n); + constexpr basic_string& append(const charT* s); + constexpr basic_string& append(size_type n, charT c); template - basic_string& append(InputIterator first, InputIterator last); - basic_string& append(initializer_list); + constexpr basic_string& append(InputIterator first, InputIterator last); + constexpr basic_string& append(initializer_list); - void push_back(charT c); + constexpr void push_back(charT c); - basic_string& assign(const basic_string& str); - basic_string& assign(basic_string&& str) + constexpr basic_string& assign(const basic_string& str); + constexpr basic_string& assign(basic_string&& str) noexcept(allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value); - basic_string& assign(const basic_string& str, size_type pos, size_type n = npos); + constexpr basic_string& assign(const basic_string& str, size_type pos, size_type n = npos); template - basic_string& assign(const T& t); + constexpr basic_string& assign(const T& t); template - basic_string& assign(const T& t, size_type pos, size_type n = npos); - basic_string& assign(const charT* s, size_type n); - basic_string& assign(const charT* s); - basic_string& assign(size_type n, charT c); + constexpr basic_string& assign(const T& t, size_type pos, size_type n = npos); + constexpr basic_string& assign(const charT* s, size_type n); + constexpr basic_string& assign(const charT* s); + constexpr basic_string& assign(size_type n, charT c); template - basic_string& assign(InputIterator first, InputIterator last); - basic_string& assign(initializer_list); + constexpr basic_string& assign(InputIterator first, InputIterator last); + constexpr basic_string& assign(initializer_list); - basic_string& insert(size_type pos, const basic_string& str); - basic_string& insert(size_type pos1, const basic_string& str, - size_type pos2, size_type n = npos); + constexpr basic_string& insert(size_type pos, const basic_string& str); + constexpr basic_string& insert(size_type pos1, const basic_string& str, + size_type pos2, size_type n = npos); template - basic_string& insert(size_type pos, const T& t); + constexpr basic_string& insert(size_type pos, const T& t); template - basic_string& insert(size_type pos1, const T& t, size_type pos2, size_type n = npos); - basic_string& insert(size_type pos, const charT* s, size_type n); - basic_string& insert(size_type pos, const charT* s); - basic_string& insert(size_type pos, size_type n, charT c); - iterator insert(const_iterator p, charT c); - iterator insert(const_iterator p, size_type n, charT c); + constexpr basic_string& insert(size_type pos1, const T& t, + size_type pos2, size_type n = npos); + constexpr basic_string& insert(size_type pos, const charT* s, size_type n); + constexpr basic_string& insert(size_type pos, const charT* s); + constexpr basic_string& insert(size_type pos, size_type n, charT c); + constexpr iterator insert(const_iterator p, charT c); + constexpr iterator insert(const_iterator p, size_type n, charT c); template - iterator insert(const_iterator p, InputIterator first, InputIterator last); - iterator insert(const_iterator p, initializer_list); + constexpr iterator insert(const_iterator p, InputIterator first, InputIterator last); + constexpr iterator insert(const_iterator p, initializer_list); - basic_string& erase(size_type pos = 0, size_type n = npos); - iterator erase(const_iterator p); - iterator erase(const_iterator first, const_iterator last); + constexpr basic_string& erase(size_type pos = 0, size_type n = npos); + constexpr iterator erase(const_iterator p); + constexpr iterator erase(const_iterator first, const_iterator last); - void pop_back(); + constexpr void pop_back(); - basic_string& replace(size_type pos1, size_type n1, const basic_string& str); - basic_string& replace(size_type pos1, size_type n1, const basic_string& str, - size_type pos2, size_type n2 = npos); + constexpr basic_string& replace(size_type pos1, size_type n1, const basic_string& str); + constexpr basic_string& replace(size_type pos1, size_type n1, const basic_string& str, + size_type pos2, size_type n2 = npos); template - basic_string& replace(size_type pos1, size_type n1, const T& t); + constexpr basic_string& replace(size_type pos1, size_type n1, const T& t); template - basic_string& replace(size_type pos1, size_type n1, const T& t, - size_type pos2, size_type n2 = npos); - basic_string& replace(size_type pos, size_type n1, const charT* s, size_type n2); - basic_string& replace(size_type pos, size_type n1, const charT* s); - basic_string& replace(size_type pos, size_type n1, size_type n2, charT c); - - basic_string& replace(const_iterator i1, const_iterator i2, const basic_string& str); + constexpr basic_string& replace(size_type pos1, size_type n1, const T& t, + size_type pos2, size_type n2 = npos); + constexpr basic_string& replace(size_type pos, size_type n1, const charT* s, size_type n2); + constexpr basic_string& replace(size_type pos, size_type n1, const charT* s); + constexpr basic_string& replace(size_type pos, size_type n1, size_type n2, charT c); + constexpr basic_string& replace(const_iterator i1, const_iterator i2, + const basic_string& str); template - basic_string& replace(const_iterator i1, const_iterator i2, const T& t); - basic_string& replace(const_iterator i1, const_iterator i2, const charT* s, size_type n); - basic_string& replace(const_iterator i1, const_iterator i2, const charT* s); - basic_string& replace(const_iterator i1, const_iterator i2, size_type n, charT c); + constexpr basic_string& replace(const_iterator i1, const_iterator i2, const T& t); + constexpr basic_string& replace(const_iterator i1, const_iterator i2, const charT* s, + size_type n); + constexpr basic_string& replace(const_iterator i1, const_iterator i2, const charT* s); + constexpr basic_string& replace(const_iterator i1, const_iterator i2, size_type n, charT c); template - basic_string& replace(const_iterator i1, const_iterator i2, - InputIterator j1, InputIterator j2); - basic_string& replace(const_iterator, const_iterator, initializer_list); + constexpr basic_string& replace(const_iterator i1, const_iterator i2, + InputIterator j1, InputIterator j2); + constexpr basic_string& replace(const_iterator, const_iterator, initializer_list); - size_type copy(charT* s, size_type n, size_type pos = 0) const; + constexpr size_type copy(charT* s, size_type n, size_type pos = 0) const; - void swap(basic_string& str) + constexpr void swap(basic_string& str) noexcept(allocator_traits::propagate_on_container_swap::value || allocator_traits::is_always_equal::value); // \ref{string.ops}, string operations - const charT* c_str() const noexcept; - const charT* data() const noexcept; - charT* data() noexcept; - operator basic_string_view() const noexcept; - allocator_type get_allocator() const noexcept; + constexpr const charT* c_str() const noexcept; + constexpr const charT* data() const noexcept; + constexpr charT* data() noexcept; + constexpr operator basic_string_view() const noexcept; + constexpr allocator_type get_allocator() const noexcept; template - size_type find (const T& t, size_type pos = 0) const noexcept(@\seebelow@); - size_type find (const basic_string& str, size_type pos = 0) const noexcept; - size_type find (const charT* s, size_type pos, size_type n) const; - size_type find (const charT* s, size_type pos = 0) const; - size_type find (charT c, size_type pos = 0) const noexcept; + constexpr size_type find(const T& t, size_type pos = 0) const noexcept(@\seebelow@); + constexpr size_type find(const basic_string& str, size_type pos = 0) const noexcept; + constexpr size_type find(const charT* s, size_type pos, size_type n) const; + constexpr size_type find(const charT* s, size_type pos = 0) const; + constexpr size_type find(charT c, size_type pos = 0) const noexcept; template - size_type rfind(const T& t, size_type pos = npos) const noexcept(@\seebelow@); - size_type rfind(const basic_string& str, size_type pos = npos) const noexcept; - size_type rfind(const charT* s, size_type pos, size_type n) const; - size_type rfind(const charT* s, size_type pos = npos) const; - size_type rfind(charT c, size_type pos = npos) const noexcept; + constexpr size_type rfind(const T& t, size_type pos = npos) const noexcept(@\seebelow@); + constexpr size_type rfind(const basic_string& str, size_type pos = npos) const noexcept; + constexpr size_type rfind(const charT* s, size_type pos, size_type n) const; + constexpr size_type rfind(const charT* s, size_type pos = npos) const; + constexpr size_type rfind(charT c, size_type pos = npos) const noexcept; template - size_type find_first_of(const T& t, size_type pos = 0) const noexcept(@\seebelow@); - size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept; - size_type find_first_of(const charT* s, size_type pos, size_type n) const; - size_type find_first_of(const charT* s, size_type pos = 0) const; - size_type find_first_of(charT c, size_type pos = 0) const noexcept; + constexpr size_type find_first_of(const T& t, size_type pos = 0) const noexcept(@\seebelow@); + constexpr size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept; + constexpr size_type find_first_of(const charT* s, size_type pos, size_type n) const; + constexpr size_type find_first_of(const charT* s, size_type pos = 0) const; + constexpr size_type find_first_of(charT c, size_type pos = 0) const noexcept; template - size_type find_last_of (const T& t, size_type pos = npos) const noexcept(@\seebelow@); - size_type find_last_of (const basic_string& str, size_type pos = npos) const noexcept; - size_type find_last_of (const charT* s, size_type pos, size_type n) const; - size_type find_last_of (const charT* s, size_type pos = npos) const; - size_type find_last_of (charT c, size_type pos = npos) const noexcept; + constexpr size_type find_last_of(const T& t, + size_type pos = npos) const noexcept(@\seebelow@); + constexpr size_type find_last_of(const basic_string& str, + size_type pos = npos) const noexcept; + constexpr size_type find_last_of(const charT* s, size_type pos, size_type n) const; + constexpr size_type find_last_of(const charT* s, size_type pos = npos) const; + constexpr size_type find_last_of(charT c, size_type pos = npos) const noexcept; template - size_type find_first_not_of(const T& t, size_type pos = 0) const noexcept(@\seebelow@); - size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept; - size_type find_first_not_of(const charT* s, size_type pos, size_type n) const; - size_type find_first_not_of(const charT* s, size_type pos = 0) const; - size_type find_first_not_of(charT c, size_type pos = 0) const noexcept; + constexpr size_type find_first_not_of(const T& t, + size_type pos = 0) const noexcept(@\seebelow@); + constexpr size_type find_first_not_of(const basic_string& str, + size_type pos = 0) const noexcept; + constexpr size_type find_first_not_of(const charT* s, size_type pos, size_type n) const; + constexpr size_type find_first_not_of(const charT* s, size_type pos = 0) const; + constexpr size_type find_first_not_of(charT c, size_type pos = 0) const noexcept; template - size_type find_last_not_of (const T& t, size_type pos = npos) const noexcept(@\seebelow@); - size_type find_last_not_of (const basic_string& str, size_type pos = npos) const noexcept; - size_type find_last_not_of (const charT* s, size_type pos, size_type n) const; - size_type find_last_not_of (const charT* s, size_type pos = npos) const; - size_type find_last_not_of (charT c, size_type pos = npos) const noexcept; + constexpr size_type find_last_not_of(const T& t, + size_type pos = npos) const noexcept(@\seebelow@); + constexpr size_type find_last_not_of(const basic_string& str, + size_type pos = npos) const noexcept; + constexpr size_type find_last_not_of(const charT* s, size_type pos, size_type n) const; + constexpr size_type find_last_not_of(const charT* s, size_type pos = npos) const; + constexpr size_type find_last_not_of(charT c, size_type pos = npos) const noexcept; + + constexpr basic_string substr(size_type pos = 0, size_type n = npos) const; - basic_string substr(size_type pos = 0, size_type n = npos) const; template - int compare(const T& t) const noexcept(@\seebelow@); + constexpr int compare(const T& t) const noexcept(@\seebelow@); template - int compare(size_type pos1, size_type n1, const T& t) const; + constexpr int compare(size_type pos1, size_type n1, const T& t) const; template - int compare(size_type pos1, size_type n1, const T& t, - size_type pos2, size_type n2 = npos) const; - int compare(const basic_string& str) const noexcept; - int compare(size_type pos1, size_type n1, const basic_string& str) const; - int compare(size_type pos1, size_type n1, const basic_string& str, - size_type pos2, size_type n2 = npos) const; - int compare(const charT* s) const; - int compare(size_type pos1, size_type n1, const charT* s) const; - int compare(size_type pos1, size_type n1, const charT* s, size_type n2) const; - - bool starts_with(basic_string_view x) const noexcept; - bool starts_with(charT x) const noexcept; - bool starts_with(const charT* x) const; - bool ends_with(basic_string_view x) const noexcept; - bool ends_with(charT x) const noexcept; - bool ends_with(const charT* x) const; + constexpr int compare(size_type pos1, size_type n1, const T& t, + size_type pos2, size_type n2 = npos) const; + constexpr int compare(const basic_string& str) const noexcept; + constexpr int compare(size_type pos1, size_type n1, const basic_string& str) const; + constexpr int compare(size_type pos1, size_type n1, const basic_string& str, + size_type pos2, size_type n2 = npos) const; + constexpr int compare(const charT* s) const; + constexpr int compare(size_type pos1, size_type n1, const charT* s) const; + constexpr int compare(size_type pos1, size_type n1, const charT* s, size_type n2) const; + + constexpr bool starts_with(basic_string_view x) const noexcept; + constexpr bool starts_with(charT x) const noexcept; + constexpr bool starts_with(const charT* x) const; + constexpr bool ends_with(basic_string_view x) const noexcept; + constexpr bool ends_with(charT x) const noexcept; + constexpr bool ends_with(const charT* x) const; }; template - basic_string(const T& t, size_type pos, size_type n, const Allocator& a = Allocator()); + constexpr basic_string(const T& t, size_type pos, size_type n, const Allocator& a = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -1207,7 +1183,7 @@ \indexlibrary{\idxcode{basic_string}!constructor}% \begin{itemdecl} template - explicit basic_string(const T& t, const Allocator& a = Allocator()); + constexpr explicit basic_string(const T& t, const Allocator& a = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -1230,7 +1206,7 @@ \indexlibrary{\idxcode{basic_string}!constructor}% \begin{itemdecl} -basic_string(const charT* s, size_type n, const Allocator& a = Allocator()); +constexpr basic_string(const charT* s, size_type n, const Allocator& a = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -1249,7 +1225,7 @@ \indexlibrary{\idxcode{basic_string}!constructor}% \begin{itemdecl} -basic_string(const charT* s, const Allocator& a = Allocator()); +constexpr basic_string(const charT* s, const Allocator& a = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -1267,7 +1243,7 @@ \indexlibrary{\idxcode{basic_string}!constructor}% \begin{itemdecl} -basic_string(size_type n, charT c, const Allocator& a = Allocator()); +constexpr basic_string(size_type n, charT c, const Allocator& a = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -1287,7 +1263,7 @@ \indexlibrary{\idxcode{basic_string}!constructor}% \begin{itemdecl} template - basic_string(InputIterator begin, InputIterator end, const Allocator& a = Allocator()); + constexpr basic_string(InputIterator begin, InputIterator end, const Allocator& a = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -1304,7 +1280,7 @@ \indexlibrary{\idxcode{basic_string}!constructor}% \begin{itemdecl} -basic_string(initializer_list il, const Allocator& a = Allocator()); +constexpr basic_string(initializer_list il, const Allocator& a = Allocator()); \end{itemdecl} \begin{itemdescr} @@ -1314,8 +1290,8 @@ \indexlibrary{\idxcode{basic_string}!constructor}% \begin{itemdecl} -basic_string(const basic_string& str, const Allocator& alloc); -basic_string(basic_string&& str, const Allocator& alloc); +constexpr basic_string(const basic_string& str, const Allocator& alloc); +constexpr basic_string(basic_string&& str, const Allocator& alloc); \end{itemdecl} \begin{itemdescr} @@ -1370,7 +1346,7 @@ \indexlibrarymember{operator=}{basic_string}% \begin{itemdecl} -basic_string& operator=(const basic_string& str); +constexpr basic_string& operator=(const basic_string& str); \end{itemdecl} \begin{itemdescr} @@ -1386,7 +1362,7 @@ \indexlibrarymember{operator=}{basic_string}% \begin{itemdecl} -basic_string& operator=(basic_string&& str) +constexpr basic_string& operator=(basic_string&& str) noexcept(allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value); \end{itemdecl} @@ -1405,7 +1381,7 @@ \indexlibrarymember{operator=}{basic_string}% \begin{itemdecl} template - basic_string& operator=(const T& t); + constexpr basic_string& operator=(const T& t); \end{itemdecl} \begin{itemdescr} @@ -1428,7 +1404,7 @@ \indexlibrarymember{operator=}{basic_string}% \begin{itemdecl} -basic_string& operator=(const charT* s); +constexpr basic_string& operator=(const charT* s); \end{itemdecl} \begin{itemdescr} @@ -1439,7 +1415,7 @@ \indexlibrarymember{operator=}{basic_string}% \begin{itemdecl} -basic_string& operator=(charT c); +constexpr basic_string& operator=(charT c); \end{itemdecl} \begin{itemdescr} @@ -1452,7 +1428,7 @@ \indexlibrarymember{operator=}{basic_string}% \begin{itemdecl} -basic_string& operator=(initializer_list il); +constexpr basic_string& operator=(initializer_list il); \end{itemdecl} \begin{itemdescr} @@ -1468,9 +1444,9 @@ \indexlibrarymember{begin}{basic_string}% \indexlibrarymember{cbegin}{basic_string}% \begin{itemdecl} -iterator begin() noexcept; -const_iterator begin() const noexcept; -const_iterator cbegin() const noexcept; +constexpr iterator begin() noexcept; +constexpr const_iterator begin() const noexcept; +constexpr const_iterator cbegin() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -1482,9 +1458,9 @@ \indexlibrarymember{end}{basic_string}% \indexlibrarymember{cend}{basic_string}% \begin{itemdecl} -iterator end() noexcept; -const_iterator end() const noexcept; -const_iterator cend() const noexcept; +constexpr iterator end() noexcept; +constexpr const_iterator end() const noexcept; +constexpr const_iterator cend() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -1496,9 +1472,9 @@ \indexlibrarymember{rbegin}{basic_string}% \indexlibrarymember{crbegin}{basic_string}% \begin{itemdecl} -reverse_iterator rbegin() noexcept; -const_reverse_iterator rbegin() const noexcept; -const_reverse_iterator crbegin() const noexcept; +constexpr reverse_iterator rbegin() noexcept; +constexpr const_reverse_iterator rbegin() const noexcept; +constexpr const_reverse_iterator crbegin() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -1511,9 +1487,9 @@ \indexlibrarymember{rend}{basic_string}% \indexlibrarymember{crend}{basic_string}% \begin{itemdecl} -reverse_iterator rend() noexcept; -const_reverse_iterator rend() const noexcept; -const_reverse_iterator crend() const noexcept; +constexpr reverse_iterator rend() noexcept; +constexpr const_reverse_iterator rend() const noexcept; +constexpr const_reverse_iterator crend() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -1528,8 +1504,8 @@ \indexlibrarymember{size}{basic_string}% \indexlibrarymember{length}{basic_string}% \begin{itemdecl} -size_type size() const noexcept; -size_type length() const noexcept; +constexpr size_type size() const noexcept; +constexpr size_type length() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -1543,7 +1519,7 @@ \indexlibrarymember{max_size}{basic_string}% \begin{itemdecl} -size_type max_size() const noexcept; +constexpr size_type max_size() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -1558,7 +1534,7 @@ \indexlibrarymember{resize}{basic_string}% \begin{itemdecl} -void resize(size_type n, charT c); +constexpr void resize(size_type n, charT c); \end{itemdecl} \begin{itemdescr} @@ -1582,7 +1558,7 @@ \indexlibrarymember{resize}{basic_string}% \begin{itemdecl} -void resize(size_type n); +constexpr void resize(size_type n); \end{itemdecl} \begin{itemdescr} @@ -1593,7 +1569,7 @@ \indexlibrarymember{capacity}{basic_string}% \begin{itemdecl} -size_type capacity() const noexcept; +constexpr size_type capacity() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -1607,7 +1583,7 @@ \indexlibrarymember{reserve}{basic_string}% \begin{itemdecl} -void reserve(size_type res_arg); +constexpr void reserve(size_type res_arg); \end{itemdecl} \begin{itemdescr} @@ -1637,7 +1613,7 @@ \indexlibrarymember{shrink_to_fit}{basic_string}% \begin{itemdecl} -void shrink_to_fit(); +constexpr void shrink_to_fit(); \end{itemdecl} \begin{itemdescr} @@ -1661,7 +1637,7 @@ \indexlibrarymember{clear}{basic_string}% \begin{itemdecl} -void clear() noexcept; +constexpr void clear() noexcept; \end{itemdecl} \begin{itemdescr} @@ -1672,7 +1648,7 @@ \indexlibrarymember{empty}{basic_string}% \begin{itemdecl} -[[nodiscard]] bool empty() const noexcept; +[[nodiscard]] constexpr bool empty() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -1685,8 +1661,8 @@ \indexlibrarymember{operator[]}{basic_string}% \begin{itemdecl} -const_reference operator[](size_type pos) const; -reference operator[](size_type pos); +constexpr const_reference operator[](size_type pos) const; +constexpr reference operator[](size_type pos); \end{itemdecl} \begin{itemdescr} @@ -1708,8 +1684,8 @@ \indexlibrarymember{at}{basic_string}% \begin{itemdecl} -const_reference at(size_type pos) const; -reference at(size_type pos); +constexpr const_reference at(size_type pos) const; +constexpr reference at(size_type pos); \end{itemdecl} \begin{itemdescr} @@ -1726,8 +1702,8 @@ \indexlibrarymember{front}{basic_string}% \begin{itemdecl} -const charT& front() const; -charT& front(); +constexpr const charT& front() const; +constexpr charT& front(); \end{itemdecl} \begin{itemdescr} @@ -1742,8 +1718,8 @@ \indexlibrarymember{back}{basic_string}% \begin{itemdecl} -const charT& back() const; -charT& back(); +constexpr const charT& back() const; +constexpr charT& back(); \end{itemdecl} \begin{itemdescr} @@ -1762,7 +1738,7 @@ \indexlibrarymember{operator+=}{basic_string}% \begin{itemdecl} -basic_string& operator+=(const basic_string& str); +constexpr basic_string& operator+=(const basic_string& str); \end{itemdecl} \begin{itemdescr} @@ -1775,7 +1751,7 @@ \indexlibrarymember{operator+=}{basic_string}% \begin{itemdecl} template - basic_string& operator+=(const T& t); + constexpr basic_string& operator+=(const T& t); \end{itemdecl} \begin{itemdescr} @@ -1801,7 +1777,7 @@ \indexlibrarymember{operator+=}{basic_string}% \begin{itemdecl} -basic_string& operator+=(const charT* s); +constexpr basic_string& operator+=(const charT* s); \end{itemdecl} \begin{itemdescr} @@ -1811,7 +1787,7 @@ \indexlibrarymember{operator+=}{basic_string}% \begin{itemdecl} -basic_string& operator+=(charT c); +constexpr basic_string& operator+=(charT c); \end{itemdecl} \begin{itemdescr} @@ -1821,7 +1797,7 @@ \indexlibrarymember{operator+=}{basic_string}% \begin{itemdecl} -basic_string& operator+=(initializer_list il); +constexpr basic_string& operator+=(initializer_list il); \end{itemdecl} \begin{itemdescr} @@ -1834,7 +1810,7 @@ \indexlibrarymember{append}{basic_string}% \begin{itemdecl} -basic_string& append(const basic_string& str); +constexpr basic_string& append(const basic_string& str); \end{itemdecl} \begin{itemdescr} @@ -1844,7 +1820,7 @@ \indexlibrarymember{append}{basic_string}% \begin{itemdecl} -basic_string& append(const basic_string& str, size_type pos, size_type n = npos); +constexpr basic_string& append(const basic_string& str, size_type pos, size_type n = npos); \end{itemdecl} \begin{itemdescr} @@ -1859,7 +1835,7 @@ \indexlibrarymember{append}{basic_string}% \begin{itemdecl} template - basic_string& append(const T& t); + constexpr basic_string& append(const T& t); \end{itemdecl} \begin{itemdescr} @@ -1886,7 +1862,7 @@ \indexlibrarymember{append}{basic_string}% \begin{itemdecl} template - basic_string& append(const T& t, size_type pos, size_type n = npos); + constexpr basic_string& append(const T& t, size_type pos, size_type n = npos); \end{itemdecl} \begin{itemdescr} @@ -1912,7 +1888,7 @@ \indexlibrarymember{append}{basic_string}% \begin{itemdecl} -basic_string& append(const charT* s, size_type n); +constexpr basic_string& append(const charT* s, size_type n); \end{itemdecl} \begin{itemdescr} @@ -1929,7 +1905,7 @@ \indexlibrarymember{append}{basic_string}% \begin{itemdecl} -basic_string& append(const charT* s); +constexpr basic_string& append(const charT* s); \end{itemdecl} \begin{itemdescr} @@ -1939,7 +1915,7 @@ \indexlibrarymember{append}{basic_string}% \begin{itemdecl} -basic_string& append(size_type n, charT c); +constexpr basic_string& append(size_type n, charT c); \end{itemdecl} \begin{itemdescr} @@ -1953,7 +1929,7 @@ \indexlibrarymember{append}{basic_string}% \begin{itemdecl} template - basic_string& append(InputIterator first, InputIterator last); + constexpr basic_string& append(InputIterator first, InputIterator last); \end{itemdecl} \begin{itemdescr} @@ -1968,7 +1944,7 @@ \indexlibrarymember{append}{basic_string}% \begin{itemdecl} -basic_string& append(initializer_list il); +constexpr basic_string& append(initializer_list il); \end{itemdecl} \begin{itemdescr} @@ -1978,7 +1954,7 @@ \indexlibrarymember{push_back}{basic_string}% \begin{itemdecl} -void push_back(charT c); +constexpr void push_back(charT c); \end{itemdecl} \begin{itemdescr} @@ -1992,7 +1968,7 @@ \indexlibrarymember{assign}{basic_string}% \begin{itemdecl} -basic_string& assign(const basic_string& str); +constexpr basic_string& assign(const basic_string& str); \end{itemdecl} \begin{itemdescr} @@ -2002,7 +1978,7 @@ \indexlibrarymember{assign}{basic_string}% \begin{itemdecl} -basic_string& assign(basic_string&& str) +constexpr basic_string& assign(basic_string&& str) noexcept(allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value); \end{itemdecl} @@ -2015,7 +1991,7 @@ \indexlibrarymember{assign}{basic_string}% \begin{itemdecl} -basic_string& assign(const basic_string& str, size_type pos, size_type n = npos); +constexpr basic_string& assign(const basic_string& str, size_type pos, size_type n = npos); \end{itemdecl} \begin{itemdescr} @@ -2030,7 +2006,7 @@ \indexlibrarymember{assign}{basic_string}% \begin{itemdecl} template - basic_string& assign(const T& t); + constexpr basic_string& assign(const T& t); \end{itemdecl} \begin{itemdescr} @@ -2057,7 +2033,7 @@ \indexlibrarymember{assign}{basic_string}% \begin{itemdecl} template - basic_string& assign(const T& t, size_type pos, size_type n = npos); + constexpr basic_string& assign(const T& t, size_type pos, size_type n = npos); \end{itemdecl} \begin{itemdescr} @@ -2082,7 +2058,7 @@ \indexlibrarymember{assign}{basic_string}% \begin{itemdecl} -basic_string& assign(const charT* s, size_type n); +constexpr basic_string& assign(const charT* s, size_type n); \end{itemdecl} \begin{itemdescr} @@ -2101,7 +2077,7 @@ \indexlibrarymember{assign}{basic_string}% \begin{itemdecl} -basic_string& assign(const charT* s); +constexpr basic_string& assign(const charT* s); \end{itemdecl} \begin{itemdescr} @@ -2111,7 +2087,7 @@ \indexlibrarymember{assign}{basic_string}% \begin{itemdecl} -basic_string& assign(initializer_list il); +constexpr basic_string& assign(initializer_list il); \end{itemdecl} \begin{itemdescr} @@ -2121,7 +2097,7 @@ \indexlibrarymember{assign}{basic_string}% \begin{itemdecl} -basic_string& assign(size_type n, charT c); +constexpr basic_string& assign(size_type n, charT c); \end{itemdecl} \begin{itemdescr} @@ -2137,7 +2113,7 @@ \indexlibrarymember{assign}{basic_string}% \begin{itemdecl} template - basic_string& assign(InputIterator first, InputIterator last); + constexpr basic_string& assign(InputIterator first, InputIterator last); \end{itemdecl} \begin{itemdescr} @@ -2154,7 +2130,7 @@ \indexlibrarymember{insert}{basic_string}% \begin{itemdecl} -basic_string& insert(size_type pos, const basic_string& str); +constexpr basic_string& insert(size_type pos, const basic_string& str); \end{itemdecl} \begin{itemdescr} @@ -2164,7 +2140,8 @@ \indexlibrarymember{insert}{basic_string}% \begin{itemdecl} -basic_string& insert(size_type pos1, const basic_string& str, size_type pos2, size_type n = npos); +constexpr basic_string& insert(size_type pos1, const basic_string& str, + size_type pos2, size_type n = npos); \end{itemdecl} \begin{itemdescr} @@ -2179,7 +2156,7 @@ \indexlibrarymember{insert}{basic_string}% \begin{itemdecl} template - basic_string& insert(size_type pos, const T& t); + constexpr basic_string& insert(size_type pos, const T& t); \end{itemdecl} \begin{itemdescr} @@ -2206,7 +2183,8 @@ \indexlibrarymember{insert}{basic_string}% \begin{itemdecl} template - basic_string& insert(size_type pos1, const T& t, size_type pos2, size_type n = npos); + constexpr basic_string& insert(size_type pos1, const T& t, + size_type pos2, size_type n = npos); \end{itemdecl} \begin{itemdescr} @@ -2231,7 +2209,7 @@ \indexlibrarymember{insert}{basic_string}% \begin{itemdecl} -basic_string& insert(size_type pos, const charT* s, size_type n); +constexpr basic_string& insert(size_type pos, const charT* s, size_type n); \end{itemdecl} \begin{itemdescr} @@ -2258,7 +2236,7 @@ \indexlibrarymember{insert}{basic_string}% \begin{itemdecl} -basic_string& insert(size_type pos, const charT* s); +constexpr basic_string& insert(size_type pos, const charT* s); \end{itemdecl} \begin{itemdescr} @@ -2268,7 +2246,7 @@ \indexlibrarymember{insert}{basic_string}% \begin{itemdecl} -basic_string& insert(size_type pos, size_type n, charT c); +constexpr basic_string& insert(size_type pos, size_type n, charT c); \end{itemdecl} \begin{itemdescr} @@ -2293,7 +2271,7 @@ \indexlibrarymember{insert}{basic_string}% \begin{itemdecl} -iterator insert(const_iterator p, charT c); +constexpr iterator insert(const_iterator p, charT c); \end{itemdecl} \begin{itemdescr} @@ -2313,7 +2291,7 @@ \indexlibrarymember{insert}{basic_string}% \begin{itemdecl} -iterator insert(const_iterator p, size_type n, charT c); +constexpr iterator insert(const_iterator p, size_type n, charT c); \end{itemdecl} \begin{itemdescr} @@ -2334,7 +2312,7 @@ \indexlibrarymember{insert}{basic_string}% \begin{itemdecl} template - iterator insert(const_iterator p, InputIterator first, InputIterator last); + constexpr iterator insert(const_iterator p, InputIterator first, InputIterator last); \end{itemdecl} \begin{itemdescr} @@ -2360,7 +2338,7 @@ \indexlibrarymember{insert}{basic_string}% \begin{itemdecl} -iterator insert(const_iterator p, initializer_list il); +constexpr iterator insert(const_iterator p, initializer_list il); \end{itemdecl} \begin{itemdescr} @@ -2372,7 +2350,7 @@ \indexlibrarymember{erase}{basic_string}% \begin{itemdecl} -basic_string& erase(size_type pos = 0, size_type n = npos); +constexpr basic_string& erase(size_type pos = 0, size_type n = npos); \end{itemdecl} \begin{itemdescr} @@ -2396,7 +2374,7 @@ \indexlibrarymember{erase}{basic_string}% \begin{itemdecl} -iterator erase(const_iterator p); +constexpr iterator erase(const_iterator p); \end{itemdecl} \begin{itemdescr} @@ -2422,7 +2400,7 @@ \indexlibrarymember{erase}{basic_string}% \begin{itemdecl} -iterator erase(const_iterator first, const_iterator last); +constexpr iterator erase(const_iterator first, const_iterator last); \end{itemdecl} \begin{itemdescr} @@ -2450,7 +2428,7 @@ \indexlibrarymember{pop_back}{basic_string}% \begin{itemdecl} -void pop_back(); +constexpr void pop_back(); \end{itemdecl} \begin{itemdescr} @@ -2470,7 +2448,7 @@ \indexlibrarymember{replace}{basic_string}% \begin{itemdecl} -basic_string& replace(size_type pos1, size_type n1, const basic_string& str); +constexpr basic_string& replace(size_type pos1, size_type n1, const basic_string& str); \end{itemdecl} \begin{itemdescr} @@ -2480,8 +2458,8 @@ \indexlibrarymember{replace}{basic_string}% \begin{itemdecl} -basic_string& replace(size_type pos1, size_type n1, const basic_string& str, - size_type pos2, size_type n2 = npos); +constexpr basic_string& replace(size_type pos1, size_type n1, const basic_string& str, + size_type pos2, size_type n2 = npos); \end{itemdecl} \begin{itemdescr} @@ -2496,7 +2474,7 @@ \indexlibrarymember{replace}{basic_string}% \begin{itemdecl} template - basic_string& replace(size_type pos1, size_type n1, const T& t); + constexpr basic_string& replace(size_type pos1, size_type n1, const T& t); \end{itemdecl} \begin{itemdescr} @@ -2523,8 +2501,8 @@ \indexlibrarymember{replace}{basic_string}% \begin{itemdecl} template - basic_string& replace(size_type pos1, size_type n1, const T& t, - size_type pos2, size_type n2 = npos); + constexpr basic_string& replace(size_type pos1, size_type n1, const T& t, + size_type pos2, size_type n2 = npos); \end{itemdecl} \begin{itemdescr} @@ -2550,7 +2528,7 @@ \indexlibrarymember{replace}{basic_string}% \begin{itemdecl} -basic_string& replace(size_type pos1, size_type n1, const charT* s, size_type n2); +constexpr basic_string& replace(size_type pos1, size_type n1, const charT* s, size_type n2); \end{itemdecl} \begin{itemdescr} @@ -2581,7 +2559,7 @@ \indexlibrarymember{replace}{basic_string}% \begin{itemdecl} -basic_string& replace(size_type pos, size_type n, const charT* s); +constexpr basic_string& replace(size_type pos, size_type n, const charT* s); \end{itemdecl} \begin{itemdescr} @@ -2591,7 +2569,7 @@ \indexlibrarymember{replace}{basic_string}% \begin{itemdecl} -basic_string& replace(size_type pos1, size_type n1, size_type n2, charT c); +constexpr basic_string& replace(size_type pos1, size_type n1, size_type n2, charT c); \end{itemdecl} \begin{itemdescr} @@ -2618,7 +2596,7 @@ \indexlibrarymember{replace}{basic_string}% \begin{itemdecl} -basic_string& replace(const_iterator i1, const_iterator i2, const basic_string& str); +constexpr basic_string& replace(const_iterator i1, const_iterator i2, const basic_string& str); \end{itemdecl} \begin{itemdescr} @@ -2630,7 +2608,7 @@ \indexlibrarymember{replace}{basic_string}% \begin{itemdecl} template - basic_string& replace(const_iterator i1, const_iterator i2, const T& t); + constexpr basic_string& replace(const_iterator i1, const_iterator i2, const T& t); \end{itemdecl} \begin{itemdescr} @@ -2660,7 +2638,7 @@ \indexlibrarymember{replace}{basic_string}% \begin{itemdecl} -basic_string& replace(const_iterator i1, const_iterator i2, const charT* s, size_type n); +constexpr basic_string& replace(const_iterator i1, const_iterator i2, const charT* s, size_type n); \end{itemdecl} \begin{itemdescr} @@ -2671,7 +2649,7 @@ \indexlibrarymember{replace}{basic_string}% \begin{itemdecl} -basic_string& replace(const_iterator i1, const_iterator i2, const charT* s); +constexpr basic_string& replace(const_iterator i1, const_iterator i2, const charT* s); \end{itemdecl} \begin{itemdescr} @@ -2682,7 +2660,7 @@ \indexlibrarymember{replace}{basic_string}% \begin{itemdecl} -basic_string& replace(const_iterator i1, const_iterator i2, size_type n, charT c); +constexpr basic_string& replace(const_iterator i1, const_iterator i2, size_type n, charT c); \end{itemdecl} \begin{itemdescr} @@ -2697,7 +2675,8 @@ \indexlibrarymember{replace}{basic_string}% \begin{itemdecl} template - basic_string& replace(const_iterator i1, const_iterator i2, InputIterator j1, InputIterator j2); + constexpr basic_string& replace(const_iterator i1, const_iterator i2, + InputIterator j1, InputIterator j2); \end{itemdecl} \begin{itemdescr} @@ -2713,7 +2692,7 @@ \indexlibrarymember{replace}{basic_string}% \begin{itemdecl} -basic_string& replace(const_iterator i1, const_iterator i2, initializer_list il); +constexpr basic_string& replace(const_iterator i1, const_iterator i2, initializer_list il); \end{itemdecl} \begin{itemdescr} @@ -2726,7 +2705,7 @@ \indexlibrarymember{copy}{basic_string}% \begin{itemdecl} -size_type copy(charT* s, size_type n, size_type pos = 0) const; +constexpr size_type copy(charT* s, size_type n, size_type pos = 0) const; \end{itemdecl} \begin{itemdescr} @@ -2741,7 +2720,7 @@ \indexlibrarymember{swap}{basic_string}% \begin{itemdecl} -void swap(basic_string& s) +constexpr void swap(basic_string& s) noexcept(allocator_traits::propagate_on_container_swap::value || allocator_traits::is_always_equal::value); \end{itemdecl} @@ -2774,8 +2753,8 @@ \indexlibrarymember{c_str}{basic_string}% \indexlibrarymember{data}{basic_string}% \begin{itemdecl} -const charT* c_str() const noexcept; -const charT* data() const noexcept; +constexpr const charT* c_str() const noexcept; +constexpr const charT* data() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -2793,7 +2772,7 @@ \indexlibrarymember{data}{basic_string}% \begin{itemdecl} -charT* data() noexcept; +constexpr charT* data() noexcept; \end{itemdecl} \begin{itemdescr} @@ -2812,7 +2791,7 @@ \indexlibrarymember{operator basic_string_view}{basic_string}% \begin{itemdecl} -operator basic_string_view() const noexcept; +constexpr operator basic_string_view() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -2823,7 +2802,7 @@ \indexlibrarymember{get_allocator}{basic_string}% \begin{itemdecl} -allocator_type get_allocator() const noexcept; +constexpr allocator_type get_allocator() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -2838,6 +2817,12 @@ \rSec4[string.find]{Searching} \pnum +\indexlibrarymember{find}{basic_string}% +\indexlibrarymember{rfind}{basic_string}% +\indexlibrarymember{find_first_of}{basic_string}% +\indexlibrarymember{find_last_of}{basic_string}% +\indexlibrarymember{find_first_not_of}{basic_string}% +\indexlibrarymember{find_last_not_of}{basic_string}% Let \placeholder{F} be one of \tcode{find}, \tcode{rfind}, \tcode{find_first_of}, \tcode{find_last_of}, \tcode{find_first_not_of}, and \tcode{find_last_not_of}. @@ -2846,7 +2831,7 @@ \item Each member function of the form \begin{codeblock} -size_type @\placeholder{F}@(const basic_string& str, size_type pos) const noexcept; +constexpr size_type @\placeholder{F}@(const basic_string& str, size_type pos) const noexcept; \end{codeblock} has effects equivalent to: \tcode{return \placeholder{F}(basic_string_view(str), pos);} @@ -2854,7 +2839,7 @@ \item Each member function of the form \begin{codeblock} -size_type @\placeholder{F}@(const charT* s, size_type pos) const; +constexpr size_type @\placeholder{F}@(const charT* s, size_type pos) const; \end{codeblock} has effects equivalent to: \tcode{return \placeholder{F}(basic_string_view(s), pos);} @@ -2862,7 +2847,7 @@ \item Each member function of the form \begin{codeblock} -size_type @\placeholder{F}@(const charT* s, size_type pos, size_type n) const; +constexpr size_type @\placeholder{F}@(const charT* s, size_type pos, size_type n) const; \end{codeblock} has effects equivalent to: \tcode{return \placeholder{F}(basic_string_view(s, n), pos);} @@ -2870,7 +2855,7 @@ \item Each member function of the form \begin{codeblock} -size_type @\placeholder{F}@(charT c, size_type pos) const noexcept; +constexpr size_type @\placeholder{F}@(charT c, size_type pos) const noexcept; \end{codeblock} has effects equivalent to: \begin{codeblock} @@ -2886,17 +2871,17 @@ \indexlibrarymember{find_last_not_of}{basic_string}% \begin{itemdecl} template - size_type find(const T& t, size_type pos = 0) const noexcept(@\seebelow@); + constexpr size_type find(const T& t, size_type pos = 0) const noexcept(@\seebelow@); template - size_type rfind(const T& t, size_type pos = npos) const noexcept(@\seebelow@); + constexpr size_type rfind(const T& t, size_type pos = npos) const noexcept(@\seebelow@); template - size_type find_first_of(const T& t, size_type pos = 0) const noexcept(@\seebelow@); + constexpr size_type find_first_of(const T& t, size_type pos = 0) const noexcept(@\seebelow@); template - size_type find_last_of(const T& t, size_type pos = npos) const noexcept(@\seebelow@); + constexpr size_type find_last_of(const T& t, size_type pos = npos) const noexcept(@\seebelow@); template - size_type find_first_not_of(const T& t, size_type pos = 0) const noexcept(@\seebelow@); + constexpr size_type find_first_not_of(const T& t, size_type pos = 0) const noexcept(@\seebelow@); template - size_type find_last_not_of(const T& t, size_type pos = npos) const noexcept(@\seebelow@); + constexpr size_type find_last_not_of(const T& t, size_type pos = npos) const noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} @@ -2930,7 +2915,7 @@ \indexlibrarymember{substr}{basic_string}% \begin{itemdecl} -basic_string substr(size_type pos = 0, size_type n = npos) const; +constexpr basic_string substr(size_type pos = 0, size_type n = npos) const; \end{itemdecl} \begin{itemdescr} @@ -2955,7 +2940,7 @@ \indexlibrarymember{compare}{basic_string}% \begin{itemdecl} template - int compare(const T& t) const noexcept(@\seebelow@); + constexpr int compare(const T& t) const noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} @@ -2983,7 +2968,7 @@ \indexlibrarymember{compare}{basic_string}% \begin{itemdecl} template - int compare(size_type pos1, size_type n1, const T& t) const; + constexpr int compare(size_type pos1, size_type n1, const T& t) const; \end{itemdecl} \begin{itemdescr} @@ -3009,7 +2994,8 @@ \indexlibrarymember{compare}{basic_string}% \begin{itemdecl} template - int compare(size_type pos1, size_type n1, const T& t, size_type pos2, size_type n2 = npos) const; + constexpr int compare(size_type pos1, size_type n1, const T& t, + size_type pos2, size_type n2 = npos) const; \end{itemdecl} \begin{itemdescr} @@ -3035,7 +3021,7 @@ \indexlibrarymember{compare}{basic_string}% \begin{itemdecl} -int compare(const basic_string& str) const noexcept; +constexpr int compare(const basic_string& str) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -3047,7 +3033,7 @@ \indexlibrarymember{compare}{basic_string}% \begin{itemdecl} -int compare(size_type pos1, size_type n1, const basic_string& str) const; +constexpr int compare(size_type pos1, size_type n1, const basic_string& str) const; \end{itemdecl} \begin{itemdescr} @@ -3059,8 +3045,8 @@ \indexlibrarymember{compare}{basic_string}% \begin{itemdecl} -int compare(size_type pos1, size_type n1, const basic_string& str, - size_type pos2, size_type n2 = npos) const; +constexpr int compare(size_type pos1, size_type n1, const basic_string& str, + size_type pos2, size_type n2 = npos) const; \end{itemdecl} \begin{itemdescr} @@ -3073,7 +3059,7 @@ \indexlibrarymember{compare}{basic_string}% \begin{itemdecl} -int compare(const charT* s) const; +constexpr int compare(const charT* s) const; \end{itemdecl} \begin{itemdescr} @@ -3084,7 +3070,7 @@ \indexlibrarymember{compare}{basic_string}% \begin{itemdecl} -int compare(size_type pos, size_type n1, const charT* s) const; +constexpr int compare(size_type pos, size_type n1, const charT* s) const; \end{itemdecl} \begin{itemdescr} @@ -3095,7 +3081,7 @@ \indexlibrarymember{compare}{basic_string}% \begin{itemdecl} -int compare(size_type pos, size_type n1, const charT* s, size_type n2) const; +constexpr int compare(size_type pos, size_type n1, const charT* s, size_type n2) const; \end{itemdecl} \begin{itemdescr} @@ -3108,9 +3094,9 @@ \indexlibrarymember{starts_with}{basic_string}% \begin{itemdecl} -bool starts_with(basic_string_view x) const noexcept; -bool starts_with(charT x) const noexcept; -bool starts_with(const charT* x) const; +constexpr bool starts_with(basic_string_view x) const noexcept; +constexpr bool starts_with(charT x) const noexcept; +constexpr bool starts_with(const charT* x) const; \end{itemdecl} \begin{itemdescr} @@ -3126,9 +3112,9 @@ \indexlibrarymember{ends_with}{basic_string}% \begin{itemdecl} -bool ends_with(basic_string_view x) const noexcept; -bool ends_with(charT x) const noexcept; -bool ends_with(const charT* x) const; +constexpr bool ends_with(basic_string_view x) const noexcept; +constexpr bool ends_with(charT x) const noexcept; +constexpr bool ends_with(const charT* x) const; \end{itemdecl} \begin{itemdescr} @@ -3149,11 +3135,11 @@ \indexlibrarymember{operator+}{basic_string}% \begin{itemdecl} template - basic_string + constexpr basic_string operator+(const basic_string& lhs, const basic_string& rhs); template - basic_string + constexpr basic_string operator+(const basic_string& lhs, const charT* rhs); \end{itemdecl} @@ -3171,11 +3157,11 @@ \indexlibrarymember{operator+}{basic_string}% \begin{itemdecl} template - basic_string + constexpr basic_string operator+(basic_string&& lhs, const basic_string& rhs); template - basic_string + constexpr basic_string operator+(basic_string&& lhs, const charT* rhs); \end{itemdecl} @@ -3192,7 +3178,7 @@ \indexlibrarymember{operator+}{basic_string}% \begin{itemdecl} template - basic_string + constexpr basic_string operator+(basic_string&& lhs, basic_string&& rhs); \end{itemdecl} @@ -3216,11 +3202,11 @@ \indexlibrarymember{operator+}{basic_string}% \begin{itemdecl} template - basic_string + constexpr basic_string operator+(const basic_string& lhs, basic_string&& rhs); template - basic_string + constexpr basic_string operator+(const charT* lhs, basic_string&& rhs); \end{itemdecl} @@ -3237,7 +3223,7 @@ \indexlibrarymember{operator+}{basic_string}% \begin{itemdecl} template - basic_string + constexpr basic_string operator+(const charT* lhs, const basic_string& rhs); \end{itemdecl} @@ -3255,7 +3241,7 @@ \indexlibrarymember{operator+}{basic_string}% \begin{itemdecl} template - basic_string + constexpr basic_string operator+(charT lhs, const basic_string& rhs); \end{itemdecl} @@ -3273,7 +3259,7 @@ \indexlibrarymember{operator+}{basic_string}% \begin{itemdecl} template - basic_string + constexpr basic_string operator+(charT lhs, basic_string&& rhs); \end{itemdecl} @@ -3290,7 +3276,7 @@ \indexlibrarymember{operator+}{basic_string}% \begin{itemdecl} template - basic_string + constexpr basic_string operator+(const basic_string& lhs, charT rhs); \end{itemdecl} @@ -3308,7 +3294,7 @@ \indexlibrarymember{operator+}{basic_string}% \begin{itemdecl} template - basic_string + constexpr basic_string operator+(basic_string&& lhs, charT rhs); \end{itemdecl} @@ -3325,59 +3311,26 @@ \rSec3[string.cmp]{Non-member comparison functions} \begin{itemdecl} template - bool operator==(const basic_string& lhs, - const basic_string& rhs) noexcept; -template - bool operator==(const charT* lhs, const basic_string& rhs); -template - bool operator==(const basic_string& lhs, const charT* rhs); - -template - bool operator!=(const basic_string& lhs, - const basic_string& rhs) noexcept; -template - bool operator!=(const charT* lhs, const basic_string& rhs); -template - bool operator!=(const basic_string& lhs, const charT* rhs); - -template - bool operator< (const basic_string& lhs, - const basic_string& rhs) noexcept; -template - bool operator< (const charT* lhs, const basic_string& rhs); -template - bool operator< (const basic_string& lhs, const charT* rhs); - -template - bool operator> (const basic_string& lhs, - const basic_string& rhs) noexcept; -template - bool operator> (const charT* lhs, const basic_string& rhs); + constexpr bool + operator==(const basic_string& lhs, + const basic_string& rhs) noexcept; template - bool operator> (const basic_string& lhs, const charT* rhs); + constexpr bool operator==(const basic_string& lhs, + const charT* rhs); template - bool operator<=(const basic_string& lhs, - const basic_string& rhs) noexcept; + constexpr @\seebelow@ operator<=>(const basic_string& lhs, + @\itcorr@ const basic_string& rhs) noexcept; template - bool operator<=(const charT* lhs, const basic_string& rhs); -template - bool operator<=(const basic_string& lhs, const charT* rhs); - -template - bool operator>=(const basic_string& lhs, - const basic_string& rhs) noexcept; -template - bool operator>=(const charT* lhs, const basic_string& rhs); -template - bool operator>=(const basic_string& lhs, const charT* rhs); + constexpr @\seebelow@ operator<=>(const basic_string& lhs, + @\itcorr@ const charT* rhs); \end{itemdecl} \begin{itemdescr} \pnum \effects Let \tcode{\placeholder{op}} be the operator. Equivalent to: \begin{codeblock} - return basic_string_view(lhs) @\placeholder{op}@ basic_string_view(rhs); +return basic_string_view(lhs) @\placeholder{op}@ basic_string_view(rhs); \end{codeblock} \end{itemdescr} @@ -3386,9 +3339,10 @@ \indexlibrarymember{swap}{basic_string}% \begin{itemdecl} template - void swap(basic_string& lhs, - basic_string& rhs) - noexcept(noexcept(lhs.swap(rhs))); + constexpr void + swap(basic_string& lhs, + basic_string& rhs) + noexcept(noexcept(lhs.swap(rhs))); \end{itemdecl} \begin{itemdescr} @@ -3563,7 +3517,7 @@ \indexlibrary{\idxcode{erase}!\idxcode{basic_string}}% \begin{itemdecl} template - void erase(basic_string& c, const U& value); + constexpr void erase(basic_string& c, const U& value); \end{itemdecl} \begin{itemdescr} @@ -3575,7 +3529,7 @@ \indexlibrary{\idxcode{erase_if}!\idxcode{basic_string}}% \begin{itemdecl} template - void erase_if(basic_string& c, Predicate pred); + constexpr void erase_if(basic_string& c, Predicate pred); \end{itemdecl} \begin{itemdescr} @@ -3810,7 +3764,7 @@ \indexlibrarymember{operator""""s}{string}% \begin{itemdecl} -string operator""s(const char* str, size_t len); +constexpr string operator""s(const char* str, size_t len); \end{itemdecl} \begin{itemdescr} @@ -3821,7 +3775,7 @@ \indexlibrarymember{operator""""s}{u8string}% \begin{itemdecl} -u8string operator""s(const char8_t* str, size_t len); +constexpr u8string operator""s(const char8_t* str, size_t len); \end{itemdecl} \begin{itemdescr} \pnum @@ -3831,7 +3785,7 @@ \indexlibrarymember{operator""""s}{u16string}% \begin{itemdecl} -u16string operator""s(const char16_t* str, size_t len); +constexpr u16string operator""s(const char16_t* str, size_t len); \end{itemdecl} \begin{itemdescr} \pnum @@ -3841,7 +3795,7 @@ \indexlibrarymember{operator""""s}{u32string}% \begin{itemdecl} -u32string operator""s(const char32_t* str, size_t len); +constexpr u32string operator""s(const char32_t* str, size_t len); \end{itemdecl} \begin{itemdescr} \pnum @@ -3851,7 +3805,7 @@ \indexlibrarymember{operator""""s}{wstring}% \begin{itemdecl} -wstring operator""s(const wchar_t* str, size_t len); +constexpr wstring operator""s(const wchar_t* str, size_t len); \end{itemdecl} \begin{itemdescr} \pnum @@ -3889,20 +3843,9 @@ constexpr bool operator==(basic_string_view x, basic_string_view y) noexcept; template - constexpr bool operator!=(basic_string_view x, - basic_string_view y) noexcept; - template - constexpr bool operator< (basic_string_view x, - basic_string_view y) noexcept; - template - constexpr bool operator> (basic_string_view x, - basic_string_view y) noexcept; - template - constexpr bool operator<=(basic_string_view x, - basic_string_view y) noexcept; - template - constexpr bool operator>=(basic_string_view x, - basic_string_view y) noexcept; + constexpr @\seebelow@ operator<=>(basic_string_view x, + @\itcorr@ basic_string_view y) noexcept; + // see \ref{string.view.comparison}, sufficient additional overloads of comparison functions // \ref{string.view.io}, inserters and extractors @@ -4149,7 +4092,7 @@ A type that meets the requirements of a constant \oldconcept{RandomAccessIterator}\iref{random.access.iterators}, -models \libconcept{ContiguousIterator}\iref{iterator.concept.contiguous}, and +models \libconcept{contiguous_iterator}\iref{iterator.concept.contiguous}, and meets the constexpr iterator requirements\iref{iterator.requirements.general}, whose \tcode{value_type} is the template parameter \tcode{charT}. @@ -4818,6 +4761,8 @@ \tcode{sv <= t} & \tcode{sv <= S(t)} \\ \tcode{t >= sv} & \tcode{S(t) >= sv} \\ \tcode{sv >= t} & \tcode{sv >= S(t)} \\ +\tcode{t <=> sv} & \tcode{S(t) <=> sv} \\ +\tcode{sv <=> t} & \tcode{sv <=> S(t)} \\ \end{libtab2} \begin{example} A sample conforming implementation for \tcode{operator==} would be: @@ -4832,11 +4777,6 @@ type_identity_t> rhs) noexcept { return lhs.compare(rhs) == 0; } -template - constexpr bool operator==(type_identity_t> lhs, - basic_string_view rhs) noexcept { - return lhs.compare(rhs) == 0; - } \end{codeblock} \end{example} @@ -4853,69 +4793,21 @@ \tcode{lhs.compare(rhs) == 0}. \end{itemdescr} -\indexlibrarymember{operator"!=}{basic_string_view}% +\indexlibrarymember{operator<=>}{basic_string_view}% \begin{itemdecl} template - constexpr bool operator!=(basic_string_view lhs, - basic_string_view rhs) noexcept; + constexpr @\seebelow@ operator<=>(basic_string_view lhs, + @\itcorr@ basic_string_view rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns -\tcode{lhs.compare(rhs) != 0}. -\end{itemdescr} +Let \tcode{R} denote the type \tcode{traits::comparison_category} if it exists, +otherwise \tcode{R} is \tcode{weak_ordering}. -\indexlibrarymember{operator<}{basic_string_view}% -\begin{itemdecl} -template - constexpr bool operator<(basic_string_view lhs, - basic_string_view rhs) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{lhs.compare(rhs) < 0}. -\end{itemdescr} - -\indexlibrarymember{operator>}{basic_string_view}% -\begin{itemdecl} -template - constexpr bool operator>(basic_string_view lhs, - basic_string_view rhs) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{lhs.compare(rhs) > 0}. -\end{itemdescr} - -\indexlibrarymember{operator<=}{basic_string_view}% -\begin{itemdecl} -template - constexpr bool operator<=(basic_string_view lhs, - basic_string_view rhs) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{lhs.compare(rhs) <= 0}. -\end{itemdescr} - -\indexlibrarymember{operator>=}{basic_string_view}% -\begin{itemdecl} -template - constexpr bool operator>=(basic_string_view lhs, - basic_string_view rhs) noexcept; -\end{itemdecl} - -\begin{itemdescr} \pnum \returns -\tcode{lhs.compare(rhs) >= 0}. +\tcode{static_cast(lhs.compare(rhs) <=> 0)}. \end{itemdescr} \rSec2[string.view.io]{Inserters and extractors} diff --git a/source/support.tex b/source/support.tex index dc2c9ba54f..dcd1a4129d 100644 --- a/source/support.tex +++ b/source/support.tex @@ -17,7 +17,6 @@ functions supporting start and termination of a \Cpp{} program, support for dynamic memory management, support for dynamic type identification, -support for contract violation handling, support for exception processing, support for initializer lists, and other runtime support, as summarized in \tref{support.summary}. @@ -31,7 +30,7 @@ \ref{support.start.term} & Start and termination & \tcode{} \\ \rowsep \ref{support.dynamic} & Dynamic memory management & \tcode{} \\ \rowsep \ref{support.rtti} & Type identification & \tcode{} \\ \rowsep -\ref{support.contract} & Contract violation handling & \tcode{} \\ \rowsep +\ref{support.srcloc} & Source location & \tcode{} \\ \rowsep \ref{support.exception} & Exception handling & \tcode{} \\ \rowsep \ref{support.initlist} & Initializer lists & \tcode{} \\ \rowsep \ref{cmp} & Comparisons & \tcode{} \\ \rowsep @@ -541,14 +540,24 @@ \tcode{} \tcode{} \\ \rowsep \defnlibxname{cpp_lib_as_const} & \tcode{201510L} & \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_atomic_flag_test} & \tcode{201907L} & + \tcode{} \\ \rowsep \defnlibxname{cpp_lib_atomic_is_always_lock_free} & \tcode{201603L} & \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_atomic_lock_free_type_aliases} & \tcode{201907L} & + \tcode{} \\ \rowsep \defnlibxname{cpp_lib_atomic_ref} & \tcode{201806L} & \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_atomic_wait} & \tcode{201907L} & + \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_barrier} & \tcode{201907L} & + \tcode{} \\ \rowsep \defnlibxname{cpp_lib_bit_cast} & \tcode{201806L} & \tcode{} \\ \rowsep -\defnlibxname{cpp_lib_bind_front} & \tcode{201811L} & +\defnlibxname{cpp_lib_bind_front} & \tcode{201907L} & \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_bitops} & \tcode{201907L} & + \tcode{} \\ \rowsep \defnlibxname{cpp_lib_bool_constant} & \tcode{201505L} & \tcode{} \\ \rowsep \defnlibxname{cpp_lib_bounded_array_traits} & \tcode{201902L} & @@ -557,11 +566,11 @@ \tcode{} \\ \rowsep \defnlibxname{cpp_lib_byte} & \tcode{201603L} & \tcode{} \\ \rowsep -\defnlibxname{cpp_lib_char8_t} & \tcode{201811L} & +\defnlibxname{cpp_lib_char8_t} & \tcode{201907L} & \tcode{} \tcode{} \tcode{} \tcode{} \tcode{} \tcode{} \tcode{} \tcode{} \\ \rowsep -\defnlibxname{cpp_lib_chrono} & \tcode{201611L} & +\defnlibxname{cpp_lib_chrono} & \tcode{201907L} & \tcode{} \\ \rowsep \defnlibxname{cpp_lib_chrono_udls} & \tcode{201304L} & \tcode{} \\ \rowsep @@ -571,15 +580,25 @@ \tcode{} \\ \rowsep \defnlibxname{cpp_lib_concepts} & \tcode{201806L} & \tcode{} \\ \rowsep -\defnlibxname{cpp_lib_constexpr_misc} & \tcode{201811L} & - \tcode{} \tcode{} \tcode{} - \tcode{} \tcode{} \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_constexpr} & \tcode{201811L} & + any C++ library header from \tref{headers.cpp} or + any C++ header for C library facilities from \tref{headers.cpp.c} \\ \rowsep +\defnlibxname{cpp_lib_constexpr_dynamic_alloc} & \tcode{201907L} & + \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_constexpr_invoke} & \tcode{201907L} & + \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_constexpr_string} & \tcode{201907L} & + \tcode{} \\ \rowsep \defnlibxname{cpp_lib_constexpr_swap_algorithms} & \tcode{201806L} & \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_constexpr_vector} & \tcode{201907L} & + \tcode{} \\ \rowsep \defnlibxname{cpp_lib_destroying_delete} & \tcode{201806L} & \tcode{} \\ \rowsep \defnlibxname{cpp_lib_enable_shared_from_this} & \tcode{201603L} & \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_endian} & \tcode{201907L} & + \tcode{} \\ \rowsep \defnlibxname{cpp_lib_erase_if} & \tcode{201811L} & \tcode{} \tcode{} \tcode{} \tcode{} \tcode{} \tcode{} \tcode{} \tcode{} @@ -590,14 +609,14 @@ \tcode{} \\ \rowsep \defnlibxname{cpp_lib_filesystem} & \tcode{201703L} & \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_format} & \tcode{201907L} & + \tcode{} \\ \rowsep \defnlibxname{cpp_lib_gcd_lcm} & \tcode{201606L} & \tcode{} \\ \rowsep \defnlibxname{cpp_lib_generic_associative_lookup} & \tcode{201304L} & \tcode{} \tcode{} \\ \rowsep \defnlibxname{cpp_lib_generic_unordered_lookup} & \tcode{201811L} & \tcode{} \tcode{} \\ \rowsep -\defnlibxname{cpp_lib_generic_unordered_hash_lookup} & \tcode{201902L} & - \tcode{} \tcode{} \\ \rowsep \defnlibxname{cpp_lib_hardware_interference_size} & \tcode{201703L} & \tcode{} \\ \rowsep \defnlibxname{cpp_lib_has_unique_object_representations} & \tcode{201606L} & @@ -622,10 +641,18 @@ \tcode{} \\ \rowsep \defnlibxname{cpp_lib_is_invocable} & \tcode{201703L} & \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_is_layout_compatible} & \tcode{201907L} & + \tcode{} \\ \rowsep \defnlibxname{cpp_lib_is_null_pointer} & \tcode{201309L} & \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_is_pointer_interconvertible} & \tcode{201907L} & + \tcode{} \\ \rowsep \defnlibxname{cpp_lib_is_swappable} & \tcode{201603L} & \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_jthread} & \tcode{201907L} & + \tcode{} \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_latch} & \tcode{201907L} & + \tcode{} \\ \rowsep \defnlibxname{cpp_lib_launder} & \tcode{201606L} & \tcode{} \\ \rowsep \defnlibxname{cpp_lib_list_remove_return_type} & \tcode{201806L} & @@ -640,6 +667,8 @@ \tcode{} \\ \rowsep \defnlibxname{cpp_lib_map_try_emplace} & \tcode{201411L} & \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_math_constants} & \tcode{201907L} & + \tcode{} \\ \rowsep \defnlibxname{cpp_lib_math_special_functions} & \tcode{201603L} & \tcode{} \\ \rowsep \defnlibxname{cpp_lib_memory_resource} & \tcode{201603L} & @@ -674,6 +703,8 @@ \tcode{} \\ \rowsep \defnlibxname{cpp_lib_scoped_lock} & \tcode{201703L} & \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_semaphore} & \tcode{201907L} & + \tcode{} \\ \rowsep \defnlibxname{cpp_lib_shared_mutex} & \tcode{201505L} & \tcode{} \\ \rowsep \defnlibxname{cpp_lib_shared_ptr_arrays} & \tcode{201611L} & @@ -682,12 +713,18 @@ \tcode{} \\ \rowsep \defnlibxname{cpp_lib_shared_timed_mutex} & \tcode{201402L} & \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_source_location} & \tcode{201907L} & + \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_spaceship} & \tcode{201907L} & + \tcode{} \\ \rowsep \defnlibxname{cpp_lib_string_udls} & \tcode{201304L} & \tcode{} \\ \rowsep \defnlibxname{cpp_lib_string_view} & \tcode{201606L} & \tcode{} \tcode{} \\ \rowsep \defnlibxname{cpp_lib_three_way_comparison} & \tcode{201711L} & \tcode{} \\ \rowsep +\defnlibxname{cpp_lib_to_array} & \tcode{201907L} & + \tcode{} \\ \rowsep \defnlibxname{cpp_lib_to_chars} & \tcode{201611L} & \tcode{} \\ \rowsep \defnlibxname{cpp_lib_transformation_trait_aliases} & \tcode{201304L} & @@ -2116,13 +2153,8 @@ \grammarterm{new-expression}\iref{expr.new} to allocate \tcode{size} bytes of storage. -The second form is called for a type with new-extended alignment, -and allocates storage -with the specified alignment. -The first form is called otherwise, -and allocates storage -suitably aligned to represent any object of that size -provided the object's type does not have new-extended alignment. +The second form is called for a type with new-extended alignment, and +the first form is called otherwise. \pnum \replaceable @@ -2387,13 +2419,8 @@ \grammarterm{new-expression}\iref{expr.new} to allocate \tcode{size} bytes of storage. -The second form is called for a type with new-extended alignment, -and allocates storage -with the specified alignment. -The first form is called otherwise, -and allocates storage -suitably aligned to represent any array object of that size or smaller, -provided the object's type does not have new-extended alignment.% +The second form is called for a type with new-extended alignment, and +the first form is called otherwise.% \footnote{It is not the direct responsibility of \tcode{operator new[]} or @@ -2998,7 +3025,6 @@ public: virtual ~type_info(); bool operator==(const type_info& rhs) const noexcept; - bool operator!=(const type_info& rhs) const noexcept; bool before(const type_info& rhs) const noexcept; size_t hash_code() const noexcept; const char* name() const noexcept; @@ -3035,17 +3061,6 @@ if the two values describe the same type. \end{itemdescr} -\indexlibrarymember{operator"!=}{type_info}% -\begin{itemdecl} -bool operator!=(const type_info& rhs) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{!(*this == rhs)}. -\end{itemdescr} - \indexlibrarymember{before}{type_info}% \begin{itemdecl} bool before(const type_info& rhs) const noexcept; @@ -3166,97 +3181,212 @@ An \impldef{return value of \tcode{bad_typeid::what}} \ntbs{}. \end{itemdescr} -\rSec1[support.contract]{Contract violation handling} +\rSec1[support.srcloc]{Class \tcode{source_location}} + +The header \tcode{} defines the class \tcode{source_location} that provides a means to obtain source location information. -\rSec2[contract.syn]{Header \tcode{} synopsis} +\rSec2[source_location.syn]{Header \tcode{} synopsis} +\indexhdr{source_location}% +\indexlibrary{\idxcode{source_location}}% -The header \tcode{} defines a type -for reporting information about contract violations -generated by the implementation. \begin{codeblock} namespace std { - class contract_violation; -} -\end{codeblock} + struct source_location { + // source location construction + static consteval source_location current() noexcept; + constexpr source_location() noexcept; -\rSec2[support.contract.cviol]{Class \tcode{contract_violation}} -\indexlibrary{\idxcode{contract_violation}}% + // source location field access + constexpr uint_least32_t line() const noexcept; + constexpr uint_least32_t column() const noexcept; + constexpr const char* file_name() const noexcept; + constexpr const char* function_name() const noexcept; -\begin{codeblock} -namespace std { - class contract_violation { - public: - uint_least32_t line_number() const noexcept; - string_view file_name() const noexcept; - string_view function_name() const noexcept; - string_view comment() const noexcept; - string_view assertion_level() const noexcept; + private: + uint_least32_t line_; // \expos + uint_least32_t column_; // \expos + const char* file_name_; // \expos + const char* function_name_; // \expos }; } \end{codeblock} \pnum -The class \tcode{contract_violation} describes information about -a contract violation generated by the implementation. +The type \tcode{source_location} meets the +\oldconcept{DefaultConstructible}, +\oldconcept{CopyConstructible}, +\oldconcept{Copy\-Assignable}, and +\oldconcept{Destructible} +requirements\iref{utility.arg.requirements}. +Lvalues of type \tcode{source_location} +are swappable\iref{swappable.requirements}. +All of the following conditions are \tcode{true}: +\begin{itemize} +\item \tcode{is_nothrow_move_constructible_v} +\item \tcode{is_nothrow_move_assignable_v} +\item \tcode{is_nothrow_swappable_v} +\end{itemize} +\begin{note} +The intent of \tcode{source_location} is +to have a small size and efficient copying. +\end{note} + +\pnum +The data members \tcode{file_name_} and \tcode{function_name_} +always each refer to an \ntbs{}. + +\pnum +The copy/move constructors and the copy/move assignment operators of +\tcode{source_location} meet the following postconditions: +Given two objects \tcode{lhs} and \tcode{rhs} of type \tcode{source_location}, +where \tcode{lhs} is a copy/move result of \tcode{rhs}, and +where \tcode{rhs_p} is a value denoting the state of \tcode{rhs} +before the corresponding copy/move operation, +then each of the following conditions is \tcode{true}: +\begin{itemize} +\item \tcode{strcmp(lhs.file_name(), rhs_p.file_name()) == 0} +\item \tcode{strcmp(lhs.function_name(), rhs_p.function_name()) == 0} +\item \tcode{lhs.line() == rhs_p.line()} +\item \tcode{lhs.column() == rhs_p.column()} +\end{itemize} + +\rSec2[support.srcloc.cons]{Creation} -\indexlibrarymember{line_number}{contract_violation}% \begin{itemdecl} -uint_least32_t line_number() const noexcept; +static consteval source_location current() noexcept; \end{itemdecl} - \begin{itemdescr} \pnum -\returns The source code location -where the contract violation happened\iref{dcl.attr.contract}. -If the location is unknown, an implementation may return \tcode{0}. +\returns +\begin{itemize} +\item + When invoked by a function call + whose \grammarterm{postfix-expression} is + a (possibly parenthesized) \grammarterm{id-expression} naming \tcode{current}, + returns a \tcode{source_location} with an implementation-defined value. + The value should be affected by \tcode{\#line}\iref{cpp.line} + in the same manner as for \mname{LINE} and \mname{FILE}. + The values of the exposition-only data members + of the returned \tcode{source_location} object + are indicated in \tref{support.srcloc.current}. + +\begin{libefftabvalue} + {Value of object returned by \tcode{current}} + {support.srcloc.current} +\tcode{line_} & + A presumed line number\iref{cpp.predefined}. + Line numbers are presumed to be 1-indexed; + however, an implementation is encouraged to use 0 + when the line number is unknown. \\ \rowsep +\tcode{column_} & + An implementation-defined value denoting + some offset from the start of the line denoted by \tcode{line_}. + Column numbers are presumed to be 1-indexed; + however, an implementation is encouraged to use 0 + when the column number is unknown. \\ \rowsep +\tcode{file_name_} & + A presumed name of the current source file\iref{cpp.predefined} as an \ntbs{}. + \\ \rowsep +\tcode{function_name_} & + A name of the current function + such as in \mname{func}\iref{dcl.fct.def.general} if any, + an empty string otherwise. \\ +\end{libefftabvalue} + +\item + Otherwise, when invoked in some other way, returns a + \tcode{source_location} whose data members are initialized + with valid but unspecified values. +\end{itemize} + +\pnum +\remarks +When a default member initializer +is used to initialize a non-static data member, +any calls to \tcode{current} should correspond to the location +of the constructor or aggregate initialization that initializes the member. + +\pnum +\begin{note} +When used as a default argument\iref{dcl.fct.default}, +the value of the \tcode{source_location} will be +the location of the call to \tcode{current} at the call site. +\end{note} \end{itemdescr} -\indexlibrarymember{file_name}{contract_violation}% +\pnum +\begin{example} +\begin{codeblock} +struct s { + source_location member = source_location::current(); + int other_member; + s(source_location loc = source_location::current()) + : member(loc) // values of \tcode{member} refer to the location of the calling function\iref{dcl.fct.default} + {} + s(int blather) : // values of \tcode{member} refer to this location + other_member(blather) + {} + s(double) // values of \tcode{member} refer to this location + {} +}; +void f(source_location a = source_location::current()) { + source_location b = source_location::current(); // values in \tcode{b} refer to this line +} + +void g() { + f(); // \tcode{f}'s first argument corresponds to this line of code + + source_location c = source_location::current(); + f(c); // \tcode{f}'s first argument gets the same values as \tcode{c}, above +} +\end{codeblock} +\end{example} + \begin{itemdecl} -string_view file_name() const noexcept; +constexpr source_location() noexcept; \end{itemdecl} - \begin{itemdescr} + \pnum -\returns The source file name -where the contract violation happened\iref{dcl.attr.contract}. -If the file name is unknown, -an implementation may return \tcode{string_view\{\}}. +\Fundesc{Effects} +The data members are initialized with valid but unspecified values. \end{itemdescr} -\indexlibrarymember{function_name}{contract_violation}% +\rSec2[support.srcloc.access]{Field access} + \begin{itemdecl} -string_view function_name() const noexcept; +constexpr uint_least32_t line() const noexcept; \end{itemdecl} - \begin{itemdescr} \pnum -\returns The name of the function -where the contract violation happened\iref{dcl.attr.contract}. -If the function name is unknown, -an implementation may return \tcode{string_view\{\}}. +\returns \tcode{line_}. \end{itemdescr} -\indexlibrarymember{comment}{contract_violation}% \begin{itemdecl} -string_view comment() const noexcept; +constexpr uint_least32_t column() const noexcept; \end{itemdecl} - \begin{itemdescr} \pnum -\returns Implementation-defined text describing -the predicate of the violated contract. +\returns +\tcode{column_}. \end{itemdescr} -\indexlibrarymember{assertion_level}{contract_violation}% \begin{itemdecl} -string_view assertion_level() const noexcept; +constexpr const char* file_name() const noexcept; \end{itemdecl} +\begin{itemdescr} +\pnum +\returns +\tcode{file_name_}. +\end{itemdescr} +\begin{itemdecl} +constexpr const char* function_name() const noexcept; +\end{itemdecl} \begin{itemdescr} \pnum -\returns Text describing the \grammarterm{assertion-level} -of the violated contract. +\returns +\tcode{function_name_}. \end{itemdescr} \rSec1[support.exception]{Exception handling} @@ -3891,12 +4021,30 @@ template using common_comparison_category_t = typename common_comparison_category::type; + // \ref{cmp.concept}, concept \libconcept{three_way_comparable} + template + concept three_way_comparable = @\seebelow@; + template + concept three_way_comparable_with = @\seebelow@; + + // \ref{cmp.result}, result of three-way comparison + template struct compare_three_way_result; + + template + using compare_three_way_result_t = typename compare_three_way_result::type; + + // \ref{cmp.object}, class \tcode{compare_three_way} + struct compare_three_way; + // \ref{cmp.alg}, comparison algorithms - template constexpr strong_ordering strong_order(const T& a, const T& b); - template constexpr weak_ordering weak_order(const T& a, const T& b); - template constexpr partial_ordering partial_order(const T& a, const T& b); - template constexpr strong_equality strong_equal(const T& a, const T& b); - template constexpr weak_equality weak_equal(const T& a, const T& b); + inline namespace @\unspec@ { + inline constexpr @\unspec@ strong_order = @\unspec@; + inline constexpr @\unspec@ weak_order = @\unspec@; + inline constexpr @\unspec@ partial_order = @\unspec@; + inline constexpr @\unspec@ compare_strong_order_fallback = @\unspec@; + inline constexpr @\unspec@ compare_weak_order_fallback = @\unspec@; + inline constexpr @\unspec@ compare_partial_order_fallback = @\unspec@; + } } \end{codeblock} @@ -3975,9 +4123,7 @@ // comparisons friend constexpr bool operator==(weak_equality v, @\unspec@) noexcept; - friend constexpr bool operator!=(weak_equality v, @\unspec@) noexcept; - friend constexpr bool operator==(@\unspec@, weak_equality v) noexcept; - friend constexpr bool operator!=(@\unspec@, weak_equality v) noexcept; + friend constexpr bool operator==(weak_equality v, weak_equality w) noexcept = default; friend constexpr weak_equality operator<=>(weak_equality v, @\unspec@) noexcept; friend constexpr weak_equality operator<=>(@\unspec@, weak_equality v) noexcept; }; @@ -3991,7 +4137,6 @@ \indexlibrarymember{operator==}{weak_equality}% \begin{itemdecl} constexpr bool operator==(weak_equality v, @\unspec@) noexcept; -constexpr bool operator==(@\unspec@, weak_equality v) noexcept; \end{itemdecl} \begin{itemdescr} @@ -4000,18 +4145,6 @@ \tcode{v.value == 0}. \end{itemdescr} -\indexlibrarymember{operator"!=}{weak_equality}% -\begin{itemdecl} -constexpr bool operator!=(weak_equality v, @\unspec@) noexcept; -constexpr bool operator!=(@\unspec@, weak_equality v) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{v.value != 0}. -\end{itemdescr} - \indexlibrarymember{operator<=>}{weak_equality}% \begin{itemdecl} constexpr weak_equality operator<=>(weak_equality v, @\unspec@) noexcept; @@ -4057,9 +4190,7 @@ // comparisons friend constexpr bool operator==(strong_equality v, @\unspec@) noexcept; - friend constexpr bool operator!=(strong_equality v, @\unspec@) noexcept; - friend constexpr bool operator==(@\unspec@, strong_equality v) noexcept; - friend constexpr bool operator!=(@\unspec@, strong_equality v) noexcept; + friend constexpr bool operator==(strong_equality v, strong_equality w) noexcept = default; friend constexpr strong_equality operator<=>(strong_equality v, @\unspec@) noexcept; friend constexpr strong_equality operator<=>(@\unspec@, strong_equality v) noexcept; }; @@ -4086,7 +4217,6 @@ \indexlibrarymember{operator==}{strong_equality}% \begin{itemdecl} constexpr bool operator==(strong_equality v, @\unspec@) noexcept; -constexpr bool operator==(@\unspec@, strong_equality v) noexcept; \end{itemdecl} \begin{itemdescr} @@ -4095,18 +4225,6 @@ \tcode{v.value == 0}. \end{itemdescr} -\indexlibrarymember{operator"!=}{strong_equality}% -\begin{itemdecl} -constexpr bool operator!=(strong_equality v, @\unspec@) noexcept; -constexpr bool operator!=(@\unspec@, strong_equality v) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{v.value != 0}. -\end{itemdescr} - \indexlibrarymember{operator<=>}{strong_equality}% \begin{itemdecl} constexpr strong_equality operator<=>(strong_equality v, @\unspec@) noexcept; @@ -4160,13 +4278,11 @@ // comparisons friend constexpr bool operator==(partial_ordering v, @\unspec@) noexcept; - friend constexpr bool operator!=(partial_ordering v, @\unspec@) noexcept; + friend constexpr bool operator==(partial_ordering v, partial_ordering w) noexcept = default; friend constexpr bool operator< (partial_ordering v, @\unspec@) noexcept; friend constexpr bool operator> (partial_ordering v, @\unspec@) noexcept; friend constexpr bool operator<=(partial_ordering v, @\unspec@) noexcept; friend constexpr bool operator>=(partial_ordering v, @\unspec@) noexcept; - friend constexpr bool operator==(@\unspec@, partial_ordering v) noexcept; - friend constexpr bool operator!=(@\unspec@, partial_ordering v) noexcept; friend constexpr bool operator< (@\unspec@, partial_ordering v) noexcept; friend constexpr bool operator> (@\unspec@, partial_ordering v) noexcept; friend constexpr bool operator<=(@\unspec@, partial_ordering v) noexcept; @@ -4216,13 +4332,11 @@ For \tcode{operator@}, \tcode{v.is_ordered \&\& v.value @ 0}. \end{itemdescr} -\indexlibrarymember{operator==}{partial_ordering}% \indexlibrarymember{operator<}{partial_ordering}% \indexlibrarymember{operator>}{partial_ordering}% \indexlibrarymember{operator<=}{partial_ordering}% \indexlibrarymember{operator>=}{partial_ordering}% \begin{itemdecl} -constexpr bool operator==(@\unspec@, partial_ordering v) noexcept; constexpr bool operator< (@\unspec@, partial_ordering v) noexcept; constexpr bool operator> (@\unspec@, partial_ordering v) noexcept; constexpr bool operator<=(@\unspec@, partial_ordering v) noexcept; @@ -4235,18 +4349,6 @@ For \tcode{operator@}, \tcode{v.is_ordered \&\& 0 @ v.value}. \end{itemdescr} -\indexlibrarymember{operator"!=}{partial_ordering}% -\begin{itemdecl} -constexpr bool operator!=(partial_ordering v, @\unspec@) noexcept; -constexpr bool operator!=(@\unspec@, partial_ordering v) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -For \tcode{operator@}, \tcode{!v.is_ordered || v.value != 0}. -\end{itemdescr} - \indexlibrarymember{operator<=>}{partial_ordering}% \begin{itemdecl} constexpr partial_ordering operator<=>(partial_ordering v, @\unspec@) noexcept; @@ -4302,13 +4404,11 @@ // comparisons friend constexpr bool operator==(weak_ordering v, @\unspec@) noexcept; - friend constexpr bool operator!=(weak_ordering v, @\unspec@) noexcept; + friend constexpr bool operator==(weak_ordering v, weak_ordering w) noexcept = default; friend constexpr bool operator< (weak_ordering v, @\unspec@) noexcept; friend constexpr bool operator> (weak_ordering v, @\unspec@) noexcept; friend constexpr bool operator<=(weak_ordering v, @\unspec@) noexcept; friend constexpr bool operator>=(weak_ordering v, @\unspec@) noexcept; - friend constexpr bool operator==(@\unspec@, weak_ordering v) noexcept; - friend constexpr bool operator!=(@\unspec@, weak_ordering v) noexcept; friend constexpr bool operator< (@\unspec@, weak_ordering v) noexcept; friend constexpr bool operator> (@\unspec@, weak_ordering v) noexcept; friend constexpr bool operator<=(@\unspec@, weak_ordering v) noexcept; @@ -4351,14 +4451,12 @@ \end{itemdescr} \indexlibrarymember{operator==}{weak_ordering}% -\indexlibrarymember{operator"!=}{weak_ordering}% \indexlibrarymember{operator<}{weak_ordering}% \indexlibrarymember{operator>}{weak_ordering}% \indexlibrarymember{operator<=}{weak_ordering}% \indexlibrarymember{operator>=}{weak_ordering}% \begin{itemdecl} constexpr bool operator==(weak_ordering v, @\unspec@) noexcept; -constexpr bool operator!=(weak_ordering v, @\unspec@) noexcept; constexpr bool operator< (weak_ordering v, @\unspec@) noexcept; constexpr bool operator> (weak_ordering v, @\unspec@) noexcept; constexpr bool operator<=(weak_ordering v, @\unspec@) noexcept; @@ -4371,15 +4469,11 @@ \tcode{v.value @ 0} for \tcode{operator@}. \end{itemdescr} -\indexlibrarymember{operator==}{weak_ordering}% -\indexlibrarymember{operator"!=}{weak_ordering}% \indexlibrarymember{operator<}{weak_ordering}% \indexlibrarymember{operator>}{weak_ordering}% \indexlibrarymember{operator<=}{weak_ordering}% \indexlibrarymember{operator>=}{weak_ordering}% \begin{itemdecl} -constexpr bool operator==(@\unspec@, weak_ordering v) noexcept; -constexpr bool operator!=(@\unspec@, weak_ordering v) noexcept; constexpr bool operator< (@\unspec@, weak_ordering v) noexcept; constexpr bool operator> (@\unspec@, weak_ordering v) noexcept; constexpr bool operator<=(@\unspec@, weak_ordering v) noexcept; @@ -4451,13 +4545,11 @@ // comparisons friend constexpr bool operator==(strong_ordering v, @\unspec@) noexcept; - friend constexpr bool operator!=(strong_ordering v, @\unspec@) noexcept; + friend constexpr bool operator==(strong_ordering v, strong_ordering w) noexcept = default; friend constexpr bool operator< (strong_ordering v, @\unspec@) noexcept; friend constexpr bool operator> (strong_ordering v, @\unspec@) noexcept; friend constexpr bool operator<=(strong_ordering v, @\unspec@) noexcept; friend constexpr bool operator>=(strong_ordering v, @\unspec@) noexcept; - friend constexpr bool operator==(@\unspec@, strong_ordering v) noexcept; - friend constexpr bool operator!=(@\unspec@, strong_ordering v) noexcept; friend constexpr bool operator< (@\unspec@, strong_ordering v) noexcept; friend constexpr bool operator> (@\unspec@, strong_ordering v) noexcept; friend constexpr bool operator<=(@\unspec@, strong_ordering v) noexcept; @@ -4527,14 +4619,12 @@ \end{itemdescr} \indexlibrarymember{operator==}{strong_ordering}% -\indexlibrarymember{operator"!=}{strong_ordering}% \indexlibrarymember{operator<}{strong_ordering}% \indexlibrarymember{operator>}{strong_ordering}% \indexlibrarymember{operator<=}{strong_ordering}% \indexlibrarymember{operator>=}{strong_ordering}% \begin{itemdecl} constexpr bool operator==(strong_ordering v, @\unspec@) noexcept; -constexpr bool operator!=(strong_ordering v, @\unspec@) noexcept; constexpr bool operator< (strong_ordering v, @\unspec@) noexcept; constexpr bool operator> (strong_ordering v, @\unspec@) noexcept; constexpr bool operator<=(strong_ordering v, @\unspec@) noexcept; @@ -4547,15 +4637,11 @@ \tcode{v.value @ 0} for \tcode{operator@}. \end{itemdescr} -\indexlibrarymember{operator==}{strong_ordering}% -\indexlibrarymember{operator"!=}{strong_ordering}% \indexlibrarymember{operator<}{strong_ordering}% \indexlibrarymember{operator>}{strong_ordering}% \indexlibrarymember{operator<=}{strong_ordering}% \indexlibrarymember{operator>=}{strong_ordering}% \begin{itemdecl} -constexpr bool operator==(@\unspec@, strong_ordering v) noexcept; -constexpr bool operator!=(@\unspec@, strong_ordering v) noexcept; constexpr bool operator< (@\unspec@, strong_ordering v) noexcept; constexpr bool operator> (@\unspec@, strong_ordering v) noexcept; constexpr bool operator<=(@\unspec@, strong_ordering v) noexcept; @@ -4623,183 +4709,431 @@ \end{note} \end{itemdescr} -\rSec2[cmp.alg]{Comparison algorithms} +\rSec2[cmp.concept]{Concept \tcode{three_way_comparable}} -\indexlibrary{\idxcode{strong_order}}% -\begin{itemdecl} -template constexpr strong_ordering strong_order(const T& a, const T& b); -\end{itemdecl} +\begin{codeblock} +template + concept @\placeholder{compares-as}@ = // \expos + same_as, Cat>; + +template + concept @\placeholder{partially-ordered-with}@ = // \expos + requires(const remove_reference_t& t, const remove_reference_t& u) { + { t < u } -> boolean; + { t > u } -> boolean; + { t <= u } -> boolean; + { t >= u } -> boolean; + { u < t } -> boolean; + { u > t } -> boolean; + { u <= t } -> boolean; + { u >= t } -> boolean; + }; +\end{codeblock} -\begin{itemdescr} \pnum -\effects -Compares two values and produces a result of type \tcode{strong_ordering}: - +Let \tcode{t} and \tcode{u} be +lvalues of types \tcode{const remove_reference_t} and +\tcode{const remove_reference_t}, respectively. +\tcode{T} and \tcode{U} model +\tcode{\placeholder{partially-ordered-with}} only if: \begin{itemize} \item -If \tcode{numeric_limits::is_iec559} is \tcode{true}, -returns a result of type \tcode{strong_ordering} -that is consistent with the \tcode{totalOrder} operation -as specified in ISO/IEC/IEEE 60559. + \tcode{t < u}, + \tcode{t <= u}, + \tcode{t > u}, + \tcode{t >= u}, + \tcode{u < t}, + \tcode{u <= t}, + \tcode{u > t}, and + \tcode{u >= t} + have the same domain. \item -Otherwise, returns \tcode{a <=> b} -if that expression is well-formed and -convertible to \tcode{strong_ordering}. + \tcode{bool(t < u) == bool(u > t)} is \tcode{true}, \item -Otherwise, if the expression \tcode{a <=> b} is well-formed, -then the function is defined as deleted. + \tcode{bool(u < t) == bool(t > u)} is \tcode{true}, \item -Otherwise, if the expressions \tcode{a == b} and \tcode{a < b} -are each well-formed and convertible to \tcode{bool}, then + \tcode{bool(t <= u) == bool(u >= t)} is \tcode{true}, and +\item + \tcode{bool(u <= t) == bool(t >= u)} is \tcode{true}. +\end{itemize} + +\indexlibrary{\idxcode{three_way_comparable}}% +\begin{codeblock} +template + concept three_way_comparable = + @\placeholder{weakly-equality-comparable-with}@ && + (!convertible_to || @\placeholder{partially-ordered-with}@) && + requires(const remove_reference_t& a, const remove_reference_t& b) { + { a <=> b } -> @\placeholder{compares-as}@; + }; +\end{codeblock} + +\pnum +Let \tcode{a} and \tcode{b} be lvalues +of type \tcode{const remove_reference_t}. +\tcode{T} and \tcode{Cat} +model \tcode{\libconcept{three_way_comparable}} only if: \begin{itemize} \item -if \tcode{a == b} is \tcode{true}, -returns \tcode{strong_ordering::equal}; + \tcode{(a <=> b == 0) == bool(a == b)} is \tcode{true}; \item -otherwise, if \tcode{a < b} is \tcode{true}, -returns \tcode{strong_ordering::less}; + \tcode{(a <=> b != 0) == bool(a != b)} is \tcode{true}; \item -otherwise, -returns \tcode{strong_ordering::greater}. -\end{itemize} + \tcode{((a <=> b) <=> 0)} and \tcode{(0 <=> (b <=> a))} are equal; +\item + if \tcode{Cat} is convertible to \tcode{strong_equality}, \tcode{T} models + \libconcept{equality_comparable}\iref{concept.equalitycomparable}; \item -Otherwise, the function is defined as deleted. + if \tcode{Cat} is convertible to \tcode{partial_ordering}: + \begin{itemize} + \item + \tcode{(a <=> b < 0) == bool(a < b)} is \tcode{true}, + \item + \tcode{(a <=> b > 0) == bool(a > b)} is \tcode{true}, + \item + \tcode{(a <=> b <= 0) == bool(a <= b)} is \tcode{true}, and + \item + \tcode{(a <=> b >= 0) == bool(a >= b)} is \tcode{true}; and + \end{itemize} +\item + If \tcode{Cat} is convertible to \tcode{strong_ordering}, \tcode{T} models + \libconcept{totally_ordered}\iref{concept.totallyordered}. \end{itemize} -\end{itemdescr} -\indexlibrary{\idxcode{weak_order}}% -\begin{itemdecl} -template constexpr weak_ordering weak_order(const T& a, const T& b); -\end{itemdecl} +\indexlibrary{\idxcode{three_way_comparable_with}}% +\begin{codeblock} +template + concept three_way_comparable_with = + @\placeholder{weakly-equality-comparable-with}@ && + (!convertible_to || @\placeholder{partially-ordered-with}@) && + three_way_comparable && + three_way_comparable && + common_reference_with&, const remove_reference_t&> && + three_way_comparable< + common_reference_t&, const remove_reference_t&>, Cat> && + requires(const remove_reference_t& t, const remove_reference_t& u) { + { t <=> u } -> @\placeholder{compares-as}@; + { u <=> t } -> @\placeholder{compares-as}@; + }; +\end{codeblock} -\begin{itemdescr} \pnum -\effects -Compares two values and produces a result of type \tcode{weak_ordering}: - +Let \tcode{t} and \tcode{u} be lvalues +of types \tcode{const remove_reference_t} and +\tcode{const remove_reference_t}, respectively. +Let \tcode{C} be +\tcode{common_reference_t\&, const remove_reference_t\&>}. +\tcode{T}, \tcode{U}, and \tcode{Cat} +model \tcode{\libconcept{three_way_comparable_with}} only if: \begin{itemize} \item -Returns \tcode{a <=> b} if that expression is well-formed and -convertible to \tcode{weak_ordering}. + \tcode{t <=> u} and \tcode{u <=> t} have the same domain; \item -Otherwise, if the expression \tcode{a <=> b} is well-formed, -then the function is defined as deleted. + \tcode{((t <=> u) <=> 0)} and \tcode{(0 <=> (u <=> t))} are equal; \item -Otherwise, if the expressions \tcode{a == b} and \tcode{a < b} -are each well-formed and convertible to \tcode{bool}, then -\begin{itemize} + \tcode{(t <=> u == 0) == bool(t == u)} is \tcode{true}; \item -if \tcode{a == b} is \tcode{true}, -returns \tcode{weak_ordering::equivalent}; + \tcode{(t <=> u != 0) == bool(t != u)} is \tcode{true}; \item -otherwise, if \tcode{a < b} is \tcode{true}, -returns \tcode{weak_ordering::less}; + \tcode{Cat(t <=> u) == Cat(C(t) <=> C(u))} is \tcode{true}; \item -otherwise, returns \tcode{weak_ordering::greater}. -\end{itemize} + if \tcode{Cat} is convertible to \tcode{strong_equality}, + \tcode{T} and \tcode{U} model + \tcode{\libconcept{equality_comparable_with}}\iref{concept.equalitycomparable}; +\item + if \tcode{Cat} is convertible to \tcode{partial_ordering}: + \begin{itemize} + \item + \tcode{(t <=> u < 0) == bool(t < u)} is \tcode{true}, + \item + \tcode{(t <=> u > 0) == bool(t > u)} is \tcode{true}, + \item + \tcode{(t <=> u <= 0) == bool(t <= u)} is \tcode{true}, + \item + \tcode{(t <=> u >= 0) == bool(t >= u)} is \tcode{true}; and + \end{itemize} \item -Otherwise, the function is defined as deleted. + if \tcode{Cat} is convertible to \tcode{strong_ordering}, + \tcode{T} and \tcode{U} model + \tcode{\libconcept{totally_ordered_with}}\iref{concept.totallyordered}. \end{itemize} -\end{itemdescr} -\indexlibrary{\idxcode{partial_order}}% +\rSec2[cmp.result]{Result of three-way comparison} + +\pnum +The behavior of a program +that adds specializations for the \tcode{compare_three_way_result} template +defined in this subclause is undefined. + +\pnum +For the \tcode{compare_three_way_result} type trait +applied to the types \tcode{T} and \tcode{U}, +let \tcode{t} and \tcode{u} denote lvalues of types +\tcode{const remove_reference_t} and \tcode{const remove_reference_t}, +respectively. +If the expression \tcode{t <=> u} is well-formed +when treated as an unevaluated operand\iref{expr.context}, +the member \grammarterm{typedef-name} \tcode{type} +denotes the type \tcode{decltype(t <=> u)}. +Otherwise, there is no member \tcode{type}. + +\rSec2[cmp.object]{Class \tcode{compare_three_way}} + +\pnum +In this subclause, \tcode{\placeholdernc{BUILTIN-PTR-THREE-WAY}(T, U)} +for types \tcode{T} and \tcode{U} is a boolean constant expression. +\tcode{\placeholdernc{BUILTIN-PTR-THREE-WAY}(T, U)} is \tcode{true} +if and only if \tcode{<=>} in the expression +\begin{codeblock} +declval() <=> declval() +\end{codeblock} +resolves to a built-in operator comparing pointers. + +\indexlibrary{\idxcode{compare_three_way}}% +\begin{codeblock} +struct compare_three_way { + template + requires three_way_comparable_with || @\placeholdernc{BUILTIN-PTR-THREE-WAY}@(T, U) + constexpr auto operator()(T&& t, U&& u) const; + + using is_transparent = @\unspec@; +}; +\end{codeblock} + +\pnum +In addition to being available via inclusion of the \tcode{} header, +the class \tcode{compare_three_way} is available +when the header \tcode{} is included. + \begin{itemdecl} -template constexpr partial_ordering partial_order(const T& a, const T& b); +template + requires three_way_comparable_with || @\placeholdernc{BUILTIN-PTR-THREE-WAY}@(T, U) +constexpr auto operator()(T&& t, U&& u) const; \end{itemdecl} \begin{itemdescr} +\pnum +\expects +If the expression \tcode{std::forward(t) <=> std::forward(u)} results in +a call to a built-in operator \tcode{<=>} comparing pointers of type \tcode{P}, +the conversion sequences from both \tcode{T} and \tcode{U} to \tcode{P} +are equality-preserving\iref{concepts.equality}. + \pnum \effects -Compares two values and produces a result of type \tcode{partial_ordering}: +\begin{itemize} +\item + If the expression \tcode{std::forward(t) <=> std::forward(u)} results in + a call to a built-in operator \tcode{<=>} comparing pointers of type \tcode{P}, + returns \tcode{strong_ordering::less} + if (the converted value of) \tcode{t} precedes \tcode{u} + in the implementation-defined strict total order\iref{range.cmp} + over pointers of type \tcode{P}, + \tcode{strong_ordering::greater} + if \tcode{u} precedes \tcode{t}, and + otherwise \tcode{strong_ordering::equal}. +\item + Otherwise, equivalent to: \tcode{return std::forward(t) <=> std::forward(u);} +\end{itemize} +\end{itemdescr} + +\rSec2[cmp.alg]{Comparison algorithms} +\indexlibrary{\idxcode{strong_order}}% +\pnum +The name \tcode{strong_order} denotes +a customization point object\iref{customization.point.object}. +The expression \tcode{strong_order(E, F)} +for some subexpressions \tcode{E} and \tcode{F} +is expression-equivalent\iref{defns.expression-equivalent} to the following: \begin{itemize} \item -Returns \tcode{a <=> b} if that expression is well-formed and -convertible to \tcode{partial_ordering}. + If the decayed types of \tcode{E} and \tcode{F} differ, + \tcode{strong_order(E, F)} is ill-formed. +\item + Otherwise, \tcode{strong_ordering(strong_order(E, F))} + if it is a well-formed expression + with overload resolution performed in a context + that does not include a declaration of \tcode{std::strong_order}. +\item + Otherwise, if the decayed type \tcode{T} of \tcode{E} is + a floating-point type, + yields a value of type \tcode{strong_ordering} + that is consistent with the ordering + observed by \tcode{T}'s comparison operators, and + if \tcode{numeric_limits::is_iec559} is \tcode{true}, + is additionally consistent with the \tcode{totalOrder} operation + as specified in ISO/IEC/IEEE 60599. \item -Otherwise, if the expression \tcode{a <=> b} is well-formed, -then the function is defined as deleted. + Otherwise, \tcode{strong_ordering(E <=> F)} if it is a well-formed expression. \item -Otherwise, if the expressions \tcode{a == b} and \tcode{a < b} -are each well-formed and convertible to \tcode{bool}, then + Otherwise, \tcode{strong_order(E, F)} is ill-formed. + \begin{note} + This case can result in substitution failure + when \tcode{strong_order(E, F)} appears in the immediate context + of a template instantiation. + \end{note} +\end{itemize} + +\indexlibrary{\idxcode{weak_order}}% +\pnum +The name \tcode{weak_order} denotes +a customization point object\iref{customization.point.object}. +The expression \tcode{weak_order(E, F)} +for some subexpressions \tcode{E} and \tcode{F} +is expression-equivalent\iref{defns.expression-equivalent} to the following: \begin{itemize} \item -if \tcode{a == b} is \tcode{true}, -returns \tcode{partial_ordering::equivalent}; + If the decayed types of \tcode{E} and \tcode{F} differ, + \tcode{weak_order(E, F)} is ill-formed. \item -otherwise, if \tcode{a < b} is \tcode{true}, -returns \tcode{partial_ordering::less}; + Otherwise, \tcode{weak_ordering(weak_order(E, F))} + if it is a well-formed expression + with overload resolution performed in a context + that does not include a declaration of \tcode{std::weak_order}. \item -otherwise, returns \tcode{partial_ordering::greater}. -\end{itemize} + Otherwise, if the decayed type \tcode{T} of \tcode{E} + is a floating-point type, + yields a value of type \tcode{weak_ordering} + that is consistent with the ordering + observed by \tcode{T}'s comparison operators and \tcode{strong_order}, and + if \tcode{numeric_limits::is_iec559} is \tcode{true}, + is additionally consistent with the following equivalence classes, + ordered from lesser to greater: + \begin{itemize} + \item together, all negative NaN values; + \item negative infinity; + \item each normal negative value; + \item each subnormal negative value; + \item together, both zero values; + \item each subnormal positive value; + \item each normal positive value; + \item positive infinity; + \item together, all positive NaN values. + \end{itemize} +\item + Otherwise, \tcode{weak_ordering(E <=> F)} if it is a well-formed expression. +\item + Otherwise, \tcode{weak_ordering(strong_order(E, F))} + if it is a well-formed expression. \item -Otherwise, the function is defined as deleted. + Otherwise, \tcode{weak_order(E, F)} is ill-formed. + \begin{note} + This case can result in substitution failure + when \tcode{std::weak_order(E, F)} appears in the immediate context + of a template instantiation. + \end{note} \end{itemize} -\end{itemdescr} -\indexlibrary{\idxcode{strong_equal}}% -\begin{itemdecl} -template constexpr strong_equality strong_equal(const T& a, const T& b); -\end{itemdecl} - -\begin{itemdescr} +\indexlibrary{\idxcode{partial_order}}% \pnum -\effects -Compares two values and produces a result of type \tcode{strong_equality}: - +The name \tcode{partial_order} denotes +a customization point object\iref{customization.point.object}. +The expression \tcode{partial_order(E, F)} +for some subexpressions \tcode{E} and \tcode{F} +is expression-equivalent\iref{defns.expression-equivalent} to the following: \begin{itemize} \item -Returns \tcode{a <=> b} if that expression is well-formed and -convertible to \tcode{strong_equality}. + If the decayed types of \tcode{E} and \tcode{F} differ, + \tcode{partial_order(E, F)} is ill-formed. \item -Otherwise, if the expression \tcode{a <=> b} is well-formed, -then the function is defined as deleted. + Otherwise, \tcode{partial_ordering(partial_order(E, F))} + if it is a well-formed expression + with overload resolution performed in a context + that does not include a declaration of \tcode{std::partial_order}. \item -Otherwise, if the expression \tcode{a == b} -is well-formed and convertible to \tcode{bool}, then -\begin{itemize} + Otherwise, \tcode{partial_ordering(E <=> F)} + if it is a well-formed expression. \item -if \tcode{a == b} is \tcode{true}, -returns \tcode{strong_equality::equal}; + Otherwise, \tcode{partial_ordering(weak_order(E, F))} + if it is a well-formed expression. \item -otherwise, returns \tcode{strong_equality::nonequal}. + Otherwise, \tcode{partial_order(E, F)} is ill-formed. + \begin{note} + This case can result in substitution failure + when \tcode{std::partial_order(E, F)} + appears in the immediate context of a template instantiation. +\end{note} \end{itemize} + +\indexlibrary{\idxcode{compare_strong_order_fallback}}% +\pnum +The name \tcode{compare_strong_order_fallback} +denotes a customization point object\iref{customization.point.object}. +The expression \tcode{compare_strong_order_fallback(E, F)} +for some subexpressions \tcode{E} and {F} +is expression-equivalent\iref{defns.expression-equivalent} to: +\begin{itemize} +\item + If the decayed types of \tcode{E} and \tcode{F} differ, + \tcode{compare_strong_order_fallback(E, F)} is ill-formed. +\item + Otherwise, \tcode{strong_order(E, F)} if it is a well-formed expression. +\item + Otherwise, if the expressions \tcode{E == F} and \tcode{E < F} + are both well-formed and convertible to \tcode{bool}, +\begin{codeblock} +E == F ? strong_ordering::equal : +E < F ? strong_ordering::less : + strong_ordering::greater +\end{codeblock} +except that \tcode{E} and \tcode{F} are evaluated only once. \item -Otherwise, the function is defined as deleted. +Otherwise, \tcode{compare_strong_order_fallback(E, F)} is ill-formed. \end{itemize} -\end{itemdescr} -\indexlibrary{\idxcode{weak_equal}}% -\begin{itemdecl} -template constexpr weak_equality weak_equal(const T& a, const T& b); -\end{itemdecl} - -\begin{itemdescr} +\indexlibrary{\idxcode{compare_weak_order_fallback}}% \pnum -\effects -Compares two values and produces a result of type \tcode{weak_equality}: - +The name \tcode{compare_weak_order_fallback} denotes +a customization point object\iref{customization.point.object}. +The expression \tcode{compare_weak_order_fallback(E, F)} +for some subexpressions \tcode{E} and \tcode{F} +is expression-equivalent\iref{defns.expression-equivalent} to: \begin{itemize} \item -Returns \tcode{a <=> b} if that expression is well-formed and -convertible to \tcode{weak_equality}. + If the decayed types of \tcode{E} and \tcode{F} differ, + \tcode{compare_weak_order_fallback(E, F)} is ill-formed. \item -Otherwise, if the expression \tcode{a <=> b} is well-formed, -then the function is defined as deleted. + Otherwise, \tcode{weak_order(E, F)} if it is a well-formed expression. \item -Otherwise, if the expression \tcode{a == b} -is well-formed and convertible to \tcode{bool}, then + Otherwise, if the expressions \tcode{E == F} and \tcode{E < F} + are both well-formed and convertible to \tcode{bool}, +\begin{codeblock} +E == F ? weak_ordering::equal : +E < F ? weak_ordering::less : + weak_ordering::greater +\end{codeblock} +except that \tcode{E} and \tcode{F} are evaluated only once. +\item + Otherwise, \tcode{compare_weak_order_fallback(E, F)} is ill-formed. +\end{itemize} + +\indexlibrary{\idxcode{compare_partial_order_fallback}}% +\pnum +The name \tcode{compare_partial_order_fallback} denotes +a customization point object\iref{customization.point.object}. +The expression \tcode{compare_partial_order_fallback(E, F)} +for some subexpressions \tcode{E} and \tcode{F} +is expression-equivalent\iref{defns.expression-equivalent} to: \begin{itemize} \item -if \tcode{a == b} is \tcode{true}, -returns \tcode{weak_equality::equivalent}; + If the decayed types of \tcode{E} and \tcode{F} differ, + \tcode{compare_partial_order_fallback(E, F)} is ill-formed. \item -otherwise, returns \tcode{weak_equality::nonequivalent}. -\end{itemize} + Otherwise, \tcode{partial_order(E, F)} if it is a well-formed expression. +\item + Otherwise, if the expressions \tcode{E == F} and \tcode{E < F} + are both well-formed and convertible to \tcode{bool}, +\begin{codeblock} +E == F ? partial_ordering::equivalent : +E < F ? partial_ordering::less : +F < E ? partial_ordering::greater : + partial_ordering::unordered +\end{codeblock} +except that \tcode{E} and \tcode{F} are evaluated only once. \item -Otherwise, the function is defined as deleted. + Otherwise, \tcode{compare_partial_order_fallback(E, F)} is ill-formed. \end{itemize} -\end{itemdescr} \rSec1[support.coroutine]{Coroutines} @@ -4827,11 +5161,7 @@ // \ref{coroutine.handle.compare}, comparison operators constexpr bool operator==(coroutine_handle<> x, coroutine_handle<> y) noexcept; - constexpr bool operator!=(coroutine_handle<> x, coroutine_handle<> y) noexcept; - constexpr bool operator<(coroutine_handle<> x, coroutine_handle<> y) noexcept; - constexpr bool operator>(coroutine_handle<> x, coroutine_handle<> y) noexcept; - constexpr bool operator<=(coroutine_handle<> x, coroutine_handle<> y) noexcept; - constexpr bool operator>=(coroutine_handle<> x, coroutine_handle<> y) noexcept; + constexpr strong_ordering operator<=>(coroutine_handle<> x, coroutine_handle<> y) noexcept; // \ref{coroutine.handle.hash}, hash support template struct hash; @@ -5039,9 +5369,9 @@ Resuming a coroutine via \tcode{resume}, \tcode{operator()}, or \tcode{destroy} on an execution agent other than the one on which it was suspended has implementation-defined behavior unless -each execution agent is either -an instance of \tcode{std::thread} or -the thread that executes \tcode{main}. +each execution agent either is +an instance of \tcode{std::thread} or \tcode{std::jthread}, +or is the thread that executes \tcode{main}. \begin{note} A coroutine that is resumed on a different execution agent should avoid relying on consistent thread identity throughout, such as holding @@ -5107,16 +5437,13 @@ \pnum \returns \tcode{x.address() == y.address()}. \end{itemdescr} -\indexlibrarymember{operator<}{coroutine_handle}% -\indexlibrarymember{operator>}{coroutine_handle}% -\indexlibrarymember{operator<=}{coroutine_handle}% -\indexlibrarymember{operator>=}{coroutine_handle}% +\indexlibrarymember{operator<=>}{coroutine_handle}% \begin{itemdecl} -constexpr bool operator<(coroutine_handle<> x, coroutine_handle<> y) noexcept; +constexpr strong_ordering operator<=>(coroutine_handle<> x, coroutine_handle<> y) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum \returns \tcode{less<>()(x.address(), y.address())}. +\pnum \returns \tcode{compare_three_way()(x.address(), y.address())}. \end{itemdescr} \rSec3[coroutine.handle.hash]{Hash support} diff --git a/source/templates.tex b/source/templates.tex index bf11adf624..1682ce7b19 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -1373,6 +1373,8 @@ \pnum A \grammarterm{template-argument} matches a template \grammarterm{template-parameter} \tcode{P} when \tcode{P} is at least as specialized as the \grammarterm{template-argument} \tcode{A}. +In this comparison, if \tcode{P} is unconstrained, +the constraints on \tcode{A} are not considered. If \tcode{P} contains a template parameter pack, then \tcode{A} also matches \tcode{P} if each of \tcode{A}'s template parameters matches the corresponding template parameter in the @@ -1497,7 +1499,7 @@ \begin{itemize} \item conjunctions\iref{temp.constr.op}, \item disjunctions\iref{temp.constr.op}, and -\item atomic constraints\iref{temp.constr.atomic} +\item atomic constraints\iref{temp.constr.atomic}. \end{itemize} \pnum @@ -1857,7 +1859,7 @@ an atomic constraint $Q_{jb}$ in $Q_j$ such that $P_{ia}$ subsumes $Q_{jb}$, and \item an atomic constraint $A$ subsumes another atomic constraint -$B$ if and only if the $A$ and $B$ are identical using the +$B$ if and only if $A$ and $B$ are identical using the rules described in \ref{temp.constr.atomic}. \end{itemize} % @@ -3586,11 +3588,11 @@ equivalent types, \item if they declare template template parameters, their template parameters are equivalent, and -\item if either is declared with a \grammarterm{qualified-concept-name}, -they both are, and the \grammarterm{qualified-concept-name}{s} are +\item if either is declared with a \grammarterm{type-constraint}, +they both are, and the \grammarterm{type-constraint}{s} are equivalent. \end{itemize} -When determining whether types or \grammarterm{qualified-concept-name}{s} +When determining whether types or \grammarterm{type-constraint}{s} are equivalent, the rules above are used to compare expressions involving template parameters. Two \grammarterm{template-head}{s} are @@ -3829,7 +3831,7 @@ \pnum A \grammarterm{template-declaration} in which the \grammarterm{declaration} is an \grammarterm{alias-declaration}\iref{dcl.dcl} declares the -\grammarterm{identifier} to be an \defn{alias template}. +\grammarterm{identifier} to be an \defnadj{alias}{template}. An alias template is a name for a family of types. The name of the alias template is a \grammarterm{template-name}. @@ -3922,7 +3924,7 @@ \begin{codeblock} template concept C = requires(T x) { - { x == x } -> bool; + { x == x } -> convertible_to; }; template @@ -5084,11 +5086,6 @@ \mname{func}\iref{dcl.fct.def.general}, where any enclosing function is a template, a member of a class template, or a generic lambda, -\item -the \grammarterm{identifier} introduced in -a postcondition\iref{dcl.attr.contract} to represent the result of -a templated function whose declared return type contains a placeholder type, - \item a \grammarterm{template-id} @@ -6426,6 +6423,10 @@ and is an explicit instantiation definition of only those members that have been defined at the point of instantiation. +\pnum +An explicit instantiation of a prospective destructor\iref{class.dtor} +shall name the selected destructor of the class. + \pnum Except for inline functions and variables, declarations with types deduced from their initializer or return value\iref{dcl.spec.auto}, \tcode{const} variables of @@ -6794,14 +6795,6 @@ \end{codeblock} \end{example} -\pnum -\begin{note} -For an explicit specialization of a function template, -the contract conditions\iref{dcl.attr.contract} -of the explicit specialization -are independent of those of the primary template. -\end{note} - \pnum An explicit specialization of a static data member of a template or an explicit specialization of a static data member template is a diff --git a/source/threads.tex b/source/threads.tex index b44121a225..4008063c68 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -11,10 +11,13 @@ \begin{libsumtab}{Thread support library summary}{thread.summary} \ref{thread.req} & Requirements & \\ \rowsep +\ref{thread.stoptoken}& Stop tokens & \tcode{} \\ \rowsep \ref{thread.threads} & Threads & \tcode{} \\ \rowsep \ref{thread.mutex} & Mutual exclusion & \tcode{}, \tcode{} \\ \rowsep \ref{thread.condition}& Condition variables & \tcode{} \\ \rowsep +\ref{thread.sema} & Semaphores & \tcode{} \\ \rowsep +\ref{thread.coord} & Coordination types & \tcode{} \tcode{} \\ \rowsep \ref{futures} & Futures & \tcode{} \\ \end{libsumtab} @@ -272,1820 +275,3240 @@ \returns \tcode{true} if the lock was acquired, \tcode{false} otherwise. \end{itemdescr} -\rSec1[thread.threads]{Threads} +\rSec1[thread.stoptoken]{Stop tokens} -\pnum -\ref{thread.threads} describes components that can be used to create and manage threads. -\begin{note} These threads are intended to map one-to-one with operating system threads. -\end{note} +\rSec2[thread.stoptoken.intro]{Introduction} -\rSec2[thread.syn]{Header \tcode{} synopsis} -\indexhdr{thread}% +\pnum +This clause describes components that can be used +to asynchonously request that an operation stops execution in a timely manner, +typically because the result is no longer required. +Such a request is called a \defn{stop request}. -\begin{codeblock} -namespace std { - class thread; +\pnum +\tcode{stop_source}, \tcode{stop_token}, and \tcode{stop_callback} +implement semantics of shared ownership of a \defn{stop state}. +Any \tcode{stop_source}, \tcode{stop_token}, or \tcode{stop_callback} +that shares ownership of the same stop state is an \defn{associated} +\tcode{stop_source}, \tcode{stop_token}, or \tcode{stop_callback}, respectively. +The last remaining owner of the stop state automatically +releases the resources associated with the stop state. - void swap(thread& x, thread& y) noexcept; +\pnum +A \tcode{stop_token} can be passed to an operation which can either +\begin{itemize} + \item actively poll the token to check if there has been a stop request, or + \item register a callback using the \tcode{stop_callback} class template which + will be called in the event that a stop request is made. +\end{itemize} +A stop request made via a \tcode{stop_source} will be visible to all +associated \tcode{stop_token} and \tcode{stop_source} objects. +Once a stop request has been made it cannot be withdrawn +(a subsequent stop request has no effect). - namespace this_thread { - thread::id get_id() noexcept; +\pnum +Callbacks registered via a \tcode{stop_callback} object are called when +a stop request is first made by any associated \tcode{stop_source} object. - void yield() noexcept; - template - void sleep_until(const chrono::time_point& abs_time); - template - void sleep_for(const chrono::duration& rel_time); - } -} -\end{codeblock} +\pnum +Calls to the functions \tcode{request_stop}, \tcode{stop_requested}, +and \tcode{stop_possible} +do not introduce data races. +A call to \tcode{request_stop} that returns \tcode{true} +synchronizes with a call to \tcode{stop_requested} +on an associated \tcode{stop_token} or \tcode{stop_source} object +that returns \tcode{true}. +Registration of a callback synchronizes with the invocation of that callback. -\rSec2[thread.thread.class]{Class \tcode{thread}} -\pnum -The class \tcode{thread} provides a mechanism to create a new thread of execution, to join with -a thread (i.e., wait for a thread to complete), and to perform other operations that manage and -query the state of a thread. A \tcode{thread} object uniquely represents a particular thread of -execution. That representation may be transferred to other \tcode{thread} objects in such a way -that no two \tcode{thread} objects simultaneously represent the same thread of execution. A -thread of execution is \term{detached} when no \tcode{thread} object represents that thread. -Objects of class \tcode{thread} can be in a state that does not represent a thread of -execution. \begin{note} A \tcode{thread} object does not represent a thread of execution after -default construction, after being moved from, or after a successful call to \tcode{detach} or -\tcode{join}. \end{note} +\rSec2[thread.stoptoken.syn]{Header \tcode{} synopsis} +\indexhdr{stop_token}% -\indexlibrary{\idxcode{thread}}% \begin{codeblock} namespace std { - class thread { - public: - // types - class id; - using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native} - - // construct/copy/destroy - thread() noexcept; - template explicit thread(F&& f, Args&&... args); - ~thread(); - thread(const thread&) = delete; - thread(thread&&) noexcept; - thread& operator=(const thread&) = delete; - thread& operator=(thread&&) noexcept; + // \ref{stoptoken}, class \tcode{stop_token} + class stop_token; - // members - void swap(thread&) noexcept; - bool joinable() const noexcept; - void join(); - void detach(); - id get_id() const noexcept; - native_handle_type native_handle(); // see~\ref{thread.req.native} + // \ref{stopsource}, class \tcode{stop_source} + class stop_source; - // static members - static unsigned int hardware_concurrency() noexcept; + // no-shared-stop-state indicator + struct nostopstate_t { + explicit nostopstate_t() = default; }; + inline constexpr nostopstate_t nostopstate{}; + + // \ref{stopcallback}, class \tcode{stop_callback} + template + class stop_callback; } \end{codeblock} -\rSec3[thread.thread.id]{Class \tcode{thread::id}} -\indexlibrary{\idxcode{thread::id}}% -\indexlibrary{\idxcode{thread}!\idxcode{id}}% +\indexlibrary{\idxcode{stop_token}}% +\rSec2[stoptoken]{Class \tcode{stop_token}} + +\pnum +\indexlibrary{\idxcode{stop_token}}% +The class \tcode{stop_token} provides an interface for querying whether +a stop request has been made (\tcode{stop_requested}) +or can ever be made (\tcode{stop_possible}) +using an associated \tcode{stop_source} object (\ref{stopsource}). +A \tcode{stop_token} can also be passed to a +\tcode{stop_callback}\iref{stopcallback} constructor +to register a callback to be called when a stop request has been made +from an associated \tcode{stop_source}. + \begin{codeblock} namespace std { - class thread::id { + class stop_token { public: - id() noexcept; + // \ref{stoptoken.cons}, constructors, copy, and assignment + stop_token() noexcept; + + stop_token(const stop_token&) noexcept; + stop_token(stop_token&&) noexcept; + stop_token& operator=(const stop_token&) noexcept; + stop_token& operator=(stop_token&&) noexcept; + ~stop_token(); + void swap(stop_token&) noexcept; + + // \ref{stoptoken.mem}, stop handling + [[nodiscard]] bool stop_requested() const noexcept; + [[nodiscard]] bool stop_possible() const noexcept; + + [[nodiscard]] friend bool operator==(const stop_token& lhs, const stop_token& rhs) noexcept; + [[nodiscard]] friend bool operator!=(const stop_token& lhs, const stop_token& rhs) noexcept; + friend void swap(stop_token& lhs, stop_token& rhs) noexcept; }; - - bool operator==(thread::id x, thread::id y) noexcept; - bool operator!=(thread::id x, thread::id y) noexcept; - bool operator<(thread::id x, thread::id y) noexcept; - bool operator>(thread::id x, thread::id y) noexcept; - bool operator<=(thread::id x, thread::id y) noexcept; - bool operator>=(thread::id x, thread::id y) noexcept; - - template - basic_ostream& - operator<<(basic_ostream& out, thread::id id); - - // hash support - template struct hash; - template<> struct hash; } \end{codeblock} -\pnum An object of type \tcode{thread::id} provides a unique identifier for -each thread of execution and a single distinct value for all \tcode{thread} -objects that do not represent a thread of -execution\iref{thread.thread.class}. Each thread of execution has an -associated \tcode{thread::id} object that is not equal to the -\tcode{thread::id} object of any other thread of execution and that is not -equal to the \tcode{thread::id} object of any \tcode{thread} object that -does not represent threads of execution. - -\pnum -\tcode{thread::id} is a trivially copyable class\iref{class.prop}. -The library may reuse the value of a \tcode{thread::id} of a terminated thread that can no longer be joined. -\pnum -\begin{note} Relational operators allow \tcode{thread::id} objects to be used as -keys in associative containers. \end{note} +\rSec3[stoptoken.cons]{Constructors, copy, and assignment} -\indexlibrary{\idxcode{thread::id}!constructor}% +\indexlibrary{\idxcode{stop_token}!constructor}% \begin{itemdecl} -id() noexcept; +stop_token() noexcept; \end{itemdecl} \begin{itemdescr} -\pnum\effects Constructs an object of type \tcode{id}. - -\pnum\ensures The constructed object does not represent a thread of execution. +\pnum +\ensures +\tcode{stop_possible()} is \tcode{false} and +\tcode{stop_requested()} is \tcode{false}. +\begin{note} +Because the created \tcode{stop_token} object can never receive a stop request, +no resources are allocated for a stop state. +\end{note} \end{itemdescr} -\indexlibrarymember{operator==}{thread::id}% +\indexlibrary{\idxcode{stop_token}!constructor}% \begin{itemdecl} -bool operator==(thread::id x, thread::id y) noexcept; +stop_token(const stop_token& rhs) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum\returns \tcode{true} only if \tcode{x} and \tcode{y} represent the same -thread of execution or neither \tcode{x} nor \tcode{y} represents a thread of -execution. +\pnum +\ensures \tcode{*this == rhs} is \tcode{true}. +\begin{note} +\tcode{*this} and \tcode{rhs} share the ownership of the same stop state, +if any. +\end{note} \end{itemdescr} -\indexlibrarymember{operator"!=}{thread::id}% +\indexlibrary{\idxcode{stop_token}!constructor}% \begin{itemdecl} -bool operator!=(thread::id x, thread::id y) noexcept; +stop_token(stop_token&& rhs) noexcept; \end{itemdecl} - \begin{itemdescr} -\pnum\returns \tcode{!(x == y)} +\pnum +\ensures +\tcode{*this} contains the value of \tcode{rhs} +prior to the start of construction +and \tcode{rhs.stop_possible()} is \tcode{false}. \end{itemdescr} -\indexlibrarymember{operator<}{thread::id}% +\indexlibrary{\idxcode{stop_token}!destructor}% \begin{itemdecl} -bool operator<(thread::id x, thread::id y) noexcept; +~stop_token(); \end{itemdecl} \begin{itemdescr} \pnum -\returns A value such that \tcode{operator<} is a total ordering as described in~\ref{alg.sorting}. +\effects Releases ownership of the stop state, if any. \end{itemdescr} -\indexlibrarymember{operator>}{thread::id}% +\indexlibrarymember{operator=}{stop_token}% \begin{itemdecl} -bool operator>(thread::id x, thread::id y) noexcept; +stop_token& operator=(const stop_token& rhs) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum\returns \tcode{y < x}. +\pnum +\effects Equivalent to: \tcode{stop_token(rhs).swap(*this)}. + +\pnum +\returns \tcode{*this}. \end{itemdescr} -\indexlibrarymember{operator<=}{thread::id}% +\indexlibrarymember{operator=}{stop_token}% \begin{itemdecl} -bool operator<=(thread::id x, thread::id y) noexcept; +stop_token& operator=(stop_token&& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{!(y < x)}. +\effects Equivalent to: \tcode{stop_token(std::move(rhs)).swap(*this)}. + +\pnum +\returns \tcode{*this}. \end{itemdescr} -\indexlibrarymember{operator>=}{thread::id}% +\indexlibrarymember{swap}{stop_token}% \begin{itemdecl} -bool operator>=(thread::id x, thread::id y) noexcept; +void swap(stop_token& rhs) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum\returns \tcode{!(x < y)}. +\pnum +\effects Exchanges the values of \tcode{*this} and \tcode{rhs}. \end{itemdescr} -\indexlibrarymember{operator<<}{thread::id}% +\rSec3[stoptoken.mem]{Members} + +\indexlibrarymember{stop_requested}{stop_token}% \begin{itemdecl} -template - basic_ostream& - operator<< (basic_ostream& out, thread::id id); +[[nodiscard]] bool stop_requested() const noexcept; \end{itemdecl} \begin{itemdescr} -\pnum\effects Inserts an unspecified text representation of \tcode{id} into -\tcode{out}. For two objects of type \tcode{thread::id} \tcode{x} and \tcode{y}, -if \tcode{x == y} the \tcode{thread::id} objects have the same text -representation and if \tcode{x != y} the \tcode{thread::id} objects have -distinct text representations. - -\pnum\returns \tcode{out}. +\pnum +\returns \tcode{true} if \tcode{*this} has ownership of a stop state +that has received a stop request; +otherwise, \tcode{false}. \end{itemdescr} -\indexlibrary{\idxcode{hash}!\idxcode{thread::id}}% +\indexlibrarymember{stop_possible}{stop_token}% \begin{itemdecl} -template<> struct hash; +[[nodiscard]] bool stop_possible() const noexcept; \end{itemdecl} \begin{itemdescr} -\pnum The specialization is enabled\iref{unord.hash}. +\pnum +\returns \tcode{false} if: +\begin{itemize} +\item \tcode{*this} does not have ownership of a stop state, or +\item a stop request was not made + and there are no associated \tcode{stop_source} objects; +\end{itemize} +otherwise, \tcode{true}. \end{itemdescr} -\rSec3[thread.thread.constr]{Constructors} +\rSec3[stoptoken.cmp]{Comparisons} -\indexlibrary{\idxcode{thread}!constructor}% +\indexlibrarymember{operator==}{stop_token}% \begin{itemdecl} -thread() noexcept; +[[nodiscard]] bool operator==(const stop_token& lhs, const stop_token& rhs) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum\effects Constructs a \tcode{thread} object that does not represent a thread of execution. - -\pnum\ensures \tcode{get_id() == id()}. +\pnum +\returns +\tcode{true} if \tcode{lhs} and \tcode{rhs} have ownership of the same stop state +or if both \tcode{lhs} and \tcode{rhs} do not have ownership of a stop state; +otherwise \tcode{false}. \end{itemdescr} -\indexlibrary{\idxcode{thread}!constructor}% +\indexlibrarymember{operator!=}{stop_token}% \begin{itemdecl} -template explicit thread(F&& f, Args&&... args); +[[nodiscard]] bool operator!=(const stop_token& lhs, const stop_token& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\requires\ \tcode{F} and each $\tcode{T}_i$ in \tcode{Args} shall meet the -\oldconcept{MoveConstructible} requirements. -\tcode{% -\placeholdernc{INVOKE}(\brk{}% -\placeholdernc{decay-copy}(std::forward(f)),% -\placeholdernc{decay-copy}(std::forward({}args))...)}\iref{func.require} -shall be a valid expression. +\returns \tcode{!(lhs==rhs)}. +\end{itemdescr} -\pnum -\remarks -This constructor shall not participate in overload resolution if \tcode{remove_cvref_t} -is the same type as \tcode{std::thread}. +\rSec3[stoptoken.special]{Specialized algorithms} + +\indexlibrarymember{swap}{stop_token}% +\begin{itemdecl} +friend void swap(stop_token& x, stop_token& y) noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum -\effects\ Constructs an object of type \tcode{thread}. The new thread of execution executes -\tcode{% -\placeholdernc{INVOKE}(\brk{}% -\placeholdernc{decay-copy}(\brk{}% -std::forward(f)), -\placeholdernc{decay-copy}(\brk{}% -std::forward(\brk{}args))...)} with the calls to -\tcode{\placeholder{decay-copy}} being evaluated in the constructing thread. Any return value from this invocation -is ignored. \begin{note} This implies that any exceptions not thrown from the invocation of the copy -of \tcode{f} will be thrown in the constructing thread, not the new thread. \end{note} If the -invocation of -\tcode{% -\placeholdernc{INVOKE}(\brk{}% -\placeholdernc{decay-copy}(\brk{}% -std::forward(f)), -\placeholdernc{decay-copy}(\brk{}% -std::forward(args))...)} -termi\-nates with an uncaught exception, \tcode{terminate} shall be called. +\effects Equivalent to: \tcode{x.swap(y)}. +\end{itemdescr} +\indexlibrary{\idxcode{stop_source}}% +\rSec2[stopsource]{Class \tcode{stop_source}} -\pnum\sync The completion of the invocation of the constructor -synchronizes with the beginning of the invocation of the copy of \tcode{f}. +\pnum +\indexlibrary{\idxcode{stop_source}}% +The class \tcode{stop_source} implements the semantics of making a stop request. +A stop request made on a \tcode{stop_source} object is visible to all +associated \tcode{stop_source} and \tcode{stop_token} (\ref{stoptoken}) objects. +Once a stop request has been made it cannot be withdrawn +(a subsequent stop request has no effect). -\pnum\ensures \tcode{get_id() != id()}. \tcode{*this} represents the newly started thread. +\indexlibrary{\idxcode{nostopstate_t}}% +\indexlibrary{\idxcode{nostopstate}}% -\pnum\throws \tcode{system_error} if unable to start the new thread. +\begin{codeblock} +namespace std { + // no-shared-stop-state indicator + struct nostopstate_t { + explicit nostopstate_t() = default; + }; + inline constexpr nostopstate_t nostopstate{}; -\pnum\errors -\begin{itemize} -\item \tcode{resource_unavailable_try_again} --- the system lacked the necessary -resources to create another thread, or the system-imposed limit on the number of -threads in a process would be exceeded. -\end{itemize} -\end{itemdescr} + class stop_source { + public: + // \ref{stopsource.cons}, constructors, copy, and assignment + stop_source(); + explicit stop_source(nostopstate_t) noexcept; + + stop_source(const stop_source&) noexcept; + stop_source(stop_source&&) noexcept; + stop_source& operator=(const stop_source&) noexcept; + stop_source& operator=(stop_source&&) noexcept; + ~stop_source(); + void swap(stop_source&) noexcept; + + // \ref{stopsource.mem}, stop handling + [[nodiscard]] stop_token get_token() const noexcept; + [[nodiscard]] bool stop_possible() const noexcept; + [[nodiscard]] bool stop_requested() const noexcept; + bool request_stop() noexcept; + + [[nodiscard]] friend bool + operator==(const stop_source& lhs, const stop_source& rhs) noexcept; + [[nodiscard]] friend bool + operator!=(const stop_source& lhs, const stop_source& rhs) noexcept; + friend void swap(stop_source& lhs, stop_source& rhs) noexcept; + }; +} +\end{codeblock} -\indexlibrary{\idxcode{thread}!constructor}% +\rSec3[stopsource.cons]{Constructors, copy, and assignment} + +\indexlibrary{\idxcode{stop_source}!constructor}% \begin{itemdecl} -thread(thread&& x) noexcept; +stop_source(); \end{itemdecl} \begin{itemdescr} \pnum -\effects Constructs an object of type \tcode{thread} from \tcode{x}, and sets -\tcode{x} to a default constructed state. +\effects Initialises \tcode{*this} to have ownership of a new stop state. \pnum -\ensures \tcode{x.get_id() == id()} and \tcode{get_id()} returns the -value of \tcode{x.get_id()} prior to the start of construction. +\ensures \tcode{stop_possible()} is \tcode{true} +and \tcode{stop_requested()} is \tcode{false}. +\pnum +\throws \tcode{bad_alloc} if memory could not be allocated for the stop state. \end{itemdescr} -\rSec3[thread.thread.destr]{Destructor} - -\indexlibrary{\idxcode{thread}!destructor}% +\indexlibrary{\idxcode{stop_source}!constructor}% \begin{itemdecl} -~thread(); +explicit stop_source(nostopstate_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -If \tcode{joinable()}, calls \tcode{terminate()}. Otherwise, has no effects. -\begin{note} Either implicitly detaching or joining a \tcode{joinable()} thread in its -destructor could result in difficult to debug correctness (for detach) or performance -(for join) bugs encountered only when an exception is thrown. Thus the programmer must -ensure that the destructor is never executed while the thread is still joinable. -\end{note} +\ensures +\tcode{stop_possible()} is \tcode{false} and +\tcode{stop_requested()} is \tcode{false}. +\begin{note} No resources are allocated for the state. \end{note} \end{itemdescr} -\rSec3[thread.thread.assign]{Assignment} - -\indexlibrarymember{operator=}{thread}% +\indexlibrary{\idxcode{stop_source}!constructor}% \begin{itemdecl} -thread& operator=(thread&& x) noexcept; +stop_source(const stop_source& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects If \tcode{joinable()}, calls \tcode{terminate()}. Otherwise, assigns the -state of \tcode{x} to \tcode{*this} and sets \tcode{x} to a default constructed state. - -\pnum -\ensures \tcode{x.get_id() == id()} and \tcode{get_id()} returns the value of -\tcode{x.get_id()} prior to the assignment. - -\pnum -\returns \tcode{*this}. +\ensures \tcode{*this == rhs} is \tcode{true}. +\begin{note} +\tcode{*this} and \tcode{rhs} share the ownership of the same stop state, +if any. +\end{note} \end{itemdescr} -\rSec3[thread.thread.member]{Members} - -\indexlibrarymember{swap}{thread}% +\indexlibrary{\idxcode{stop_source}!constructor}% \begin{itemdecl} -void swap(thread& x) noexcept; +stop_source(stop_source&& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects Swaps the state of \tcode{*this} and \tcode{x}. +\ensures +\tcode{*this} contains the value of \tcode{rhs} +prior to the start of construction +and \tcode{rhs.stop_possible()} is \tcode{false}. \end{itemdescr} -\indexlibrarymember{joinable}{thread}% +\indexlibrary{\idxcode{stop_source}!destructor}% \begin{itemdecl} -bool joinable() const noexcept; +~stop_source(); \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{get_id() != id()}. +\effects Releases ownership of the stop state, if any. \end{itemdescr} -\indexlibrarymember{join}{thread}% +\indexlibrarymember{operator=}{stop_source}% \begin{itemdecl} -void join(); +stop_source& operator=(const stop_source& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects\ Blocks until the thread represented by \tcode{*this} has completed. +\effects Equivalent to: \tcode{stop_source(rhs).swap(*this)}. \pnum -\sync The completion of the thread represented by \tcode{*this} synchronizes with\iref{intro.multithread} -the corresponding successful -\tcode{join()} return. \begin{note} Operations on -\tcode{*this} are not synchronized. \end{note} - -\pnum -\ensures The thread represented by \tcode{*this} has completed. \tcode{get_id() == id()}. - -\pnum -\throws \tcode{system_error} when -an exception is required\iref{thread.req.exception}. - -\pnum -\errors -\begin{itemize} -\item \tcode{resource_deadlock_would_occur} --- if deadlock is detected or -\tcode{get_id() == this_thread::\brk{}get_id()}. - -\item \tcode{no_such_process} --- if the thread is not valid. - -\item \tcode{invalid_argument} --- if the thread is not joinable. -\end{itemize} +\returns \tcode{*this}. \end{itemdescr} -\indexlibrarymember{detach}{thread}% +\indexlibrarymember{operator=}{stop_source}% \begin{itemdecl} -void detach(); +stop_source& operator=(stop_source&& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects The thread represented by \tcode{*this} continues execution without the calling thread -blocking. When \tcode{detach()} returns, \tcode{*this} no longer represents the possibly continuing -thread of execution. When the thread previously represented by \tcode{*this} ends execution, the -implementation shall release any owned resources. - -\pnum\ensures \tcode{get_id() == id()}. - -\pnum\throws \tcode{system_error} when -an exception is required\iref{thread.req.exception}. +\effects Equivalent to: \tcode{stop_source(std::move(rhs)).swap(*this)}. -\pnum \errors -\begin{itemize} -\item \tcode{no_such_process} --- if the thread is not valid. -\item \tcode{invalid_argument} --- if the thread is not joinable. -\end{itemize} +\pnum +\returns \tcode{*this}. \end{itemdescr} -\indexlibrarymember{get_id}{thread}% +\indexlibrarymember{swap}{stop_source}% \begin{itemdecl} -id get_id() const noexcept; +void swap(stop_source& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns A default constructed \tcode{id} object if \tcode{*this} does not represent a thread, -otherwise \tcode{this_thread::get_id()} for the thread of execution represented by -\tcode{*this}. +\effects Exchanges the values of \tcode{*this} and \tcode{rhs}. \end{itemdescr} -\rSec3[thread.thread.static]{Static members} +\rSec3[stopsource.mem]{Members} -\indexlibrarymember{hardware_concurrency}{thread}% +\indexlibrarymember{get_token}{stop_source sc}% \begin{itemdecl} -unsigned hardware_concurrency() noexcept; +[[nodiscard]] stop_token get_token() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns The number of hardware thread contexts. \begin{note} This value should -only be considered to be a hint. \end{note} If this value is not computable or -well-defined, an implementation should return 0. +\returns +\tcode{stop_token()} if \tcode{stop_possible()} is \tcode{false}; +otherwise a new associated \tcode{stop_token} object. \end{itemdescr} -\rSec3[thread.thread.algorithm]{Specialized algorithms} -\indexlibrarymember{swap}{thread}% +\indexlibrarymember{stop_possible}{stop_source}% \begin{itemdecl} -void swap(thread& x, thread& y) noexcept; +[[nodiscard]] bool stop_possible() const noexcept; \end{itemdecl} \begin{itemdescr} -\pnum\effects As if by \tcode{x.swap(y)}. +\pnum +\returns +\tcode{true} if \tcode{*this} has ownership of a stop state; +otherwise, \tcode{false}. \end{itemdescr} -\rSec2[thread.thread.this]{Namespace \tcode{this_thread}} - -\begin{codeblock} -namespace std::this_thread { - thread::id get_id() noexcept; - - void yield() noexcept; - template - void sleep_until(const chrono::time_point& abs_time); - template - void sleep_for(const chrono::duration& rel_time); -} -\end{codeblock} - -\indexlibrarymember{get_id}{this_thread}% +\indexlibrarymember{stop_requested}{stop_source}% \begin{itemdecl} -thread::id this_thread::get_id() noexcept; +[[nodiscard]] bool stop_requested() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns An object of type \tcode{thread::id} that uniquely identifies the current thread of -execution. No other thread of execution shall have this id and this thread of execution shall -always have this id. The object returned shall not compare equal to a default constructed -\tcode{thread::id}. +\returns +\tcode{true} if \tcode{*this} has ownership of a stop state +that has received a stop request; +otherwise, \tcode{false}. \end{itemdescr} -\indexlibrarymember{yield}{this_thread}% + +\indexlibrarymember{request_stop}{stop_source}% \begin{itemdecl} -void this_thread::yield() noexcept; +bool request_stop() noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects Offers the implementation the opportunity to reschedule. +\effects +If \tcode{*this} does not have ownership of a stop state, returns \tcode{false}. +Otherwise, atomically determines whether the owned stop state +has received a stop request, +and if not, makes a stop request. +The determination and making of the stop request are an +atomic read-modify-write operation\iref{intro.races}. +If the request was made, +the callbacks registered by associated \tcode{stop_callback} objects +are synchronously called. +If an invocation of a callback exits via an exception +then \tcode{terminate} is called\iref{except.terminate}. +\begin{note} +A stop request includes notifying all condition variables +of type \tcode{condition_variable_any} +temporarily registered during +an interruptible wait\iref{thread.condvarany.intwait}. +\end{note} \pnum -\sync None. +\ensures +\tcode{stop_possible()} is \tcode{false} +or \tcode{stop_requested()} is \tcode{true}. + +\pnum +\returns +\tcode{true} if this call made a stop request; +otherwise \tcode{false}. \end{itemdescr} -\indexlibrarymember{sleep_until}{this_thread}% +\rSec3[stopsource.cmp]{Comparisons} + +\indexlibrarymember{operator==}{stop_source}% \begin{itemdecl} -template - void sleep_until(const chrono::time_point& abs_time); +[[nodiscard]] bool operator==(const stop_source& lhs, const stop_source& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects Blocks the calling thread for the absolute timeout\iref{thread.req.timing} specified -by \tcode{abs_time}. - -\pnum -\sync None. - -\pnum -\throws Timeout-related exceptions\iref{thread.req.timing}. +\returns +\tcode{true} if \tcode{lhs} and \tcode{rhs} have ownership +of the same stop state +or if both \tcode{lhs} and \tcode{rhs} do not have ownership of a stop state; +otherwise \tcode{false}. \end{itemdescr} -\indexlibrarymember{sleep_for}{this_thread}% +\indexlibrarymember{operator!=}{stop_source}% \begin{itemdecl} -template - void sleep_for(const chrono::duration& rel_time); +[[nodiscard]] bool operator!=(const stop_source& lhs, const stop_source& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects Blocks the calling thread for the relative timeout\iref{thread.req.timing} specified -by \tcode{rel_time}. +\returns \tcode{!(lhs==rhs)}. +\end{itemdescr} -\pnum -\sync None. +\rSec3[stopsource.special]{Specialized algorithms} +\indexlibrarymember{swap}{stop_source}% +\begin{itemdecl} +friend void swap(stop_source& x, stop_source& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} \pnum -\throws Timeout-related exceptions\iref{thread.req.timing}. +\effects Equivalent to: \tcode{x.swap(y)}. \end{itemdescr} -\rSec1[thread.mutex]{Mutual exclusion} +\indexlibrary{\idxcode{stop_callback}}% +\rSec2[stopcallback]{Class template \tcode{stop_callback}} \pnum -This subclause provides mechanisms for mutual exclusion: mutexes, locks, and call -once. These mechanisms ease the production of race-free -programs\iref{intro.multithread}. - -\rSec2[mutex.syn]{Header \tcode{} synopsis} -\indexhdr{mutex}% - +\indexlibrary{\idxcode{stop_callback}}% \begin{codeblock} namespace std { - class mutex; - class recursive_mutex; - class timed_mutex; - class recursive_timed_mutex; - - struct defer_lock_t { explicit defer_lock_t() = default; }; - struct try_to_lock_t { explicit try_to_lock_t() = default; }; - struct adopt_lock_t { explicit adopt_lock_t() = default; }; - - inline constexpr defer_lock_t defer_lock { }; - inline constexpr try_to_lock_t try_to_lock { }; - inline constexpr adopt_lock_t adopt_lock { }; - - template class lock_guard; - template class scoped_lock; - template class unique_lock; - - template - void swap(unique_lock& x, unique_lock& y) noexcept; - - template int try_lock(L1&, L2&, L3&...); - template void lock(L1&, L2&, L3&...); - - struct once_flag; - - template - void call_once(once_flag& flag, Callable&& func, Args&&... args); -} -\end{codeblock} + template + class stop_callback { + public: + using callback_type = Callback; + + // \ref{stopcallback.cons}, constructors and destructor + template + explicit stop_callback(const stop_token& st, C&& cb) + noexcept(is_nothrow_constructible_v); + template + explicit stop_callback(stop_token&& st, C&& cb) + noexcept(is_nothrow_constructible_v); + ~stop_callback(); + + stop_callback(const stop_callback&) = delete; + stop_callback(stop_callback&&) = delete; + stop_callback& operator=(const stop_callback&) = delete; + stop_callback& operator=(stop_callback&&) = delete; -\rSec2[shared.mutex.syn]{Header \tcode{} synopsis} -\indexhdr{shared_mutex}% + private: + Callback callback; // \expos + }; -\begin{codeblock} -namespace std { - class shared_mutex; - class shared_timed_mutex; - template class shared_lock; - template - void swap(shared_lock& x, shared_lock& y) noexcept; + template + stop_callback(stop_token, Callback) -> stop_callback; } \end{codeblock} -\rSec2[thread.mutex.requirements]{Mutex requirements} - -\rSec3[thread.mutex.requirements.general]{In general} +\pnum +\mandates +\tcode{stop_callback} is instantiated with an argument for the +template parameter \tcode{Callback} +that satisfies both \tcode{invocable} +and \tcode{destructible}. \pnum -A mutex object facilitates protection against data races and allows safe synchronization of -data between execution agents\iref{thread.req.lockable}. -An execution agent \term{owns} a mutex from the time it successfully calls one of the -lock functions until it calls unlock. Mutexes can be either recursive or non-recursive, and can -grant simultaneous ownership to one or many execution agents. Both -recursive and non-recursive mutexes are supplied. +\expects +\tcode{stop_callback} is instantiated with an argument for the +template parameter \tcode{Callback} +that models both \tcode{invocable} +and \tcode{destructible}. -\rSec3[thread.mutex.requirements.mutex]{Mutex types} -\pnum -The \defn{mutex types} are the standard library types \tcode{mutex}, -\tcode{recursive_mutex}, \tcode{timed_mutex}, \tcode{recursive_timed_mutex}, -\tcode{shared_mutex}, and \tcode{shared_timed_mutex}. -They shall meet the requirements set out in this subclause. In this description, \tcode{m} -denotes an object of a mutex type. +\rSec3[stopcallback.cons]{Constructors and destructor} +\indexlibrary{\idxcode{stop_callback}!constructor}% +\begin{itemdecl} +template +explicit stop_callback(const stop_token& st, C&& cb) + noexcept(is_nothrow_constructible_v); +template +explicit stop_callback(stop_token&& st, C&& cb) + noexcept(is_nothrow_constructible_v); +\end{itemdecl} +\begin{itemdescr} \pnum -The mutex types shall meet the \oldconcept{Lockable} requirements\iref{thread.req.lockable.req}. +\constraints +\tcode{Callback} and \tcode{C} satisfy \libconcept{constructible_from}. \pnum -The mutex types shall be \oldconcept{DefaultConstructible} and \oldconcept{Destructible}. If -initialization of an object of a mutex type fails, an exception of type -\tcode{system_error} shall be thrown. The mutex types shall not be copyable or movable. +\expects +\tcode{Callback} and \tcode{C} model \libconcept{constructible_from}. \pnum -The error conditions for error codes, if any, reported by member functions of the mutex types -shall be: -\begin{itemize} -\item \tcode{resource_unavailable_try_again} --- if any native handle type manipulated is not available. -\item \tcode{operation_not_permitted} --- if the thread does not have the -privilege to perform the operation. -\item \tcode{invalid_argument} --- if any native handle type manipulated as part of mutex -construction is incorrect. -\end{itemize} +\effects +Initializes \tcode{callback} with \tcode{std::forward(cb)}. +If \tcode{st.stop_requested()} is \tcode{true}, then +\tcode{std::forward(callback)()} +is evaluated in the current thread before the constructor returns. +Otherwise, if \tcode{st} has ownership of a stop state, +acquires shared ownership of that stop state and registers +the callback with that stop state +such that \tcode{std::forward(callback)()} +is evaluated by the first call to \tcode{request_stop()} +on an associated \tcode{stop_source}. \pnum -The implementation shall provide lock and unlock operations, as described below. -For purposes of determining the existence of a data race, these behave as -atomic operations\iref{intro.multithread}. The lock and unlock operations on -a single mutex shall appear to occur in a single total order. \begin{note} This -can be viewed as the modification order\iref{intro.multithread} of the -mutex. \end{note} -\begin{note} Construction and -destruction of an object of a mutex type need not be thread-safe; other -synchronization should be used to ensure that mutex objects are initialized -and visible to other threads. \end{note} +\remarks +If evaluating +\tcode{std::forward(callback)()} +exits via an exception, +then \tcode{terminate} is called\iref{except.terminate}. \pnum -The expression \tcode{m.lock()} shall be well-formed and have the following semantics: +\throws Any exception thrown by the initialization of \tcode{callback}. +\end{itemdescr} + +\indexlibrary{\idxcode{stop_callback}!destructor}% +\begin{itemdecl} +~stop_callback(); +\end{itemdecl} \begin{itemdescr} \pnum -\requires If \tcode{m} is of type \tcode{mutex}, \tcode{timed_mutex}, -\tcode{shared_mutex}, or \tcode{shared_timed_mutex}, the calling -thread does not own the mutex. +\effects +Unregisters the callback from the owned stop state, if any. +The destructor does not block waiting for the execution of another callback +registered by an associated \tcode{stop_callback}. +If \tcode{callback} is concurrently executing on another thread, +then the return from the invocation of \tcode{callback} +strongly happens before\iref{intro.races} +\tcode{callback} is destroyed. +If \tcode{callback} is executing on the current thread, +then the destructor does not block\iref{defns.block} waiting for +the return from the invocation of \tcode{callback}. +Releases ownership of the stop state, if any. +\end{itemdescr} -\pnum -\effects Blocks the calling thread until ownership of the mutex can be obtained for the calling thread. -\pnum -\ensures The calling thread owns the mutex. +\rSec1[thread.threads]{Threads} \pnum -\returntype \tcode{void}. +\ref{thread.threads} describes components that can be used to create and manage threads. +\begin{note} These threads are intended to map one-to-one with operating system threads. +\end{note} -\pnum -\sync Prior \tcode{unlock()} operations on the same object shall -\term{synchronize with}\iref{intro.multithread} this operation. +\rSec2[thread.syn]{Header \tcode{} synopsis} +\indexhdr{thread}% -\pnum -\throws \tcode{system_error} when -an exception is required\iref{thread.req.exception}. +\begin{codeblock} +namespace std { + class thread; -\pnum \errors -\begin{itemize} -\item \tcode{operation_not_permitted} --- if the thread does not have the -privilege to perform the operation. + void swap(thread& x, thread& y) noexcept; -\item \tcode{resource_deadlock_would_occur} --- if the implementation detects -that a deadlock would occur. -\end{itemize} -\end{itemdescr} + // \ref{thread.jthread.class} class \tcode{jthread} + class jthread; -\pnum -The expression \tcode{m.try_lock()} shall be well-formed and have the following semantics: + namespace this_thread { + thread::id get_id() noexcept; -\begin{itemdescr} -\pnum + void yield() noexcept; + template + void sleep_until(const chrono::time_point& abs_time); + template + void sleep_for(const chrono::duration& rel_time); + } +} +\end{codeblock} + +\rSec2[thread.thread.class]{Class \tcode{thread}} + +\pnum +The class \tcode{thread} provides a mechanism to create a new thread of execution, to join with +a thread (i.e., wait for a thread to complete), and to perform other operations that manage and +query the state of a thread. A \tcode{thread} object uniquely represents a particular thread of +execution. That representation may be transferred to other \tcode{thread} objects in such a way +that no two \tcode{thread} objects simultaneously represent the same thread of execution. A +thread of execution is \term{detached} when no \tcode{thread} object represents that thread. +Objects of class \tcode{thread} can be in a state that does not represent a thread of +execution. \begin{note} A \tcode{thread} object does not represent a thread of execution after +default construction, after being moved from, or after a successful call to \tcode{detach} or +\tcode{join}. \end{note} + +\indexlibrary{\idxcode{thread}}% +\begin{codeblock} +namespace std { + class thread { + public: + // types + class id; + using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native} + + // construct/copy/destroy + thread() noexcept; + template explicit thread(F&& f, Args&&... args); + ~thread(); + thread(const thread&) = delete; + thread(thread&&) noexcept; + thread& operator=(const thread&) = delete; + thread& operator=(thread&&) noexcept; + + // members + void swap(thread&) noexcept; + bool joinable() const noexcept; + void join(); + void detach(); + id get_id() const noexcept; + native_handle_type native_handle(); // see~\ref{thread.req.native} + + // static members + static unsigned int hardware_concurrency() noexcept; + }; +} +\end{codeblock} + +\rSec3[thread.thread.id]{Class \tcode{thread::id}} + +\indexlibrary{\idxcode{thread::id}}% +\indexlibrary{\idxcode{thread}!\idxcode{id}}% +\begin{codeblock} +namespace std { + class thread::id { + public: + id() noexcept; + }; + + bool operator==(thread::id x, thread::id y) noexcept; + strong_ordering operator<=>(thread::id x, thread::id y) noexcept; + + template + basic_ostream& + operator<<(basic_ostream& out, thread::id id); + + // hash support + template struct hash; + template<> struct hash; +} +\end{codeblock} + +\pnum An object of type \tcode{thread::id} provides a unique identifier for +each thread of execution and a single distinct value for all \tcode{thread} +objects that do not represent a thread of +execution\iref{thread.thread.class}. Each thread of execution has an +associated \tcode{thread::id} object that is not equal to the +\tcode{thread::id} object of any other thread of execution and that is not +equal to the \tcode{thread::id} object of any \tcode{thread} object that +does not represent threads of execution. + +\pnum +\tcode{thread::id} is a trivially copyable class\iref{class.prop}. +The library may reuse the value of a \tcode{thread::id} of a terminated thread that can no longer be joined. + +\pnum +\begin{note} Relational operators allow \tcode{thread::id} objects to be used as +keys in associative containers. \end{note} + +\indexlibrary{\idxcode{thread::id}!constructor}% +\begin{itemdecl} +id() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum\effects Constructs an object of type \tcode{id}. + +\pnum\ensures The constructed object does not represent a thread of execution. +\end{itemdescr} + +\indexlibrarymember{operator==}{thread::id}% +\begin{itemdecl} +bool operator==(thread::id x, thread::id y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum\returns \tcode{true} only if \tcode{x} and \tcode{y} represent the same +thread of execution or neither \tcode{x} nor \tcode{y} represents a thread of +execution. +\end{itemdescr} + +\indexlibrarymember{operator<=>}{thread::id}% +\begin{itemdecl} +strong_ordering operator<=>(thread::id x, thread::id y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let $P(\tcode{x}, \tcode{y})$ be +an unspecified total ordering over \tcode{thread::id} +as described in \ref{alg.sorting}. + +\pnum +\returns +\tcode{strong_ordering::less} if $P(\tcode{x}, \tcode{y})$ is \tcode{true}. +Otherwise, \tcode{strong_ordering::greater} +if $P(\tcode{y}, \tcode{x})$ is \tcode{true}. +Otherwise, \tcode{strong_ordering::equal}. +\end{itemdescr} + +\indexlibrarymember{operator<<}{thread::id}% +\begin{itemdecl} +template + basic_ostream& + operator<< (basic_ostream& out, thread::id id); +\end{itemdecl} + +\begin{itemdescr} +\pnum\effects Inserts an unspecified text representation of \tcode{id} into +\tcode{out}. For two objects of type \tcode{thread::id} \tcode{x} and \tcode{y}, +if \tcode{x == y} the \tcode{thread::id} objects have the same text +representation and if \tcode{x != y} the \tcode{thread::id} objects have +distinct text representations. + +\pnum\returns \tcode{out}. +\end{itemdescr} + +\indexlibrary{\idxcode{hash}!\idxcode{thread::id}}% +\begin{itemdecl} +template<> struct hash; +\end{itemdecl} + +\begin{itemdescr} +\pnum The specialization is enabled\iref{unord.hash}. +\end{itemdescr} + +\rSec3[thread.thread.constr]{Constructors} + +\indexlibrary{\idxcode{thread}!constructor}% +\begin{itemdecl} +thread() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum\effects Constructs a \tcode{thread} object that does not represent a thread of execution. + +\pnum\ensures \tcode{get_id() == id()}. +\end{itemdescr} + +\indexlibrary{\idxcode{thread}!constructor}% +\begin{itemdecl} +template explicit thread(F&& f, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\requires\ \tcode{F} and each $\tcode{T}_i$ in \tcode{Args} shall meet the +\oldconcept{MoveConstructible} requirements. +\tcode{% +\placeholdernc{INVOKE}(\brk{}% +\placeholdernc{decay-copy}(std::forward(f)),% +\placeholdernc{decay-copy}(std::forward({}args))...)}\iref{func.require} +shall be a valid expression. + +\pnum +\remarks +This constructor shall not participate in overload resolution if \tcode{remove_cvref_t} +is the same type as \tcode{std::thread}. + +\pnum +\effects\ Constructs an object of type \tcode{thread}. The new thread of execution executes +\tcode{% +\placeholdernc{INVOKE}(\brk{}% +\placeholdernc{decay-copy}(\brk{}% +std::forward(f)), +\placeholdernc{decay-copy}(\brk{}% +std::forward(\brk{}args))...)} with the calls to +\tcode{\placeholder{decay-copy}} being evaluated in the constructing thread. Any return value from this invocation +is ignored. \begin{note} This implies that any exceptions not thrown from the invocation of the copy +of \tcode{f} will be thrown in the constructing thread, not the new thread. \end{note} If the +invocation of +\tcode{% +\placeholdernc{INVOKE}(\brk{}% +\placeholdernc{decay-copy}(\brk{}% +std::forward(f)), +\placeholdernc{decay-copy}(\brk{}% +std::forward(args))...)} +termi\-nates with an uncaught exception, \tcode{terminate} shall be called. + + +\pnum\sync The completion of the invocation of the constructor +synchronizes with the beginning of the invocation of the copy of \tcode{f}. + +\pnum\ensures \tcode{get_id() != id()}. \tcode{*this} represents the newly started thread. + +\pnum\throws \tcode{system_error} if unable to start the new thread. + +\pnum\errors +\begin{itemize} +\item \tcode{resource_unavailable_try_again} --- the system lacked the necessary +resources to create another thread, or the system-imposed limit on the number of +threads in a process would be exceeded. +\end{itemize} +\end{itemdescr} + +\indexlibrary{\idxcode{thread}!constructor}% +\begin{itemdecl} +thread(thread&& x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Constructs an object of type \tcode{thread} from \tcode{x}, and sets +\tcode{x} to a default constructed state. + +\pnum +\ensures \tcode{x.get_id() == id()} and \tcode{get_id()} returns the +value of \tcode{x.get_id()} prior to the start of construction. + +\end{itemdescr} + +\rSec3[thread.thread.destr]{Destructor} + +\indexlibrary{\idxcode{thread}!destructor}% +\begin{itemdecl} +~thread(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +If \tcode{joinable()}, calls \tcode{terminate()}. Otherwise, has no effects. +\begin{note} Either implicitly detaching or joining a \tcode{joinable()} thread in its +destructor could result in difficult to debug correctness (for detach) or performance +(for join) bugs encountered only when an exception is thrown. Thus the programmer must +ensure that the destructor is never executed while the thread is still joinable. +\end{note} +\end{itemdescr} + +\rSec3[thread.thread.assign]{Assignment} + +\indexlibrarymember{operator=}{thread}% +\begin{itemdecl} +thread& operator=(thread&& x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects If \tcode{joinable()}, calls \tcode{terminate()}. Otherwise, assigns the +state of \tcode{x} to \tcode{*this} and sets \tcode{x} to a default constructed state. + +\pnum +\ensures \tcode{x.get_id() == id()} and \tcode{get_id()} returns the value of +\tcode{x.get_id()} prior to the assignment. + +\pnum +\returns \tcode{*this}. +\end{itemdescr} + +\rSec3[thread.thread.member]{Members} + +\indexlibrarymember{swap}{thread}% +\begin{itemdecl} +void swap(thread& x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Swaps the state of \tcode{*this} and \tcode{x}. +\end{itemdescr} + +\indexlibrarymember{joinable}{thread}% +\begin{itemdecl} +bool joinable() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns \tcode{get_id() != id()}. +\end{itemdescr} + +\indexlibrarymember{join}{thread}% +\begin{itemdecl} +void join(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects\ Blocks until the thread represented by \tcode{*this} has completed. + +\pnum +\sync The completion of the thread represented by \tcode{*this} synchronizes with\iref{intro.multithread} +the corresponding successful +\tcode{join()} return. \begin{note} Operations on +\tcode{*this} are not synchronized. \end{note} + +\pnum +\ensures The thread represented by \tcode{*this} has completed. \tcode{get_id() == id()}. + +\pnum +\throws \tcode{system_error} when +an exception is required\iref{thread.req.exception}. + +\pnum +\errors +\begin{itemize} +\item \tcode{resource_deadlock_would_occur} --- if deadlock is detected or +\tcode{get_id() == this_thread::\brk{}get_id()}. + +\item \tcode{no_such_process} --- if the thread is not valid. + +\item \tcode{invalid_argument} --- if the thread is not joinable. +\end{itemize} +\end{itemdescr} + +\indexlibrarymember{detach}{thread}% +\begin{itemdecl} +void detach(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects The thread represented by \tcode{*this} continues execution without the calling thread +blocking. When \tcode{detach()} returns, \tcode{*this} no longer represents the possibly continuing +thread of execution. When the thread previously represented by \tcode{*this} ends execution, the +implementation shall release any owned resources. + +\pnum\ensures \tcode{get_id() == id()}. + +\pnum\throws \tcode{system_error} when +an exception is required\iref{thread.req.exception}. + +\pnum \errors +\begin{itemize} +\item \tcode{no_such_process} --- if the thread is not valid. +\item \tcode{invalid_argument} --- if the thread is not joinable. +\end{itemize} +\end{itemdescr} + +\indexlibrarymember{get_id}{thread}% +\begin{itemdecl} +id get_id() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns A default constructed \tcode{id} object if \tcode{*this} does not represent a thread, +otherwise \tcode{this_thread::get_id()} for the thread of execution represented by +\tcode{*this}. +\end{itemdescr} + +\rSec3[thread.thread.static]{Static members} + +\indexlibrarymember{hardware_concurrency}{thread}% +\begin{itemdecl} +unsigned hardware_concurrency() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns The number of hardware thread contexts. \begin{note} This value should +only be considered to be a hint. \end{note} If this value is not computable or +well-defined, an implementation should return 0. +\end{itemdescr} + +\rSec3[thread.thread.algorithm]{Specialized algorithms} + +\indexlibrarymember{swap}{thread}% +\begin{itemdecl} +void swap(thread& x, thread& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum\effects As if by \tcode{x.swap(y)}. +\end{itemdescr} + +\rSec2[thread.jthread.class]{Class \tcode{jthread}} + +\pnum +The class \tcode{jthread} provides a mechanism +to create a new thread of execution. +The functionality is the same as for +class \tcode{thread}\iref{thread.thread.class} +with the additional ability to request that the thread stops +and then joins the started thread. + + +\indexlibrary{\idxcode{jthread}}% +\begin{codeblock} +namespace std { + class jthread { + public: + // types + using id = thread::id; + using native_handle_type = thread::native_handle_type; + + // \ref{thread.jthread.cons}, constructors, move, and assignment + jthread() noexcept; + template explicit jthread(F&& f, Args&&... args); + ~jthread(); + jthread(const jthread&) = delete; + jthread(jthread&&) noexcept; + jthread& operator=(const jthread&) = delete; + jthread& operator=(jthread&&) noexcept; + + // \ref{thread.jthread.mem}, members + void swap(jthread&) noexcept; + [[nodiscard]] bool joinable() const noexcept; + void join(); + void detach(); + [[nodiscard]] id get_id() const noexcept; + [[nodiscard]] native_handle_type native_handle(); // see~\ref{thread.req.native} + + // \ref{thread.jthread.mem}, stop token handling + [[nodiscard]] stop_source get_stop_source() noexcept; + [[nodiscard]] stop_token get_stop_token() const noexcept; + bool request_stop() noexcept; + + // \ref{thread.jthread.special}, specialized algorithms + friend void swap(jthread& lhs, jthread& rhs) noexcept; + + // \ref{thread.jthread.static}, static members + [[nodiscard]] static unsigned int hardware_concurrency() noexcept; + + private: + stop_source ssource; // \expos + }; +\end{codeblock} + +\rSec3[thread.jthread.cons]{Constructors, move, and assignment} + +\indexlibrary{\idxcode{jthread}!constructor}% +\begin{itemdecl} +jthread() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Constructs a \tcode{jthread} object that does not represent +a thread of execution. + +\pnum +\ensures +\tcode{get_id() == id()} is \tcode{true} +and \tcode{ssource.stop_possible()} is \tcode{false}. +\end{itemdescr} + +\indexlibrary{\idxcode{jthread}!constructor}% +\begin{itemdecl} +template explicit jthread(F&& f, Args&&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\requires +\tcode{F} and each $\tcode{T}_i$ in \tcode{Args} meet the +\oldconcept{MoveConstructible} requirements. +Either +\begin{codeblock} +@\placeholdernc{INVOKE}@(@\placeholdernc{decay-copy}@(std::forward(f)), get_stop_token(), + @\placeholdernc{decay-copy}@(std::forward(args))...) +\end{codeblock} +is a valid expression or +\begin{codeblock} +@\placeholdernc{INVOKE}@(@\placeholdernc{decay-copy}@(std::forward(f)), @\placeholdernc{decay-copy}@(std::forward(args))...) +\end{codeblock} +is a valid expression. + +\pnum +\constraints +\tcode{remove_cvref_t} is not the same type as \tcode{jthread}. + +\pnum +\effects +Initializes \tcode{ssource} and +constructs an object of type \tcode{jthread}. +The new thread of execution executes +\begin{codeblock} +@\placeholdernc{INVOKE}@(@\placeholdernc{decay-copy}@(std::forward(f)), get_stop_token(), + @\placeholdernc{decay-copy}@(std::forward(args))...) +\end{codeblock} +if that expression is well-formed, +otherwise +\begin{codeblock} +@\placeholdernc{INVOKE}@(@\placeholdernc{decay-copy}@(std::forward(f)), @\placeholdernc{decay-copy}@(std::forward(args))...) +\end{codeblock} +with the calls to +\tcode{\placeholder{decay-copy}} being evaluated in the constructing thread. +Any return value from this invocation is ignored. +\begin{note} +This implies that any exceptions not thrown from the invocation of the copy +of \tcode{f} will be thrown in the constructing thread, not the new thread. +\end{note} +If the \tcode{\placeholdernc{INVOKE}} expression exits via an exception, +\tcode{terminate} is called. + +\pnum +\sync The completion of the invocation of the constructor +synchronizes with the beginning of the invocation of the copy of \tcode{f}. + +\pnum\ensures +\tcode{get_id() != id()} is \tcode{true} +and \tcode{ssource.stop_possible()} is \tcode{true} +and \tcode{*this} represents the newly started thread. +\begin{note} +The calling thread can make a stop request only once, +because it cannot replace this stop token. +\end{note} + +\pnum\throws \tcode{system_error} if unable to start the new thread. + +\pnum +\errors +\begin{itemize} +\item \tcode{resource_unavailable_try_again} --- the system lacked +the necessary resources to create another thread, +or the system-imposed limit on the number of threads in a process +would be exceeded. +\end{itemize} +\end{itemdescr} + +\indexlibrary{\idxcode{jthread}!constructor}% +\begin{itemdecl} +jthread(jthread&& x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Constructs an object of type \tcode{jthread} from \tcode{x}, and sets +\tcode{x} to a default constructed state. + +\pnum +\ensures +\tcode{x.get_id() == id()} +and \tcode{get_id()} returns the value of \tcode{x.get_id()} +prior to the start of construction. +\tcode{ssource} has the value of \tcode{x.ssource} +prior to the start of construction +and \tcode{x.ssource.stop_possible()} is \tcode{false}. +\end{itemdescr} + +\indexlibrary{\idxcode{jthread}!destructor}% +\begin{itemdecl} +~jthread(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +If \tcode{joinable()} is \tcode{true}, +calls \tcode{request_stop()} and then \tcode{join()}. +\begin{note} Operations on \tcode{*this} are not synchronized. \end{note} +\end{itemdescr} + +\indexlibrarymember{operator=}{jthread}% +\begin{itemdecl} +jthread& operator=(jthread&& x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +If \tcode{joinable()} is \tcode{true}, +calls \tcode{request_stop()} and then \tcode{join()}. +Assigns the state of \tcode{x} to \tcode{*this} +and sets \tcode{x} to a default constructed state. + +\pnum +\ensures +\tcode{x.get_id() == id()} +and \tcode{get_id()} returns the value of \tcode{x.get_id()} +prior to the assignment. +\tcode{ssource} has the value of \tcode{x.ssource} +prior to the assignment +and \tcode{x.ssource.stop_possible()} is \tcode{false}. + +\pnum +\returns \tcode{*this}. +\end{itemdescr} + +\rSec3[thread.jthread.mem]{Members} + +\indexlibrarymember{swap}{jthread}% +\begin{itemdecl} +void swap(jthread& x) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Exchanges the values of \tcode{*this} and \tcode{x}. +\end{itemdescr} + + +\indexlibrarymember{joinable}{jthread}% +\begin{itemdecl} +[[nodiscard]] bool joinable() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns \tcode{get_id() != id()}. +\end{itemdescr} + +\indexlibrarymember{join}{jthread}% +\begin{itemdecl} +void join(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Blocks until the thread represented by \tcode{*this} has completed. + +\pnum +\sync The completion of the thread represented by \tcode{*this} +synchronizes with\iref{intro.multithread} +the corresponding successful \tcode{join()} return. +\begin{note} Operations on \tcode{*this} are not synchronized. \end{note} + +\pnum +\ensures The thread represented by \tcode{*this} has completed. +\tcode{get_id() == id()}. + +\pnum +\throws +\tcode{system_error} when an exception is required\iref{thread.req.exception}. + +\pnum +\errors +\begin{itemize} +\item \tcode{resource_deadlock_would_occur} --- if deadlock is detected or +\tcode{get_id() == this_thread::\brk{}get_id()}. + +\item \tcode{no_such_process} --- if the thread is not valid. + +\item \tcode{invalid_argument} --- if the thread is not joinable. +\end{itemize} +\end{itemdescr} + +\indexlibrarymember{detach}{jthread}% +\begin{itemdecl} +void detach(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +The thread represented by \tcode{*this} continues execution +without the calling thread blocking. +When \tcode{detach()} returns, +\tcode{*this} no longer represents the possibly continuing thread of execution. +When the thread previously represented by \tcode{*this} ends execution, +the implementation shall release any owned resources. + +\pnum +\ensures \tcode{get_id() == id()}. + +\pnum +\throws +\tcode{system_error} when an exception is required\iref{thread.req.exception}. + +\pnum \errors +\begin{itemize} +\item \tcode{no_such_process} --- if the thread is not valid. +\item \tcode{invalid_argument} --- if the thread is not joinable. +\end{itemize} +\end{itemdescr} + +\indexlibrarymember{get_id}{jthread}% +\begin{itemdecl} +id get_id() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A default constructed \tcode{id} object +if \tcode{*this} does not represent a thread, +otherwise \tcode{this_thread::get_id()} +for the thread of execution represented by \tcode{*this}. +\end{itemdescr} + +\rSec3[thread.jthread.stop]{Stop token handling} + +\indexlibrarymember{get_stop_source}{jthread}% +\begin{itemdecl} +[[nodiscard]] stop_source get_stop_source() noexcept +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: \tcode{return ssource;} +\end{itemdescr} + +\indexlibrarymember{get_stop_token}{jthread}% +\begin{itemdecl} +[[nodiscard]] stop_token get_stop_token() const noexcept +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: \tcode{return ssource.get_token();} +\end{itemdescr} + +\indexlibrarymember{request_stop}{jthread}% +\begin{itemdecl} +bool request_stop() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: \tcode{return ssource.request_stop();} +\end{itemdescr} + + +\rSec3[thread.jthread.special]{Specialized algorithms} + +\indexlibrarymember{swap}{jthread}% +\begin{itemdecl} +friend void swap(jthread& x, jthread& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: \tcode{x.swap(y)}. +\end{itemdescr} + +\rSec3[thread.jthread.static]{Static members} + +\indexlibrarymember{hardware_concurrency}{jthread}% +\begin{itemdecl} +unsigned hardware_concurrency() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns \tcode{thread::hardware_concurrency()}. +\end{itemdescr} + + +\rSec2[thread.thread.this]{Namespace \tcode{this_thread}} + +\begin{codeblock} +namespace std::this_thread { + thread::id get_id() noexcept; + + void yield() noexcept; + template + void sleep_until(const chrono::time_point& abs_time); + template + void sleep_for(const chrono::duration& rel_time); +} +\end{codeblock} + +\indexlibrarymember{get_id}{this_thread}% +\begin{itemdecl} +thread::id this_thread::get_id() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns An object of type \tcode{thread::id} that uniquely identifies the current thread of +execution. No other thread of execution shall have this id and this thread of execution shall +always have this id. The object returned shall not compare equal to a default constructed +\tcode{thread::id}. +\end{itemdescr} + +\indexlibrarymember{yield}{this_thread}% +\begin{itemdecl} +void this_thread::yield() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Offers the implementation the opportunity to reschedule. + +\pnum +\sync None. +\end{itemdescr} + +\indexlibrarymember{sleep_until}{this_thread}% +\begin{itemdecl} +template + void sleep_until(const chrono::time_point& abs_time); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Blocks the calling thread for the absolute timeout\iref{thread.req.timing} specified +by \tcode{abs_time}. + +\pnum +\sync None. + +\pnum +\throws Timeout-related exceptions\iref{thread.req.timing}. +\end{itemdescr} + +\indexlibrarymember{sleep_for}{this_thread}% +\begin{itemdecl} +template + void sleep_for(const chrono::duration& rel_time); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Blocks the calling thread for the relative timeout\iref{thread.req.timing} specified +by \tcode{rel_time}. + +\pnum +\sync None. + +\pnum +\throws Timeout-related exceptions\iref{thread.req.timing}. +\end{itemdescr} + +\rSec1[thread.mutex]{Mutual exclusion} + +\pnum +This subclause provides mechanisms for mutual exclusion: mutexes, locks, and call +once. These mechanisms ease the production of race-free +programs\iref{intro.multithread}. + +\rSec2[mutex.syn]{Header \tcode{} synopsis} +\indexhdr{mutex}% + +\begin{codeblock} +namespace std { + class mutex; + class recursive_mutex; + class timed_mutex; + class recursive_timed_mutex; + + struct defer_lock_t { explicit defer_lock_t() = default; }; + struct try_to_lock_t { explicit try_to_lock_t() = default; }; + struct adopt_lock_t { explicit adopt_lock_t() = default; }; + + inline constexpr defer_lock_t defer_lock { }; + inline constexpr try_to_lock_t try_to_lock { }; + inline constexpr adopt_lock_t adopt_lock { }; + + template class lock_guard; + template class scoped_lock; + template class unique_lock; + + template + void swap(unique_lock& x, unique_lock& y) noexcept; + + template int try_lock(L1&, L2&, L3&...); + template void lock(L1&, L2&, L3&...); + + struct once_flag; + + template + void call_once(once_flag& flag, Callable&& func, Args&&... args); +} +\end{codeblock} + +\rSec2[shared.mutex.syn]{Header \tcode{} synopsis} +\indexhdr{shared_mutex}% + +\begin{codeblock} +namespace std { + class shared_mutex; + class shared_timed_mutex; + template class shared_lock; + template + void swap(shared_lock& x, shared_lock& y) noexcept; +} +\end{codeblock} + +\rSec2[thread.mutex.requirements]{Mutex requirements} + +\rSec3[thread.mutex.requirements.general]{In general} + +\pnum +A mutex object facilitates protection against data races and allows safe synchronization of +data between execution agents\iref{thread.req.lockable}. +An execution agent \term{owns} a mutex from the time it successfully calls one of the +lock functions until it calls unlock. Mutexes can be either recursive or non-recursive, and can +grant simultaneous ownership to one or many execution agents. Both +recursive and non-recursive mutexes are supplied. + +\rSec3[thread.mutex.requirements.mutex]{Mutex types} + +\pnum +The \defn{mutex types} are the standard library types \tcode{mutex}, +\tcode{recursive_mutex}, \tcode{timed_mutex}, \tcode{recursive_timed_mutex}, +\tcode{shared_mutex}, and \tcode{shared_timed_mutex}. +They shall meet the requirements set out in this subclause. In this description, \tcode{m} +denotes an object of a mutex type. + +\pnum +The mutex types shall meet the \oldconcept{Lockable} requirements\iref{thread.req.lockable.req}. + +\pnum +The mutex types shall be \oldconcept{DefaultConstructible} and \oldconcept{Destructible}. If +initialization of an object of a mutex type fails, an exception of type +\tcode{system_error} shall be thrown. The mutex types shall not be copyable or movable. + +\pnum +The error conditions for error codes, if any, reported by member functions of the mutex types +shall be: +\begin{itemize} +\item \tcode{resource_unavailable_try_again} --- if any native handle type manipulated is not available. +\item \tcode{operation_not_permitted} --- if the thread does not have the +privilege to perform the operation. +\item \tcode{invalid_argument} --- if any native handle type manipulated as part of mutex +construction is incorrect. +\end{itemize} + +\pnum +The implementation shall provide lock and unlock operations, as described below. +For purposes of determining the existence of a data race, these behave as +atomic operations\iref{intro.multithread}. The lock and unlock operations on +a single mutex shall appear to occur in a single total order. \begin{note} This +can be viewed as the modification order\iref{intro.multithread} of the +mutex. \end{note} +\begin{note} Construction and +destruction of an object of a mutex type need not be thread-safe; other +synchronization should be used to ensure that mutex objects are initialized +and visible to other threads. \end{note} + +\pnum +The expression \tcode{m.lock()} shall be well-formed and have the following semantics: + +\begin{itemdescr} +\pnum +\requires If \tcode{m} is of type \tcode{mutex}, \tcode{timed_mutex}, +\tcode{shared_mutex}, or \tcode{shared_timed_mutex}, the calling +thread does not own the mutex. + +\pnum +\effects Blocks the calling thread until ownership of the mutex can be obtained for the calling thread. + +\pnum +\ensures The calling thread owns the mutex. + +\pnum +\returntype \tcode{void}. + +\pnum +\sync Prior \tcode{unlock()} operations on the same object shall +\term{synchronize with}\iref{intro.multithread} this operation. + +\pnum +\throws \tcode{system_error} when +an exception is required\iref{thread.req.exception}. + +\pnum \errors +\begin{itemize} +\item \tcode{operation_not_permitted} --- if the thread does not have the +privilege to perform the operation. + +\item \tcode{resource_deadlock_would_occur} --- if the implementation detects +that a deadlock would occur. +\end{itemize} +\end{itemdescr} + +\pnum +The expression \tcode{m.try_lock()} shall be well-formed and have the following semantics: + +\begin{itemdescr} +\pnum \requires If \tcode{m} is of type \tcode{mutex}, \tcode{timed_mutex}, \tcode{shared_mutex}, or \tcode{shared_timed_mutex}, the calling thread does not own the mutex. \pnum -\effects Attempts to obtain ownership of the mutex for the calling thread without -blocking. If ownership is not obtained, there is no effect and \tcode{try_lock()} -immediately returns. An implementation may fail to obtain the lock even if it is not -held by any other thread. \begin{note} This spurious failure is normally uncommon, but -allows interesting implementations based on a simple -compare and exchange\iref{atomics}. -\end{note} -An implementation should ensure that \tcode{try_lock()} does not consistently return \tcode{false} -in the absence of contending mutex acquisitions. +\effects Attempts to obtain ownership of the mutex for the calling thread without +blocking. If ownership is not obtained, there is no effect and \tcode{try_lock()} +immediately returns. An implementation may fail to obtain the lock even if it is not +held by any other thread. \begin{note} This spurious failure is normally uncommon, but +allows interesting implementations based on a simple +compare and exchange\iref{atomics}. +\end{note} +An implementation should ensure that \tcode{try_lock()} does not consistently return \tcode{false} +in the absence of contending mutex acquisitions. + +\pnum +\returntype \tcode{bool}. + +\pnum +\returns \tcode{true} if ownership of the mutex was obtained for the calling +thread, otherwise \tcode{false}. + +\pnum +\sync If \tcode{try_lock()} returns \tcode{true}, prior \tcode{unlock()} operations +on the same object \term{synchronize with}\iref{intro.multithread} this operation. +\begin{note} Since \tcode{lock()} does not synchronize with a failed subsequent +\tcode{try_lock()}, the visibility rules are weak enough that little would be +known about the state after a failure, even in the absence of spurious failures. \end{note} + +\pnum +\throws Nothing. +\end{itemdescr} + +\pnum +The expression \tcode{m.unlock()} shall be well-formed and have the following semantics: + +\begin{itemdescr} +\pnum +\requires The calling thread shall own the mutex. + +\pnum +\effects Releases the calling thread's ownership of the mutex. + +\pnum +\returntype \tcode{void}. + +\pnum +\sync This operation synchronizes with\iref{intro.multithread} subsequent +lock operations that obtain ownership on the same object. + +\pnum +\throws Nothing. +\end{itemdescr} + +\rSec4[thread.mutex.class]{Class \tcode{mutex}} + +\indexlibrary{\idxcode{mutex}}% +\begin{codeblock} +namespace std { + class mutex { + public: + constexpr mutex() noexcept; + ~mutex(); + + mutex(const mutex&) = delete; + mutex& operator=(const mutex&) = delete; + + void lock(); + bool try_lock(); + void unlock(); + + using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native} + native_handle_type native_handle(); // see~\ref{thread.req.native} + }; +} +\end{codeblock} + +\pnum +The class \tcode{mutex} provides a non-recursive mutex with exclusive ownership +semantics. If one thread owns a mutex object, attempts by another thread to acquire +ownership of that object will fail (for \tcode{try_lock()}) or block (for +\tcode{lock()}) until the owning thread has released ownership with a call to +\tcode{unlock()}. + +\pnum +\begin{note} +After a thread \tcode{A} has called \tcode{unlock()}, releasing a mutex, it is possible for another +thread \tcode{B} to lock the same mutex, observe that it is no longer in use, unlock it, and +destroy it, before thread \tcode{A} appears to have returned from its unlock call. Implementations +are required to handle such scenarios correctly, as long as thread \tcode{A} doesn't access the +mutex after the unlock call returns. These cases typically occur when a reference-counted object +contains a mutex that is used to protect the reference count. +\end{note} + +\pnum +The class \tcode{mutex} shall meet all of the mutex +requirements\iref{thread.mutex.requirements}. It shall be a standard-layout +class\iref{class.prop}. + +\pnum +\begin{note} A program may deadlock if the thread that owns a \tcode{mutex} object calls +\tcode{lock()} on that object. If the implementation can detect the deadlock, +a \tcode{resource_deadlock_would_occur} error condition may be observed. \end{note} + +\pnum +The behavior of a program is undefined if +it destroys a \tcode{mutex} object owned by any thread or +a thread terminates while owning a \tcode{mutex} object. + +\rSec4[thread.mutex.recursive]{Class \tcode{recursive_mutex}} + +\indexlibrary{\idxcode{recursive_mutex}}% +\begin{codeblock} +namespace std { + class recursive_mutex { + public: + recursive_mutex(); + ~recursive_mutex(); + + recursive_mutex(const recursive_mutex&) = delete; + recursive_mutex& operator=(const recursive_mutex&) = delete; + + void lock(); + bool try_lock() noexcept; + void unlock(); + + using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native} + native_handle_type native_handle(); // see~\ref{thread.req.native} + }; +} +\end{codeblock} + +\pnum +The class \tcode{recursive_mutex} provides a recursive mutex with exclusive ownership +semantics. If one thread owns a \tcode{recursive_mutex} object, attempts by another +thread to acquire ownership of that object will fail (for \tcode{try_lock()}) or block +(for \tcode{lock()}) until the first thread has completely released ownership. + +\pnum +The class \tcode{recursive_mutex} shall meet all of the mutex +requirements\iref{thread.mutex.requirements}. It shall be a standard-layout +class\iref{class.prop}. + +\pnum +A thread that owns a \tcode{recursive_mutex} object may acquire additional levels of +ownership by calling \tcode{lock()} or \tcode{try_lock()} on that object. It is +unspecified how many levels of ownership may be acquired by a single thread. If a thread +has already acquired the maximum level of ownership for a \tcode{recursive_mutex} +object, additional calls to \tcode{try_lock()} shall fail, and additional calls to +\tcode{lock()} shall throw an exception of type \tcode{system_error}. A thread +shall call \tcode{unlock()} once for each level of ownership acquired by calls to +\tcode{lock()} and \tcode{try_lock()}. Only when all levels of ownership have been +released may ownership be acquired by another thread. + +\pnum +The behavior of a program is undefined if: + +\begin{itemize} +\item it destroys a \tcode{recursive_mutex} object owned by any thread or +\item a thread terminates while owning a \tcode{recursive_mutex} object. +\end{itemize} + +\rSec3[thread.timedmutex.requirements]{Timed mutex types} + +\pnum +The \defn{timed mutex types} are the standard library types \tcode{timed_mutex}, +\tcode{recursive_timed_mutex}, and \tcode{shared_timed_mutex}. They shall +meet the requirements set out below. +In this description, \tcode{m} denotes an object of a mutex type, +\tcode{rel_time} denotes an object of an +instantiation of \tcode{duration}\iref{time.duration}, and \tcode{abs_time} denotes an +object of an +instantiation of \tcode{time_point}\iref{time.point}. + +\pnum +The timed mutex types shall meet the \oldconcept{TimedLockable} +requirements\iref{thread.req.lockable.timed}. + +\pnum +The expression \tcode{m.try_lock_for(rel_time)} shall be well-formed and have the +following semantics: + +\begin{itemdescr} +\pnum +\requires If \tcode{m} is of type \tcode{timed_mutex} or +\tcode{shared_timed_mutex}, the calling thread does not +own the mutex. + +\pnum +\effects The function attempts to obtain ownership of the mutex within the +relative timeout\iref{thread.req.timing} +specified by \tcode{rel_time}. If the time specified by \tcode{rel_time} is less than or +equal to \tcode{rel_time.zero()}, the function attempts to obtain ownership without blocking (as if by calling +\tcode{try_lock()}). The function shall return within the timeout specified by +\tcode{rel_time} only if it has obtained ownership of the mutex object. \begin{note} As +with \tcode{try_lock()}, there is no guarantee that ownership will be obtained if the +lock is available, but implementations are expected to make a strong effort to do so. +\end{note} + +\pnum +\returntype \tcode{bool}. + +\pnum +\returns \tcode{true} if ownership was obtained, otherwise \tcode{false}. + +\pnum +\sync If \tcode{try_lock_for()} returns \tcode{true}, prior \tcode{unlock()} operations +on the same object \term{synchronize with}\iref{intro.multithread} this operation. + +\pnum\throws Timeout-related exceptions\iref{thread.req.timing}. +\end{itemdescr} + +\pnum +The expression \tcode{m.try_lock_until(abs_time)} shall be well-formed and have the +following semantics: + +\begin{itemdescr} +\pnum +\requires If \tcode{m} is of type \tcode{timed_mutex} or +\tcode{shared_timed_mutex}, the calling thread does not own the +mutex. + +\pnum +\effects The function attempts to obtain ownership of the mutex. If +\tcode{abs_time} has already passed, the function attempts to obtain ownership +without blocking (as if by calling \tcode{try_lock()}). The function shall +return before the absolute timeout\iref{thread.req.timing} specified by +\tcode{abs_time} only if it has obtained ownership of the mutex object. +\begin{note} As with \tcode{try_lock()}, there is no guarantee that ownership will +be obtained if the lock is available, but implementations are expected to make a +strong effort to do so. \end{note} + +\pnum\returntype \tcode{bool}. + +\pnum +\returns \tcode{true} if ownership was obtained, otherwise \tcode{false}. + +\pnum +\sync If \tcode{try_lock_until()} returns \tcode{true}, prior \tcode{unlock()} +operations on the same object \term{synchronize with}\iref{intro.multithread} +this operation. + +\pnum\throws Timeout-related exceptions\iref{thread.req.timing}. +\end{itemdescr} + +\rSec4[thread.timedmutex.class]{Class \tcode{timed_mutex}} + +\indexlibrary{\idxcode{timed_mutex}}% +\begin{codeblock} +namespace std { + class timed_mutex { + public: + timed_mutex(); + ~timed_mutex(); + + timed_mutex(const timed_mutex&) = delete; + timed_mutex& operator=(const timed_mutex&) = delete; + + void lock(); // blocking + bool try_lock(); + template + bool try_lock_for(const chrono::duration& rel_time); + template + bool try_lock_until(const chrono::time_point& abs_time); + void unlock(); + + using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native} + native_handle_type native_handle(); // see~\ref{thread.req.native} + }; +} +\end{codeblock} + +\pnum +The class \tcode{timed_mutex} provides a non-recursive mutex with exclusive ownership +semantics. If one thread owns a \tcode{timed_mutex} object, attempts by another thread +to acquire ownership of that object will fail (for \tcode{try_lock()}) or block +(for \tcode{lock()}, \tcode{try_lock_for()}, and \tcode{try_lock_until()}) until +the owning thread has released ownership with a call to \tcode{unlock()} or the +call to \tcode{try_lock_for()} or \tcode{try_lock_until()} times out (having +failed to obtain ownership). + +\pnum +The class \tcode{timed_mutex} shall meet all of the timed mutex +requirements\iref{thread.timedmutex.requirements}. It shall be a standard-layout +class\iref{class.prop}. + +\pnum +The behavior of a program is undefined if: + +\begin{itemize} +\item it destroys a \tcode{timed_mutex} object owned by any thread, +\item a thread that owns a \tcode{timed_mutex} object calls \tcode{lock()}, +\tcode{try_lock()}, \tcode{try_lock_for()}, or \tcode{try_lock_until()} on that object, or +\item a thread terminates while owning a \tcode{timed_mutex} object. +\end{itemize} + +\rSec4[thread.timedmutex.recursive]{Class \tcode{recursive_timed_mutex}} + +\indexlibrary{\idxcode{recursive_timed_mutex}}% +\begin{codeblock} +namespace std { + class recursive_timed_mutex { + public: + recursive_timed_mutex(); + ~recursive_timed_mutex(); + + recursive_timed_mutex(const recursive_timed_mutex&) = delete; + recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; + + void lock(); // blocking + bool try_lock() noexcept; + template + bool try_lock_for(const chrono::duration& rel_time); + template + bool try_lock_until(const chrono::time_point& abs_time); + void unlock(); + + using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native} + native_handle_type native_handle(); // see~\ref{thread.req.native} + }; +} +\end{codeblock} + +\pnum +The class \tcode{recursive_timed_mutex} provides a recursive mutex with exclusive +ownership semantics. If one thread owns a \tcode{recursive_timed_mutex} object, +attempts by another thread to acquire ownership of that object will fail (for +\tcode{try_lock()}) or block (for \tcode{lock()}, \tcode{try_lock_for()}, and +\tcode{try_lock_until()}) until the owning thread has completely released +ownership or the call to \tcode{try_lock_for()} or \tcode{try_lock_until()} +times out (having failed to obtain ownership). + +\pnum +The class \tcode{recursive_timed_mutex} shall meet all of the timed mutex +requirements\iref{thread.timedmutex.requirements}. It shall be a standard-layout +class\iref{class.prop}. + +\pnum +A thread that owns a \tcode{recursive_timed_mutex} object may acquire additional +levels of ownership by calling \tcode{lock()}, \tcode{try_lock()}, +\tcode{try_lock_for()}, or \tcode{try_lock_until()} on that object. It is +unspecified how many levels of ownership may be acquired by a single thread. If +a thread has already acquired the maximum level of ownership for a +\tcode{recursive_timed_mutex} object, additional calls to \tcode{try_lock()}, +\tcode{try_lock_for()}, or \tcode{try_lock_until()} shall fail, and additional +calls to \tcode{lock()} shall throw an exception of type \tcode{system_error}. A +thread shall call \tcode{unlock()} once for each level of ownership acquired by +calls to \tcode{lock()}, \tcode{try_lock()}, \tcode{try_lock_for()}, and +\tcode{try_lock_until()}. Only when all levels of ownership have been released +may ownership of the object be acquired by another thread. + +\pnum +The behavior of a program is undefined if: + +\begin{itemize} +\item it destroys a \tcode{recursive_timed_mutex} object owned by any thread, or +\item a thread terminates while owning a \tcode{recursive_timed_mutex} object. +\end{itemize} + + +\rSec3[thread.sharedmutex.requirements]{Shared mutex types} + +\pnum +The standard library types \tcode{shared_mutex} and \tcode{shared_timed_mutex} +are \defn{shared mutex types}. Shared mutex types shall meet the requirements of +mutex types\iref{thread.mutex.requirements.mutex}, and additionally +shall meet the requirements set out below. In this description, +\tcode{m} denotes an object of a shared mutex type. + +\pnum +In addition to the exclusive lock ownership mode specified +in~\ref{thread.mutex.requirements.mutex}, shared mutex types provide a +\defn{shared lock} ownership mode. Multiple execution agents can +simultaneously hold a shared lock ownership of a shared mutex type. But no +execution agent shall hold a shared lock while another execution agent holds an +exclusive lock on the same shared mutex type, and vice-versa. The maximum +number of execution agents which can share a shared lock on a single shared +mutex type is unspecified, but shall be at least 10000. If more than the +maximum number of execution agents attempt to obtain a shared lock, the +excess execution agents shall block until the number of shared locks are +reduced below the maximum amount by other execution agents releasing their +shared lock. + +\pnum +The expression \tcode{m.lock_shared()} shall be well-formed and have the +following semantics: + +\begin{itemdescr} +\pnum +\requires The calling thread has no ownership of the mutex. + +\pnum +\effects Blocks the calling thread until shared ownership of the mutex can be obtained for the calling thread. +If an exception is thrown then a shared lock shall not have been acquired for the current thread. + +\pnum +\ensures The calling thread has a shared lock on the mutex. + +\pnum +\returntype \tcode{void}. + +\pnum +\sync Prior \tcode{unlock()} operations on the same object shall synchronize with\iref{intro.multithread} this operation. + +\pnum +\throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. + +\pnum +\errors +\begin{itemize} +\item \tcode{operation_not_permitted} --- if the thread does not have the privilege to perform the operation. +\item \tcode{resource_deadlock_would_occur} --- if the implementation detects that a deadlock would occur. +\end{itemize} +\end{itemdescr} + +\pnum +The expression \tcode{m.unlock_shared()} shall be well-formed and have the following semantics: + +\begin{itemdescr} +\pnum +\requires The calling thread shall hold a shared lock on the mutex. + +\pnum +\effects Releases a shared lock on the mutex held by the calling thread. + +\pnum +\returntype \tcode{void}. + +\pnum +\sync This operation synchronizes with\iref{intro.multithread} subsequent +\tcode{lock()} operations that obtain ownership on the same object. + +\pnum +\throws Nothing. +\end{itemdescr} + +\pnum +The expression \tcode{m.try_lock_shared()} shall be well-formed and have the following semantics: + +\begin{itemdescr} +\pnum +\requires The calling thread has no ownership of the mutex. + +\pnum +\effects Attempts to obtain shared ownership of the mutex for the calling +thread without blocking. If shared ownership is not obtained, there is no +effect and \tcode{try_lock_shared()} immediately returns. An implementation +may fail to obtain the lock even if it is not held by any other thread. + +\pnum +\returntype \tcode{bool}. + +\pnum +\returns \tcode{true} if the shared ownership lock was acquired, \tcode{false} +otherwise. + +\pnum +\sync If \tcode{try_lock_shared()} returns \tcode{true}, prior \tcode{unlock()} +operations on the same object synchronize with\iref{intro.multithread} this +operation. + +\pnum +\throws Nothing. +\end{itemdescr} + +\rSec4[thread.sharedmutex.class]{Class \tcode{shared_mutex}} + +\indexlibrary{\idxcode{shared_mutex}}% +\begin{codeblock} +namespace std { + class shared_mutex { + public: + shared_mutex(); + ~shared_mutex(); + + shared_mutex(const shared_mutex&) = delete; + shared_mutex& operator=(const shared_mutex&) = delete; + + // exclusive ownership + void lock(); // blocking + bool try_lock(); + void unlock(); + + // shared ownership + void lock_shared(); // blocking + bool try_lock_shared(); + void unlock_shared(); + + using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native} + native_handle_type native_handle(); // see~\ref{thread.req.native} + }; +} +\end{codeblock} + +\pnum +The class \tcode{shared_mutex} provides a non-recursive mutex +with shared ownership semantics. + +\pnum +The class \tcode{shared_mutex} shall meet all of the +shared mutex requirements\iref{thread.sharedmutex.requirements}. +It shall be a standard-layout class\iref{class.prop}. + +\pnum +The behavior of a program is undefined if: +\begin{itemize} +\item it destroys a \tcode{shared_mutex} object owned by any thread, +\item a thread attempts to recursively gain any ownership of a \tcode{shared_mutex}, or +\item a thread terminates while possessing any ownership of a \tcode{shared_mutex}. +\end{itemize} + +\pnum +\tcode{shared_mutex} may be a synonym for \tcode{shared_timed_mutex}. + +\rSec3[thread.sharedtimedmutex.requirements]{Shared timed mutex types} + +\pnum +The standard library type \tcode{shared_timed_mutex} is a +\defn{shared timed mutex type}. Shared timed mutex types shall meet the requirements of +timed mutex types\iref{thread.timedmutex.requirements}, +shared mutex types\iref{thread.sharedmutex.requirements}, and additionally +shall meet the requirements set out below. In this description, +\tcode{m} denotes an object of a shared timed mutex type, +\tcode{rel_type} denotes an object of an instantiation of +\tcode{duration}\iref{time.duration}, and +\tcode{abs_time} denotes an object of an instantiation of +\tcode{time_point}\iref{time.point}. + +\pnum +The expression \tcode{m.try_lock_shared_for(rel_time)} shall be well-formed and +have the following semantics: + +\begin{itemdescr} +\pnum +\requires The calling thread has no ownership of the mutex. + +\pnum +\effects Attempts to obtain +shared lock ownership for the calling thread within the relative +timeout\iref{thread.req.timing} specified by \tcode{rel_time}. If the time +specified by \tcode{rel_time} is less than or equal to \tcode{rel_time.zero()}, +the function attempts to obtain ownership without blocking (as if by calling +\tcode{try_lock_shared()}). The function shall return within the timeout +specified by \tcode{rel_time} only if it has obtained shared ownership of the +mutex object. \begin{note} As with \tcode{try_lock()}, there is no guarantee that +ownership will be obtained if the lock is available, but implementations are +expected to make a strong effort to do so. \end{note} +If an exception is thrown then a shared lock shall not have been acquired for +the current thread. \pnum \returntype \tcode{bool}. \pnum -\returns \tcode{true} if ownership of the mutex was obtained for the calling -thread, otherwise \tcode{false}. +\returns \tcode{true} if the shared lock was acquired, \tcode{false} otherwise. \pnum -\sync If \tcode{try_lock()} returns \tcode{true}, prior \tcode{unlock()} operations -on the same object \term{synchronize with}\iref{intro.multithread} this operation. -\begin{note} Since \tcode{lock()} does not synchronize with a failed subsequent -\tcode{try_lock()}, the visibility rules are weak enough that little would be -known about the state after a failure, even in the absence of spurious failures. \end{note} +\sync If \tcode{try_lock_shared_for()} returns \tcode{true}, prior +\tcode{unlock()} operations on the same object synchronize +with\iref{intro.multithread} this operation. \pnum -\throws Nothing. +\throws Timeout-related exceptions\iref{thread.req.timing}. \end{itemdescr} \pnum -The expression \tcode{m.unlock()} shall be well-formed and have the following semantics: +The expression \tcode{m.try_lock_shared_until(abs_time)} shall be well-formed +and have the following semantics: \begin{itemdescr} \pnum -\requires The calling thread shall own the mutex. +\requires The calling thread has no ownership of the mutex. \pnum -\effects Releases the calling thread's ownership of the mutex. +\effects The function attempts to obtain shared ownership of the mutex. If +\tcode{abs_time} has already passed, the function attempts to obtain shared +ownership without blocking (as if by calling \tcode{try_lock_shared()}). The +function shall return before the absolute timeout\iref{thread.req.timing} +specified by \tcode{abs_time} only if it has obtained shared ownership of the +mutex object. \begin{note} As with \tcode{try_lock()}, there is no guarantee that +ownership will be obtained if the lock is available, but implementations are +expected to make a strong effort to do so. \end{note} +If an exception is thrown then a shared lock shall not have been acquired for +the current thread. \pnum -\returntype \tcode{void}. +\returntype \tcode{bool}. \pnum -\sync This operation synchronizes with\iref{intro.multithread} subsequent -lock operations that obtain ownership on the same object. +\returns \tcode{true} if the shared lock was acquired, \tcode{false} otherwise. \pnum -\throws Nothing. +\sync If \tcode{try_lock_shared_until()} returns \tcode{true}, prior +\tcode{unlock()} operations on the same object synchronize +with\iref{intro.multithread} this operation. + +\pnum +\throws Timeout-related exceptions\iref{thread.req.timing}. \end{itemdescr} -\rSec4[thread.mutex.class]{Class \tcode{mutex}} +\rSec4[thread.sharedtimedmutex.class]{Class \tcode{shared_timed_mutex}} -\indexlibrary{\idxcode{mutex}}% +\indexlibrary{\idxcode{shared_timed_mutex}}% \begin{codeblock} namespace std { - class mutex { + class shared_timed_mutex { public: - constexpr mutex() noexcept; - ~mutex(); + shared_timed_mutex(); + ~shared_timed_mutex(); - mutex(const mutex&) = delete; - mutex& operator=(const mutex&) = delete; + shared_timed_mutex(const shared_timed_mutex&) = delete; + shared_timed_mutex& operator=(const shared_timed_mutex&) = delete; - void lock(); + // exclusive ownership + void lock(); // blocking bool try_lock(); + template + bool try_lock_for(const chrono::duration& rel_time); + template + bool try_lock_until(const chrono::time_point& abs_time); void unlock(); - using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native} - native_handle_type native_handle(); // see~\ref{thread.req.native} + // shared ownership + void lock_shared(); // blocking + bool try_lock_shared(); + template + bool try_lock_shared_for(const chrono::duration& rel_time); + template + bool try_lock_shared_until(const chrono::time_point& abs_time); + void unlock_shared(); }; } \end{codeblock} \pnum -The class \tcode{mutex} provides a non-recursive mutex with exclusive ownership -semantics. If one thread owns a mutex object, attempts by another thread to acquire -ownership of that object will fail (for \tcode{try_lock()}) or block (for -\tcode{lock()}) until the owning thread has released ownership with a call to -\tcode{unlock()}. +The class \tcode{shared_timed_mutex} provides a non-recursive mutex with shared +ownership semantics. \pnum -\begin{note} -After a thread \tcode{A} has called \tcode{unlock()}, releasing a mutex, it is possible for another -thread \tcode{B} to lock the same mutex, observe that it is no longer in use, unlock it, and -destroy it, before thread \tcode{A} appears to have returned from its unlock call. Implementations -are required to handle such scenarios correctly, as long as thread \tcode{A} doesn't access the -mutex after the unlock call returns. These cases typically occur when a reference-counted object -contains a mutex that is used to protect the reference count. -\end{note} +The class \tcode{shared_timed_mutex} shall meet all of the +shared timed mutex requirements\iref{thread.sharedtimedmutex.requirements}. +It shall be a standard-layout class\iref{class.prop}. \pnum -The class \tcode{mutex} shall meet all of the mutex -requirements\iref{thread.mutex.requirements}. It shall be a standard-layout -class\iref{class.prop}. +The behavior of a program is undefined if: +\begin{itemize} +\item it destroys a \tcode{shared_timed_mutex} object owned by any thread, +\item a thread attempts to recursively gain any ownership of a \tcode{shared_timed_mutex}, or +\item a thread terminates while possessing any ownership of a \tcode{shared_timed_mutex}. +\end{itemize} -\pnum -\begin{note} A program may deadlock if the thread that owns a \tcode{mutex} object calls -\tcode{lock()} on that object. If the implementation can detect the deadlock, -a \tcode{resource_deadlock_would_occur} error condition may be observed. \end{note} +\rSec2[thread.lock]{Locks} \pnum -The behavior of a program is undefined if -it destroys a \tcode{mutex} object owned by any thread or -a thread terminates while owning a \tcode{mutex} object. +A \term{lock} is an object that holds a reference to a lockable object and may unlock the +lockable object during the lock's destruction (such as when leaving block scope). An execution +agent may use a lock to aid in managing ownership of a lockable object in an exception safe +manner. A lock is said to \term{own} a lockable object if it is currently managing the +ownership of that lockable object for an execution agent. A lock does not manage the lifetime +of the lockable object it references. \begin{note} Locks are intended to ease the burden of +unlocking the lockable object under both normal and exceptional circumstances. \end{note} -\rSec4[thread.mutex.recursive]{Class \tcode{recursive_mutex}} +\pnum +Some lock constructors take tag types which describe what should be done with the lockable +object during the lock's construction. -\indexlibrary{\idxcode{recursive_mutex}}% +\indexlibrary{\idxcode{defer_lock_t}}% +\indexlibrary{\idxcode{try_to_lock_t}}% +\indexlibrary{\idxcode{adopt_lock_t}}% +\indexlibrary{\idxcode{defer_lock}}% +\indexlibrary{\idxcode{try_to_lock}}% +\indexlibrary{\idxcode{adopt_lock}}% \begin{codeblock} namespace std { - class recursive_mutex { - public: - recursive_mutex(); - ~recursive_mutex(); - - recursive_mutex(const recursive_mutex&) = delete; - recursive_mutex& operator=(const recursive_mutex&) = delete; - - void lock(); - bool try_lock() noexcept; - void unlock(); + struct defer_lock_t { }; // do not acquire ownership of the mutex + struct try_to_lock_t { }; // try to acquire ownership of the mutex + // without blocking + struct adopt_lock_t { }; // assume the calling thread has already + // obtained mutex ownership and manage it - using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native} - native_handle_type native_handle(); // see~\ref{thread.req.native} - }; + inline constexpr defer_lock_t defer_lock { }; + inline constexpr try_to_lock_t try_to_lock { }; + inline constexpr adopt_lock_t adopt_lock { }; } \end{codeblock} -\pnum -The class \tcode{recursive_mutex} provides a recursive mutex with exclusive ownership -semantics. If one thread owns a \tcode{recursive_mutex} object, attempts by another -thread to acquire ownership of that object will fail (for \tcode{try_lock()}) or block -(for \tcode{lock()}) until the first thread has completely released ownership. - -\pnum -The class \tcode{recursive_mutex} shall meet all of the mutex -requirements\iref{thread.mutex.requirements}. It shall be a standard-layout -class\iref{class.prop}. - -\pnum -A thread that owns a \tcode{recursive_mutex} object may acquire additional levels of -ownership by calling \tcode{lock()} or \tcode{try_lock()} on that object. It is -unspecified how many levels of ownership may be acquired by a single thread. If a thread -has already acquired the maximum level of ownership for a \tcode{recursive_mutex} -object, additional calls to \tcode{try_lock()} shall fail, and additional calls to -\tcode{lock()} shall throw an exception of type \tcode{system_error}. A thread -shall call \tcode{unlock()} once for each level of ownership acquired by calls to -\tcode{lock()} and \tcode{try_lock()}. Only when all levels of ownership have been -released may ownership be acquired by another thread. +\rSec3[thread.lock.guard]{Class template \tcode{lock_guard}} -\pnum -The behavior of a program is undefined if: +\indexlibrary{\idxcode{lock_guard}}% +\begin{codeblock} +namespace std { + template + class lock_guard { + public: + using mutex_type = Mutex; -\begin{itemize} -\item it destroys a \tcode{recursive_mutex} object owned by any thread or -\item a thread terminates while owning a \tcode{recursive_mutex} object. -\end{itemize} + explicit lock_guard(mutex_type& m); + lock_guard(mutex_type& m, adopt_lock_t); + ~lock_guard(); -\rSec3[thread.timedmutex.requirements]{Timed mutex types} + lock_guard(const lock_guard&) = delete; + lock_guard& operator=(const lock_guard&) = delete; -\pnum -The \defn{timed mutex types} are the standard library types \tcode{timed_mutex}, -\tcode{recursive_timed_mutex}, and \tcode{shared_timed_mutex}. They shall -meet the requirements set out below. -In this description, \tcode{m} denotes an object of a mutex type, -\tcode{rel_time} denotes an object of an -instantiation of \tcode{duration}\iref{time.duration}, and \tcode{abs_time} denotes an -object of an -instantiation of \tcode{time_point}\iref{time.point}. + private: + mutex_type& pm; // \expos + }; +} +\end{codeblock} \pnum -The timed mutex types shall meet the \oldconcept{TimedLockable} -requirements\iref{thread.req.lockable.timed}. +An object of type \tcode{lock_guard} controls the ownership of a lockable object +within a scope. A \tcode{lock_guard} object maintains ownership of a lockable +object throughout the \tcode{lock_guard} object's lifetime\iref{basic.life}. +The behavior of a program is undefined if the lockable object referenced by +\tcode{pm} does not exist for the entire lifetime of the \tcode{lock_guard} +object. The supplied \tcode{Mutex} type shall meet the \oldconcept{BasicLockable} +requirements\iref{thread.req.lockable.basic}. -\pnum -The expression \tcode{m.try_lock_for(rel_time)} shall be well-formed and have the -following semantics: +\indexlibrary{\idxcode{lock_guard}!constructor}% +\begin{itemdecl} +explicit lock_guard(mutex_type& m); +\end{itemdecl} \begin{itemdescr} \pnum -\requires If \tcode{m} is of type \tcode{timed_mutex} or -\tcode{shared_timed_mutex}, the calling thread does not -own the mutex. - -\pnum -\effects The function attempts to obtain ownership of the mutex within the -relative timeout\iref{thread.req.timing} -specified by \tcode{rel_time}. If the time specified by \tcode{rel_time} is less than or -equal to \tcode{rel_time.zero()}, the function attempts to obtain ownership without blocking (as if by calling -\tcode{try_lock()}). The function shall return within the timeout specified by -\tcode{rel_time} only if it has obtained ownership of the mutex object. \begin{note} As -with \tcode{try_lock()}, there is no guarantee that ownership will be obtained if the -lock is available, but implementations are expected to make a strong effort to do so. -\end{note} - -\pnum -\returntype \tcode{bool}. - -\pnum -\returns \tcode{true} if ownership was obtained, otherwise \tcode{false}. +\requires If \tcode{mutex_type} is not a recursive mutex, +the calling thread does not own the mutex \tcode{m}. \pnum -\sync If \tcode{try_lock_for()} returns \tcode{true}, prior \tcode{unlock()} operations -on the same object \term{synchronize with}\iref{intro.multithread} this operation. - -\pnum\throws Timeout-related exceptions\iref{thread.req.timing}. +\effects Initializes \tcode{pm} with \tcode{m}. Calls \tcode{m.lock()}. \end{itemdescr} -\pnum -The expression \tcode{m.try_lock_until(abs_time)} shall be well-formed and have the -following semantics: +\indexlibrary{\idxcode{lock_guard}!constructor}% +\begin{itemdecl} +lock_guard(mutex_type& m, adopt_lock_t); +\end{itemdecl} \begin{itemdescr} \pnum -\requires If \tcode{m} is of type \tcode{timed_mutex} or -\tcode{shared_timed_mutex}, the calling thread does not own the -mutex. +\requires The calling thread owns the mutex \tcode{m}. \pnum -\effects The function attempts to obtain ownership of the mutex. If -\tcode{abs_time} has already passed, the function attempts to obtain ownership -without blocking (as if by calling \tcode{try_lock()}). The function shall -return before the absolute timeout\iref{thread.req.timing} specified by -\tcode{abs_time} only if it has obtained ownership of the mutex object. -\begin{note} As with \tcode{try_lock()}, there is no guarantee that ownership will -be obtained if the lock is available, but implementations are expected to make a -strong effort to do so. \end{note} - -\pnum\returntype \tcode{bool}. +\effects Initializes \tcode{pm} with \tcode{m}. \pnum -\returns \tcode{true} if ownership was obtained, otherwise \tcode{false}. +\throws Nothing. +\end{itemdescr} -\pnum -\sync If \tcode{try_lock_until()} returns \tcode{true}, prior \tcode{unlock()} -operations on the same object \term{synchronize with}\iref{intro.multithread} -this operation. +\indexlibrary{\idxcode{lock_guard}!destructor}% +\begin{itemdecl} +~lock_guard(); +\end{itemdecl} -\pnum\throws Timeout-related exceptions\iref{thread.req.timing}. +\begin{itemdescr} +\pnum +\effects As if by \tcode{pm.unlock()}. \end{itemdescr} -\rSec4[thread.timedmutex.class]{Class \tcode{timed_mutex}} -\indexlibrary{\idxcode{timed_mutex}}% +\rSec3[thread.lock.scoped]{Class template \tcode{scoped_lock}} + +\indexlibrary{\idxcode{scoped_lock}}% \begin{codeblock} namespace std { - class timed_mutex { + template + class scoped_lock { public: - timed_mutex(); - ~timed_mutex(); + using mutex_type = Mutex; // If \tcode{MutexTypes...} consists of the single type \tcode{Mutex} - timed_mutex(const timed_mutex&) = delete; - timed_mutex& operator=(const timed_mutex&) = delete; + explicit scoped_lock(MutexTypes&... m); + explicit scoped_lock(adopt_lock_t, MutexTypes&... m); + ~scoped_lock(); - void lock(); // blocking - bool try_lock(); - template - bool try_lock_for(const chrono::duration& rel_time); - template - bool try_lock_until(const chrono::time_point& abs_time); - void unlock(); + scoped_lock(const scoped_lock&) = delete; + scoped_lock& operator=(const scoped_lock&) = delete; - using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native} - native_handle_type native_handle(); // see~\ref{thread.req.native} + private: + tuple pm; // \expos }; } \end{codeblock} \pnum -The class \tcode{timed_mutex} provides a non-recursive mutex with exclusive ownership -semantics. If one thread owns a \tcode{timed_mutex} object, attempts by another thread -to acquire ownership of that object will fail (for \tcode{try_lock()}) or block -(for \tcode{lock()}, \tcode{try_lock_for()}, and \tcode{try_lock_until()}) until -the owning thread has released ownership with a call to \tcode{unlock()} or the -call to \tcode{try_lock_for()} or \tcode{try_lock_until()} times out (having -failed to obtain ownership). +An object of type \tcode{scoped_lock} controls the ownership of lockable objects +within a scope. A \tcode{scoped_lock} object maintains ownership of lockable +objects throughout the \tcode{scoped_lock} object's lifetime\iref{basic.life}. +The behavior of a program is undefined if the lockable objects referenced by +\tcode{pm} do not exist for the entire lifetime of the \tcode{scoped_lock} +object. +When \tcode{sizeof...(MutexTypes)} is \tcode{1}, +the supplied \tcode{Mutex} type +shall meet the \oldconcept{BasicLockable} requirements\iref{thread.req.lockable.basic}. +Otherwise, each of the mutex types +shall meet the \oldconcept{Lockable} requirements\iref{thread.req.lockable.req}. -\pnum -The class \tcode{timed_mutex} shall meet all of the timed mutex -requirements\iref{thread.timedmutex.requirements}. It shall be a standard-layout -class\iref{class.prop}. +\indexlibrary{\idxcode{scoped_lock}!constructor}% +\begin{itemdecl} +explicit scoped_lock(MutexTypes&... m); +\end{itemdecl} +\begin{itemdescr} \pnum -The behavior of a program is undefined if: +\requires If a \tcode{MutexTypes} type is not a recursive mutex, +the calling thread does not own the corresponding mutex element of \tcode{m}. -\begin{itemize} -\item it destroys a \tcode{timed_mutex} object owned by any thread, -\item a thread that owns a \tcode{timed_mutex} object calls \tcode{lock()}, -\tcode{try_lock()}, \tcode{try_lock_for()}, or \tcode{try_lock_until()} on that object, or -\item a thread terminates while owning a \tcode{timed_mutex} object. -\end{itemize} +\pnum +\effects Initializes \tcode{pm} with \tcode{tie(m...)}. +Then if \tcode{sizeof...(MutexTypes)} is \tcode{0}, no effects. +Otherwise if \tcode{sizeof...(MutexTypes)} is \tcode{1}, then \tcode{m.lock()}. +Otherwise, \tcode{lock(m...)}. +\end{itemdescr} -\rSec4[thread.timedmutex.recursive]{Class \tcode{recursive_timed_mutex}} +\indexlibrary{\idxcode{scoped_lock}!constructor}% +\begin{itemdecl} +explicit scoped_lock(adopt_lock_t, MutexTypes&... m); +\end{itemdecl} -\indexlibrary{\idxcode{recursive_timed_mutex}}% -\begin{codeblock} -namespace std { - class recursive_timed_mutex { - public: - recursive_timed_mutex(); - ~recursive_timed_mutex(); +\begin{itemdescr} +\pnum +\requires The calling thread owns all the mutexes in \tcode{m}. - recursive_timed_mutex(const recursive_timed_mutex&) = delete; - recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; +\pnum +\effects Initializes \tcode{pm} with \tcode{tie(m...)}. - void lock(); // blocking - bool try_lock() noexcept; - template - bool try_lock_for(const chrono::duration& rel_time); - template - bool try_lock_until(const chrono::time_point& abs_time); - void unlock(); +\pnum +\throws Nothing. +\end{itemdescr} - using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native} - native_handle_type native_handle(); // see~\ref{thread.req.native} - }; -} -\end{codeblock} +\indexlibrary{\idxcode{scoped_lock}!destructor}% +\begin{itemdecl} +~scoped_lock(); +\end{itemdecl} +\begin{itemdescr} \pnum -The class \tcode{recursive_timed_mutex} provides a recursive mutex with exclusive -ownership semantics. If one thread owns a \tcode{recursive_timed_mutex} object, -attempts by another thread to acquire ownership of that object will fail (for -\tcode{try_lock()}) or block (for \tcode{lock()}, \tcode{try_lock_for()}, and -\tcode{try_lock_until()}) until the owning thread has completely released -ownership or the call to \tcode{try_lock_for()} or \tcode{try_lock_until()} -times out (having failed to obtain ownership). +\effects For all \tcode{i} in \range{0}{sizeof...(MutexTypes)}, +\tcode{get(pm).unlock()}. +\end{itemdescr} -\pnum -The class \tcode{recursive_timed_mutex} shall meet all of the timed mutex -requirements\iref{thread.timedmutex.requirements}. It shall be a standard-layout -class\iref{class.prop}. +\rSec3[thread.lock.unique]{Class template \tcode{unique_lock}} -\pnum -A thread that owns a \tcode{recursive_timed_mutex} object may acquire additional -levels of ownership by calling \tcode{lock()}, \tcode{try_lock()}, -\tcode{try_lock_for()}, or \tcode{try_lock_until()} on that object. It is -unspecified how many levels of ownership may be acquired by a single thread. If -a thread has already acquired the maximum level of ownership for a -\tcode{recursive_timed_mutex} object, additional calls to \tcode{try_lock()}, -\tcode{try_lock_for()}, or \tcode{try_lock_until()} shall fail, and additional -calls to \tcode{lock()} shall throw an exception of type \tcode{system_error}. A -thread shall call \tcode{unlock()} once for each level of ownership acquired by -calls to \tcode{lock()}, \tcode{try_lock()}, \tcode{try_lock_for()}, and -\tcode{try_lock_until()}. Only when all levels of ownership have been released -may ownership of the object be acquired by another thread. +\indexlibrary{\idxcode{unique_lock}}% +\begin{codeblock} +namespace std { + template + class unique_lock { + public: + using mutex_type = Mutex; -\pnum -The behavior of a program is undefined if: + // \ref{thread.lock.unique.cons}, construct/copy/destroy + unique_lock() noexcept; + explicit unique_lock(mutex_type& m); + unique_lock(mutex_type& m, defer_lock_t) noexcept; + unique_lock(mutex_type& m, try_to_lock_t); + unique_lock(mutex_type& m, adopt_lock_t); + template + unique_lock(mutex_type& m, const chrono::time_point& abs_time); + template + unique_lock(mutex_type& m, const chrono::duration& rel_time); + ~unique_lock(); -\begin{itemize} -\item it destroys a \tcode{recursive_timed_mutex} object owned by any thread, or -\item a thread terminates while owning a \tcode{recursive_timed_mutex} object. -\end{itemize} + unique_lock(const unique_lock&) = delete; + unique_lock& operator=(const unique_lock&) = delete; + unique_lock(unique_lock&& u) noexcept; + unique_lock& operator=(unique_lock&& u); -\rSec3[thread.sharedmutex.requirements]{Shared mutex types} + // \ref{thread.lock.unique.locking}, locking + void lock(); + bool try_lock(); -\pnum -The standard library types \tcode{shared_mutex} and \tcode{shared_timed_mutex} -are \defn{shared mutex types}. Shared mutex types shall meet the requirements of -mutex types\iref{thread.mutex.requirements.mutex}, and additionally -shall meet the requirements set out below. In this description, -\tcode{m} denotes an object of a shared mutex type. + template + bool try_lock_for(const chrono::duration& rel_time); + template + bool try_lock_until(const chrono::time_point& abs_time); -\pnum -In addition to the exclusive lock ownership mode specified -in~\ref{thread.mutex.requirements.mutex}, shared mutex types provide a -\defn{shared lock} ownership mode. Multiple execution agents can -simultaneously hold a shared lock ownership of a shared mutex type. But no -execution agent shall hold a shared lock while another execution agent holds an -exclusive lock on the same shared mutex type, and vice-versa. The maximum -number of execution agents which can share a shared lock on a single shared -mutex type is unspecified, but shall be at least 10000. If more than the -maximum number of execution agents attempt to obtain a shared lock, the -excess execution agents shall block until the number of shared locks are -reduced below the maximum amount by other execution agents releasing their -shared lock. + void unlock(); -\pnum -The expression \tcode{m.lock_shared()} shall be well-formed and have the -following semantics: + // \ref{thread.lock.unique.mod}, modifiers + void swap(unique_lock& u) noexcept; + mutex_type* release() noexcept; -\begin{itemdescr} -\pnum -\requires The calling thread has no ownership of the mutex. + // \ref{thread.lock.unique.obs}, observers + bool owns_lock() const noexcept; + explicit operator bool () const noexcept; + mutex_type* mutex() const noexcept; + + private: + mutex_type* pm; // \expos + bool owns; // \expos + }; + + template + void swap(unique_lock& x, unique_lock& y) noexcept; +} +\end{codeblock} \pnum -\effects Blocks the calling thread until shared ownership of the mutex can be obtained for the calling thread. -If an exception is thrown then a shared lock shall not have been acquired for the current thread. +An object of type \tcode{unique_lock} controls the ownership of a lockable +object within a scope. Ownership of the lockable object may be acquired at +construction or after construction, and may be transferred, after +acquisition, to another \tcode{unique_lock} object. Objects of type \tcode{unique_lock} are not +copyable but are movable. The behavior of a program is undefined if the contained pointer +\tcode{pm} is not null and the lockable object pointed +to by \tcode{pm} does not exist for the entire remaining +lifetime\iref{basic.life} of the \tcode{unique_lock} object. The supplied +\tcode{Mutex} type shall meet the \oldconcept{BasicLockable} +requirements\iref{thread.req.lockable.basic}. \pnum -\ensures The calling thread has a shared lock on the mutex. +\begin{note} \tcode{unique_lock} meets the \oldconcept{BasicLockable} requirements. If \tcode{Mutex} +meets the \oldconcept{Lockable} requirements\iref{thread.req.lockable.req}, +\tcode{unique_lock} also meets the \oldconcept{Lockable} requirements; +if \tcode{Mutex} +meets the \oldconcept{TimedLockable} requirements\iref{thread.req.lockable.timed}, +\tcode{unique_lock} also meets the \oldconcept{TimedLockable} requirements. \end{note} -\pnum -\returntype \tcode{void}. +\rSec4[thread.lock.unique.cons]{Constructors, destructor, and assignment} -\pnum -\sync Prior \tcode{unlock()} operations on the same object shall synchronize with\iref{intro.multithread} this operation. +\indexlibrary{\idxcode{unique_lock}!constructor}% +\begin{itemdecl} +unique_lock() noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum -\throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. +\effects Constructs an object of type \tcode{unique_lock}. \pnum -\errors -\begin{itemize} -\item \tcode{operation_not_permitted} --- if the thread does not have the privilege to perform the operation. -\item \tcode{resource_deadlock_would_occur} --- if the implementation detects that a deadlock would occur. -\end{itemize} +\ensures \tcode{pm == 0} and \tcode{owns == false}. \end{itemdescr} -\pnum -The expression \tcode{m.unlock_shared()} shall be well-formed and have the following semantics: +\indexlibrary{\idxcode{unique_lock}!constructor}% +\begin{itemdecl} +explicit unique_lock(mutex_type& m); +\end{itemdecl} \begin{itemdescr} \pnum -\requires The calling thread shall hold a shared lock on the mutex. - -\pnum -\effects Releases a shared lock on the mutex held by the calling thread. - -\pnum -\returntype \tcode{void}. +\requires If \tcode{mutex_type} is not a recursive mutex the calling thread does not own the mutex. \pnum -\sync This operation synchronizes with\iref{intro.multithread} subsequent -\tcode{lock()} operations that obtain ownership on the same object. +\effects Constructs an object of type \tcode{unique_lock} and calls \tcode{m.lock()}. \pnum -\throws Nothing. +\ensures \tcode{pm == addressof(m)} and \tcode{owns == true}. \end{itemdescr} -\pnum -The expression \tcode{m.try_lock_shared()} shall be well-formed and have the following semantics: +\indexlibrary{\idxcode{unique_lock}!constructor}% +\begin{itemdecl} +unique_lock(mutex_type& m, defer_lock_t) noexcept; +\end{itemdecl} \begin{itemdescr} \pnum -\requires The calling thread has no ownership of the mutex. +\effects Constructs an object of type \tcode{unique_lock}. \pnum -\effects Attempts to obtain shared ownership of the mutex for the calling -thread without blocking. If shared ownership is not obtained, there is no -effect and \tcode{try_lock_shared()} immediately returns. An implementation -may fail to obtain the lock even if it is not held by any other thread. +\ensures \tcode{pm == addressof(m)} and \tcode{owns == false}. +\end{itemdescr} -\pnum -\returntype \tcode{bool}. +\indexlibrary{\idxcode{unique_lock}!constructor}% +\begin{itemdecl} +unique_lock(mutex_type& m, try_to_lock_t); +\end{itemdecl} +\begin{itemdescr} \pnum -\returns \tcode{true} if the shared ownership lock was acquired, \tcode{false} -otherwise. +\requires +The supplied \tcode{Mutex} type shall meet the \oldconcept{Lockable} +requirements\iref{thread.req.lockable.req}. +If \tcode{mutex_type} is not a recursive mutex the calling thread does not own the mutex. \pnum -\sync If \tcode{try_lock_shared()} returns \tcode{true}, prior \tcode{unlock()} -operations on the same object synchronize with\iref{intro.multithread} this -operation. +\effects Constructs an object of type \tcode{unique_lock} and calls \tcode{m.try_lock()}. \pnum -\throws Nothing. +\ensures \tcode{pm == addressof(m)} and \tcode{owns == res}, +where \tcode{res} is the value returned by the call to \tcode{m.try_lock()}. \end{itemdescr} -\rSec4[thread.sharedmutex.class]{Class \tcode{shared_mutex}} - -\indexlibrary{\idxcode{shared_mutex}}% -\begin{codeblock} -namespace std { - class shared_mutex { - public: - shared_mutex(); - ~shared_mutex(); - - shared_mutex(const shared_mutex&) = delete; - shared_mutex& operator=(const shared_mutex&) = delete; - - // exclusive ownership - void lock(); // blocking - bool try_lock(); - void unlock(); - - // shared ownership - void lock_shared(); // blocking - bool try_lock_shared(); - void unlock_shared(); - - using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native} - native_handle_type native_handle(); // see~\ref{thread.req.native} - }; -} -\end{codeblock} - -\pnum -The class \tcode{shared_mutex} provides a non-recursive mutex -with shared ownership semantics. +\indexlibrary{\idxcode{unique_lock}!constructor}% +\begin{itemdecl} +unique_lock(mutex_type& m, adopt_lock_t); +\end{itemdecl} +\begin{itemdescr} \pnum -The class \tcode{shared_mutex} shall meet all of the -shared mutex requirements\iref{thread.sharedmutex.requirements}. -It shall be a standard-layout class\iref{class.prop}. +\requires The calling thread owns the mutex. \pnum -The behavior of a program is undefined if: -\begin{itemize} -\item it destroys a \tcode{shared_mutex} object owned by any thread, -\item a thread attempts to recursively gain any ownership of a \tcode{shared_mutex}, or -\item a thread terminates while possessing any ownership of a \tcode{shared_mutex}. -\end{itemize} +\effects Constructs an object of type \tcode{unique_lock}. \pnum -\tcode{shared_mutex} may be a synonym for \tcode{shared_timed_mutex}. - -\rSec3[thread.sharedtimedmutex.requirements]{Shared timed mutex types} +\ensures \tcode{pm == addressof(m)} and \tcode{owns == true}. \pnum -The standard library type \tcode{shared_timed_mutex} is a -\defn{shared timed mutex type}. Shared timed mutex types shall meet the requirements of -timed mutex types\iref{thread.timedmutex.requirements}, -shared mutex types\iref{thread.sharedmutex.requirements}, and additionally -shall meet the requirements set out below. In this description, -\tcode{m} denotes an object of a shared timed mutex type, -\tcode{rel_type} denotes an object of an instantiation of -\tcode{duration}\iref{time.duration}, and -\tcode{abs_time} denotes an object of an instantiation of -\tcode{time_point}\iref{time.point}. +\throws Nothing. +\end{itemdescr} -\pnum -The expression \tcode{m.try_lock_shared_for(rel_time)} shall be well-formed and -have the following semantics: +\indexlibrary{\idxcode{unique_lock}!constructor}% +\begin{itemdecl} +template + unique_lock(mutex_type& m, const chrono::time_point& abs_time); +\end{itemdecl} \begin{itemdescr} \pnum -\requires The calling thread has no ownership of the mutex. +\requires If \tcode{mutex_type} is not a recursive mutex the calling thread +does not own the mutex. The supplied \tcode{Mutex} type shall meet the +\oldconcept{TimedLockable} requirements\iref{thread.req.lockable.timed}. \pnum -\effects Attempts to obtain -shared lock ownership for the calling thread within the relative -timeout\iref{thread.req.timing} specified by \tcode{rel_time}. If the time -specified by \tcode{rel_time} is less than or equal to \tcode{rel_time.zero()}, -the function attempts to obtain ownership without blocking (as if by calling -\tcode{try_lock_shared()}). The function shall return within the timeout -specified by \tcode{rel_time} only if it has obtained shared ownership of the -mutex object. \begin{note} As with \tcode{try_lock()}, there is no guarantee that -ownership will be obtained if the lock is available, but implementations are -expected to make a strong effort to do so. \end{note} -If an exception is thrown then a shared lock shall not have been acquired for -the current thread. +\effects Constructs an object of type \tcode{unique_lock} and calls \tcode{m.try_lock_until(abs_time)}. \pnum -\returntype \tcode{bool}. +\ensures \tcode{pm == addressof(m)} and \tcode{owns == res}, +where \tcode{res} is +the value returned by the call to \tcode{m.try_lock_until(abs_time)}. +\end{itemdescr} + +\indexlibrary{\idxcode{unique_lock}!constructor}% +\begin{itemdecl} +template + unique_lock(mutex_type& m, const chrono::duration& rel_time); +\end{itemdecl} +\begin{itemdescr} \pnum -\returns \tcode{true} if the shared lock was acquired, \tcode{false} otherwise. +\requires If \tcode{mutex_type} is not a recursive mutex the calling thread does not own the mutex. +The supplied \tcode{Mutex} type shall meet the \oldconcept{TimedLockable} requirements\iref{thread.req.lockable.timed}. \pnum -\sync If \tcode{try_lock_shared_for()} returns \tcode{true}, prior -\tcode{unlock()} operations on the same object synchronize -with\iref{intro.multithread} this operation. +\effects Constructs an object of type \tcode{unique_lock} and calls \tcode{m.try_lock_for(rel_time)}. \pnum -\throws Timeout-related exceptions\iref{thread.req.timing}. +\ensures \tcode{pm == addressof(m)} and \tcode{owns == res}, +where \tcode{res} is the value returned by the call to \tcode{m.try_lock_for(rel_time)}. \end{itemdescr} -\pnum -The expression \tcode{m.try_lock_shared_until(abs_time)} shall be well-formed -and have the following semantics: +\indexlibrary{\idxcode{unique_lock}!constructor}% +\begin{itemdecl} +unique_lock(unique_lock&& u) noexcept; +\end{itemdecl} \begin{itemdescr} -\pnum -\requires The calling thread has no ownership of the mutex. +\pnum\ensures \tcode{pm == u_p.pm} and \tcode{owns == u_p.owns} (where \tcode{u_p} is the state of \tcode{u} just prior to this construction), \tcode{u.pm == 0} and \tcode{u.owns == false}. +\end{itemdescr} -\pnum -\effects The function attempts to obtain shared ownership of the mutex. If -\tcode{abs_time} has already passed, the function attempts to obtain shared -ownership without blocking (as if by calling \tcode{try_lock_shared()}). The -function shall return before the absolute timeout\iref{thread.req.timing} -specified by \tcode{abs_time} only if it has obtained shared ownership of the -mutex object. \begin{note} As with \tcode{try_lock()}, there is no guarantee that -ownership will be obtained if the lock is available, but implementations are -expected to make a strong effort to do so. \end{note} -If an exception is thrown then a shared lock shall not have been acquired for -the current thread. +\indexlibrarymember{operator=}{unique_lock}% +\begin{itemdecl} +unique_lock& operator=(unique_lock&& u); +\end{itemdecl} -\pnum -\returntype \tcode{bool}. +\begin{itemdescr} +\pnum\effects If \tcode{owns} calls \tcode{pm->unlock()}. -\pnum -\returns \tcode{true} if the shared lock was acquired, \tcode{false} otherwise. +\pnum\ensures \tcode{pm == u_p.pm} and \tcode{owns == u_p.owns} (where \tcode{u_p} is the state of \tcode{u} just prior to this construction), \tcode{u.pm == 0} and \tcode{u.owns == false}. \pnum -\sync If \tcode{try_lock_shared_until()} returns \tcode{true}, prior -\tcode{unlock()} operations on the same object synchronize -with\iref{intro.multithread} this operation. +\begin{note} With a recursive mutex it is possible for both \tcode{*this} and \tcode{u} to own the same mutex before the assignment. In this case, \tcode{*this} will own the mutex after the assignment and \tcode{u} will not. \end{note} -\pnum -\throws Timeout-related exceptions\iref{thread.req.timing}. +\pnum\throws Nothing. \end{itemdescr} -\rSec4[thread.sharedtimedmutex.class]{Class \tcode{shared_timed_mutex}} - -\indexlibrary{\idxcode{shared_timed_mutex}}% -\begin{codeblock} -namespace std { - class shared_timed_mutex { - public: - shared_timed_mutex(); - ~shared_timed_mutex(); - - shared_timed_mutex(const shared_timed_mutex&) = delete; - shared_timed_mutex& operator=(const shared_timed_mutex&) = delete; - // exclusive ownership - void lock(); // blocking - bool try_lock(); - template - bool try_lock_for(const chrono::duration& rel_time); - template - bool try_lock_until(const chrono::time_point& abs_time); - void unlock(); +\indexlibrary{\idxcode{unique_lock}!destructor}% +\begin{itemdecl} +~unique_lock(); +\end{itemdecl} - // shared ownership - void lock_shared(); // blocking - bool try_lock_shared(); - template - bool try_lock_shared_for(const chrono::duration& rel_time); - template - bool try_lock_shared_until(const chrono::time_point& abs_time); - void unlock_shared(); - }; -} -\end{codeblock} +\begin{itemdescr} +\pnum\effects If \tcode{owns} calls \tcode{pm->unlock()}. +\end{itemdescr} + +\rSec4[thread.lock.unique.locking]{Locking} +\indexlibrarymember{lock}{unique_lock}% +\begin{itemdecl} +void lock(); +\end{itemdecl} + +\begin{itemdescr} \pnum -The class \tcode{shared_timed_mutex} provides a non-recursive mutex with shared -ownership semantics. +\effects As if by \tcode{pm->lock()}. \pnum -The class \tcode{shared_timed_mutex} shall meet all of the -shared timed mutex requirements\iref{thread.sharedtimedmutex.requirements}. -It shall be a standard-layout class\iref{class.prop}. +\ensures \tcode{owns == true}. \pnum -The behavior of a program is undefined if: +\throws +Any exception thrown by \tcode{pm->lock()}. \tcode{system_error} when an exception +is required\iref{thread.req.exception}. + +\pnum +\errors \begin{itemize} -\item it destroys a \tcode{shared_timed_mutex} object owned by any thread, -\item a thread attempts to recursively gain any ownership of a \tcode{shared_timed_mutex}, or -\item a thread terminates while possessing any ownership of a \tcode{shared_timed_mutex}. +\item \tcode{operation_not_permitted} --- if \tcode{pm} is \tcode{nullptr}. +\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} +is \tcode{true}. \end{itemize} +\end{itemdescr} -\rSec2[thread.lock]{Locks} +\indexlibrarymember{try_lock}{unique_lock}% +\begin{itemdecl} +bool try_lock(); +\end{itemdecl} +\begin{itemdescr} \pnum -A \term{lock} is an object that holds a reference to a lockable object and may unlock the -lockable object during the lock's destruction (such as when leaving block scope). An execution -agent may use a lock to aid in managing ownership of a lockable object in an exception safe -manner. A lock is said to \term{own} a lockable object if it is currently managing the -ownership of that lockable object for an execution agent. A lock does not manage the lifetime -of the lockable object it references. \begin{note} Locks are intended to ease the burden of -unlocking the lockable object under both normal and exceptional circumstances. \end{note} +\requires The supplied \tcode{Mutex} shall meet the \oldconcept{Lockable} +requirements\iref{thread.req.lockable.req}. \pnum -Some lock constructors take tag types which describe what should be done with the lockable -object during the lock's construction. +\effects As if by \tcode{pm->try_lock()}. -\indexlibrary{\idxcode{defer_lock_t}}% -\indexlibrary{\idxcode{try_to_lock_t}}% -\indexlibrary{\idxcode{adopt_lock_t}}% -\indexlibrary{\idxcode{defer_lock}}% -\indexlibrary{\idxcode{try_to_lock}}% -\indexlibrary{\idxcode{adopt_lock}}% -\begin{codeblock} -namespace std { - struct defer_lock_t { }; // do not acquire ownership of the mutex - struct try_to_lock_t { }; // try to acquire ownership of the mutex - // without blocking - struct adopt_lock_t { }; // assume the calling thread has already - // obtained mutex ownership and manage it +\pnum\returns The value returned by the call to \tcode{try_lock()}. - inline constexpr defer_lock_t defer_lock { }; - inline constexpr try_to_lock_t try_to_lock { }; - inline constexpr adopt_lock_t adopt_lock { }; -} -\end{codeblock} +\pnum +\ensures \tcode{owns == res}, where \tcode{res} is the value returned by +the call to \tcode{try_lock()}. -\rSec3[thread.lock.guard]{Class template \tcode{lock_guard}} +\pnum +\throws +Any exception thrown by \tcode{pm->try_lock()}. \tcode{system_error} when an exception +is required\iref{thread.req.exception}. -\indexlibrary{\idxcode{lock_guard}}% -\begin{codeblock} -namespace std { - template - class lock_guard { - public: - using mutex_type = Mutex; +\pnum +\errors +\begin{itemize} +\item \tcode{operation_not_permitted} --- if \tcode{pm} is \tcode{nullptr}. +\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} +is \tcode{true}. +\end{itemize} +\end{itemdescr} - explicit lock_guard(mutex_type& m); - lock_guard(mutex_type& m, adopt_lock_t); - ~lock_guard(); +\indexlibrarymember{try_lock_until}{unique_lock}% +\begin{itemdecl} +template + bool try_lock_until(const chrono::time_point& abs_time); +\end{itemdecl} - lock_guard(const lock_guard&) = delete; - lock_guard& operator=(const lock_guard&) = delete; +\begin{itemdescr} +\pnum +\requires The supplied \tcode{Mutex} type shall meet the \oldconcept{TimedLockable} +requirements\iref{thread.req.lockable.timed}. - private: - mutex_type& pm; // \expos - }; -} -\end{codeblock} +\pnum +\effects As if by \tcode{pm->try_lock_until(abs_time)}. \pnum -An object of type \tcode{lock_guard} controls the ownership of a lockable object -within a scope. A \tcode{lock_guard} object maintains ownership of a lockable -object throughout the \tcode{lock_guard} object's lifetime\iref{basic.life}. -The behavior of a program is undefined if the lockable object referenced by -\tcode{pm} does not exist for the entire lifetime of the \tcode{lock_guard} -object. The supplied \tcode{Mutex} type shall meet the \oldconcept{BasicLockable} -requirements\iref{thread.req.lockable.basic}. +\returns The value returned by the call to \tcode{try_lock_until(abs_time)}. -\indexlibrary{\idxcode{lock_guard}!constructor}% -\begin{itemdecl} -explicit lock_guard(mutex_type& m); -\end{itemdecl} +\pnum +\ensures \tcode{owns == res}, where \tcode{res} is the value returned by +the call to \tcode{try_lock_until(abs_time)}. -\begin{itemdescr} \pnum -\requires If \tcode{mutex_type} is not a recursive mutex, -the calling thread does not own the mutex \tcode{m}. +\throws Any exception thrown by \tcode{pm->try_lock_until()}. \tcode{system_error} when an +exception is required\iref{thread.req.exception}. \pnum -\effects Initializes \tcode{pm} with \tcode{m}. Calls \tcode{m.lock()}. +\errors +\begin{itemize} +\item \tcode{operation_not_permitted} --- if \tcode{pm} is \tcode{nullptr}. +\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is +\tcode{true}. +\end{itemize} \end{itemdescr} -\indexlibrary{\idxcode{lock_guard}!constructor}% +\indexlibrarymember{try_lock_for}{unique_lock}% \begin{itemdecl} -lock_guard(mutex_type& m, adopt_lock_t); +template + bool try_lock_for(const chrono::duration& rel_time); \end{itemdecl} \begin{itemdescr} \pnum -\requires The calling thread owns the mutex \tcode{m}. +\requires The supplied \tcode{Mutex} type shall meet the \oldconcept{TimedLockable} requirements\iref{thread.req.lockable.timed}. \pnum -\effects Initializes \tcode{pm} with \tcode{m}. +\effects As if by \tcode{pm->try_lock_for(rel_time)}. \pnum -\throws Nothing. +\returns The value returned by the call to \tcode{try_lock_until(rel_time)}. + +\pnum +\ensures \tcode{owns == res}, where \tcode{res} is the value returned by the call to \tcode{try_lock_for(rel_time)}. + +\pnum +\throws Any exception thrown by \tcode{pm->try_lock_for()}. \tcode{system_error} when an +exception is required\iref{thread.req.exception}. + +\pnum +\errors +\begin{itemize} +\item \tcode{operation_not_permitted} --- if \tcode{pm} is \tcode{nullptr}. +\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is +\tcode{true}. +\end{itemize} \end{itemdescr} -\indexlibrary{\idxcode{lock_guard}!destructor}% +\indexlibrarymember{unlock}{unique_lock}% \begin{itemdecl} -~lock_guard(); +void unlock(); \end{itemdecl} \begin{itemdescr} -\pnum -\effects As if by \tcode{pm.unlock()}. -\end{itemdescr} - +\pnum\effects As if by \tcode{pm->unlock()}. -\rSec3[thread.lock.scoped]{Class template \tcode{scoped_lock}} +\pnum\ensures \tcode{owns == false}. -\indexlibrary{\idxcode{scoped_lock}}% -\begin{codeblock} -namespace std { - template - class scoped_lock { - public: - using mutex_type = Mutex; // If \tcode{MutexTypes...} consists of the single type \tcode{Mutex} +\pnum\throws \tcode{system_error} when +an exception is required\iref{thread.req.exception}. - explicit scoped_lock(MutexTypes&... m); - explicit scoped_lock(adopt_lock_t, MutexTypes&... m); - ~scoped_lock(); +\pnum \errors +\begin{itemize} +\item \tcode{operation_not_permitted} --- if on entry \tcode{owns} is \tcode{false}. +\end{itemize} +\end{itemdescr} - scoped_lock(const scoped_lock&) = delete; - scoped_lock& operator=(const scoped_lock&) = delete; +\rSec4[thread.lock.unique.mod]{Modifiers} - private: - tuple pm; // \expos - }; -} -\end{codeblock} +\indexlibrarymember{swap}{unique_lock}% +\begin{itemdecl} +void swap(unique_lock& u) noexcept; +\end{itemdecl} -\pnum -An object of type \tcode{scoped_lock} controls the ownership of lockable objects -within a scope. A \tcode{scoped_lock} object maintains ownership of lockable -objects throughout the \tcode{scoped_lock} object's lifetime\iref{basic.life}. -The behavior of a program is undefined if the lockable objects referenced by -\tcode{pm} do not exist for the entire lifetime of the \tcode{scoped_lock} -object. -When \tcode{sizeof...(MutexTypes)} is \tcode{1}, -the supplied \tcode{Mutex} type -shall meet the \oldconcept{BasicLockable} requirements\iref{thread.req.lockable.basic}. -Otherwise, each of the mutex types -shall meet the \oldconcept{Lockable} requirements\iref{thread.req.lockable.req}. +\begin{itemdescr} +\pnum\effects Swaps the data members of \tcode{*this} and \tcode{u}. +\end{itemdescr} -\indexlibrary{\idxcode{scoped_lock}!constructor}% +\indexlibrarymember{release}{unique_lock}% \begin{itemdecl} -explicit scoped_lock(MutexTypes&... m); +mutex_type* release() noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\requires If a \tcode{MutexTypes} type is not a recursive mutex, -the calling thread does not own the corresponding mutex element of \tcode{m}. +\pnum\returns The previous value of \tcode{pm}. -\pnum -\effects Initializes \tcode{pm} with \tcode{tie(m...)}. -Then if \tcode{sizeof...(MutexTypes)} is \tcode{0}, no effects. -Otherwise if \tcode{sizeof...(MutexTypes)} is \tcode{1}, then \tcode{m.lock()}. -Otherwise, \tcode{lock(m...)}. +\pnum\ensures \tcode{pm == 0} and \tcode{owns == false}. +\end{itemdescr} + +\indexlibrarymember{swap}{unique_lock}% +\begin{itemdecl} +template + void swap(unique_lock& x, unique_lock& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum\effects As if by \tcode{x.swap(y)}. \end{itemdescr} -\indexlibrary{\idxcode{scoped_lock}!constructor}% +\rSec4[thread.lock.unique.obs]{Observers} + +\indexlibrarymember{owns_lock}{unique_lock}% \begin{itemdecl} -explicit scoped_lock(adopt_lock_t, MutexTypes&... m); +bool owns_lock() const noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\requires The calling thread owns all the mutexes in \tcode{m}. +\pnum\returns \tcode{owns}. +\end{itemdescr} -\pnum -\effects Initializes \tcode{pm} with \tcode{tie(m...)}. +\indexlibrarymember{operator bool}{unique_lock}% +\begin{itemdecl} +explicit operator bool() const noexcept; +\end{itemdecl} -\pnum -\throws Nothing. +\begin{itemdescr} +\pnum\returns \tcode{owns}. \end{itemdescr} -\indexlibrary{\idxcode{scoped_lock}!destructor}% +\indexlibrarymember{mutex}{unique_lock}% \begin{itemdecl} -~scoped_lock(); +mutex_type *mutex() const noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\effects For all \tcode{i} in \range{0}{sizeof...(MutexTypes)}, -\tcode{get(pm).unlock()}. +\pnum\returns \tcode{pm}. \end{itemdescr} -\rSec3[thread.lock.unique]{Class template \tcode{unique_lock}} +\rSec3[thread.lock.shared]{Class template \tcode{shared_lock}} -\indexlibrary{\idxcode{unique_lock}}% +\indexlibrary{\idxcode{shared_lock}}% \begin{codeblock} namespace std { template - class unique_lock { + class shared_lock { public: using mutex_type = Mutex; - // \ref{thread.lock.unique.cons}, construct/copy/destroy - unique_lock() noexcept; - explicit unique_lock(mutex_type& m); - unique_lock(mutex_type& m, defer_lock_t) noexcept; - unique_lock(mutex_type& m, try_to_lock_t); - unique_lock(mutex_type& m, adopt_lock_t); + // \ref{thread.lock.shared.cons}, construct/copy/destroy + shared_lock() noexcept; + explicit shared_lock(mutex_type& m); // blocking + shared_lock(mutex_type& m, defer_lock_t) noexcept; + shared_lock(mutex_type& m, try_to_lock_t); + shared_lock(mutex_type& m, adopt_lock_t); template - unique_lock(mutex_type& m, const chrono::time_point& abs_time); + shared_lock(mutex_type& m, const chrono::time_point& abs_time); template - unique_lock(mutex_type& m, const chrono::duration& rel_time); - ~unique_lock(); + shared_lock(mutex_type& m, const chrono::duration& rel_time); + ~shared_lock(); - unique_lock(const unique_lock&) = delete; - unique_lock& operator=(const unique_lock&) = delete; + shared_lock(const shared_lock&) = delete; + shared_lock& operator=(const shared_lock&) = delete; - unique_lock(unique_lock&& u) noexcept; - unique_lock& operator=(unique_lock&& u); + shared_lock(shared_lock&& u) noexcept; + shared_lock& operator=(shared_lock&& u) noexcept; - // \ref{thread.lock.unique.locking}, locking - void lock(); + // \ref{thread.lock.shared.locking}, locking + void lock(); // blocking bool try_lock(); - template bool try_lock_for(const chrono::duration& rel_time); template bool try_lock_until(const chrono::time_point& abs_time); - void unlock(); - // \ref{thread.lock.unique.mod}, modifiers - void swap(unique_lock& u) noexcept; + // \ref{thread.lock.shared.mod}, modifiers + void swap(shared_lock& u) noexcept; mutex_type* release() noexcept; - // \ref{thread.lock.unique.obs}, observers + // \ref{thread.lock.shared.obs}, observers bool owns_lock() const noexcept; explicit operator bool () const noexcept; mutex_type* mutex() const noexcept; private: - mutex_type* pm; // \expos - bool owns; // \expos + mutex_type* pm; // \expos + bool owns; // \expos }; template - void swap(unique_lock& x, unique_lock& y) noexcept; + void swap(shared_lock& x, shared_lock& y) noexcept; } \end{codeblock} \pnum -An object of type \tcode{unique_lock} controls the ownership of a lockable -object within a scope. Ownership of the lockable object may be acquired at -construction or after construction, and may be transferred, after -acquisition, to another \tcode{unique_lock} object. Objects of type \tcode{unique_lock} are not -copyable but are movable. The behavior of a program is undefined if the contained pointer -\tcode{pm} is not null and the lockable object pointed -to by \tcode{pm} does not exist for the entire remaining -lifetime\iref{basic.life} of the \tcode{unique_lock} object. The supplied -\tcode{Mutex} type shall meet the \oldconcept{BasicLockable} -requirements\iref{thread.req.lockable.basic}. +An object of type \tcode{shared_lock} controls the shared ownership of a +lockable object within a scope. Shared ownership of the lockable object may be +acquired at construction or after construction, and may be transferred, after +acquisition, to another \tcode{shared_lock} object. Objects of type +\tcode{shared_lock} are not copyable but are movable. The behavior of a program +is undefined if the contained pointer \tcode{pm} is not null and the lockable +object pointed to by \tcode{pm} does not exist for the entire remaining +lifetime\iref{basic.life} of the \tcode{shared_lock} object. The supplied +\tcode{Mutex} type shall meet the shared mutex +requirements\iref{thread.sharedtimedmutex.requirements}. \pnum -\begin{note} \tcode{unique_lock} meets the \oldconcept{BasicLockable} requirements. If \tcode{Mutex} -meets the \oldconcept{Lockable} requirements\iref{thread.req.lockable.req}, -\tcode{unique_lock} also meets the \oldconcept{Lockable} requirements; -if \tcode{Mutex} -meets the \oldconcept{TimedLockable} requirements\iref{thread.req.lockable.timed}, -\tcode{unique_lock} also meets the \oldconcept{TimedLockable} requirements. \end{note} +\begin{note} \tcode{shared_lock} meets the \oldconcept{TimedLockable} +requirements\iref{thread.req.lockable.timed}. \end{note} -\rSec4[thread.lock.unique.cons]{Constructors, destructor, and assignment} +\rSec4[thread.lock.shared.cons]{Constructors, destructor, and assignment} -\indexlibrary{\idxcode{unique_lock}!constructor}% +\indexlibrary{\idxcode{shared_lock}!constructor}% \begin{itemdecl} -unique_lock() noexcept; +shared_lock() noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects Constructs an object of type \tcode{unique_lock}. +\effects Constructs an object of type \tcode{shared_lock}. \pnum -\ensures \tcode{pm == 0} and \tcode{owns == false}. +\ensures \tcode{pm == nullptr} and \tcode{owns == false}. \end{itemdescr} -\indexlibrary{\idxcode{unique_lock}!constructor}% +\indexlibrary{\idxcode{shared_lock}!constructor}% \begin{itemdecl} -explicit unique_lock(mutex_type& m); +explicit shared_lock(mutex_type& m); \end{itemdecl} \begin{itemdescr} \pnum -\requires If \tcode{mutex_type} is not a recursive mutex the calling thread does not own the mutex. +\requires The calling thread does not own the mutex for any ownership mode. \pnum -\effects Constructs an object of type \tcode{unique_lock} and calls \tcode{m.lock()}. +\effects Constructs an object of type \tcode{shared_lock} and calls \tcode{m.lock_shared()}. \pnum \ensures \tcode{pm == addressof(m)} and \tcode{owns == true}. \end{itemdescr} -\indexlibrary{\idxcode{unique_lock}!constructor}% +\indexlibrary{\idxcode{shared_lock}!constructor}% \begin{itemdecl} -unique_lock(mutex_type& m, defer_lock_t) noexcept; +shared_lock(mutex_type& m, defer_lock_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects Constructs an object of type \tcode{unique_lock}. +\effects Constructs an object of type \tcode{shared_lock}. \pnum \ensures \tcode{pm == addressof(m)} and \tcode{owns == false}. \end{itemdescr} -\indexlibrary{\idxcode{unique_lock}!constructor}% +\indexlibrary{\idxcode{shared_lock}!constructor}% \begin{itemdecl} -unique_lock(mutex_type& m, try_to_lock_t); +shared_lock(mutex_type& m, try_to_lock_t); \end{itemdecl} \begin{itemdescr} \pnum -\requires -The supplied \tcode{Mutex} type shall meet the \oldconcept{Lockable} -requirements\iref{thread.req.lockable.req}. -If \tcode{mutex_type} is not a recursive mutex the calling thread does not own the mutex. +\requires The calling thread does not own the mutex for any ownership mode. \pnum -\effects Constructs an object of type \tcode{unique_lock} and calls \tcode{m.try_lock()}. +\effects Constructs an object of type \tcode{shared_lock} and calls \tcode{m.try_lock_shared()}. \pnum -\ensures \tcode{pm == addressof(m)} and \tcode{owns == res}, -where \tcode{res} is the value returned by the call to \tcode{m.try_lock()}. +\ensures \tcode{pm == addressof(m)} and \tcode{owns == res} +where \tcode{res} is the +value returned by the call to \tcode{m.try_lock_shared()}. \end{itemdescr} -\indexlibrary{\idxcode{unique_lock}!constructor}% +\indexlibrary{\idxcode{shared_lock}!constructor}% \begin{itemdecl} -unique_lock(mutex_type& m, adopt_lock_t); +shared_lock(mutex_type& m, adopt_lock_t); \end{itemdecl} \begin{itemdescr} \pnum -\requires The calling thread owns the mutex. +\requires The calling thread has shared ownership of the mutex. \pnum -\effects Constructs an object of type \tcode{unique_lock}. +\effects Constructs an object of type \tcode{shared_lock}. \pnum \ensures \tcode{pm == addressof(m)} and \tcode{owns == true}. - -\pnum -\throws Nothing. \end{itemdescr} -\indexlibrary{\idxcode{unique_lock}!constructor}% +\indexlibrary{\idxcode{shared_lock}!constructor}% \begin{itemdecl} template - unique_lock(mutex_type& m, const chrono::time_point& abs_time); + shared_lock(mutex_type& m, + const chrono::time_point& abs_time); \end{itemdecl} \begin{itemdescr} \pnum -\requires If \tcode{mutex_type} is not a recursive mutex the calling thread -does not own the mutex. The supplied \tcode{Mutex} type shall meet the -\oldconcept{TimedLockable} requirements\iref{thread.req.lockable.timed}. +\requires The calling thread does not own the mutex for any ownership mode. \pnum -\effects Constructs an object of type \tcode{unique_lock} and calls \tcode{m.try_lock_until(abs_time)}. +\effects Constructs an object of type \tcode{shared_lock} and calls +\tcode{m.try_lock_shared_until(abs_time)}. \pnum -\ensures \tcode{pm == addressof(m)} and \tcode{owns == res}, -where \tcode{res} is -the value returned by the call to \tcode{m.try_lock_until(abs_time)}. +\ensures \tcode{pm == addressof(m)} and \tcode{owns == res} +where \tcode{res} +is the value returned by the call to \tcode{m.try_lock_shared_until(abs_time)}. \end{itemdescr} -\indexlibrary{\idxcode{unique_lock}!constructor}% +\indexlibrary{\idxcode{shared_lock}!constructor}% \begin{itemdecl} template - unique_lock(mutex_type& m, const chrono::duration& rel_time); + shared_lock(mutex_type& m, + const chrono::duration& rel_time); \end{itemdecl} \begin{itemdescr} \pnum -\requires If \tcode{mutex_type} is not a recursive mutex the calling thread does not own the mutex. -The supplied \tcode{Mutex} type shall meet the \oldconcept{TimedLockable} requirements\iref{thread.req.lockable.timed}. +\requires The calling thread does not own the mutex for any ownership mode. \pnum -\effects Constructs an object of type \tcode{unique_lock} and calls \tcode{m.try_lock_for(rel_time)}. +\effects Constructs an object of type \tcode{shared_lock} and calls +\tcode{m.try_lock_shared_for(rel_time)}. \pnum -\ensures \tcode{pm == addressof(m)} and \tcode{owns == res}, -where \tcode{res} is the value returned by the call to \tcode{m.try_lock_for(rel_time)}. +\ensures \tcode{pm == addressof(m)} and \tcode{owns == res} +where \tcode{res} is +the value returned by the call to \tcode{m.try_lock_shared_for(rel_time)}. \end{itemdescr} -\indexlibrary{\idxcode{unique_lock}!constructor}% +\indexlibrary{\idxcode{shared_lock}!destructor}% \begin{itemdecl} -unique_lock(unique_lock&& u) noexcept; +~shared_lock(); \end{itemdecl} \begin{itemdescr} -\pnum\ensures \tcode{pm == u_p.pm} and \tcode{owns == u_p.owns} (where \tcode{u_p} is the state of \tcode{u} just prior to this construction), \tcode{u.pm == 0} and \tcode{u.owns == false}. +\pnum +\effects If \tcode{owns} calls \tcode{pm->unlock_shared()}. \end{itemdescr} -\indexlibrarymember{operator=}{unique_lock}% +\indexlibrary{\idxcode{shared_lock}!constructor}% \begin{itemdecl} -unique_lock& operator=(unique_lock&& u); +shared_lock(shared_lock&& sl) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum\effects If \tcode{owns} calls \tcode{pm->unlock()}. - -\pnum\ensures \tcode{pm == u_p.pm} and \tcode{owns == u_p.owns} (where \tcode{u_p} is the state of \tcode{u} just prior to this construction), \tcode{u.pm == 0} and \tcode{u.owns == false}. - \pnum -\begin{note} With a recursive mutex it is possible for both \tcode{*this} and \tcode{u} to own the same mutex before the assignment. In this case, \tcode{*this} will own the mutex after the assignment and \tcode{u} will not. \end{note} - -\pnum\throws Nothing. +\ensures \tcode{pm == sl_p.pm} and \tcode{owns == sl_p.owns} (where +\tcode{sl_p} is the state of \tcode{sl} just prior to this construction), +\tcode{sl.pm == nullptr} and \tcode{sl.owns == false}. \end{itemdescr} - -\indexlibrary{\idxcode{unique_lock}!destructor}% +\indexlibrarymember{operator=}{shared_lock}% \begin{itemdecl} -~unique_lock(); +shared_lock& operator=(shared_lock&& sl) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum\effects If \tcode{owns} calls \tcode{pm->unlock()}. +\pnum +\effects If \tcode{owns} calls \tcode{pm->unlock_shared()}. + +\pnum +\ensures \tcode{pm == sl_p.pm} and \tcode{owns == sl_p.owns} (where +\tcode{sl_p} is the state of \tcode{sl} just prior to this assignment), +\tcode{sl.pm == nullptr} and \tcode{sl.owns == false}. \end{itemdescr} -\rSec4[thread.lock.unique.locking]{Locking} +\rSec4[thread.lock.shared.locking]{Locking} -\indexlibrarymember{lock}{unique_lock}% +\indexlibrarymember{lock}{shared_lock}% \begin{itemdecl} void lock(); \end{itemdecl} \begin{itemdescr} \pnum -\effects As if by \tcode{pm->lock()}. +\effects As if by \tcode{pm->lock_shared()}. \pnum \ensures \tcode{owns == true}. \pnum -\throws -Any exception thrown by \tcode{pm->lock()}. \tcode{system_error} when an exception -is required\iref{thread.req.exception}. +\throws Any exception thrown by \tcode{pm->lock_shared()}. +\tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{operation_not_permitted} --- if \tcode{pm} is \tcode{nullptr}. -\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} -is \tcode{true}. +\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is +\tcode{true}. \end{itemize} \end{itemdescr} -\indexlibrarymember{try_lock}{unique_lock}% +\indexlibrarymember{try_lock}{shared_lock}% \begin{itemdecl} bool try_lock(); \end{itemdecl} \begin{itemdescr} \pnum -\requires The supplied \tcode{Mutex} shall meet the \oldconcept{Lockable} -requirements\iref{thread.req.lockable.req}. +\effects As if by \tcode{pm->try_lock_shared()}. \pnum -\effects As if by \tcode{pm->try_lock()}. - -\pnum\returns The value returned by the call to \tcode{try_lock()}. +\returns The value returned by the call to \tcode{pm->try_lock_shared()}. \pnum \ensures \tcode{owns == res}, where \tcode{res} is the value returned by -the call to \tcode{try_lock()}. - -\pnum -\throws -Any exception thrown by \tcode{pm->try_lock()}. \tcode{system_error} when an exception -is required\iref{thread.req.exception}. +the call to \tcode{pm->try_lock_shared()}. + +\pnum +\throws Any exception thrown by \tcode{pm->try_lock_shared()}. +\tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{operation_not_permitted} --- if \tcode{pm} is \tcode{nullptr}. -\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} -is \tcode{true}. +\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is +\tcode{true}. \end{itemize} \end{itemdescr} -\indexlibrarymember{try_lock_until}{unique_lock}% +\indexlibrarymember{try_lock_until}{shared_lock}% \begin{itemdecl} template bool try_lock_until(const chrono::time_point& abs_time); @@ -2093,22 +3516,19 @@ \begin{itemdescr} \pnum -\requires The supplied \tcode{Mutex} type shall meet the \oldconcept{TimedLockable} -requirements\iref{thread.req.lockable.timed}. - -\pnum -\effects As if by \tcode{pm->try_lock_until(abs_time)}. +\effects As if by \tcode{pm->try_lock_shared_until(abs_time)}. \pnum -\returns The value returned by the call to \tcode{try_lock_until(abs_time)}. +\returns The value returned by the call to +\tcode{pm->try_lock_shared_until(abs_time)}. \pnum \ensures \tcode{owns == res}, where \tcode{res} is the value returned by -the call to \tcode{try_lock_until(abs_time)}. +the call to \tcode{pm->try_lock_shared_until(abs_time)}. \pnum -\throws Any exception thrown by \tcode{pm->try_lock_until()}. \tcode{system_error} when an -exception is required\iref{thread.req.exception}. +\throws Any exception thrown by \tcode{pm->try_lock_shared_until(abs_time)}. +\tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors @@ -2119,7 +3539,7 @@ \end{itemize} \end{itemdescr} -\indexlibrarymember{try_lock_for}{unique_lock}% +\indexlibrarymember{try_lock_for}{shared_lock}% \begin{itemdecl} template bool try_lock_for(const chrono::duration& rel_time); @@ -2127,20 +3547,16 @@ \begin{itemdescr} \pnum -\requires The supplied \tcode{Mutex} type shall meet the \oldconcept{TimedLockable} requirements\iref{thread.req.lockable.timed}. - -\pnum -\effects As if by \tcode{pm->try_lock_for(rel_time)}. +\effects As if by \tcode{pm->try_lock_shared_for(rel_time)}. \pnum -\returns The value returned by the call to \tcode{try_lock_until(rel_time)}. +\returns The value returned by the call to \tcode{pm->try_lock_shared_for(rel_time)}. \pnum -\ensures \tcode{owns == res}, where \tcode{res} is the value returned by the call to \tcode{try_lock_for(rel_time)}. +\ensures \tcode{owns == res}, where \tcode{res} is the value returned by the call to \tcode{pm->try_lock_shared_for(rel_time)}. \pnum -\throws Any exception thrown by \tcode{pm->try_lock_for()}. \tcode{system_error} when an -exception is required\iref{thread.req.exception}. +\throws Any exception thrown by \tcode{pm->try_lock_shared_for(rel_time)}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors @@ -2151,441 +3567,403 @@ \end{itemize} \end{itemdescr} -\indexlibrarymember{unlock}{unique_lock}% +\indexlibrarymember{unlock}{shared_lock}% \begin{itemdecl} void unlock(); \end{itemdecl} \begin{itemdescr} -\pnum\effects As if by \tcode{pm->unlock()}. +\pnum +\effects As if by \tcode{pm->unlock_shared()}. -\pnum\ensures \tcode{owns == false}. +\pnum +\ensures \tcode{owns == false}. -\pnum\throws \tcode{system_error} when -an exception is required\iref{thread.req.exception}. +\pnum +\throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. -\pnum \errors +\pnum +\errors \begin{itemize} -\item \tcode{operation_not_permitted} --- if on entry \tcode{owns} is \tcode{false}. +\item \tcode{operation_not_permitted} --- if on entry \tcode{owns} is +\tcode{false}. \end{itemize} \end{itemdescr} -\rSec4[thread.lock.unique.mod]{Modifiers} +\rSec4[thread.lock.shared.mod]{Modifiers} -\indexlibrarymember{swap}{unique_lock}% +\indexlibrarymember{swap}{shared_lock}% \begin{itemdecl} -void swap(unique_lock& u) noexcept; +void swap(shared_lock& sl) noexcept; \end{itemdecl} \begin{itemdescr} -\pnum\effects Swaps the data members of \tcode{*this} and \tcode{u}. +\pnum +\effects Swaps the data members of \tcode{*this} and \tcode{sl}. \end{itemdescr} -\indexlibrarymember{release}{unique_lock}% +\indexlibrarymember{release}{shared_lock}% \begin{itemdecl} mutex_type* release() noexcept; \end{itemdecl} -\begin{itemdescr} -\pnum\returns The previous value of \tcode{pm}. - -\pnum\ensures \tcode{pm == 0} and \tcode{owns == false}. -\end{itemdescr} - -\indexlibrarymember{swap}{unique_lock}% -\begin{itemdecl} -template - void swap(unique_lock& x, unique_lock& y) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum\effects As if by \tcode{x.swap(y)}. -\end{itemdescr} - -\rSec4[thread.lock.unique.obs]{Observers} - -\indexlibrarymember{owns_lock}{unique_lock}% -\begin{itemdecl} -bool owns_lock() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{owns}. -\end{itemdescr} - -\indexlibrarymember{operator bool}{unique_lock}% -\begin{itemdecl} -explicit operator bool() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{owns}. -\end{itemdescr} - -\indexlibrarymember{mutex}{unique_lock}% -\begin{itemdecl} -mutex_type *mutex() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{pm}. -\end{itemdescr} - -\rSec3[thread.lock.shared]{Class template \tcode{shared_lock}} - -\indexlibrary{\idxcode{shared_lock}}% -\begin{codeblock} -namespace std { - template - class shared_lock { - public: - using mutex_type = Mutex; - - // \ref{thread.lock.shared.cons}, construct/copy/destroy - shared_lock() noexcept; - explicit shared_lock(mutex_type& m); // blocking - shared_lock(mutex_type& m, defer_lock_t) noexcept; - shared_lock(mutex_type& m, try_to_lock_t); - shared_lock(mutex_type& m, adopt_lock_t); - template - shared_lock(mutex_type& m, const chrono::time_point& abs_time); - template - shared_lock(mutex_type& m, const chrono::duration& rel_time); - ~shared_lock(); - - shared_lock(const shared_lock&) = delete; - shared_lock& operator=(const shared_lock&) = delete; - - shared_lock(shared_lock&& u) noexcept; - shared_lock& operator=(shared_lock&& u) noexcept; - - // \ref{thread.lock.shared.locking}, locking - void lock(); // blocking - bool try_lock(); - template - bool try_lock_for(const chrono::duration& rel_time); - template - bool try_lock_until(const chrono::time_point& abs_time); - void unlock(); - - // \ref{thread.lock.shared.mod}, modifiers - void swap(shared_lock& u) noexcept; - mutex_type* release() noexcept; - - // \ref{thread.lock.shared.obs}, observers - bool owns_lock() const noexcept; - explicit operator bool () const noexcept; - mutex_type* mutex() const noexcept; - - private: - mutex_type* pm; // \expos - bool owns; // \expos - }; - - template - void swap(shared_lock& x, shared_lock& y) noexcept; -} -\end{codeblock} - -\pnum -An object of type \tcode{shared_lock} controls the shared ownership of a -lockable object within a scope. Shared ownership of the lockable object may be -acquired at construction or after construction, and may be transferred, after -acquisition, to another \tcode{shared_lock} object. Objects of type -\tcode{shared_lock} are not copyable but are movable. The behavior of a program -is undefined if the contained pointer \tcode{pm} is not null and the lockable -object pointed to by \tcode{pm} does not exist for the entire remaining -lifetime\iref{basic.life} of the \tcode{shared_lock} object. The supplied -\tcode{Mutex} type shall meet the shared mutex -requirements\iref{thread.sharedtimedmutex.requirements}. - -\pnum -\begin{note} \tcode{shared_lock} meets the \oldconcept{TimedLockable} -requirements\iref{thread.req.lockable.timed}. \end{note} - -\rSec4[thread.lock.shared.cons]{Constructors, destructor, and assignment} - -\indexlibrary{\idxcode{shared_lock}!constructor}% -\begin{itemdecl} -shared_lock() noexcept; -\end{itemdecl} - \begin{itemdescr} \pnum -\effects Constructs an object of type \tcode{shared_lock}. +\returns The previous value of \tcode{pm}. \pnum \ensures \tcode{pm == nullptr} and \tcode{owns == false}. \end{itemdescr} -\indexlibrary{\idxcode{shared_lock}!constructor}% -\begin{itemdecl} -explicit shared_lock(mutex_type& m); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\requires The calling thread does not own the mutex for any ownership mode. - -\pnum -\effects Constructs an object of type \tcode{shared_lock} and calls \tcode{m.lock_shared()}. - -\pnum -\ensures \tcode{pm == addressof(m)} and \tcode{owns == true}. -\end{itemdescr} - -\indexlibrary{\idxcode{shared_lock}!constructor}% +\indexlibrarymember{swap}{shared_lock}% \begin{itemdecl} -shared_lock(mutex_type& m, defer_lock_t) noexcept; +template + void swap(shared_lock& x, shared_lock& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects Constructs an object of type \tcode{shared_lock}. - -\pnum -\ensures \tcode{pm == addressof(m)} and \tcode{owns == false}. +\effects As if by \tcode{x.swap(y)}. \end{itemdescr} -\indexlibrary{\idxcode{shared_lock}!constructor}% -\begin{itemdecl} -shared_lock(mutex_type& m, try_to_lock_t); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\requires The calling thread does not own the mutex for any ownership mode. - -\pnum -\effects Constructs an object of type \tcode{shared_lock} and calls \tcode{m.try_lock_shared()}. - -\pnum -\ensures \tcode{pm == addressof(m)} and \tcode{owns == res} -where \tcode{res} is the -value returned by the call to \tcode{m.try_lock_shared()}. -\end{itemdescr} +\rSec4[thread.lock.shared.obs]{Observers} -\indexlibrary{\idxcode{shared_lock}!constructor}% +\indexlibrarymember{owns_lock}{shared_lock}% \begin{itemdecl} -shared_lock(mutex_type& m, adopt_lock_t); +bool owns_lock() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\requires The calling thread has shared ownership of the mutex. - -\pnum -\effects Constructs an object of type \tcode{shared_lock}. - -\pnum -\ensures \tcode{pm == addressof(m)} and \tcode{owns == true}. +\returns \tcode{owns}. \end{itemdescr} -\indexlibrary{\idxcode{shared_lock}!constructor}% +\indexlibrarymember{operator bool}{shared_lock}% \begin{itemdecl} -template - shared_lock(mutex_type& m, - const chrono::time_point& abs_time); +explicit operator bool() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\requires The calling thread does not own the mutex for any ownership mode. +\returns \tcode{owns}. +\end{itemdescr} -\pnum -\effects Constructs an object of type \tcode{shared_lock} and calls -\tcode{m.try_lock_shared_until(abs_time)}. +\indexlibrarymember{mutex}{shared_lock}% +\begin{itemdecl} +mutex_type* mutex() const noexcept; +\end{itemdecl} +\begin{itemdescr} \pnum -\ensures \tcode{pm == addressof(m)} and \tcode{owns == res} -where \tcode{res} -is the value returned by the call to \tcode{m.try_lock_shared_until(abs_time)}. +\returns \tcode{pm}. \end{itemdescr} -\indexlibrary{\idxcode{shared_lock}!constructor}% +\rSec2[thread.lock.algorithm]{Generic locking algorithms} + +\indexlibrary{\idxcode{try_lock}}% \begin{itemdecl} -template - shared_lock(mutex_type& m, - const chrono::duration& rel_time); +template int try_lock(L1&, L2&, L3&...); \end{itemdecl} \begin{itemdescr} \pnum -\requires The calling thread does not own the mutex for any ownership mode. +\requires Each template parameter type shall meet the \oldconcept{Lockable} requirements. \begin{note} The +\tcode{unique_lock} class template meets these requirements when suitably instantiated. +\end{note} \pnum -\effects Constructs an object of type \tcode{shared_lock} and calls -\tcode{m.try_lock_shared_for(rel_time)}. +\effects Calls \tcode{try_lock()} for each argument in order beginning with the +first until all arguments have been processed or a call to \tcode{try_lock()} fails, +either by returning \tcode{false} or by throwing an exception. If a call to +\tcode{try_lock()} fails, \tcode{unlock()} is called for all prior arguments +with no further calls to \tcode{try_lock()}. \pnum -\ensures \tcode{pm == addressof(m)} and \tcode{owns == res} -where \tcode{res} is -the value returned by the call to \tcode{m.try_lock_shared_for(rel_time)}. +\returns \tcode{-1} if all calls to \tcode{try_lock()} returned \tcode{true}, +otherwise a zero-based index value that indicates the argument for which \tcode{try_lock()} +returned \tcode{false}. \end{itemdescr} -\indexlibrary{\idxcode{shared_lock}!destructor}% +\indexlibrary{\idxcode{lock}}% \begin{itemdecl} -~shared_lock(); +template void lock(L1&, L2&, L3&...); \end{itemdecl} \begin{itemdescr} \pnum -\effects If \tcode{owns} calls \tcode{pm->unlock_shared()}. +\requires Each template parameter type shall meet the \oldconcept{Lockable} requirements, +\begin{note} The +\tcode{unique_lock} class template meets these requirements when suitably instantiated. +\end{note} + +\pnum +\effects All arguments are locked via a sequence of calls to \tcode{lock()}, +\tcode{try_lock()}, or \tcode{unlock()} on each argument. The sequence of calls does +not result in deadlock, but is otherwise unspecified. \begin{note} A deadlock avoidance +algorithm such as try-and-back-off must be used, but the specific algorithm is not +specified to avoid over-constraining implementations. \end{note} If a call to +\tcode{lock()} or \tcode{try_lock()} throws an exception, \tcode{unlock()} is +called for any argument that had been locked by a call to \tcode{lock()} or +\tcode{try_lock()}. \end{itemdescr} -\indexlibrary{\idxcode{shared_lock}!constructor}% -\begin{itemdecl} -shared_lock(shared_lock&& sl) noexcept; -\end{itemdecl} +\rSec2[thread.once]{Call once} + +\rSec3[thread.once.onceflag]{Struct \tcode{once_flag}} + +\indexlibrary{\idxcode{once_flag}}% +\begin{codeblock} +namespace std { + struct once_flag { + constexpr once_flag() noexcept; + + once_flag(const once_flag&) = delete; + once_flag& operator=(const once_flag&) = delete; + }; +} +\end{codeblock} -\begin{itemdescr} \pnum -\ensures \tcode{pm == sl_p.pm} and \tcode{owns == sl_p.owns} (where -\tcode{sl_p} is the state of \tcode{sl} just prior to this construction), -\tcode{sl.pm == nullptr} and \tcode{sl.owns == false}. -\end{itemdescr} +The class \tcode{once_flag} is an opaque data structure that \tcode{call_once} uses to +initialize data without causing a data race or deadlock. -\indexlibrarymember{operator=}{shared_lock}% +\indexlibrary{\idxcode{once_flag}}% \begin{itemdecl} -shared_lock& operator=(shared_lock&& sl) noexcept; +constexpr once_flag() noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\effects If \tcode{owns} calls \tcode{pm->unlock_shared()}. +\pnum\effects Constructs an object of type \tcode{once_flag}. -\pnum -\ensures \tcode{pm == sl_p.pm} and \tcode{owns == sl_p.owns} (where -\tcode{sl_p} is the state of \tcode{sl} just prior to this assignment), -\tcode{sl.pm == nullptr} and \tcode{sl.owns == false}. +\pnum\sync The construction of a \tcode{once_flag} object is not synchronized. + +\pnum\ensures The object's internal state is set to indicate to an invocation of +\tcode{call_once} with the object as its initial argument that no function has been +called. \end{itemdescr} -\rSec4[thread.lock.shared.locking]{Locking} +\rSec3[thread.once.callonce]{Function \tcode{call_once}} -\indexlibrarymember{lock}{shared_lock}% +\indexlibrary{\idxcode{call_once}}% \begin{itemdecl} -void lock(); +template + void call_once(once_flag& flag, Callable&& func, Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum -\effects As if by \tcode{pm->lock_shared()}. +\requires +\begin{codeblock} +@\placeholdernc{INVOKE}@(std::forward(func), std::forward(args)...) +\end{codeblock} +(see \ref{func.require}) shall be a valid expression. \pnum -\ensures \tcode{owns == true}. +\effects An execution of \tcode{call_once} that does not call its \tcode{func} is a +\term{passive} execution. An execution of \tcode{call_once} that calls its \tcode{func} +is an \term{active} execution. An active execution shall call +\tcode{\placeholdernc{INVOKE}(\brk{}% +std::forward(func), +std::forward(args)...)}. If such a call to \tcode{func} +throws an exception the execution is \term{exceptional}, otherwise it is \term{returning}. +An exceptional execution shall propagate the exception to the caller of +\tcode{call_once}. Among all executions of \tcode{call_once} for any given +\tcode{once_flag}: at most one shall be a returning execution; if there is a +returning execution, it shall be the last active execution; and there are +passive executions only if there is a returning execution. \begin{note} Passive +executions allow other threads to reliably observe the results produced by the +earlier returning execution. \end{note} \pnum -\throws Any exception thrown by \tcode{pm->lock_shared()}. -\tcode{system_error} when an exception is required\iref{thread.req.exception}. +\sync For any given \tcode{once_flag}: all active executions occur in a total +order; completion of an active execution synchronizes with\iref{intro.multithread} +the start of the next one in this total order; and the returning execution +synchronizes with the return from all passive executions. + +\pnum\throws \tcode{system_error} when +an exception is required\iref{thread.req.exception}, or any exception thrown by \tcode{func}. \pnum -\errors -\begin{itemize} -\item \tcode{operation_not_permitted} --- if \tcode{pm} is \tcode{nullptr}. -\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is -\tcode{true}. -\end{itemize} +\begin{example} +\begin{codeblock} +// global flag, regular function +void init(); +std::once_flag flag; + +void f() { + std::call_once(flag, init); +} + +// function static flag, function object +struct initializer { + void operator()(); +}; + +void g() { + static std::once_flag flag2; + std::call_once(flag2, initializer()); +} + +// object flag, member function +class information { + std::once_flag verified; + void verifier(); +public: + void verify() { std::call_once(verified, &information::verifier, *this); } +}; +\end{codeblock} +\end{example} \end{itemdescr} -\indexlibrarymember{try_lock}{shared_lock}% -\begin{itemdecl} -bool try_lock(); -\end{itemdecl} -\begin{itemdescr} +\rSec1[thread.condition]{Condition variables} + \pnum -\effects As if by \tcode{pm->try_lock_shared()}. +Condition variables provide synchronization primitives used to block a thread until +notified by some other thread that some condition is met or until a system time is +reached. Class \tcode{condition_variable} provides a condition variable that can only +wait on an object of type \tcode{unique_lock}, allowing the implementation +to be more efficient. Class \tcode{condition_variable_any} provides a general +condition variable that can wait on objects of user-supplied lock types. \pnum -\returns The value returned by the call to \tcode{pm->try_lock_shared()}. +Condition variables permit concurrent invocation of the \tcode{wait}, \tcode{wait_for}, +\tcode{wait_until}, \tcode{notify_one} and \tcode{notify_all} member functions. \pnum -\ensures \tcode{owns == res}, where \tcode{res} is the value returned by -the call to \tcode{pm->try_lock_shared()}. +The execution of \tcode{notify_one} and \tcode{notify_all} shall be atomic. The +execution of \tcode{wait}, \tcode{wait_for}, and \tcode{wait_until} shall be performed +in three atomic parts: + +\begin{enumerate} +\item the release of the mutex and entry into the waiting state; +\item the unblocking of the wait; and +\item the reacquisition of the lock. +\end{enumerate} \pnum -\throws Any exception thrown by \tcode{pm->try_lock_shared()}. -\tcode{system_error} when an exception is required\iref{thread.req.exception}. +The implementation shall behave as if all executions of \tcode{notify_one}, \tcode{notify_all}, and each +part of the \tcode{wait}, \tcode{wait_for}, and \tcode{wait_until} executions are +executed in a single unspecified total order consistent with the "happens before" order. \pnum -\errors -\begin{itemize} -\item \tcode{operation_not_permitted} --- if \tcode{pm} is \tcode{nullptr}. -\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is -\tcode{true}. -\end{itemize} -\end{itemdescr} +Condition variable construction and destruction need not be synchronized. -\indexlibrarymember{try_lock_until}{shared_lock}% +\rSec2[condition.variable.syn]{Header \tcode{} synopsis} +\indexhdr{condition_variable}% + +\indexlibrary{\idxcode{cv_status}}% +\begin{codeblock} +namespace std { + class condition_variable; + class condition_variable_any; + + void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); + + enum class cv_status { no_timeout, timeout }; +} +\end{codeblock} + +\rSec2[thread.condition.nonmember]{Non-member functions} +\indexlibrary{\idxcode{notify_all_at_thread_exit}}% \begin{itemdecl} -template - bool try_lock_until(const chrono::time_point& abs_time); +void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); \end{itemdecl} \begin{itemdescr} \pnum -\effects As if by \tcode{pm->try_lock_shared_until(abs_time)}. +\requires \tcode{lk} is locked by the calling thread and either + +\begin{itemize} +\item no other thread is waiting on \tcode{cond}, or +\item \tcode{lk.mutex()} returns the same value for each of the lock arguments +supplied by all concurrently waiting (via \tcode{wait}, \tcode{wait_for}, +or \tcode{wait_until}) threads. +\end{itemize} \pnum -\returns The value returned by the call to -\tcode{pm->try_lock_shared_until(abs_time)}. +\effects Transfers ownership of the lock associated with \tcode{lk} into +internal storage and schedules \tcode{cond} to be notified when the current +thread exits, after all objects of thread storage duration associated with +the current thread have been destroyed. This notification shall be as if: +\begin{codeblock} +lk.unlock(); +cond.notify_all(); +\end{codeblock} \pnum -\ensures \tcode{owns == res}, where \tcode{res} is the value returned by -the call to \tcode{pm->try_lock_shared_until(abs_time)}. +\sync The implied \tcode{lk.unlock()} call is sequenced after the destruction of +all objects with thread storage duration associated with the current thread. \pnum -\throws Any exception thrown by \tcode{pm->try_lock_shared_until(abs_time)}. -\tcode{system_error} when an exception is required\iref{thread.req.exception}. +\begin{note} +The supplied lock will be held until the thread exits, and care +should be taken to ensure that this does not cause deadlock due to lock +ordering issues. After calling \tcode{notify_all_at_thread_exit} it is +recommended that the thread should be exited as soon as possible, and +that no blocking or time-consuming tasks are run on that thread. +\end{note} \pnum -\errors -\begin{itemize} -\item \tcode{operation_not_permitted} --- if \tcode{pm} is \tcode{nullptr}. -\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is -\tcode{true}. -\end{itemize} +\begin{note} +It is the user's responsibility to ensure that waiting threads +do not erroneously assume that the thread has finished if they experience +spurious wakeups. This typically requires that the condition being waited +for is satisfied while holding the lock on \tcode{lk}, and that this lock +is not released and reacquired prior to calling \tcode{notify_all_at_thread_exit}. +\end{note} \end{itemdescr} -\indexlibrarymember{try_lock_for}{shared_lock}% -\begin{itemdecl} -template - bool try_lock_for(const chrono::duration& rel_time); -\end{itemdecl} +\rSec2[thread.condition.condvar]{Class \tcode{condition_variable}} -\begin{itemdescr} -\pnum -\effects As if by \tcode{pm->try_lock_shared_for(rel_time)}. +\indexlibrary{\idxcode{condition_variable}}% +\begin{codeblock} +namespace std { + class condition_variable { + public: + condition_variable(); + ~condition_variable(); -\pnum -\returns The value returned by the call to \tcode{pm->try_lock_shared_for(rel_time)}. + condition_variable(const condition_variable&) = delete; + condition_variable& operator=(const condition_variable&) = delete; -\pnum -\ensures \tcode{owns == res}, where \tcode{res} is the value returned by the call to \tcode{pm->try_lock_shared_for(rel_time)}. + void notify_one() noexcept; + void notify_all() noexcept; + void wait(unique_lock& lock); + template + void wait(unique_lock& lock, Predicate pred); + template + cv_status wait_until(unique_lock& lock, + const chrono::time_point& abs_time); + template + bool wait_until(unique_lock& lock, + const chrono::time_point& abs_time, + Predicate pred); + template + cv_status wait_for(unique_lock& lock, + const chrono::duration& rel_time); + template + bool wait_for(unique_lock& lock, + const chrono::duration& rel_time, + Predicate pred); -\pnum -\throws Any exception thrown by \tcode{pm->try_lock_shared_for(rel_time)}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. + using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native} + native_handle_type native_handle(); // see~\ref{thread.req.native} + }; +} +\end{codeblock} \pnum -\errors -\begin{itemize} -\item \tcode{operation_not_permitted} --- if \tcode{pm} is \tcode{nullptr}. -\item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is -\tcode{true}. -\end{itemize} -\end{itemdescr} +The class \tcode{condition_variable} shall be a standard-layout class\iref{class.prop}. -\indexlibrarymember{unlock}{shared_lock}% +\indexlibrary{\idxcode{condition_variable}!constructor}% \begin{itemdecl} -void unlock(); +condition_variable(); \end{itemdecl} \begin{itemdescr} \pnum -\effects As if by \tcode{pm->unlock_shared()}. - -\pnum -\ensures \tcode{owns == false}. +\effects Constructs an object of type \tcode{condition_variable}. \pnum \throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. @@ -2593,400 +3971,410 @@ \pnum \errors \begin{itemize} -\item \tcode{operation_not_permitted} --- if on entry \tcode{owns} is -\tcode{false}. +\item \tcode{resource_unavailable_try_again} --- if some non-memory resource +limitation prevents initialization. \end{itemize} \end{itemdescr} -\rSec4[thread.lock.shared.mod]{Modifiers} - -\indexlibrarymember{swap}{shared_lock}% +\indexlibrary{\idxcode{condition_variable}!destructor}% \begin{itemdecl} -void swap(shared_lock& sl) noexcept; +~condition_variable(); \end{itemdecl} \begin{itemdescr} \pnum -\effects Swaps the data members of \tcode{*this} and \tcode{sl}. +\requires There shall be no thread blocked on \tcode{*this}. \begin{note} That is, all +threads shall have been notified; they may subsequently block on the lock specified in the +wait. +This relaxes the usual rules, which would have required all wait calls to happen before +destruction. Only the notification to unblock the wait needs to happen before destruction. +The user should take care to ensure that no threads wait on \tcode{*this} once the destructor has +been started, especially when the waiting threads are calling the wait functions in a loop or +using the overloads of \tcode{wait}, \tcode{wait_for}, or \tcode{wait_until} that take a predicate. +\end{note} + +\pnum\effects Destroys the object. \end{itemdescr} -\indexlibrarymember{release}{shared_lock}% +\indexlibrarymember{notify_one}{condition_variable}% \begin{itemdecl} -mutex_type* release() noexcept; +void notify_one() noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\returns The previous value of \tcode{pm}. - -\pnum -\ensures \tcode{pm == nullptr} and \tcode{owns == false}. +\pnum\effects If any threads are blocked waiting for \tcode{*this}, unblocks one of those threads. \end{itemdescr} -\indexlibrarymember{swap}{shared_lock}% +\indexlibrarymember{notify_all}{condition_variable}% \begin{itemdecl} -template - void swap(shared_lock& x, shared_lock& y) noexcept; +void notify_all() noexcept; \end{itemdecl} \begin{itemdescr} -\pnum -\effects As if by \tcode{x.swap(y)}. +\pnum\effects Unblocks all threads that are blocked waiting for \tcode{*this}. \end{itemdescr} -\rSec4[thread.lock.shared.obs]{Observers} - -\indexlibrarymember{owns_lock}{shared_lock}% +\indexlibrarymember{wait}{condition_variable}% \begin{itemdecl} -bool owns_lock() const noexcept; +void wait(unique_lock& lock); \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{owns}. -\end{itemdescr} +\requires \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} +is locked by the calling thread, and either +\begin{itemize} +\item no other thread is waiting on this \tcode{condition_variable} object or +\item \tcode{lock.mutex()} returns the same value for each of the \tcode{lock} +arguments supplied by all concurrently waiting (via \tcode{wait}, +\tcode{wait_for}, or \tcode{wait_until}) threads. +\end{itemize} -\indexlibrarymember{operator bool}{shared_lock}% -\begin{itemdecl} -explicit operator bool() const noexcept; -\end{itemdecl} +\pnum\effects +\begin{itemize} +\item Atomically calls \tcode{lock.unlock()} and blocks on \tcode{*this}. +\item When unblocked, calls \tcode{lock.lock()} (possibly blocking on the lock), then returns. +\item The function will unblock when signaled by a call to \tcode{notify_one()} +or a call to \tcode{notify_all()}, or spuriously. +\end{itemize} -\begin{itemdescr} \pnum -\returns \tcode{owns}. +\remarks +If the function fails to meet the postcondition, \tcode{terminate()} +shall be called\iref{except.terminate}. +\begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} + +\pnum +\ensures \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} +is locked by the calling thread. + +\pnum\throws Nothing. + \end{itemdescr} -\indexlibrarymember{mutex}{shared_lock}% +\indexlibrarymember{wait}{condition_variable}% \begin{itemdecl} -mutex_type* mutex() const noexcept; +template + void wait(unique_lock& lock, Predicate pred); \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{pm}. -\end{itemdescr} +\requires \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} is +locked by the calling thread, and either -\rSec2[thread.lock.algorithm]{Generic locking algorithms} +\begin{itemize} +\item no other thread is waiting on this \tcode{condition_variable} object or +\item \tcode{lock.mutex()} returns the same value for each of the \tcode{lock} +arguments supplied by all concurrently waiting (via \tcode{wait}, +\tcode{wait_for}, or \tcode{wait_until}) threads. +\end{itemize} -\indexlibrary{\idxcode{try_lock}}% -\begin{itemdecl} -template int try_lock(L1&, L2&, L3&...); -\end{itemdecl} +\pnum +\effects Equivalent to: +\begin{codeblock} +while (!pred()) + wait(lock); +\end{codeblock} -\begin{itemdescr} \pnum -\requires Each template parameter type shall meet the \oldconcept{Lockable} requirements. \begin{note} The -\tcode{unique_lock} class template meets these requirements when suitably instantiated. -\end{note} +\remarks +If the function fails to meet the postcondition, \tcode{terminate()} +shall be called\iref{except.terminate}. +\begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} \pnum -\effects Calls \tcode{try_lock()} for each argument in order beginning with the -first until all arguments have been processed or a call to \tcode{try_lock()} fails, -either by returning \tcode{false} or by throwing an exception. If a call to -\tcode{try_lock()} fails, \tcode{unlock()} is called for all prior arguments -with no further calls to \tcode{try_lock()}. +\ensures \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} +is locked by the calling thread. \pnum -\returns \tcode{-1} if all calls to \tcode{try_lock()} returned \tcode{true}, -otherwise a zero-based index value that indicates the argument for which \tcode{try_lock()} -returned \tcode{false}. +\throws Any exception thrown by \tcode{pred}. + \end{itemdescr} -\indexlibrary{\idxcode{lock}}% +\indexlibrarymember{wait_until}{condition_variable}% \begin{itemdecl} -template void lock(L1&, L2&, L3&...); +template + cv_status wait_until(unique_lock& lock, + const chrono::time_point& abs_time); \end{itemdecl} \begin{itemdescr} \pnum -\requires Each template parameter type shall meet the \oldconcept{Lockable} requirements, -\begin{note} The -\tcode{unique_lock} class template meets these requirements when suitably instantiated. -\end{note} +\requires \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} +is locked by the calling thread, and either +\begin{itemize} +\item no other thread is waiting on this \tcode{condition_variable} object or +\item \tcode{lock.mutex()} returns the same value for each of the \tcode{lock} +arguments supplied by all concurrently waiting (via \tcode{wait}, +\tcode{wait_for}, or \tcode{wait_until}) threads. +\end{itemize} \pnum -\effects All arguments are locked via a sequence of calls to \tcode{lock()}, -\tcode{try_lock()}, or \tcode{unlock()} on each argument. The sequence of calls does -not result in deadlock, but is otherwise unspecified. \begin{note} A deadlock avoidance -algorithm such as try-and-back-off must be used, but the specific algorithm is not -specified to avoid over-constraining implementations. \end{note} If a call to -\tcode{lock()} or \tcode{try_lock()} throws an exception, \tcode{unlock()} is -called for any argument that had been locked by a call to \tcode{lock()} or -\tcode{try_lock()}. -\end{itemdescr} - -\rSec2[thread.once]{Call once} +\effects +\begin{itemize} +\item +Atomically calls \tcode{lock.unlock()} and blocks on \tcode{*this}. -\rSec3[thread.once.onceflag]{Struct \tcode{once_flag}} +\item +When unblocked, calls \tcode{lock.lock()} (possibly blocking on the lock), then returns. -\indexlibrary{\idxcode{once_flag}}% -\begin{codeblock} -namespace std { - struct once_flag { - constexpr once_flag() noexcept; +\item +The function will unblock when signaled by a call to \tcode{notify_one()}, a call to \tcode{notify_all()}, +expiration of the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time}, +or spuriously. - once_flag(const once_flag&) = delete; - once_flag& operator=(const once_flag&) = delete; - }; -} -\end{codeblock} +\item +If the function exits via an exception, \tcode{lock.lock()} shall be called prior to exiting the function. +\end{itemize} \pnum -The class \tcode{once_flag} is an opaque data structure that \tcode{call_once} uses to -initialize data without causing a data race or deadlock. +\remarks +If the function fails to meet the postcondition, \tcode{terminate()} +shall be called\iref{except.terminate}. +\begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} -\indexlibrary{\idxcode{once_flag}}% -\begin{itemdecl} -constexpr once_flag() noexcept; -\end{itemdecl} +\pnum +\ensures \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} +is locked by the calling thread. -\begin{itemdescr} -\pnum\effects Constructs an object of type \tcode{once_flag}. +\pnum +\returns \tcode{cv_status::timeout} if +the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time} expired, +otherwise \tcode{cv_status::no_timeout}. -\pnum\sync The construction of a \tcode{once_flag} object is not synchronized. +\pnum\throws Timeout-related +exceptions\iref{thread.req.timing}. -\pnum\ensures The object's internal state is set to indicate to an invocation of -\tcode{call_once} with the object as its initial argument that no function has been -called. \end{itemdescr} -\rSec3[thread.once.callonce]{Function \tcode{call_once}} - -\indexlibrary{\idxcode{call_once}}% +\indexlibrarymember{wait_for}{condition_variable}% \begin{itemdecl} -template - void call_once(once_flag& flag, Callable&& func, Args&&... args); +template + cv_status wait_for(unique_lock& lock, + const chrono::duration& rel_time); \end{itemdecl} \begin{itemdescr} \pnum -\requires +\requires \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} +is locked by the calling thread, and either +\begin{itemize} +\item no other thread is waiting on this \tcode{condition_variable} object or +\item \tcode{lock.mutex()} returns the same value for each of the \tcode{lock} arguments +supplied by all concurrently waiting (via \tcode{wait}, \tcode{wait_for}, or +\tcode{wait_until}) threads. +\end{itemize} + +\pnum +\effects Equivalent to: \begin{codeblock} -@\placeholdernc{INVOKE}@(std::forward(func), std::forward(args)...) +return wait_until(lock, chrono::steady_clock::now() + rel_time); \end{codeblock} -(see \ref{func.require}) shall be a valid expression. \pnum -\effects An execution of \tcode{call_once} that does not call its \tcode{func} is a -\term{passive} execution. An execution of \tcode{call_once} that calls its \tcode{func} -is an \term{active} execution. An active execution shall call -\tcode{\placeholdernc{INVOKE}(\brk{}% -std::forward(func), -std::forward(args)...)}. If such a call to \tcode{func} -throws an exception the execution is \term{exceptional}, otherwise it is \term{returning}. -An exceptional execution shall propagate the exception to the caller of -\tcode{call_once}. Among all executions of \tcode{call_once} for any given -\tcode{once_flag}: at most one shall be a returning execution; if there is a -returning execution, it shall be the last active execution; and there are -passive executions only if there is a returning execution. \begin{note} Passive -executions allow other threads to reliably observe the results produced by the -earlier returning execution. \end{note} +\returns \tcode{cv_status::timeout} if +the relative timeout\iref{thread.req.timing} specified by \tcode{rel_time} expired, +otherwise \tcode{cv_status::no_timeout}. \pnum -\sync For any given \tcode{once_flag}: all active executions occur in a total -order; completion of an active execution synchronizes with\iref{intro.multithread} -the start of the next one in this total order; and the returning execution -synchronizes with the return from all passive executions. - -\pnum\throws \tcode{system_error} when -an exception is required\iref{thread.req.exception}, or any exception thrown by \tcode{func}. +\remarks +If the function fails to meet the postcondition, \tcode{terminate()} +shall be called\iref{except.terminate}. +\begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} \pnum -\begin{example} -\begin{codeblock} -// global flag, regular function -void init(); -std::once_flag flag; - -void f() { - std::call_once(flag, init); -} - -// function static flag, function object -struct initializer { - void operator()(); -}; +\ensures \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} +is locked by the calling thread. -void g() { - static std::once_flag flag2; - std::call_once(flag2, initializer()); -} +\pnum +\throws Timeout-related +exceptions\iref{thread.req.timing}. -// object flag, member function -class information { - std::once_flag verified; - void verifier(); -public: - void verify() { std::call_once(verified, &information::verifier, *this); } -}; -\end{codeblock} -\end{example} \end{itemdescr} +\indexlibrarymember{wait_until}{condition_variable}% +\begin{itemdecl} +template + bool wait_until(unique_lock& lock, + const chrono::time_point& abs_time, + Predicate pred); +\end{itemdecl} -\rSec1[thread.condition]{Condition variables} - +\begin{itemdescr} \pnum -Condition variables provide synchronization primitives used to block a thread until -notified by some other thread that some condition is met or until a system time is -reached. Class \tcode{condition_variable} provides a condition variable that can only -wait on an object of type \tcode{unique_lock}, allowing the implementation -to be more efficient. Class \tcode{condition_variable_any} provides a general -condition variable that can wait on objects of user-supplied lock types. +\requires \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} is +locked by the calling thread, and either -\pnum -Condition variables permit concurrent invocation of the \tcode{wait}, \tcode{wait_for}, -\tcode{wait_until}, \tcode{notify_one} and \tcode{notify_all} member functions. +\begin{itemize} +\item no other thread is waiting on this \tcode{condition_variable} object or +\item \tcode{lock.mutex()} returns the same value for each of the \tcode{lock} +arguments supplied by all concurrently waiting (via \tcode{wait}, +\tcode{wait_for}, or \tcode{wait_until}) threads. +\end{itemize} \pnum -The execution of \tcode{notify_one} and \tcode{notify_all} shall be atomic. The -execution of \tcode{wait}, \tcode{wait_for}, and \tcode{wait_until} shall be performed -in three atomic parts: - -\begin{enumerate} -\item the release of the mutex and entry into the waiting state; -\item the unblocking of the wait; and -\item the reacquisition of the lock. -\end{enumerate} +\effects Equivalent to: +\begin{codeblock} +while (!pred()) + if (wait_until(lock, abs_time) == cv_status::timeout) + return pred(); +return true; +\end{codeblock} \pnum -The implementation shall behave as if all executions of \tcode{notify_one}, \tcode{notify_all}, and each -part of the \tcode{wait}, \tcode{wait_for}, and \tcode{wait_until} executions are -executed in a single unspecified total order consistent with the "happens before" order. +\remarks +If the function fails to meet the postcondition, \tcode{terminate()} +shall be called\iref{except.terminate}. +\begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} \pnum -Condition variable construction and destruction need not be synchronized. - -\rSec2[condition.variable.syn]{Header \tcode{} synopsis} -\indexhdr{condition_variable}% +\ensures \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} +is locked by the calling thread. -\indexlibrary{\idxcode{cv_status}}% -\begin{codeblock} -namespace std { - class condition_variable; - class condition_variable_any; +\pnum +\begin{note} The returned value indicates whether the predicate evaluated to +\tcode{true} regardless of whether the timeout was triggered. \end{note} - void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); +\pnum +\throws Timeout-related +exceptions\iref{thread.req.timing} or any exception thrown by \tcode{pred}. - enum class cv_status { no_timeout, timeout }; -} -\end{codeblock} +\end{itemdescr} -\rSec2[thread.condition.nonmember]{Non-member functions} -\indexlibrary{\idxcode{notify_all_at_thread_exit}}% +\indexlibrarymember{wait_for}{condition_variable}% \begin{itemdecl} -void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); +template + bool wait_for(unique_lock& lock, + const chrono::duration& rel_time, + Predicate pred); \end{itemdecl} \begin{itemdescr} \pnum -\requires \tcode{lk} is locked by the calling thread and either - +\requires \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} +is locked by the calling thread, and either \begin{itemize} -\item no other thread is waiting on \tcode{cond}, or -\item \tcode{lk.mutex()} returns the same value for each of the lock arguments -supplied by all concurrently waiting (via \tcode{wait}, \tcode{wait_for}, -or \tcode{wait_until}) threads. +\item +no other thread is waiting on this \tcode{condition_variable} object or + +\item +\tcode{lock.mutex()} returns the same value for each of the \tcode{lock} arguments +supplied by all concurrently waiting (via \tcode{wait}, \tcode{wait_for}, or +\tcode{wait_until}) threads. \end{itemize} \pnum -\effects Transfers ownership of the lock associated with \tcode{lk} into -internal storage and schedules \tcode{cond} to be notified when the current -thread exits, after all objects of thread storage duration associated with -the current thread have been destroyed. This notification shall be as if: +\effects Equivalent to: \begin{codeblock} -lk.unlock(); -cond.notify_all(); +return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred)); \end{codeblock} \pnum -\sync The implied \tcode{lk.unlock()} call is sequenced after the destruction of -all objects with thread storage duration associated with the current thread. +\begin{note} There is no blocking if \tcode{pred()} is initially \tcode{true}, even if the +timeout has already expired. \end{note} \pnum -\begin{note} -The supplied lock will be held until the thread exits, and care -should be taken to ensure that this does not cause deadlock due to lock -ordering issues. After calling \tcode{notify_all_at_thread_exit} it is -recommended that the thread should be exited as soon as possible, and -that no blocking or time-consuming tasks are run on that thread. -\end{note} +\remarks +If the function fails to meet the postcondition, \tcode{terminate()} +shall be called\iref{except.terminate}. +\begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} \pnum -\begin{note} -It is the user's responsibility to ensure that waiting threads -do not erroneously assume that the thread has finished if they experience -spurious wakeups. This typically requires that the condition being waited -for is satisfied while holding the lock on \tcode{lk}, and that this lock -is not released and reacquired prior to calling \tcode{notify_all_at_thread_exit}. -\end{note} +\ensures \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} +is locked by the calling thread. + +\pnum +\begin{note} The returned value indicates whether the predicate evaluates to \tcode{true} +regardless of whether the timeout was triggered. \end{note} + +\pnum +\throws Timeout-related +exceptions\iref{thread.req.timing} or any exception thrown by \tcode{pred}. + \end{itemdescr} -\rSec2[thread.condition.condvar]{Class \tcode{condition_variable}} +\rSec2[thread.condition.condvarany]{Class \tcode{condition_variable_any}} -\indexlibrary{\idxcode{condition_variable}}% +\pnum +A \tcode{Lock} type shall meet the \oldconcept{BasicLockable} +requirements\iref{thread.req.lockable.basic}. \begin{note} All of the standard +mutex types meet this requirement. If a \tcode{Lock} type other than one of the +standard mutex types or a \tcode{unique_lock} wrapper for a standard mutex type +is used with \tcode{condition_variable_any}, the user should ensure that any +necessary synchronization is in place with respect to the predicate associated +with the \tcode{condition_variable_any} instance. \end{note} + +\indexlibrary{\idxcode{condition_variable_any}}% \begin{codeblock} namespace std { - class condition_variable { + class condition_variable_any { public: - condition_variable(); - ~condition_variable(); + condition_variable_any(); + ~condition_variable_any(); - condition_variable(const condition_variable&) = delete; - condition_variable& operator=(const condition_variable&) = delete; + condition_variable_any(const condition_variable_any&) = delete; + condition_variable_any& operator=(const condition_variable_any&) = delete; void notify_one() noexcept; void notify_all() noexcept; - void wait(unique_lock& lock); - template - void wait(unique_lock& lock, Predicate pred); - template - cv_status wait_until(unique_lock& lock, - const chrono::time_point& abs_time); - template - bool wait_until(unique_lock& lock, - const chrono::time_point& abs_time, + + // \ref{thread.condvarany.wait}, noninterruptible waits + template + void wait(Lock& lock); + template + void wait(Lock& lock, Predicate pred); + + template + cv_status wait_until(Lock& lock, const chrono::time_point& abs_time); + template + bool wait_until(Lock& lock, const chrono::time_point& abs_time, Predicate pred); - template - cv_status wait_for(unique_lock& lock, - const chrono::duration& rel_time); - template - bool wait_for(unique_lock& lock, - const chrono::duration& rel_time, - Predicate pred); + template + cv_status wait_for(Lock& lock, const chrono::duration& rel_time); + template + bool wait_for(Lock& lock, const chrono::duration& rel_time, Predicate pred); - using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native} - native_handle_type native_handle(); // see~\ref{thread.req.native} + // \ref{thread.condvarany.intwait}, interruptible waits + template + bool wait_until(Lock& lock, Predicate pred, stop_token stoken); + template + bool wait_until(Lock& lock, const chrono::time_point& abs_time + Predicate pred, stop_token stoken); + template + bool wait_for(Lock& lock, const chrono::duration& rel_time, + Predicate pred, stop_token stoken); }; } \end{codeblock} -\pnum -The class \tcode{condition_variable} shall be a standard-layout class\iref{class.prop}. - -\indexlibrary{\idxcode{condition_variable}!constructor}% +\indexlibrary{\idxcode{condition_variable_any}!constructor}% \begin{itemdecl} -condition_variable(); +condition_variable_any(); \end{itemdecl} \begin{itemdescr} \pnum -\effects Constructs an object of type \tcode{condition_variable}. +\effects Constructs an object of type \tcode{condition_variable_any}. \pnum -\throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. +\throws \tcode{bad_alloc} or \tcode{system_error} when an exception is +required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{resource_unavailable_try_again} --- if some non-memory resource limitation prevents initialization. + +\item \tcode{operation_not_permitted} --- if the thread does not have the +privilege to perform the operation. \end{itemize} \end{itemdescr} -\indexlibrary{\idxcode{condition_variable}!destructor}% +\indexlibrary{\idxcode{condition_variable_any}!destructor}% \begin{itemdecl} -~condition_variable(); +~condition_variable_any(); \end{itemdecl} \begin{itemdescr} @@ -3004,7 +4392,7 @@ \pnum\effects Destroys the object. \end{itemdescr} -\indexlibrarymember{notify_one}{condition_variable}% +\indexlibrarymember{notify_one}{condition_variable_any}% \begin{itemdecl} void notify_one() noexcept; \end{itemdecl} @@ -3013,7 +4401,7 @@ \pnum\effects If any threads are blocked waiting for \tcode{*this}, unblocks one of those threads. \end{itemdescr} -\indexlibrarymember{notify_all}{condition_variable}% +\indexlibrarymember{notify_all}{condition_variable_any}% \begin{itemdecl} void notify_all() noexcept; \end{itemdecl} @@ -3022,28 +4410,74 @@ \pnum\effects Unblocks all threads that are blocked waiting for \tcode{*this}. \end{itemdescr} -\indexlibrarymember{wait}{condition_variable}% +\rSec3[thread.condvarany.wait]{Noninterruptible waits} + +\indexlibrarymember{wait}{condition_variable_any}% \begin{itemdecl} -void wait(unique_lock& lock); +template + void wait(Lock& lock); \end{itemdecl} \begin{itemdescr} \pnum -\requires \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} -is locked by the calling thread, and either +\effects \begin{itemize} -\item no other thread is waiting on this \tcode{condition_variable} object or -\item \tcode{lock.mutex()} returns the same value for each of the \tcode{lock} -arguments supplied by all concurrently waiting (via \tcode{wait}, -\tcode{wait_for}, or \tcode{wait_until}) threads. +\item Atomically calls \tcode{lock.unlock()} and blocks on \tcode{*this}. +\item When unblocked, calls \tcode{lock.lock()} (possibly blocking on the lock) and returns. +\item The function will unblock when signaled by a call to \tcode{notify_one()}, +a call to \tcode{notify_all()}, or spuriously. \end{itemize} +\pnum +\remarks +If the function fails to meet the postcondition, \tcode{terminate()} +shall be called\iref{except.terminate}. +\begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} + +\pnum\ensures \tcode{lock} is locked by the calling thread. + +\pnum\throws Nothing. + +\end{itemdescr} + +\indexlibrarymember{wait}{condition_variable_any}% +\begin{itemdecl} +template + void wait(Lock& lock, Predicate pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\begin{codeblock} +while (!pred()) + wait(lock); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{wait_until}{condition_variable_any}% +\begin{itemdecl} +template + cv_status wait_until(Lock& lock, const chrono::time_point& abs_time); +\end{itemdecl} + +\begin{itemdescr} \pnum\effects + \begin{itemize} -\item Atomically calls \tcode{lock.unlock()} and blocks on \tcode{*this}. -\item When unblocked, calls \tcode{lock.lock()} (possibly blocking on the lock), then returns. -\item The function will unblock when signaled by a call to \tcode{notify_one()} -or a call to \tcode{notify_all()}, or spuriously. +\item +Atomically calls \tcode{lock.unlock()} and blocks on \tcode{*this}. + +\item +When unblocked, calls \tcode{lock.lock()} (possibly blocking on the lock) and returns. + +\item +The function will unblock when signaled by a call to \tcode{notify_one()}, a call to \tcode{notify_all()}, +expiration of the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time}, +or spuriously. + +\item +If the function exits via an exception, \tcode{lock.lock()} shall be called prior to exiting the function. \end{itemize} \pnum @@ -3053,517 +4487,852 @@ \begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} \pnum -\ensures \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} -is locked by the calling thread. +\ensures \tcode{lock} is locked by the calling thread. + +\pnum +\returns \tcode{cv_status::timeout} if +the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time} expired, +otherwise \tcode{cv_status::no_timeout}. + +\pnum +\throws Timeout-related +exceptions\iref{thread.req.timing}. + +\end{itemdescr} + +\indexlibrarymember{wait_for}{condition_variable_any}% +\begin{itemdecl} +template + cv_status wait_for(Lock& lock, const chrono::duration& rel_time); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\begin{codeblock} +return wait_until(lock, chrono::steady_clock::now() + rel_time); +\end{codeblock} + +\pnum +\returns \tcode{cv_status::timeout} if +the relative timeout\iref{thread.req.timing} specified by \tcode{rel_time} expired, +otherwise \tcode{cv_status::no_timeout}. + +\pnum +\remarks +If the function fails to meet the postcondition, \tcode{terminate()} +shall be called\iref{except.terminate}. +\begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} + +\pnum +\ensures \tcode{lock} is locked by the calling thread. + +\pnum +\throws Timeout-related +exceptions\iref{thread.req.timing}. + +\end{itemdescr} + +\indexlibrarymember{wait_until}{condition_variable_any}% +\begin{itemdecl} +template + bool wait_until(Lock& lock, const chrono::time_point& abs_time, Predicate pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\begin{codeblock} +while (!pred()) + if (wait_until(lock, abs_time) == cv_status::timeout) + return pred(); +return true; +\end{codeblock} + +\pnum +\begin{note} There is no blocking if \tcode{pred()} is initially \tcode{true}, or +if the timeout has already expired. \end{note} + +\pnum +\begin{note} The returned value indicates whether the predicate evaluates to \tcode{true} +regardless of whether the timeout was triggered. \end{note} +\end{itemdescr} + +\indexlibrarymember{wait_for}{condition_variable_any}% +\begin{itemdecl} +template + bool wait_for(Lock& lock, const chrono::duration& rel_time, Predicate pred); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\begin{codeblock} +return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred)); +\end{codeblock} +\end{itemdescr} + +\rSec3[thread.condvarany.intwait]{Interruptible waits} + +\pnum +The following wait functions will be notified +when there is a stop request on the passed \tcode{stop_token}. +In that case the functions return immediately, +returning \tcode{false} if the predicate evaluates to \tcode{false}. + +\begin{itemdecl} +template + bool wait_until(Lock& lock, Predicate pred, stop_token stoken); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Registers for the duration of this call \tcode{*this} +to get notified on a stop request on \tcode{stoken} +during this call and then equivalent to: +\begin{codeblock} +while (!stoken.stop_requested()) { + if (pred()) + return true; + wait(lock); +} +return pred(); +\end{codeblock} + +\pnum +\begin{note} +The returned value indicates whether the predicate evaluated to +\tcode{true} regardless of whether there was a stop request. +\end{note} + +\pnum +\ensures \tcode{lock} is locked by the calling thread. -\pnum\throws Nothing. +\pnum +\remarks +If the function fails to meet the postcondition, +\tcode{terminate} is called\iref{except.terminate}. +\begin{note} +This can happen if the re-locking of the mutex throws an exception. +\end{note} +\pnum +\throws Any exception thrown by \tcode{pred}. \end{itemdescr} -\indexlibrarymember{wait}{condition_variable}% \begin{itemdecl} -template - void wait(unique_lock& lock, Predicate pred); +template + bool wait_until(Lock& lock, const chrono::time_point& abs_time + Predicate pred, stop_token stoken); \end{itemdecl} \begin{itemdescr} \pnum -\requires \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} is -locked by the calling thread, and either - -\begin{itemize} -\item no other thread is waiting on this \tcode{condition_variable} object or -\item \tcode{lock.mutex()} returns the same value for each of the \tcode{lock} -arguments supplied by all concurrently waiting (via \tcode{wait}, -\tcode{wait_for}, or \tcode{wait_until}) threads. -\end{itemize} - -\pnum -\effects Equivalent to: +\effects +Registers for the duration of this call \tcode{*this} +to get notified on a stop request on \tcode{stoken} +during this call and then equivalent to: \begin{codeblock} -while (!pred()) - wait(lock); +while (!stoken.stop_requested()) { + if (pred()) + return true; + if (cv.wait_until(lock, abs_time) == cv_status::timeout) + return pred(); +} +return pred(); \end{codeblock} \pnum -\remarks -If the function fails to meet the postcondition, \tcode{terminate()} -shall be called\iref{except.terminate}. -\begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} +\begin{note} +There is no blocking if \tcode{pred()} is initially \tcode{true}, +\tcode{stoken.stop_requested()} was already \tcode{true} +or the timeout has already expired. +\end{note} \pnum -\ensures \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} -is locked by the calling thread. +\begin{note} +The returned value indicates whether the predicate evaluated to \tcode{true} +regardless of whether the timeout was triggered or a stop request was made. +\end{note} \pnum -\throws Any exception thrown by \tcode{pred}. +\ensures \tcode{lock} is locked by the calling thread. + +\pnum +\remarks +If the function fails to meet the postcondition, +\tcode{terminate} is called\iref{except.terminate}. +\begin{note} +This can happen if the re-locking of the mutex throws an exception. +\end{note} +\pnum +\throws +Timeout-related exceptions \iref{thread.req.timing}, +or any exception thrown by \tcode{pred}. \end{itemdescr} -\indexlibrarymember{wait_until}{condition_variable}% \begin{itemdecl} -template - cv_status wait_until(unique_lock& lock, - const chrono::time_point& abs_time); +template + bool wait_for(Lock& lock, const chrono::duration& rel_time, + Predicate pred, stop_token stoken); \end{itemdecl} \begin{itemdescr} \pnum -\requires \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} -is locked by the calling thread, and either -\begin{itemize} -\item no other thread is waiting on this \tcode{condition_variable} object or -\item \tcode{lock.mutex()} returns the same value for each of the \tcode{lock} -arguments supplied by all concurrently waiting (via \tcode{wait}, -\tcode{wait_for}, or \tcode{wait_until}) threads. -\end{itemize} +\effects Equivalent to: +\begin{codeblock} +return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred), + std::move(stoken)); +\end{codeblock} +\end{itemdescr} + +\rSec1[thread.sema]{Semaphore} \pnum -\effects -\begin{itemize} -\item -Atomically calls \tcode{lock.unlock()} and blocks on \tcode{*this}. +Semaphores are lightweight synchronization primitives +used to constrain concurrent access to a shared resource. +They are widely used to implement other synchronization primitives and, +whenever both are applicable, can be more efficient than condition variables. -\item -When unblocked, calls \tcode{lock.lock()} (possibly blocking on the lock), then returns. +\pnum +A counting semaphore is a semaphore object +that models a non-negative resource count. +A binary semaphore is a semaphore object that has only two states. +A binary semaphore should be more efficient than +the default implementation of a counting semaphore with a unit resource count. -\item -The function will unblock when signaled by a call to \tcode{notify_one()}, a call to \tcode{notify_all()}, -expiration of the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time}, -or spuriously. +\rSec2[semaphore.syn]{Header \tcode{} synopsis} +\indexhdr{semaphore}% -\item -If the function exits via an exception, \tcode{lock.lock()} shall be called prior to exiting the function. -\end{itemize} +\begin{codeblock} +namespace std { + template + class counting_semaphore; + + using binary_semaphore = counting_semaphore<1>; +} +\end{codeblock} + +\rSec2[thread.sema.cnt]{Class template \tcode{counting_semaphore}} + +\begin{codeblock} +namespace std { + template + class counting_semaphore { + public: + static constexpr ptrdiff_t max() noexcept; + + constexpr explicit counting_semaphore(ptrdiff_t desired); + ~counting_semaphore(); + + counting_semaphore(const counting_semaphore&) = delete; + counting_semaphore& operator=(const counting_semaphore&) = delete; + + void release(ptrdiff_t update = 1); + void acquire(); + bool try_acquire() noexcept; + template + bool try_acquire_for(const chrono::duration& rel_time); + template + bool try_acquire_until(const chrono::time_point& abs_time); + + private: + ptrdiff_t counter; // \expos + }; +} +\end{codeblock} \pnum -\remarks -If the function fails to meet the postcondition, \tcode{terminate()} -shall be called\iref{except.terminate}. -\begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} +Class template \tcode{counting_semaphore} maintains an internal counter +that is initialized when the semaphore is created. +The counter is decremented when a thread acquires the semaphore, and +is incremented when a thread releases the semaphore. +If a thread tries to acquire the semaphore when the counter is zero, +the thread will block +until another thread increments the counter by releasing the semaphore. \pnum -\ensures \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} -is locked by the calling thread. +\tcode{least_max_value} shall be non-negative; otherwise the program is ill-formed. \pnum -\returns \tcode{cv_status::timeout} if -the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time} expired, -otherwise \tcode{cv_status::no_timeout}. +Concurrent invocations of the member functions of \tcode{counting_semaphore}, +other than its destructor, do not introduce data races. -\pnum\throws Timeout-related -exceptions\iref{thread.req.timing}. +\indexlibrarymember{max}{counting_semaphore}% +\begin{itemdecl} +static constexpr ptrdiff_t max() noexcept; +\end{itemdecl} +\begin{itemdescr} +\pnum +\returns +The maximum value of \tcode{counter}. +This value is greater than or equal to \tcode{least_max_value}. \end{itemdescr} -\indexlibrarymember{wait_for}{condition_variable}% +\indexlibrary{\idxcode{counting_semaphore}!constructor}% \begin{itemdecl} -template - cv_status wait_for(unique_lock& lock, - const chrono::duration& rel_time); +constexpr explicit counting_semaphore(ptrdiff_t desired); \end{itemdecl} \begin{itemdescr} \pnum -\requires \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} -is locked by the calling thread, and either -\begin{itemize} -\item no other thread is waiting on this \tcode{condition_variable} object or -\item \tcode{lock.mutex()} returns the same value for each of the \tcode{lock} arguments -supplied by all concurrently waiting (via \tcode{wait}, \tcode{wait_for}, or -\tcode{wait_until}) threads. -\end{itemize} +\expects +\tcode{desired >= 0} is \tcode{true}, and +\tcode{desired <= max()} is \tcode{true}. \pnum -\effects Equivalent to: -\begin{codeblock} -return wait_until(lock, chrono::steady_clock::now() + rel_time); -\end{codeblock} +\effects +Initializes \tcode{counter} with \tcode{desired}. \pnum -\returns \tcode{cv_status::timeout} if -the relative timeout\iref{thread.req.timing} specified by \tcode{rel_time} expired, -otherwise \tcode{cv_status::no_timeout}. +\throws +Nothing. +\end{itemdescr} + +\indexlibrarymember{release}{counting_semaphore}% +\begin{itemdecl} +void release(ptrdiff_t update = 1); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{update >= 0} is \tcode{true}, and +\tcode{update <= max() - counter} is \tcode{true}. \pnum -\remarks -If the function fails to meet the postcondition, \tcode{terminate()} -shall be called\iref{except.terminate}. -\begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} +\effects +Atomically execute \tcode{counter += update}. +Then, unblocks any threads +that are waiting for \tcode{counter} to be greater than zero. \pnum -\ensures \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} -is locked by the calling thread. +\sync +Strongly happens before invocations of \tcode{try_acquire} +that observe the result of the effects. \pnum -\throws Timeout-related -exceptions\iref{thread.req.timing}. +\throws +\tcode{system_error} when an exception is required\iref{thread.req.exception}. +\pnum +\errors +Any of the error conditions +allowed for mutex types\iref{thread.mutex.requirements.mutex}. \end{itemdescr} -\indexlibrarymember{wait_until}{condition_variable}% +\indexlibrarymember{try_acquire}{counting_semaphore}% \begin{itemdecl} -template - bool wait_until(unique_lock& lock, - const chrono::time_point& abs_time, - Predicate pred); +bool try_acquire() noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\requires \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} is -locked by the calling thread, and either - +\effects \begin{itemize} -\item no other thread is waiting on this \tcode{condition_variable} object or -\item \tcode{lock.mutex()} returns the same value for each of the \tcode{lock} -arguments supplied by all concurrently waiting (via \tcode{wait}, -\tcode{wait_for}, or \tcode{wait_until}) threads. +\item + With low probability, returns immediately. + An implementation should ensure + that \tcode{try_acquire} does not consistently return \tcode{false} + in the absence of contending acquisitions. +\item + Otherwise, atomically check whether \tcode{counter} is greater than zero and, + if so, decrement \tcode{counter} by one. \end{itemize} \pnum -\effects Equivalent to: -\begin{codeblock} -while (!pred()) - if (wait_until(lock, abs_time) == cv_status::timeout) - return pred(); -return true; -\end{codeblock} +\returns +\tcode{true} if \tcode{counter} was decremented, otherwise \tcode{false}. +\end{itemdescr} -\pnum -\remarks -If the function fails to meet the postcondition, \tcode{terminate()} -shall be called\iref{except.terminate}. -\begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} +\indexlibrarymember{acquire}{counting_semaphore}% +\begin{itemdecl} +void acquire(); +\end{itemdecl} +\begin{itemdescr} \pnum -\ensures \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} -is locked by the calling thread. +\effects +Repeatedly performs the following steps, in order: +\begin{itemize} +\item Evaluates \tcode{try_acquire}. If the result is \tcode{true}, returns. +\item Blocks on \tcode{*this} until \tcode{counter} is greater than zero. +\end{itemize} \pnum -\begin{note} The returned value indicates whether the predicate evaluated to -\tcode{true} regardless of whether the timeout was triggered. \end{note} +\throws +\tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum -\throws Timeout-related -exceptions\iref{thread.req.timing} or any exception thrown by \tcode{pred}. - +\errors +Any of the error conditions +allowed for mutex types\iref{thread.mutex.requirements.mutex}. \end{itemdescr} -\indexlibrarymember{wait_for}{condition_variable}% +\indexlibrarymember{try_acquire_for}{counting_semaphore}% +\indexlibrarymember{try_acquire_until}{counting_semaphore}% \begin{itemdecl} -template - bool wait_for(unique_lock& lock, - const chrono::duration& rel_time, - Predicate pred); +template + bool try_acquire_for(const chrono::duration& rel_time); +template + bool try_acquire_until(const chrono::time_point& abs_time); \end{itemdecl} \begin{itemdescr} \pnum -\requires \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} -is locked by the calling thread, and either +\effects +Repeatedly performs the following steps, in order: \begin{itemize} \item -no other thread is waiting on this \tcode{condition_variable} object or - + Evaluates \tcode{try_acquire()}. + If the result is \tcode{true}, returns \tcode{true}. \item -\tcode{lock.mutex()} returns the same value for each of the \tcode{lock} arguments -supplied by all concurrently waiting (via \tcode{wait}, \tcode{wait_for}, or -\tcode{wait_until}) threads. + Blocks on \tcode{*this} + until \tcode{counter} is greater than zero or until the timeout expires. + If it is unblocked by the timeout expiring, returns \tcode{false}. \end{itemize} +The timeout expires\iref{thread.req.timing} +when the current time is after \tcode{abs_time} (for \tcode{try_acquire_until}) +or when at least \tcode{rel_time} has passed +from the start of the function (for \tcode{try_acquire_for}). \pnum -\effects Equivalent to: -\begin{codeblock} -return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred)); -\end{codeblock} +\throws +Timeout-related exceptions\iref{thread.req.timing}, or \tcode{system_error} +when a non-timeout-related exception is required\iref{thread.req.exception}. \pnum -\begin{note} There is no blocking if \tcode{pred()} is initially \tcode{true}, even if the -timeout has already expired. \end{note} +\errors +Any of the error conditions +allowed for mutex types\iref{thread.mutex.requirements.mutex}. +\end{itemdescr} -\pnum -\remarks -If the function fails to meet the postcondition, \tcode{terminate()} -shall be called\iref{except.terminate}. -\begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} +\rSec1[thread.coord]{Coordination types} \pnum -\ensures \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} -is locked by the calling thread. +This subclause describes various concepts related to thread coordination, and +defines the coordination types \tcode{latch} and \tcode{barrier}. +These types facilitate concurrent computation performed by a number of threads. -\pnum -\begin{note} The returned value indicates whether the predicate evaluates to \tcode{true} -regardless of whether the timeout was triggered. \end{note} +\rSec2[thread.latch]{Latches} \pnum -\throws Timeout-related -exceptions\iref{thread.req.timing} or any exception thrown by \tcode{pred}. - -\end{itemdescr} +A latch is a thread coordination mechanism +that allows any number of threads to block +until an expected number of threads arrive at the latch +(via the \tcode{count_down} function). +The expected count is set when the latch is created. +An individual latch is a single-use object; +once the expected count has been reached, the latch cannot be reused. -\rSec2[thread.condition.condvarany]{Class \tcode{condition_variable_any}} +\rSec2[latch.syn]{Header \tcode{} synopsis} +\indexhdr{latch}% -\pnum -A \tcode{Lock} type shall meet the \oldconcept{BasicLockable} -requirements\iref{thread.req.lockable.basic}. \begin{note} All of the standard -mutex types meet this requirement. If a \tcode{Lock} type other than one of the -standard mutex types or a \tcode{unique_lock} wrapper for a standard mutex type -is used with \tcode{condition_variable_any}, the user should ensure that any -necessary synchronization is in place with respect to the predicate associated -with the \tcode{condition_variable_any} instance. \end{note} +\begin{codeblock} +namespace std { + class latch; +} +\end{codeblock} + +\rSec2[thread.latch.class]{Class \tcode{latch}} -\indexlibrary{\idxcode{condition_variable_any}}% \begin{codeblock} namespace std { - class condition_variable_any { + class latch { public: - condition_variable_any(); - ~condition_variable_any(); + constexpr explicit latch(ptrdiff_t expected); + ~latch(); - condition_variable_any(const condition_variable_any&) = delete; - condition_variable_any& operator=(const condition_variable_any&) = delete; + latch(const latch&) = delete; + latch& operator=(const latch&) = delete; - void notify_one() noexcept; - void notify_all() noexcept; - template - void wait(Lock& lock); - template - void wait(Lock& lock, Predicate pred); + void count_down(ptrdiff_t update = 1); + bool try_wait() const noexcept; + void wait() const; + void arrive_and_wait(ptrdiff_t update = 1); - template - cv_status wait_until(Lock& lock, const chrono::time_point& abs_time); - template - bool wait_until(Lock& lock, const chrono::time_point& abs_time, - Predicate pred); - template - cv_status wait_for(Lock& lock, const chrono::duration& rel_time); - template - bool wait_for(Lock& lock, const chrono::duration& rel_time, Predicate pred); + private: + ptrdiff_t counter; // \expos }; } \end{codeblock} -\indexlibrary{\idxcode{condition_variable_any}!constructor}% +\pnum +A \tcode{latch} maintains an internal counter +that is initialized when the latch is created. +Threads can block on the latch object, +waiting for counter to be decremented to zero. + +\pnum +Concurrent invocations of the member functions of \tcode{latch}, +other than its destructor, do not introduce data races. + +\indexlibrary{\idxcode{latch}!constructor}% \begin{itemdecl} -condition_variable_any(); +constexpr explicit latch(ptrdiff_t expected); \end{itemdecl} \begin{itemdescr} \pnum -\effects Constructs an object of type \tcode{condition_variable_any}. +\expects +\tcode{expected >= 0} is \tcode{true}. \pnum -\throws \tcode{bad_alloc} or \tcode{system_error} when an exception is -required\iref{thread.req.exception}. +\effects +Initializes \tcode{counter} with \tcode{expected}. \pnum -\errors -\begin{itemize} -\item \tcode{resource_unavailable_try_again} --- if some non-memory resource -limitation prevents initialization. - -\item \tcode{operation_not_permitted} --- if the thread does not have the -privilege to perform the operation. -\end{itemize} +\throws +Nothing. \end{itemdescr} -\indexlibrary{\idxcode{condition_variable_any}!destructor}% +\indexlibrarymember{count_down}{latch}% \begin{itemdecl} -~condition_variable_any(); +void count_down(ptrdiff_t update = 1); \end{itemdecl} \begin{itemdescr} \pnum -\requires There shall be no thread blocked on \tcode{*this}. \begin{note} That is, all -threads shall have been notified; they may subsequently block on the lock specified in the -wait. -This relaxes the usual rules, which would have required all wait calls to happen before -destruction. Only the notification to unblock the wait needs to happen before destruction. -The user should take care to ensure that no threads wait on \tcode{*this} once the destructor has -been started, especially when the waiting threads are calling the wait functions in a loop or -using the overloads of \tcode{wait}, \tcode{wait_for}, or \tcode{wait_until} that take a predicate. -\end{note} +\expects +\tcode{update >= 0} is \tcode{true}, and +\tcode{update <= counter} is \tcode{true}. -\pnum\effects Destroys the object. -\end{itemdescr} +\pnum +\effects +Atomically decrements \tcode{counter} by \tcode{update}. +If \tcode{counter} is equal to zero, +unblocks all threads blocked on \tcode{*this}. -\indexlibrarymember{notify_one}{condition_variable_any}% -\begin{itemdecl} -void notify_one() noexcept; -\end{itemdecl} +\pnum +\sync +Strongly happens before the returns from all calls that are unblocked. -\begin{itemdescr} -\pnum\effects If any threads are blocked waiting for \tcode{*this}, unblocks one of those threads. +\pnum +\throws +\tcode{system_error} when an exception is required\iref{thread.req.exception}. + +\pnum +\errors +Any of the error conditions +allowed for mutex types\iref{thread.mutex.requirements.mutex}. \end{itemdescr} -\indexlibrarymember{notify_all}{condition_variable_any}% +\indexlibrarymember{try_wait}{latch}% \begin{itemdecl} -void notify_all() noexcept; +bool try_wait() const noexcept; \end{itemdecl} \begin{itemdescr} -\pnum\effects Unblocks all threads that are blocked waiting for \tcode{*this}. +\pnum +\returns +With very low probability \tcode{false}. Otherwise \tcode{counter == 0}. \end{itemdescr} -\indexlibrarymember{wait}{condition_variable_any}% +\indexlibrarymember{wait}{latch}% \begin{itemdecl} -template - void wait(Lock& lock); +void wait() const; \end{itemdecl} \begin{itemdescr} \pnum \effects -\begin{itemize} -\item Atomically calls \tcode{lock.unlock()} and blocks on \tcode{*this}. -\item When unblocked, calls \tcode{lock.lock()} (possibly blocking on the lock) and returns. -\item The function will unblock when signaled by a call to \tcode{notify_one()}, -a call to \tcode{notify_all()}, or spuriously. -\end{itemize} +If \tcode{counter} equals zero, returns immediately. +Otherwise, blocks on \tcode{*this} +until a call to \tcode{count_down} that decrements \tcode{counter} to zero. \pnum -\remarks -If the function fails to meet the postcondition, \tcode{terminate()} -shall be called\iref{except.terminate}. -\begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} - -\pnum\ensures \tcode{lock} is locked by the calling thread. - -\pnum\throws Nothing. +\throws +\tcode{system_error} when an exception is required\iref{thread.req.exception}. +\pnum +\errors +Any of the error conditions +allowed for mutex types\iref{thread.mutex.requirements.mutex}. \end{itemdescr} -\indexlibrarymember{wait}{condition_variable_any}% +\indexlibrarymember{arrive_and_wait}{latch}% \begin{itemdecl} -template - void wait(Lock& lock, Predicate pred); +void arrive_and_wait(ptrdiff_t update = 1); \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: +\effects +Equivalent to: \begin{codeblock} -while (!pred()) - wait(lock); +count_down(update); +wait(); \end{codeblock} \end{itemdescr} -\indexlibrarymember{wait_until}{condition_variable_any}% -\begin{itemdecl} -template - cv_status wait_until(Lock& lock, const chrono::time_point& abs_time); -\end{itemdecl} +\rSec2[thread.barrier]{Barriers} -\begin{itemdescr} -\pnum\effects +\pnum +A barrier is a thread coordination mechanism +whose lifetime consists of a sequence of barrier phases, +where each phase allows at most an expected number of threads to block +until the expected number of threads arrive at the barrier. +\begin{note} +A barrier is useful for managing repeated tasks +that are handled by multiple threads. +\end{note} + +\rSec3[barrier.syn]{Header \tcode{} synopsis} +\indexhdr{barrier}% + +\begin{codeblock} +namespace std { + template + class barrier; +} +\end{codeblock} + +\rSec3[thread.barrier.class]{Class template \tcode{barrier}} + +\begin{codeblock} +namespace std { + template + class barrier { + public: + using arrival_token = @\seebelow@; + + constexpr explicit barrier(ptrdiff_t expected, + CompletionFunction f = CompletionFunction()); + ~barrier(); + barrier(const barrier&) = delete; + barrier& operator=(const barrier&) = delete; + + [[nodiscard]] arrival_token arrive(ptrdiff_t update = 1); + void wait(arrival_token&& arrival) const; + + void arrive_and_wait(); + void arrive_and_drop(); + + private: + CompletionFunction completion; // \expos + }; +} +\end{codeblock} + +\pnum +Each \defn{barrier phase} consists of the following steps: \begin{itemize} \item -Atomically calls \tcode{lock.unlock()} and blocks on \tcode{*this}. - + The expected count is decremented + by each call to \tcode{arrive} or \tcode{arrive_and_drop}. \item -When unblocked, calls \tcode{lock.lock()} (possibly blocking on the lock) and returns. - + When the expected count reaches zero, the phase completion step is run. + For the specialization + with the default value of the \tcode{CompletionFunction} template parameter, + the completion step is run + as part of the call to \tcode{arrive} or \tcode{arrive_and_drop} + that caused the expected count to reach zero. + For other specializations, + the completion step is run on one of the threads + that arrived at the barrier during the phase. \item -The function will unblock when signaled by a call to \tcode{notify_one()}, a call to \tcode{notify_all()}, -expiration of the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time}, -or spuriously. + When the completion step finishes, + the expected count is reset + to what was specified by the \tcode{expected} argument to the constructor, + possibly adjusted by calls to \tcode{arrive_and_drop}, and + the next phase starts. +\end{itemize} -\item -If the function exits via an exception, \tcode{lock.lock()} shall be called prior to exiting the function. +\indextext{phase synchronization point|see{barrier, phase synchronization point }}% +\pnum +Each phase defines a \defnx{phase synchronization point}{barrier!phase synchronization point}. +Threads that arrive at the barrier during the phase +can block on the phase synchronization point by calling \tcode{wait}, and +will remain blocked until the phase completion step is run. + +\pnum +The \defn{phase completion step} +that is executed at the end of each phase has the following effects: +\begin{itemize} +\item Invokes the completion function, equivalent to \tcode{completion()}. +\item Unblocks all threads that are blocked on the phase synchronization point. \end{itemize} +The end of the completion step strongly happens before +the returns from all calls that were unblocked by the completion step. +For specializations that do not have +the default value of the \tcode{CompletionFunction} template parameter, +the behavior is undefined if any of the barrier object's member functions +other than \tcode{wait} are called while the completion step is in progress. \pnum -\remarks -If the function fails to meet the postcondition, \tcode{terminate()} -shall be called\iref{except.terminate}. -\begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} +Concurrent invocations of the member functions of \tcode{barrier}, +other than its destructor, do not introduce data races. +The member functions \tcode{arrive} and \tcode{arrive_and_drop} +execute atomically. \pnum -\ensures \tcode{lock} is locked by the calling thread. +\tcode{CompletionFunction} shall meet the +\oldconcept{MoveConstructible} (\tref{cpp17.moveconstructible}) and +\oldconcept{Destructible} (\tref{cpp17.destructible}) requirements. +\tcode{is_nothrow_invocable_v} shall be \tcode{true}. \pnum -\returns \tcode{cv_status::timeout} if -the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time} expired, -otherwise \tcode{cv_status::no_timeout}. +The default value of the \tcode{CompletionFunction} template parameter is +an unspecified type, such that, +in addition to satisfying the requirements of \tcode{CompletionFunction}, +it meets the \oldconcept{DefaultConstructible} +requirements (\tref{cpp17.defaultconstructible}) and +\tcode{completion()} has no effects. \pnum -\throws Timeout-related -exceptions\iref{thread.req.timing}. +\tcode{barrier::arrival_token} is an unspecified type, +such that it meets the +\oldconcept{MoveConstructible} (\tref{cpp17.moveconstructible}), +\oldconcept{MoveAssignable} (\tref{cpp17.moveassignable}), and +\oldconcept{Destructible} (\tref{cpp17.destructible}) requirements. + +\indexlibrary{\idxcode{barrier}!constructor} +\begin{itemdecl} +constexpr explicit barrier(ptrdiff_t expected, + CompletionFunction f = CompletionFunction()); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{expected >= 0} is \tcode{true}. + +\pnum +\effects +Sets both the initial expected count for each barrier phase and +the current expected count for the first phase to \tcode{expected}. +Initializes \tcode{completion} with \tcode{std::move(f)}. +Starts the first phase. +\begin{note} +If \tcode{expected} is 0 this object can only be destroyed. +\end{note} +\pnum +\throws +Any exception thrown by \tcode{CompletionFunction}'s move constructor. \end{itemdescr} -\indexlibrarymember{wait_for}{condition_variable_any}% +\indexlibrarymember{arrive}{barrier}% \begin{itemdecl} -template - cv_status wait_for(Lock& lock, const chrono::duration& rel_time); +[[nodiscard]] arrival_token arrive(ptrdiff_t update = 1); \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: -\begin{codeblock} -return wait_until(lock, chrono::steady_clock::now() + rel_time); -\end{codeblock} +\expects +\tcode{update > 0} is \tcode{true}, and +\tcode{update} is less than or equal to +the expected count for the current barrier phase. \pnum -\returns \tcode{cv_status::timeout} if -the relative timeout\iref{thread.req.timing} specified by \tcode{rel_time} expired, -otherwise \tcode{cv_status::no_timeout}. +\effects +Constructs an object of type \tcode{arrival_token} +that is associated with the phase synchronization point for the current phase. +Then, decrements the expected count by \tcode{update}. \pnum -\remarks -If the function fails to meet the postcondition, \tcode{terminate()} -shall be called\iref{except.terminate}. -\begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} +\sync +The call to \tcode{arrive} strongly happens before +the start of the phase completion step for the current phase. \pnum -\ensures \tcode{lock} is locked by the calling thread. +\returns +The constructed \tcode{arrival_token} object. \pnum -\throws Timeout-related -exceptions\iref{thread.req.timing}. +\throws +\tcode{system_error} when an exception is required\iref{thread.req.exception}. +\pnum +\errors +Any of the error conditions +allowed for mutex types\iref{thread.mutex.requirements.mutex}. + +\pnum +\begin{note} +This call can cause the completion step for the current phase to start. +\end{note} \end{itemdescr} -\indexlibrarymember{wait_until}{condition_variable_any}% +\indexlibrarymember{wait}{barrier}% \begin{itemdecl} -template - bool wait_until(Lock& lock, const chrono::time_point& abs_time, Predicate pred); +void wait(arrival_token&& arrival) const; \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: -\begin{codeblock} -while (!pred()) - if (wait_until(lock, abs_time) == cv_status::timeout) - return pred(); -return true; -\end{codeblock} +\expects +\tcode{arrival} is associated with +the phase synchronization point for the current phase or +the immediately preceding phase of the same barrier object. \pnum -\begin{note} There is no blocking if \tcode{pred()} is initially \tcode{true}, or -if the timeout has already expired. \end{note} +\effects +Blocks at the synchronization point associated with \tcode{std::move(arrival)} +until the phase completion step of the synchronization point's phase is run. +\begin{note} +If \tcode{arrival} is associated with the synchronization point +for a previous phase, the call returns immediately. +\end{note} \pnum -\begin{note} The returned value indicates whether the predicate evaluates to \tcode{true} -regardless of whether the timeout was triggered. \end{note} +\throws +\tcode{system_error} when an exception is required\iref{thread.req.exception}. + +\pnum +\errors +Any of the error conditions +allowed for mutex types\iref{thread.mutex.requirements.mutex}. \end{itemdescr} -\indexlibrarymember{wait_for}{condition_variable_any}% +\indexlibrarymember{arrive_and_wait}{barrier}% \begin{itemdecl} -template - bool wait_for(Lock& lock, const chrono::duration& rel_time, Predicate pred); +void arrive_and_wait(); \end{itemdecl} \begin{itemdescr} \pnum -\effects Equivalent to: -\begin{codeblock} -return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred)); -\end{codeblock} +\effects +Equivalent to: \tcode{wait(arrive())}. +\end{itemdescr} + +\indexlibrarymember{arrive_and_drop}{barrier}% +\begin{itemdecl} +void arrive_and_drop(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +The expected count for the current barrier phase is greater than zero. + +\pnum +\effects +Decrements the initial expected count for all subsequent phases by one. +Then decrements the expected count for the current phase by one. + +\pnum +\sync +The call to \tcode{arrive_and_drop} strongly happens before +the start of the phase completion step for the current phase. + +\pnum +\throws +\tcode{system_error} when an exception is required\iref{thread.req.exception}. + +\pnum +\errors +Any of the error conditions +allowed for mutex types\iref{thread.mutex.requirements.mutex}. + +\pnum +\begin{note} +This call can cause the completion step for the current phase to start. +\end{note} \end{itemdescr} \rSec1[futures]{Futures} diff --git a/source/time.tex b/source/time.tex index 4bcdba97b2..a17ac52108 100644 --- a/source/time.tex +++ b/source/time.tex @@ -16,13 +16,20 @@ \ref{time.point} & Class template \tcode{time_point} & \\ \ref{time.clock} & Clocks & \\ \ref{time.cal} & Civil calendar & \\ -\ref{time.tod} & Class template \tcode{time_of_day} & \\ +\ref{time.hms} & Class template \tcode{hh_mm_ss} & \\ +\ref{time.12} & 12/24 hour functions & \\ \ref{time.zone} & Time zones & \\ \ref{time.format} & Formatting & \\ \ref{time.parse} & Parsing & \\ \rowsep \ref{ctime.syn} & C library time utilities & \tcode{} \\ \rowsep \end{libsumtab} +\pnum +\indextext{STATICALLY-WIDEN@\exposid{STATICALLY-WIDEN}}% +Let \exposid{STATICALLY-WIDEN}\tcode{("...")} be +\tcode{"..."} if \tcode{charT} is \tcode{char} and +\tcode{L"..."} if \tcode{charT} is \tcode{wchar_t}. + \rSec1[time.syn]{Header \tcode{} synopsis} \indexhdr{chrono}% @@ -114,9 +121,6 @@ template constexpr bool operator==(const duration& lhs, const duration& rhs); - template - constexpr bool operator!=(const duration& lhs, - const duration& rhs); template constexpr bool operator< (const duration& lhs, const duration& rhs); @@ -129,6 +133,10 @@ template constexpr bool operator>=(const duration& lhs, const duration& rhs); + template + requires @\seebelow@ + constexpr auto operator<=>(const duration& lhs, + const duration& rhs); // \ref{time.duration.cast}, \tcode{duration_cast} template @@ -145,10 +153,6 @@ basic_ostream& operator<<(basic_ostream& os, const duration& d); - template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, - const duration& d); template> basic_istream& from_stream(basic_istream& is, const charT* fmt, @@ -191,9 +195,6 @@ template constexpr bool operator==(const time_point& lhs, const time_point& rhs); - template - constexpr bool operator!=(const time_point& lhs, - const time_point& rhs); template constexpr bool operator< (const time_point& lhs, const time_point& rhs); @@ -206,6 +207,9 @@ template constexpr bool operator>=(const time_point& lhs, const time_point& rhs); + template Duration2> + constexpr auto operator<=>(const time_point& lhs, + const time_point& rhs); // \ref{time.point.cast}, \tcode{time_point_cast} template @@ -238,11 +242,6 @@ basic_ostream& operator<<(basic_ostream& os, const sys_days& dp); - template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, - const sys_time& tp); - template> basic_istream& from_stream(basic_istream& is, const charT* fmt, @@ -260,10 +259,6 @@ template basic_ostream& operator<<(basic_ostream& os, const utc_time& t); - template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, - const utc_time& tp); template> basic_istream& from_stream(basic_istream& is, const charT* fmt, @@ -271,6 +266,11 @@ basic_string* abbrev = nullptr, minutes* offset = nullptr); + struct leap_second_info; + + template + leap_second_info get_leap_second_info(const utc_time& ut); + // \ref{time.clock.tai}, class \tcode{tai_clock} class tai_clock; @@ -281,10 +281,6 @@ template basic_ostream& operator<<(basic_ostream& os, const tai_time& t); - template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, - const tai_time& tp); template> basic_istream& from_stream(basic_istream& is, const charT* fmt, @@ -302,10 +298,6 @@ template basic_ostream& operator<<(basic_ostream& os, const gps_time& t); - template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, - const gps_time& tp); template> basic_istream& from_stream(basic_istream& is, const charT* fmt, @@ -322,10 +314,6 @@ template basic_ostream& operator<<(basic_ostream& os, const file_time& tp); - template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, - const file_time& tp); template> basic_istream& from_stream(basic_istream& is, const charT* fmt, @@ -349,11 +337,6 @@ template basic_ostream& operator<<(basic_ostream& os, const local_time& tp); - template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, - const local_time& tp, - const string* abbrev = nullptr, const seconds* offset_sec = nullptr); template> basic_istream& from_stream(basic_istream& is, const charT* fmt, @@ -375,11 +358,7 @@ class day; constexpr bool operator==(const day& x, const day& y) noexcept; - constexpr bool operator!=(const day& x, const day& y) noexcept; - constexpr bool operator< (const day& x, const day& y) noexcept; - constexpr bool operator> (const day& x, const day& y) noexcept; - constexpr bool operator<=(const day& x, const day& y) noexcept; - constexpr bool operator>=(const day& x, const day& y) noexcept; + constexpr strong_ordering operator<=>(const day& x, const day& y) noexcept; constexpr day operator+(const day& x, const days& y) noexcept; constexpr day operator+(const days& x, const day& y) noexcept; @@ -389,9 +368,6 @@ template basic_ostream& operator<<(basic_ostream& os, const day& d); - template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const day& d); template> basic_istream& from_stream(basic_istream& is, const charT* fmt, @@ -402,11 +378,7 @@ class month; constexpr bool operator==(const month& x, const month& y) noexcept; - constexpr bool operator!=(const month& x, const month& y) noexcept; - constexpr bool operator< (const month& x, const month& y) noexcept; - constexpr bool operator> (const month& x, const month& y) noexcept; - constexpr bool operator<=(const month& x, const month& y) noexcept; - constexpr bool operator>=(const month& x, const month& y) noexcept; + constexpr strong_ordering operator<=>(const month& x, const month& y) noexcept; constexpr month operator+(const month& x, const months& y) noexcept; constexpr month operator+(const months& x, const month& y) noexcept; @@ -416,9 +388,6 @@ template basic_ostream& operator<<(basic_ostream& os, const month& m); - template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const month& m); template> basic_istream& from_stream(basic_istream& is, const charT* fmt, @@ -429,11 +398,7 @@ class year; constexpr bool operator==(const year& x, const year& y) noexcept; - constexpr bool operator!=(const year& x, const year& y) noexcept; - constexpr bool operator< (const year& x, const year& y) noexcept; - constexpr bool operator> (const year& x, const year& y) noexcept; - constexpr bool operator<=(const year& x, const year& y) noexcept; - constexpr bool operator>=(const year& x, const year& y) noexcept; + constexpr strong_ordering operator<=>(const year& x, const year& y) noexcept; constexpr year operator+(const year& x, const years& y) noexcept; constexpr year operator+(const years& x, const year& y) noexcept; @@ -444,10 +409,6 @@ basic_ostream& operator<<(basic_ostream& os, const year& y); - template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const year& y); - template> basic_istream& from_stream(basic_istream& is, const charT* fmt, @@ -458,7 +419,6 @@ class weekday; constexpr bool operator==(const weekday& x, const weekday& y) noexcept; - constexpr bool operator!=(const weekday& x, const weekday& y) noexcept; constexpr weekday operator+(const weekday& x, const days& y) noexcept; constexpr weekday operator+(const days& x, const weekday& y) noexcept; @@ -469,10 +429,6 @@ basic_ostream& operator<<(basic_ostream& os, const weekday& wd); - template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const weekday& wd); - template> basic_istream& from_stream(basic_istream& is, const charT* fmt, @@ -483,7 +439,6 @@ class weekday_indexed; constexpr bool operator==(const weekday_indexed& x, const weekday_indexed& y) noexcept; - constexpr bool operator!=(const weekday_indexed& x, const weekday_indexed& y) noexcept; template basic_ostream& @@ -493,7 +448,6 @@ class weekday_last; constexpr bool operator==(const weekday_last& x, const weekday_last& y) noexcept; - constexpr bool operator!=(const weekday_last& x, const weekday_last& y) noexcept; template basic_ostream& @@ -503,20 +457,12 @@ class month_day; constexpr bool operator==(const month_day& x, const month_day& y) noexcept; - constexpr bool operator!=(const month_day& x, const month_day& y) noexcept; - constexpr bool operator< (const month_day& x, const month_day& y) noexcept; - constexpr bool operator> (const month_day& x, const month_day& y) noexcept; - constexpr bool operator<=(const month_day& x, const month_day& y) noexcept; - constexpr bool operator>=(const month_day& x, const month_day& y) noexcept; + constexpr strong_ordering operator<=>(const month_day& x, const month_day& y) noexcept; template basic_ostream& operator<<(basic_ostream& os, const month_day& md); - template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const month_day& md); - template> basic_istream& from_stream(basic_istream& is, const charT* fmt, @@ -527,11 +473,8 @@ class month_day_last; constexpr bool operator==(const month_day_last& x, const month_day_last& y) noexcept; - constexpr bool operator!=(const month_day_last& x, const month_day_last& y) noexcept; - constexpr bool operator< (const month_day_last& x, const month_day_last& y) noexcept; - constexpr bool operator> (const month_day_last& x, const month_day_last& y) noexcept; - constexpr bool operator<=(const month_day_last& x, const month_day_last& y) noexcept; - constexpr bool operator>=(const month_day_last& x, const month_day_last& y) noexcept; + constexpr strong_ordering operator<=>(const month_day_last& x, + const month_day_last& y) noexcept; template basic_ostream& @@ -541,7 +484,6 @@ class month_weekday; constexpr bool operator==(const month_weekday& x, const month_weekday& y) noexcept; - constexpr bool operator!=(const month_weekday& x, const month_weekday& y) noexcept; template basic_ostream& @@ -551,7 +493,6 @@ class month_weekday_last; constexpr bool operator==(const month_weekday_last& x, const month_weekday_last& y) noexcept; - constexpr bool operator!=(const month_weekday_last& x, const month_weekday_last& y) noexcept; template basic_ostream& @@ -561,11 +502,7 @@ class year_month; constexpr bool operator==(const year_month& x, const year_month& y) noexcept; - constexpr bool operator!=(const year_month& x, const year_month& y) noexcept; - constexpr bool operator< (const year_month& x, const year_month& y) noexcept; - constexpr bool operator> (const year_month& x, const year_month& y) noexcept; - constexpr bool operator<=(const year_month& x, const year_month& y) noexcept; - constexpr bool operator>=(const year_month& x, const year_month& y) noexcept; + constexpr strong_ordering operator<=>(const year_month& x, const year_month& y) noexcept; constexpr year_month operator+(const year_month& ym, const months& dm) noexcept; constexpr year_month operator+(const months& dm, const year_month& ym) noexcept; @@ -579,10 +516,6 @@ basic_ostream& operator<<(basic_ostream& os, const year_month& ym); - template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const year_month& ym); - template> basic_istream& from_stream(basic_istream& is, const charT* fmt, @@ -593,11 +526,8 @@ class year_month_day; constexpr bool operator==(const year_month_day& x, const year_month_day& y) noexcept; - constexpr bool operator!=(const year_month_day& x, const year_month_day& y) noexcept; - constexpr bool operator< (const year_month_day& x, const year_month_day& y) noexcept; - constexpr bool operator> (const year_month_day& x, const year_month_day& y) noexcept; - constexpr bool operator<=(const year_month_day& x, const year_month_day& y) noexcept; - constexpr bool operator>=(const year_month_day& x, const year_month_day& y) noexcept; + constexpr strong_ordering operator<=>(const year_month_day& x, + const year_month_day& y) noexcept; constexpr year_month_day operator+(const year_month_day& ymd, const months& dm) noexcept; constexpr year_month_day operator+(const months& dm, const year_month_day& ymd) noexcept; @@ -610,11 +540,6 @@ basic_ostream& operator<<(basic_ostream& os, const year_month_day& ymd); - template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, - const year_month_day& ymd); - template> basic_istream& from_stream(basic_istream& is, const charT* fmt, @@ -627,16 +552,8 @@ constexpr bool operator==(const year_month_day_last& x, const year_month_day_last& y) noexcept; - constexpr bool operator!=(const year_month_day_last& x, - const year_month_day_last& y) noexcept; - constexpr bool operator< (const year_month_day_last& x, - const year_month_day_last& y) noexcept; - constexpr bool operator> (const year_month_day_last& x, - const year_month_day_last& y) noexcept; - constexpr bool operator<=(const year_month_day_last& x, - const year_month_day_last& y) noexcept; - constexpr bool operator>=(const year_month_day_last& x, - const year_month_day_last& y) noexcept; + constexpr strong_ordering operator<=>(const year_month_day_last& x, + const year_month_day_last& y) noexcept; constexpr year_month_day_last operator+(const year_month_day_last& ymdl, const months& dm) noexcept; @@ -660,8 +577,6 @@ constexpr bool operator==(const year_month_weekday& x, const year_month_weekday& y) noexcept; - constexpr bool operator!=(const year_month_weekday& x, - const year_month_weekday& y) noexcept; constexpr year_month_weekday operator+(const year_month_weekday& ymwd, const months& dm) noexcept; @@ -685,8 +600,6 @@ constexpr bool operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) noexcept; - constexpr bool operator!=(const year_month_weekday_last& x, - const year_month_weekday_last& y) noexcept; constexpr year_month_weekday_last operator+(const year_month_weekday_last& ymwdl, const months& dm) noexcept; @@ -787,29 +700,18 @@ constexpr year_month_weekday_last operator/(const month_weekday_last& mwdl, int y) noexcept; - // \ref{time.tod}, class template \tcode{time_of_day} - template class time_of_day; - template<> class time_of_day; - template<> class time_of_day; - template<> class time_of_day; - template class time_of_day>; - - template - basic_ostream& - operator<<(basic_ostream& os, const time_of_day& t); - - template - basic_ostream& - operator<<(basic_ostream& os, const time_of_day& t); + // \ref{time.hms}, class template \tcode{hh_mm_ss} + template class hh_mm_ss; - template + template basic_ostream& - operator<<(basic_ostream& os, const time_of_day& t); + operator<<(basic_ostream& os, const hh_mm_ss& hms); - template - basic_ostream& - operator<<(basic_ostream& os, - const time_of_day>& t); + // \ref{time.12}, 12/24 hour functions + constexpr bool is_am(const hours& h) noexcept; + constexpr bool is_pm(const hours& h) noexcept; + constexpr hours make12(const hours& h) noexcept; + constexpr hours make24(const hours& h, bool is_pm) noexcept; // \ref{time.zone.db}, time zone database struct tzdb; @@ -845,12 +747,7 @@ class time_zone; bool operator==(const time_zone& x, const time_zone& y) noexcept; - bool operator!=(const time_zone& x, const time_zone& y) noexcept; - - bool operator<(const time_zone& x, const time_zone& y) noexcept; - bool operator>(const time_zone& x, const time_zone& y) noexcept; - bool operator<=(const time_zone& x, const time_zone& y) noexcept; - bool operator>=(const time_zone& x, const time_zone& y) noexcept; + strong_ordering operator<=>(const time_zone& x, const time_zone& y) noexcept; // \ref{time.zone.zonedtraits}, class template \tcode{zoned_traits} template struct zoned_traits; @@ -864,38 +761,19 @@ bool operator==(const zoned_time& x, const zoned_time& y); - template - bool operator!=(const zoned_time& x, - const zoned_time& y); - template basic_ostream& operator<<(basic_ostream& os, const zoned_time& t); - template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, - const zoned_time& tp); - // \ref{time.zone.leap}, leap second support class leap; bool operator==(const leap& x, const leap& y); - bool operator!=(const leap& x, const leap& y); - bool operator< (const leap& x, const leap& y); - bool operator> (const leap& x, const leap& y); - bool operator<=(const leap& x, const leap& y); - bool operator>=(const leap& x, const leap& y); + strong_ordering operator<=>(const leap& x, const leap& y); template bool operator==(const leap& x, const sys_time& y); - template - bool operator==(const sys_time& x, const leap& y); - template - bool operator!=(const leap& x, const sys_time& y); - template - bool operator!=(const sys_time& x, const leap& y); template bool operator< (const leap& x, const sys_time& y); template @@ -912,32 +790,62 @@ bool operator>=(const leap& x, const sys_time& y); template bool operator>=(const sys_time& x, const leap& y); + template Duration> + auto operator<=>(const leap& x, const sys_time& y); // \ref{time.zone.link}, class \tcode{link} class link; bool operator==(const link& x, const link& y); - bool operator!=(const link& x, const link& y); - bool operator< (const link& x, const link& y); - bool operator> (const link& x, const link& y); - bool operator<=(const link& x, const link& y); - bool operator>=(const link& x, const link& y); + strong_ordering operator<=>(const link& x, const link& y); // \ref{time.format}, formatting - template - basic_string - format(const charT* fmt, const Streamable& s); - template - basic_string - format(const locale& loc, const charT* fmt, const Streamable& s); - template - basic_string - format(const basic_string& fmt, const Streamable& s); - template - basic_string - format(const locale& loc, const basic_string& fmt, - const Streamable& s); + template struct @\placeholder{local-time-format-t}@; // \expos + template + @\placeholder{local-time-format-t}@ + local_time_format(local_time time, const string* abbrev = nullptr, + const seconds* offset_sec = nullptr); + } + template + struct formatter, charT>; + template + struct formatter, charT>; + template + struct formatter, charT>; + template + struct formatter, charT>; + template + struct formatter, charT>; + template + struct formatter, charT>; + template + struct formatter, charT>; + template + struct formatter, charT>; + template struct formatter; + template struct formatter; + template struct formatter; + template struct formatter; + template struct formatter; + template struct formatter; + template struct formatter; + template struct formatter; + template struct formatter; + template struct formatter; + template struct formatter; + template struct formatter; + template struct formatter; + template struct formatter; + template struct formatter; + template + struct formatter>, charT>; + template struct formatter; + template struct formatter; + template + struct formatter, charT>; + + namespace chrono { // \ref{time.parse}, parsing template @\unspec@ @@ -1742,18 +1650,6 @@ \returns \tcode{CT(lhs).count() == CT(rhs).count()}. \end{itemdescr} -\indexlibrarymember{operator"!=}{duration}% -\begin{itemdecl} -template - constexpr bool operator!=(const duration& lhs, - const duration& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{!(lhs == rhs)}. -\end{itemdescr} - \indexlibrarymember{operator<}{duration}% \begin{itemdecl} template @@ -1802,6 +1698,19 @@ \returns \tcode{!(lhs < rhs)}. \end{itemdescr} +\indexlibrarymember{operator<=>}{duration}% +\begin{itemdecl} +template + requires three_way_comparable + constexpr auto operator<=>(const duration& lhs, + const duration& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns \tcode{CT(lhs).count() <=> CT(rhs).count()}. +\end{itemdescr} + \rSec2[time.duration.cast]{\tcode{duration_cast}} \indexlibrary{\idxcode{duration}!\idxcode{duration_cast}}% @@ -2083,6 +1992,7 @@ \item Otherwise, if \tcode{Period::type} is \tcode{exa}, the suffix is \tcode{"Es"}. \item Otherwise, if \tcode{Period::type} is \tcode{ratio<60>}, the suffix is \tcode{"min"}. \item Otherwise, if \tcode{Period::type} is \tcode{ratio<3600>}, the suffix is \tcode{"h"}. +\item Otherwise, if \tcode{Period::type} is \tcode{ratio<86400>}, the suffix is \tcode{"d"}. \item Otherwise, if \tcode{Period::type::den == 1}, the suffix is \tcode{"[\placeholder{num}]s"}. \item Otherwise, the suffix is \tcode{"[\placeholder{num}/\placeholder{den}]s"}. \end{itemize} @@ -2100,25 +2010,6 @@ \returns \tcode{os}. \end{itemdescr} -\indexlibrarymember{to_stream}{duration}% -\begin{itemdecl} -template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, - const duration& d); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Streams \tcode{d} into \tcode{os} using -the format specified by the NTCTS \tcode{fmt}. -\tcode{fmt} encoding follows the rules specified in \ref{time.format}. - -\pnum -\returns \tcode{os}. -\end{itemdescr} - \indexlibrarymember{from_stream}{duration}% \begin{itemdecl} template> @@ -2416,18 +2307,6 @@ \returns \tcode{lhs.time_since_epoch() == rhs.time_since_epoch()}. \end{itemdescr} -\indexlibrarymember{operator"!=}{time_point}% -\begin{itemdecl} -template - constexpr bool operator!=(const time_point& lhs, - const time_point& rhs); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{!(lhs == rhs)}. -\end{itemdescr} - \indexlibrarymember{operator<}{time_point}% \begin{itemdecl} template @@ -2476,6 +2355,19 @@ \returns \tcode{!(lhs < rhs)}. \end{itemdescr} +\indexlibrarymember{operator>=}{time_point}% +\begin{itemdecl} +template Duration2> + constexpr auto operator<=>(const time_point& lhs, + const time_point& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns \tcode{lhs.time_since_epoch() <=> rhs.time_since_epoch()}. +\end{itemdescr} + \rSec2[time.point.cast]{\tcode{time_point_cast}} \indexlibrary{\idxcode{time_point}!\idxcode{time_point_cast}}% @@ -2651,14 +2543,13 @@ \pnum \effects +Equivalent to: \begin{codeblock} auto const dp = floor(tp); -os << year_month_day{dp} << ' ' << time_of_day{tp-dp}; +return os << format(os.getloc(), @\placeholder{STATICALLY-WIDEN}@("{} {}"), + year_month_day{dp}, hh_mm_ss{tp-dp}); \end{codeblock} -\pnum -\returns \tcode{os}. - \pnum \begin{example} \begin{codeblock} @@ -2684,28 +2575,6 @@ \returns \tcode{os}. \end{itemdescr} -\indexlibrarymember{to_stream}{sys_time}% -\begin{itemdecl} -template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const sys_time& tp); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Streams \tcode{tp} into \tcode{os} using -the format specified by the NTCTS \tcode{fmt}. -\tcode{fmt} encoding follows the rules specified in \ref{time.format}. -If \tcode{\%Z} is used, it will be replaced with -\tcode{"UTC"} widened to \tcode{charT}. -If \tcode{\%z} is used (or a modified variant of \tcode{\%z}), -an offset of \tcode{0min} will be formatted. - -\pnum -\returns \tcode{os}. -\end{itemdescr} - \indexlibrarymember{from_stream}{sys_time}% \begin{itemdecl} template> @@ -2733,7 +2602,7 @@ prior to assigning that difference to \tcode{tp}. \pnum -\returns is. +\returns \tcode{is}. \end{itemdescr} \rSec2[time.clock.utc]{Class \tcode{utc_clock}} @@ -2794,7 +2663,7 @@ \indexlibrarymember{to_sys}{utc_clock}% \begin{itemdecl} -template +template static sys_time> to_sys(const utc_time& u); \end{itemdecl} @@ -2812,7 +2681,7 @@ \indexlibrarymember{from_sys}{utc_clock}% \begin{itemdecl} -template +template static utc_time> from_sys(const sys_time& t); \end{itemdecl} @@ -2857,36 +2726,10 @@ \begin{itemdescr} \pnum \effects -Calls \tcode{to_stream(os, fmt, t)}, -where \tcode{fmt} is a string containing \tcode{"\%F \%T"} -widened to \tcode{charT}. - -\pnum -\returns \tcode{os}. -\end{itemdescr} - -\indexlibrarymember{to_stream}{utc_time}% -\begin{itemdecl} -template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const utc_time& tp); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Streams \tcode{tp} into \tcode{os} using -the format specified by the NTCTS \tcode{fmt}. -\tcode{fmt} encoding follows the rules specified in \ref{time.format}. -If \tcode{\%Z} is used, it will be replaced with \tcode{"UTC"} widened to \tcode{charT}. -If \tcode{\%z} is used (or a modified variant of \tcode{\%z}), -an offset of \tcode{0min} will be formatted. -If \tcode{tp} represents a time during a leap second insertion, -and if a seconds field is formatted, -the integral portion of that format shall be \tcode{"60"} widened to \tcode{charT}. - -\pnum -\returns \tcode{os}. +Equivalent to: +\begin{codeblock} +return os << format(@\placeholder{STATICALLY-WIDEN}@("{:%F %T}"), t); +\end{codeblock} \pnum \begin{example} @@ -2943,6 +2786,37 @@ \returns \tcode{is}. \end{itemdescr} +\indexlibrary{\idxcode{leap_second_info}}% +\begin{itemdecl} +struct leap_second_info { + bool is_leap_second; + seconds elapsed; +}; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The type \tcode{leap_second_info} +has data members and special members specified above. +It has no base classes or members other than those specified. +\end{itemdescr} + +\indexlibrary{\idxcode{get_leap_second_info}}% +\begin{itemdecl} +template + leap_second_info get_leap_second_info(const utc_time& ut); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A \tcode{leap_second_info} where \tcode{is_leap_second} is \tcode{true} +if \tcode{ut} is during a leap second insertion, and otherwise \tcode{false}. +\tcode{elapsed} is the number of leap seconds between 1970-01-01 and \tcode{ut}. +If \tcode{is_leap_second} is \tcode{true}, +the leap second referred to by \tcode{ut} is included in the count. +\end{itemdescr} + \rSec2[time.clock.tai]{Class \tcode{tai_clock}} \rSec3[time.clock.tai.overview]{Overview} @@ -3053,46 +2927,18 @@ \begin{itemdescr} \pnum \effects -Calls \tcode{to_stream(os, fmt, t)}, -where \tcode{fmt} is a string containing -\tcode{"\%F \%T"} widened to \tcode{charT}. - -\pnum -\returns \tcode{os}. -\end{itemdescr} - -\indexlibrarymember{to_stream}{tai_time}% -\begin{itemdecl} -template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const tai_time& tp); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Streams \tcode{tp} into \tcode{os} using -the format specified by the NTCTS \tcode{fmt}. -\tcode{fmt} encoding follows the rules specified in \ref{time.format}. -If \tcode{\%Z} is used, it will be replaced with \tcode{"TAI"}. -If \tcode{\%z} is used (or a modified variant of \tcode{\%z}), -an offset of \tcode{0min} will be formatted. -The date and time formatted shall be equivalent to -that formatted by a \tcode{sys_time} initialized with: +Equivalent to: \begin{codeblock} -sys_time{tp.time_since_epoch()} - - (sys_days{1970y/January/1} - sys_days{1958y/January/1}) +return os << format(@\placeholder{STATICALLY-WIDEN}@("{:%F %T}"), t); \end{codeblock} -\pnum -\returns os. - \pnum \begin{example} +% FIXME: This example is not an example of this function. \begin{codeblock} auto st = sys_days{2000y/January/1}; auto tt = clock_cast(st); -cout << format("%F %T %Z == ", st) << format("%F %T %Z\n", tt); +cout << format("{0:%F %T %Z} == {1:%F %T %Z}\n", st, tt); \end{codeblock} Produces this output: @@ -3241,45 +3087,19 @@ \begin{itemdescr} \pnum -\effects Calls \tcode{to_stream(os, fmt, t)}, -where \tcode{fmt} is a string containing -\tcode{"\%F \%T"} widened to \tcode{charT}. - -\pnum -\returns \tcode{os}. -\end{itemdescr} - -\indexlibrarymember{to_stream}{gps_time}% -\begin{itemdecl} -template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const gps_time& tp); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects Streams \tcode{tp} into \tcode{os} using -the format specified by the NTCTS \tcode{fmt}. -\tcode{fmt} encoding follows the rules specified in \ref{time.format}. -If \tcode{\%Z} is used, it will be replaced with \tcode{"GPS"}. -If \tcode{\%z} is used (or a modified variant of \tcode{\%z}), -an offset of \tcode{0min} will be formatted. -The date and time formatted -shall be equivalent to that formatted by a \tcode{sys_time} initialized with: +\effects +Equivalent to: \begin{codeblock} -sys_time{tp.time_since_epoch()} + - (sys_days{1980y/January/Sunday[1]} - sys_days{1970y/January/1}) +return os << format(@\placeholder{STATICALLY-WIDEN}@("{:%F %T}"), t); \end{codeblock} \pnum -\returns os. - -\pnum +% FIXME: This example is not an example of this function. \begin{example} \begin{codeblock} auto st = sys_days{2000y/January/1}; auto gt = clock_cast(st); -cout << format("%F %T %Z == ", st) << format("%F %T %Z\n", gt); +cout << format("{0:%F %T %Z} == {1:%F %T %Z}\n", st, gt); \end{codeblock} Produces this output: @@ -3387,40 +3207,13 @@ operator<<(basic_ostream& os, const file_time& t); \end{itemdecl} -\begin{itemdescr} -\pnum -\effects Calls \tcode{to_stream(os, fmt, t)}, -where \tcode{fmt} is a string containing -\tcode{"\%F \%T"} widened to \tcode{charT}. - -\pnum -\returns \tcode{os}. -\end{itemdescr} - -\indexlibrarymember{to_stream}{file_time}% -\begin{itemdecl} -template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const file_time& tp); -\end{itemdecl} - \begin{itemdescr} \pnum \effects -Streams \tcode{tp} into \tcode{os} using -the format specified by the NTCTS \tcode{fmt}. -\tcode{fmt} encoding follows the rules specified in \ref{time.format}. -If \tcode{\%Z} is used, it will be replaced with \tcode{"UTC"} widened to \tcode{charT}. -If \tcode{\%z} is used (or a modified variant of \tcode{\%z}), -an offset of \tcode{0min} will be formatted. -The date and time formatted shall be equivalent to -that formatted by a \tcode{sys_time} initialized with -\tcode{clock_cast(tp)}, -or by a \tcode{utc_time} initialized with -\tcode{clock_cast(tp)}. - -\pnum -\returns \tcode{os}. +Equivalent to: +\begin{codeblock} +return os << format(@\placeholder{STATICALLY-WIDEN}@("{:%F %T}"), t); +\end{codeblock} \end{itemdescr} \indexlibrarymember{from_stream}{file_time}% @@ -3532,35 +3325,6 @@ \returns \tcode{os}. \end{itemdescr} -\indexlibrarymember{to_stream}{local_time}% -\begin{itemdecl} -template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const local_time& tp, - const string* abbrev = nullptr, const seconds* offset_sec = nullptr); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Streams \tcode{tp} into \tcode{os} using -the format specified by the NTCTS \tcode{fmt}. -\tcode{fmt} encoding follows the rules specified in \ref{time.format}. -If \tcode{\%Z} is used, -it will be replaced with \tcode{*abbrev} if \tcode{abbrev} is not equal to \tcode{nullptr}. -If \tcode{abbrev} is equal to \tcode{nullptr} (and \tcode{\%Z} is used), -\tcode{os.setstate(ios_base::failbit)} shall be called. -If \tcode{\%z} is used (or a modified variant of \tcode{\%z}), -it will be formatted with the value of \tcode{*offset_sec} -if \tcode{offset_sec} is not equal to \tcode{nullptr}. -If \tcode{\%z} (or a modified variant of \tcode{\%z}) is used, -and \tcode{offset_sec} is equal to \tcode{nullptr}, then -\tcode{os.setstate(ios_base::failbit)} shall be called. - -\pnum -\returns \tcode{os}. -\end{itemdescr} - \indexlibrarymember{from_stream}{local_time}% \begin{itemdecl} template> @@ -3632,7 +3396,7 @@ \rSec3[time.clock.cast.id]{Identity conversions} \begin{codeblock} -template +template struct clock_time_conversion { template time_point @@ -4116,14 +3880,14 @@ \returns \tcode{unsigned\{x\} == unsigned\{y\}}. \end{itemdescr} -\indexlibrarymember{operator<}{day}% +\indexlibrarymember{operator<=>}{day}% \begin{itemdecl} -constexpr bool operator<(const day& x, const day& y) noexcept; +constexpr strong_ordering operator<=>(const day& x, const day& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{unsigned\{x\} < unsigned\{y\}}. +\returns \tcode{unsigned\{x\} <=> unsigned\{y\}}. \end{itemdescr} \indexlibrarymember{operator+}{day}% @@ -4176,33 +3940,15 @@ \begin{itemdescr} \pnum \effects -Inserts \tcode{format(fmt, d)} -where \tcode{fmt} is \tcode{"\%d"} widened to \tcode{charT}. -If \tcode{!d.ok()}, appends with \tcode{" is not a valid day"}. - -\pnum -\returns \tcode{os}. +Equivalent to: +\begin{codeblock} +return os << (d.ok() ? + format(@\placeholder{STATICALLY-WIDEN}@("{:%d}"), d) : + format(@\placeholder{STATICALLY-WIDEN}@("{:%d} is not a valid day"), d)); +\end{codeblock} \end{itemdescr} -\indexlibrarymember{to_stream}{day}% -\begin{itemdecl} -template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const day& d); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Streams \tcode{d} into \tcode{os} using -the format specified by the NTCTS \tcode{fmt}. -\tcode{fmt} encoding follows the rules specified in \ref{time.format}. - -\pnum -\returns \tcode{os}. -\end{itemdescr} - -\indexlibrarymember{from_stream}{day}% +\indexlibrarymember{from_stream}{day}% \begin{itemdecl} template> basic_istream& @@ -4406,14 +4152,14 @@ \returns \tcode{unsigned\{x\} == unsigned\{y\}}. \end{itemdescr} -\indexlibrarymember{operator<}{month}% +\indexlibrarymember{operator<=>}{month}% \begin{itemdecl} -constexpr bool operator<(const month& x, const month& y) noexcept; +constexpr strong_ordering operator<=>(const month& x, const month& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{unsigned\{x\} < unsigned\{y\}}. +\returns \tcode{unsigned\{x\} <=> unsigned\{y\}}. \end{itemdescr} \indexlibrarymember{operator+}{month}% @@ -4488,31 +4234,13 @@ \begin{itemdescr} \pnum \effects -If \tcode{m.ok() == true} -inserts \tcode{format(os.getloc(), fmt, m)} -where fmt is \tcode{"\%b"} widened to \tcode{charT}. -Otherwise inserts \tcode{unsigned\{m\} << " is not a valid month"}. - -\pnum -\returns \tcode{os}. -\end{itemdescr} - -\indexlibrarymember{to_stream}{month}% -\begin{itemdecl} -template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const month& m); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Streams \tcode{m} into \tcode{os} using -the format specified by the NTCTS \tcode{fmt}. -\tcode{fmt} encoding follows the rules specified in \ref{time.format}. - -\pnum -\returns \tcode{os}. +Equivalent to: +\begin{codeblock} +return os << (m.ok() ? + format(os.getloc(), @\placeholder{STATICALLY-WIDEN}@("{:%b}"), m) : + format(os.getloc(), @\placeholder{STATICALLY-WIDEN}@("{} is not a valid month"), + static_cast(m))); +\end{codeblock} \end{itemdescr} \indexlibrarymember{from_stream}{month}% @@ -4731,7 +4459,7 @@ \begin{itemdescr} \pnum -\returns \tcode{min() <= y_ \&\& y_ <= max()}. +\returns \tcode{min().y_ <= y_ \&\& y_ <= max().y_}. \end{itemdescr} \indexlibrarymember{min}{year}% @@ -4766,14 +4494,14 @@ \returns \tcode{int\{x\} == int\{y\}}. \end{itemdescr} -\indexlibrarymember{operator<}{year}% +\indexlibrarymember{operator<=>}{year}% \begin{itemdecl} -constexpr bool operator<(const year& x, const year& y) noexcept; +constexpr strong_ordering operator<=>(const year& x, const year& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{int\{x\} < int\{y\}}. +\returns \tcode{int\{x\} <=> int\{y\}}. \end{itemdescr} \indexlibrarymember{operator+}{year}% @@ -4826,30 +4554,12 @@ \begin{itemdescr} \pnum \effects -Inserts \tcode{format(fmt, y)} where \tcode{fmt} is -\tcode{"\%Y"} widened to \tcode{charT}. -If \tcode{!y.ok()}, appends with \tcode{" is not a valid year"}. - -\pnum -\returns \tcode{os}. -\end{itemdescr} - -\indexlibrarymember{to_stream}{year}% -\begin{itemdecl} -template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const year& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Streams \tcode{y} into \tcode{os} using -the format specified by the NTCTS \tcode{fmt}. -\tcode{fmt} encoding follows the rules specified in \ref{time.format}. - -\pnum -\returns \tcode{os}. +Equivalent to: +\begin{codeblock} +return os << (y.ok() ? + format(@\placeholder{STATICALLY-WIDEN}@("{:%Y}"), y) : + format(@\placeholder{STATICALLY-WIDEN}@("{:%Y} is not a valid year"), y)); +\end{codeblock} \end{itemdescr} \indexlibrarymember{from_stream}{year}% @@ -4913,7 +4623,8 @@ constexpr weekday& operator+=(const days& d) noexcept; constexpr weekday& operator-=(const days& d) noexcept; - constexpr explicit operator unsigned() const noexcept; + constexpr unsigned c_encoding() const noexcept; + constexpr unsigned iso_encoding() const noexcept; constexpr bool ok() const noexcept; constexpr weekday_indexed operator[](unsigned index) const noexcept; @@ -4952,7 +4663,7 @@ \pnum \effects Constructs an object of type \tcode{weekday} by -initializing \tcode{wd_} with \tcode{wd}. +initializing \tcode{wd_} with \tcode{wd == 7 ?\ 0 :\ wd}. The value held is unspecified if \tcode{wd} is not in the range \crange{0}{255}. \end{itemdescr} @@ -5072,9 +4783,9 @@ \returns \tcode{*this}. \end{itemdescr} -\indexlibrarymember{operator unsigned}{weekday}% +\indexlibrarymember{c_encoding}{weekday}% \begin{itemdecl} -constexpr explicit operator unsigned() const noexcept; +constexpr unsigned c_encoding() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -5082,6 +4793,16 @@ \returns \tcode{wd_}. \end{itemdescr} +\indexlibrarymember{iso_encoding}{weekday}% +\begin{itemdecl} +constexpr unsigned iso_encoding() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns \tcode{wd_ == 0u ?\ 7u :\ wd_}. +\end{itemdescr} + \indexlibrarymember{ok}{weekday}% \begin{itemdecl} constexpr bool ok() const noexcept; @@ -5121,7 +4842,7 @@ \begin{itemdescr} \pnum -\returns \tcode{unsigned\{x\} == unsigned\{y\}}. +\returns \tcode{x.wd_ == y.wd_}. \end{itemdescr} \indexlibrarymember{operator+}{weekday}% @@ -5133,7 +4854,7 @@ \pnum \returns \begin{codeblock} -weekday{modulo(static_cast(unsigned{x}) + y.count(), 7)} +weekday{modulo(static_cast(x.wd_) + y.count(), 7)} \end{codeblock} where \tcode{modulo(n, 7)} computes the remainder of \tcode{n} divided by 7 using Euclidean division. \begin{note} @@ -5196,31 +4917,13 @@ \begin{itemdescr} \pnum \effects -If \tcode{wd.ok() == true} -inserts \tcode{format(os.getloc(), fmt, wd)} -where \tcode{fmt} is \tcode{"\%a"} widened to \tcode{charT}. -Otherwise inserts \tcode{unsigned\{wd\} << " is not a valid weekday"}. - -\pnum -\returns \tcode{os}. -\end{itemdescr} - -\indexlibrarymember{to_stream}{weekday}% -\begin{itemdecl} -template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const weekday& wd); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Streams \tcode{wd} into \tcode{os} using -the format specified by the NTCTS \tcode{fmt}. -\tcode{fmt} encoding follows the rules specified in \ref{time.format}. - -\pnum -\returns \tcode{os}. +Equivalent to: +\begin{codeblock} +return os << (wd.ok() ? + format(os.getloc(), @\placeholder{STATICALLY-WIDEN}@("{:%a}"), wd) : + format(os.getloc(), @\placeholder{STATICALLY-WIDEN}@("{} is not a valid weekday"), + static_cast(wd.wd_))); +\end{codeblock} \end{itemdescr} \indexlibrarymember{from_stream}{weekday}% @@ -5363,14 +5066,14 @@ \begin{itemdescr} \pnum \effects -\tcode{os << wdi.weekday() << '[' << wdi.index()}. -If \tcode{wdi.index()} is in the range \crange{1}{5}, -appends with \tcode{']'}, -otherwise -appends with \tcode{" is not a valid index]"}. - -\pnum -\returns \tcode{os}. +Equivalent to: +\begin{codeblock} +auto i = wdi.index(); +return os << (i >= 1 && i <= 5 ? + format(os.getloc(), @\placeholder{STATICALLY-WIDEN}@("{}[{}]"), wdi.weekday(), i) : + format(os.getloc(), @\placeholder{STATICALLY-WIDEN}@("{}[{} is not a valid index"]"), + wdi.weekday(), i)); +\end{codeblock} \end{itemdescr} \rSec2[time.cal.wdlast]{Class \tcode{weekday_last}} @@ -5465,7 +5168,11 @@ \begin{itemdescr} \pnum -\returns \tcode{os << wdl.weekday() << "[last]"}. +\effects +Equivalent to: +\begin{codeblock} +return os << format(os.getloc(), @\placeholder{STATICALLY-WIDEN}@("{}[last]"), wdl.weekday()); +\end{codeblock} \end{itemdescr} \rSec2[time.cal.md]{Class \tcode{month_day}} @@ -5562,17 +5269,19 @@ \returns \tcode{x.month() == y.month() \&\& x.day() == y.day()}. \end{itemdescr} -\indexlibrarymember{operator<}{month_day}% +\indexlibrarymember{operator<=>}{month_day}% \begin{itemdecl} -constexpr bool operator<(const month_day& x, const month_day& y) noexcept; +constexpr strong_ordering operator<=>(const month_day& x, const month_day& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns -If \tcode{x.month() < y.month()} returns \tcode{true}. -Otherwise, if \tcode{x.month() > y.month()} returns \tcode{false}. -Otherwise, returns \tcode{x.day() < y.day()}. +\effects +Equivalent to: +\begin{codeblock} +if (auto c = x.month() <=> y.month(); c != 0) return c; +return x.day() <=> y.day(); +\end{codeblock} \end{itemdescr} \indexlibrarymember{operator<<}{month_day}% @@ -5582,27 +5291,14 @@ operator<<(basic_ostream& os, const month_day& md); \end{itemdecl} -\begin{itemdescr} -\pnum -\returns \tcode{os << md.month() << '/' << md.day()}. -\end{itemdescr} - -\indexlibrarymember{to_stream}{month_day}% -\begin{itemdecl} -template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const month_day& md); -\end{itemdecl} - \begin{itemdescr} \pnum \effects -Streams \tcode{md} into \tcode{os} using -the format specified by the NTCTS \tcode{fmt}. -\tcode{fmt} encoding follows the rules specified in \ref{time.format}. - -\pnum -\returns \tcode{os}. +Equivalent to: +\begin{codeblock} +return os << format(os.getloc(), @\placeholder{STATICALLY-WIDEN}@("{}/{}"), + md.month(), md.day()); +\end{codeblock} \end{itemdescr} \indexlibrarymember{from_stream}{month_day}% @@ -5711,14 +5407,14 @@ \returns \tcode{x.month() == y.month()}. \end{itemdescr} -\indexlibrarymember{operator<}{month_day_last}% +\indexlibrarymember{operator<=>}{month_day_last}% \begin{itemdecl} -constexpr bool operator<(const month_day_last& x, const month_day_last& y) noexcept; +constexpr strong_ordering operator<=>(const month_day_last& x, const month_day_last& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{x.month() < y.month()}. +\returns \tcode{x.month() <=> y.month()}. \end{itemdescr} \indexlibrarymember{operator<<}{month_day_last}% @@ -5730,7 +5426,11 @@ \begin{itemdescr} \pnum -\returns \tcode{os << mdl.month() << "/last"}. +\effects +Equivalent to: +\begin{codeblock} +return os << format(os.getloc(), @\placeholder{STATICALLY-WIDEN}@("{}/last"), mdl.month()); +\end{codeblock} \end{itemdescr} \rSec2[time.cal.mwd]{Class \tcode{month_weekday}} @@ -5836,7 +5536,12 @@ \begin{itemdescr} \pnum -\returns \tcode{os << mwd.month() << '/' << mwd.weekday_indexed()}. +\effects +Equivalent to: +\begin{codeblock} +return os << format(os.getloc(), @\placeholder{STATICALLY-WIDEN}@("{}/{}"), + mwd.month(), mwd.weekday_indexed()); +\end{codeblock} \end{itemdescr} \rSec2[time.cal.mwdlast]{Class \tcode{month_weekday_last}} @@ -5944,7 +5649,12 @@ \begin{itemdescr} \pnum -\returns \tcode{os << mwdl.month() << '/' << mwdl.weekday_last()}. +\effects +Equivalent to: +\begin{codeblock} +return os << format(os.getloc(), @\placeholder{STATICALLY-WIDEN}@("{}/{}"), + mwdl.month(), mwdl.weekday_last()); +\end{codeblock} \end{itemdescr} \rSec2[time.cal.ym]{Class \tcode{year_month}} @@ -6093,17 +5803,19 @@ \returns \tcode{x.year() == y.year() \&\& x.month() == y.month()}. \end{itemdescr} -\indexlibrarymember{operator<}{year_month}% +\indexlibrarymember{operator<=>}{year_month}% \begin{itemdecl} -constexpr bool operator<(const year_month& x, const year_month& y) noexcept; +constexpr strong_ordering operator<=>(const year_month& x, const year_month& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns -If \tcode{x.year() < y.year()} returns \tcode{true}. -Otherwise, if \tcode{x.year() > y.year()} returns \tcode{false}. -Otherwise, returns \tcode{x.month() < y.month()}. +\effects +Equivalent to: +\begin{codeblock} +if (auto c = x.year() <=> y.year(); c != 0) return c; +return x.month() <=> y.month(); +\end{codeblock} \end{itemdescr} \indexlibrarymember{operator+}{year_month}% @@ -6191,27 +5903,14 @@ operator<<(basic_ostream& os, const year_month& ym); \end{itemdecl} -\begin{itemdescr} -\pnum -\returns \tcode{os << ym.year() << '/' << ym.month()}. -\end{itemdescr} - -\indexlibrarymember{to_stream}{year_month}% -\begin{itemdecl} -template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const year_month& ym); -\end{itemdecl} - \begin{itemdescr} \pnum \effects -Streams \tcode{ym} into \tcode{os} using -the format specified by the NTCTS \tcode{fmt}. -\tcode{fmt} encoding follows the rules specified in \ref{time.format}. - -\pnum -\returns \tcode{os}. +Equivalent to: +\begin{codeblock} +return os << format(os.getloc(), @\placeholder{STATICALLY-WIDEN}@("{}/{}"), + ym.year(), ym.month()); +\end{codeblock} \end{itemdescr} \indexlibrarymember{from_stream}{year_month}% @@ -6461,9 +6160,7 @@ holding a count of days from the \tcode{sys_days} epoch to \tcode{*this} (a negative value if \tcode{*this} represents a date prior to the \tcode{sys_days} epoch). Otherwise, if \tcode{y_.ok() \&\& m_.ok()} is \tcode{true}, -returns a \tcode{sys_days} -which is offset from \tcode{sys_days\{y_/m_/last\}} -by the number of days \tcode{d_} is offset from \tcode{sys_days\{y_/m_/last\}.day()}. +returns \tcode{sys_days\{y_/m_/1d\} + (d_ - 1d)}. Otherwise the value returned is unspecified. \pnum @@ -6518,19 +6215,20 @@ \returns \tcode{x.year() == y.year() \&\& x.month() == y.month() \&\& x.day() == y.day()}. \end{itemdescr} -\indexlibrarymember{operator<}{year_month_day}% +\indexlibrarymember{operator<=>}{year_month_day}% \begin{itemdecl} -constexpr bool operator<(const year_month_day& x, const year_month_day& y) noexcept; +constexpr strong_ordering operator<=>(const year_month_day& x, const year_month_day& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns -If \tcode{x.year() < y.year()}, returns \tcode{true}. -Otherwise, if \tcode{x.year() > y.year()}, returns \tcode{false}. -Otherwise, if \tcode{x.month() < y.month()}, returns \tcode{true}. -Otherwise, if \tcode{x.month() > y.month()}, returns \tcode{false}. -Otherwise, returns \tcode{x.day() < y.day()}. +\effects +Equivalent to: +\begin{codeblock} +if (auto c = x.year() <=> y.year(); c != 0) return c; +if (auto c = x.month() <=> y.month(); c != 0) return c; +return x.day() <=> y.day(); +\end{codeblock} \end{itemdescr} \indexlibrarymember{operator+}{year_month_day}% @@ -6618,30 +6316,12 @@ \begin{itemdescr} \pnum \effects -Inserts \tcode{format(fmt, ymd)} -where \tcode{fmt} is \tcode{"\%F"} widened to \tcode{charT}. -If \tcode{!ymd.ok()}, appends with \tcode{" is not a valid date"}. - -\pnum -\returns \tcode{os}. -\end{itemdescr} - -\indexlibrarymember{to_stream}{year_month_day}% -\begin{itemdecl} -template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, const year_month_day& ymd); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Streams \tcode{ymd} into \tcode{os} using -the format specified by the NTCTS \tcode{fmt}. -\tcode{fmt} encoding follows the rules specified in \ref{time.format}. - -\pnum -\returns \tcode{os}. +Equivalent to: +\begin{codeblock} +return os << (ymd.ok() ? + format(@\placeholder{STATICALLY-WIDEN}@("{:%F}"), ymd) : + format(@\placeholder{STATICALLY-WIDEN}@("{:%F} is not a valid date"), ymd)); +\end{codeblock} \end{itemdescr} \indexlibrarymember{from_stream}{year_month_day}% @@ -6876,17 +6556,20 @@ \returns \tcode{x.year() == y.year() \&\& x.month_day_last() == y.month_day_last()}. \end{itemdescr} -\indexlibrarymember{operator<}{year_month_day_last}% +\indexlibrarymember{operator<=>}{year_month_day_last}% \begin{itemdecl} -constexpr bool operator<(const year_month_day_last& x, const year_month_day_last& y) noexcept; +constexpr strong_ordering operator<=>(const year_month_day_last& x, + const year_month_day_last& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns -If \tcode{x.year() < y.year()}, returns \tcode{true}. -Otherwise, if \tcode{x.year() > y.year()}, returns \tcode{false}. -Otherwise, returns \tcode{x.month_day_last() < y.month_day_last()}. +\effects +Equivalent to: +\begin{codeblock} +if (auto c = x.year() <=> y.year(); c != 0) return c; +return x.month_day_last() <=> y.month_day_last(); +\end{codeblock} \end{itemdescr} \indexlibrarymember{operator+}{year_month_day_last}% @@ -6964,7 +6647,12 @@ \begin{itemdescr} \pnum -\returns \tcode{os << ymdl.year() << '/' << ymdl.month_day_last()}. +\effects +Equivalent to: +\begin{codeblock} +return os << format(os.getloc(), @\placeholder{STATICALLY-WIDEN}@("{}/{}"), + ymdl.year(), ymdl.month_day_last()); +\end{codeblock} \end{itemdescr} \rSec2[time.cal.ymwd]{Class \tcode{year_month_weekday}} @@ -7301,7 +6989,12 @@ \begin{itemdescr} \pnum -\returns \tcode{os << ymwdi.year() << '/' << ymwdi.month() << '/' << ymwdi.weekday_indexed()}. +\effects +Equivalent to: +\begin{codeblock} +return os << format(os.getloc(), @\placeholder{STATICALLY-WIDEN}@("{}/{}/{}"), + ymwd.year(), ymwd.month(), ymwd.weekday_indexed()); +\end{codeblock} \end{itemdescr} \rSec2[time.cal.ymwdlast]{Class \tcode{year_month_weekday_last}} @@ -7585,7 +7278,12 @@ \begin{itemdescr} \pnum -\returns \tcode{os << ymwdl.year() << '/' << ymwdl.month() << '/' << ymwdl.weekday_last()}. +\effects +Equivalent to: +\begin{codeblock} +return os << format(os.getloc(), @\placeholder{STATICALLY-WIDEN}@("{}/{}/{}"), + ymwdl.year(), ymwdl.month(), ymwdl.weekday_last()); +\end{codeblock} \end{itemdescr} \rSec2[time.cal.operators]{Conventional syntax operators} @@ -8039,713 +7737,340 @@ \indexlibrary{\idxcode{operator/}!calendar types|)} -\rSec1[time.tod]{Class template \tcode{time_of_day}} - -\rSec2[time.tod.overview]{Overview} -\indexlibrary{\idxcode{time_of_day}} - -\begin{codeblock} -namespace std::chrono { - template class time_of_day; - - template<> class time_of_day; - template<> class time_of_day; - template<> class time_of_day; - template class time_of_day>; -} -\end{codeblock} - -\pnum -The \tcode{time_of_day} class template -splits a \tcode{duration} representing the time elapsed since midnight -into a ``broken down'' time of day such as -$hours$:$minutes$:$seconds$. -The \tcode{Duration} template parameter dictates -the precision to which the time is broken down. -\begin{note} -This can vary from a coarse precision of hours -to a very fine precision of nanoseconds. -\end{note} -A \tcode{time_of_day} object also tracks -whether it should be output -as a 12-hour time format or a 24-hour time format. - -\pnum -The primary \tcode{time_of_day} template is not defined. -Four specializations are provided to handle four different -levels of precision. - -\pnum -Each specialization of \tcode{time_of_day} is a trivially copyable -and standard-layout class type. +\rSec1[time.hms]{Class template \tcode{hh_mm_ss}} -\rSec2[time.tod.hours]{Hours precision} -\indexlibrary{\idxcode{time_of_day}} +\rSec2[time.hms.overview]{Overview} +\indexlibrary{\idxcode{hms}} \begin{codeblock} namespace std::chrono { - template<> - class time_of_day { + template class hh_mm_ss { public: - using precision = chrono::hours; + static constexpr unsigned fractional_width = @\seebelow@; + using precision = @\seebelow@; - time_of_day() = default; - constexpr explicit time_of_day(chrono::hours since_midnight) noexcept; + constexpr hh_mm_ss() noexcept : hh_mm_ss{Duration::zero()} {} + constexpr explicit hh_mm_ss(Duration d); + constexpr bool is_negative() const noexcept; constexpr chrono::hours hours() const noexcept; + constexpr chrono::minutes minutes() const noexcept; + constexpr chrono::seconds seconds() const noexcept; + constexpr precision subseconds() const noexcept; - constexpr explicit operator precision() const noexcept; - constexpr precision to_duration() const noexcept; + constexpr explicit operator precision() const noexcept; + constexpr precision to_duration() const noexcept; - constexpr void make24() noexcept; - constexpr void make12() noexcept; + private: + bool is_neg; // \expos + chrono::hours h; // \expos + chrono::minutes m; // \expos + chrono::seconds s; // \expos + precision ss; // \expos }; } \end{codeblock} \pnum -\begin{note} -This specialization handles hours since midnight. -\end{note} +The \tcode{hh_mm_ss} class template +splits a \tcode{duration} +into a multi-field time structure +\placeholdernc{hours}:\placeholdernc{minutes}:\placeholder{seconds} and +possibly \placeholder{subseconds}, +where \placeholder{subseconds} will be a duration unit +based on a non-positive power of 10. +The \tcode{Duration} template parameter dictates the precision +to which the time is split. +A \tcode{hh_mm_ss} models negative durations +with a distinct \tcode{is_negative} getter +that returns \tcode{true} when the input duration is negative. +The individual duration fields always return non-negative durations +even when \tcode{is_negative()} indicates +the structure is representing a negative duration. + +\pnum +If \tcode{Duration} is not an instance of \tcode{duration}, +the program is ill-formed. + +\rSec2[time.hms.members]{Members} -\indexlibrary{\idxcode{time_of_day}!constructor}% \begin{itemdecl} -constexpr explicit time_of_day(chrono::hours since_midnight) noexcept; +static constexpr unsigned fractional_width = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Constructs an object of type \tcode{time_of_day} in 24-hour format -corresponding to \tcode{since_midnight} hours after 00:00:00. - -\pnum -\ensures -\tcode{hours()} returns the integral number of hours \tcode{since_midnight} is after 00:00:00. +\tcode{fractional_width} is the number of fractional decimal digits +represented by \tcode{precision}. +\tcode{fractional_width} has the value +of the smallest possible integer in the range \crange{0}{18} such that +\tcode{precision} will exactly represent all values of \tcode{Duration}. +If no such value of \tcode{fractional_width} exists, then +\tcode{fractional_width} is 6. +\begin{example} +See~\tref{time.hms.width} +for some durations, +the resulting \tcode{fractional_width}, and +the formatted fractional second output of \tcode{Duration\{1\}}. +\begin{LongTable} + {Examples for \tcode{fractional_width}} + {time.hms.width} + {llx{.3\hsize}} +\\ \topline +\lhdr{Duration} & +\chdr{\tcode{fractional_width}} & +\rhdr{Formatted fractional second output} \\ \capsep +\endfirsthead +\continuedcaption\\ +\hline +\lhdr{Duration} & +\chdr{\tcode{fractional_width}} & +\rhdr{Formatted fractional second output} \\ \capsep +\endhead +\tcode{hours}, \tcode{minutes}, and \tcode{seconds} & \tcode{0} & \\ \rowsep +\tcode{milliseconds} & \tcode{3} & \tcode{0.001} \\ \rowsep +\tcode{microseconds} & \tcode{6} & \tcode{0.000001} \\ \rowsep +\tcode{nanoseconds} & \tcode{9} & \tcode{0.000000001} \\ \rowsep +\tcode{duration>} & \tcode{1} & \tcode{0.5} \\ \rowsep +\tcode{duration>} & \tcode{6} & \tcode{0.333333} \\ \rowsep +\tcode{duration>} & \tcode{2} & \tcode{0.25} \\ \rowsep +\tcode{duration>} & \tcode{1} & \tcode{0.2} \\ \rowsep +\tcode{duration>} & \tcode{6} & \tcode{0.166666} \\ \rowsep +\tcode{duration>} & \tcode{6} & \tcode{0.142857} \\ \rowsep +\tcode{duration>} & \tcode{3} & \tcode{0.125} \\ \rowsep +\tcode{duration>} & \tcode{6} & \tcode{0.111111} \\ \rowsep +\tcode{duration>} & \tcode{1} & \tcode{0.1} \\ \rowsep +\tcode{duration>} & \tcode{4} & \tcode{0.2096} \\ +\end{LongTable} +\end{example} \end{itemdescr} -\indexlibrarymember{hours}{time_of_day}% \begin{itemdecl} -constexpr chrono::hours hours() const noexcept; +using precision = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum -\returns The stored hour of \tcode{*this}. +\tcode{precision} is +\begin{codeblock} +duration, ratio<1, @$10^\tcode{fractional_width}$@>> +\end{codeblock} \end{itemdescr} -\indexlibrarymember{operator precision}{time_of_day}% \begin{itemdecl} -constexpr explicit operator precision() const noexcept; +constexpr explicit hh_mm_ss(Duration d); \end{itemdecl} \begin{itemdescr} \pnum -\returns The number of hours since midnight. +\effects +Constructs an object of type \tcode{hh_mm_ss} +which represents the \tcode{Duration d} with precision \tcode{precision}. +\begin{itemize} +\item + Initializes \tcode{is_neg} with \tcode{d < Duration::zero()}. +\item + Initializes \tcode{h} with \tcode{duration_cast(abs(d))}. +\item + Initializes \tcode{m} + with \tcode{duration_cast(abs(d) - hours())}. +\item + Initializes \tcode{s} + with \tcode{duration_cast(abs(d) - hours() - minutes())}. +\item + If \tcode{treat_as_floating_point_v} is \tcode{true}, + initializes \tcode{ss} with \tcode{abs(d) - hours() - minutes() - seconds()}. + Otherwise, initializes \tcode{ss} + with \tcode{duration_cast(abs(d) - hours() - minutes() - seconds())}. +\end{itemize} +\begin{note} +When \tcode{precision::rep} is integral and +\tcode{precision::period} is \tcode{ratio<1>}, +\tcode{subseconds()} always returns a value equal to \tcode{0s}. +\end{note} + +\pnum +\ensures +If \tcode{treat_as_floating_point_v} is \tcode{true}, +\tcode{to_duration()} returns \tcode{d}, +otherwise \tcode{to_duration()} returns \tcode{duration_cast(d)}. \end{itemdescr} -\indexlibrarymember{to_duration}{time_of_day}% +\indexlibrarymember{is_negative}{hh_mm_ss}% \begin{itemdecl} -constexpr precision to_duration() const noexcept; +constexpr bool is_negative() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{precision\{*this\}}. +\returns +\tcode{is_neg}. \end{itemdescr} -\indexlibrarymember{make24}{time_of_day}% +\indexlibrarymember{hours}{hh_mm_ss}% \begin{itemdecl} -constexpr void make24() noexcept; +constexpr chrono::hours hours() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -If \tcode{*this} is a 12-hour time, -converts to a 24-hour time. -Otherwise, no effects. +\returns +\tcode{h}. \end{itemdescr} -\indexlibrarymember{make12}{time_of_day}% +\indexlibrarymember{minutes}{hh_mm_ss}% \begin{itemdecl} -constexpr void make12() noexcept; +constexpr chrono::minutes minutes() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -If \tcode{*this} is a 24-hour time, -converts to a 12-hour time. -Otherwise, no effects. +\returns +\tcode{m}. \end{itemdescr} -\rSec2[time.tod.minutes]{Minutes precision} -\indexlibrary{\idxcode{time_of_day}} - -\begin{codeblock} -namespace std::chrono { - template<> - class time_of_day { - public: - using precision = chrono::minutes; - - time_of_day() = default; - constexpr explicit time_of_day(chrono::minutes since_midnight) noexcept; - - constexpr chrono::hours hours() const noexcept; - constexpr chrono::minutes minutes() const noexcept; - - constexpr explicit operator precision() const noexcept; - constexpr precision to_duration() const noexcept; - - constexpr void make24() noexcept; - constexpr void make12() noexcept; - }; -} -\end{codeblock} - -\pnum -\begin{note} -This specialization handles hours and minutes since midnight. -\end{note} - -\indexlibrary{\idxcode{time_of_day}!constructor}% +\indexlibrarymember{seconds}{hh_mm_ss}% \begin{itemdecl} -constexpr explicit time_of_day(minutes since_midnight) noexcept; +constexpr chrono::seconds seconds() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\effects -Constructs an object of type \tcode{time_of_day} -in 24-hour format -corresponding to \tcode{since_midnight} minutes after 00:00:00. - -\pnum -\ensures -\tcode{hours()} returns the integral number of hours -\tcode{since_midnight} is after 00:00:00. -\tcode{minutes()} returns the integral number of minutes -\tcode{since_midnight} is after \tcode{(\textrm{00:00:00} + hours())}. +\returns +\tcode{s}. \end{itemdescr} -\indexlibrarymember{hours}{time_of_day}% +\indexlibrarymember{subseconds}{hh_mm_ss}% \begin{itemdecl} -constexpr chrono::hours hours() const noexcept; +constexpr precision subseconds() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns The stored hour of \tcode{*this}. +\returns +\tcode{ss}. \end{itemdescr} -\indexlibrarymember{minutes}{time_of_day}% +\indexlibrarymember{to_duration}{hh_mm_ss}% \begin{itemdecl} -constexpr chrono::minutes minutes() const noexcept; +constexpr precision to_duration() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns The stored minute of \tcode{*this}. +\returns +If \tcode{is_neg}, returns \tcode{-(h + m + s + ss)}, +otherwise returns \tcode{h + m + s + ss}. \end{itemdescr} -\indexlibrarymember{operator precision}{time_of_day}% +\indexlibrarymember{operator precision}{hh_mm_ss}% \begin{itemdecl} constexpr explicit operator precision() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns The number of minutes since midnight. +\returns +\tcode{to_duration()}. \end{itemdescr} -\indexlibrarymember{to_duration}{time_of_day}% +\rSec2[time.hms.nonmembers]{Non-members} + \begin{itemdecl} -constexpr precision to_duration() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{precision\{*this\}}. -\end{itemdescr} - -\indexlibrarymember{make24}{time_of_day}% -\begin{itemdecl} -constexpr void make24() noexcept; +template +basic_ostream& +operator<<(basic_ostream& os, const hh_mm_ss& hms); \end{itemdecl} \begin{itemdescr} \pnum \effects -If \tcode{*this} is a 12-hour time, -converts to a 24-hour time. -Otherwise, no effects. -\end{itemdescr} - -\indexlibrarymember{make12}{time_of_day}% -\begin{itemdecl} -constexpr void make12() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If \tcode{*this} is a 24-hour time, -converts to a 12-hour time. -Otherwise, no effects. -\end{itemdescr} - -\rSec2[time.tod.seconds]{Seconds precision} -\indexlibrary{\idxcode{time_of_day}} - +Equivalent to: \begin{codeblock} -namespace std::chrono { - template<> - class time_of_day { - public: - using precision = chrono::seconds; - - time_of_day() = default; - constexpr explicit time_of_day(chrono::seconds since_midnight) noexcept; - - constexpr chrono::hours hours() const noexcept; - constexpr chrono::minutes minutes() const noexcept; - constexpr chrono::seconds seconds() const noexcept; - - constexpr explicit operator precision() const noexcept; - constexpr precision to_duration() const noexcept; - - constexpr void make24() noexcept; - constexpr void make12() noexcept; - }; -} +return os << format(os.getloc(), + hms.is_negative() ? @\placeholder{STATICALLY-WIDEN}@("-{:%T}") + : @\placeholder{STATICALLY-WIDEN}@("{:%T}"), + abs(hms.to_duration())); \end{codeblock} \pnum -\begin{note} -This specialization handles hours, minutes, and seconds since midnight. -\end{note} - -\indexlibrary{\idxcode{time_of_day}!constructor}% -\begin{itemdecl} -constexpr explicit time_of_day(seconds since_midnight) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Constructs an object of type \tcode{time_of_day} -in 24-hour format -corresponding to \tcode{since_midnight} seconds after 00:00:00. - -\pnum -\ensures -\tcode{hours()} returns the integral number of hours -\tcode{since_midnight} is after 00:00:00. -\tcode{minutes()} returns the integral number of minutes -\tcode{since_midnight} is after \tcode{(\textrm{00:00:00} + hours())}. -\tcode{seconds()} returns the integral number of seconds -\tcode{since_midnight} is after \tcode{(\textrm{00:00:00} + hours() + minutes())}. -\end{itemdescr} - -\indexlibrarymember{hours}{time_of_day}% -\begin{itemdecl} -constexpr chrono::hours hours() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The stored hour of \tcode{*this}. -\end{itemdescr} - -\indexlibrarymember{minutes}{time_of_day}% -\begin{itemdecl} -constexpr chrono::minutes minutes() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The stored minute of \tcode{*this}. -\end{itemdescr} - -\indexlibrarymember{seconds}{time_of_day}% -\begin{itemdecl} -constexpr chrono::seconds seconds() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The stored second of \tcode{*this}. -\end{itemdescr} - -\indexlibrarymember{operator precision}{time_of_day}% -\begin{itemdecl} -constexpr explicit operator precision() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The number of seconds since midnight. -\end{itemdescr} - -\indexlibrarymember{to_duration}{time_of_day}% -\begin{itemdecl} -constexpr precision to_duration() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{precision\{*this\}}. -\end{itemdescr} - -\indexlibrarymember{make24}{time_of_day}% -\begin{itemdecl} -constexpr void make24() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If \tcode{*this} is a 12-hour time, -converts to a 24-hour time. -Otherwise, no effects. -\end{itemdescr} - -\indexlibrarymember{make12}{time_of_day}% -\begin{itemdecl} -constexpr void make12() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If \tcode{*this} is a 24-hour time, -converts to a 12-hour time. -Otherwise, no effects. -\end{itemdescr} - -\rSec2[time.tod.subsecond]{Sub-second precision} -\indexlibrary{\idxcode{time_of_day<\placeholder{sub-second duration}>}} - +\begin{example} \begin{codeblock} -namespace std::chrono { - template - class time_of_day> { - public: - using precision = duration; - - time_of_day() = default; - constexpr explicit time_of_day(precision since_midnight) noexcept; - - constexpr chrono::hours hours() const noexcept; - constexpr chrono::minutes minutes() const noexcept; - constexpr chrono::seconds seconds() const noexcept; - constexpr precision subseconds() const noexcept; - - constexpr explicit operator precision() const noexcept; - constexpr precision to_duration() const noexcept; - - constexpr void make24() noexcept; - constexpr void make12() noexcept; - }; +for (auto ms : {-4083007ms, 4083007ms, 65745123ms}) { + hh_mm_ss hms{ms}; + cout << hms << '\n'; } +cout << hh_mm_ss{65745s} << '\n'; \end{codeblock} - -\pnum -This specialization shall not exist unless -\tcode{treat_as_floating_point_v} is \tcode{false} -and -\tcode{duration} is not convertible to \tcode{seconds}. -\begin{note} -This specialization handles hours, minutes, seconds, and fractional seconds since midnight. -Typical uses are with \tcode{milliseconds}, \tcode{microseconds} and \tcode{nanoseconds}. -\end{note} - -\indexlibrary{\idxcode{time_of_day<\placeholder{sub-second duration}>}!constructor}% -\begin{itemdecl} -constexpr explicit time_of_day(precision since_midnight) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Constructs an object of type \tcode{time_of_day} -in 24-hour format -corresponding to \tcode{since_midnight} fractional seconds after 00:00:00. - -\pnum -\ensures -\tcode{hours()} returns the integral number of hours -\tcode{since_midnight} is after 00:00:00. -\tcode{minutes()} returns the integral number of minutes -\tcode{since_midnight }is after \tcode{(\textrm{00:00:00} + hours())}. -\tcode{seconds()} returns the integral number of seconds -\tcode{since_midnight }is after \tcode{(\textrm{00:00:00} + hours() + minutes())}. -\tcode{subseconds()} returns the integral number of fractional seconds -\tcode{since_midnight} is after \tcode{(\textrm{00:00:00} + hours() + minutes() + seconds())}. -\end{itemdescr} - -\indexlibrarymember{hours}{time_of_day<\placeholder{sub-second duration}>}% -\begin{itemdecl} -constexpr chrono::hours hours() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The stored hour of \tcode{*this}. +Produces the output (assuming the "C" locale): +\begin{codeblock} +-01:08:03.007 +01:08:03.007 +18:15:45.123 +18:15:45 +\end{codeblock} +\end{example} \end{itemdescr} -\indexlibrarymember{minutes}{time_of_day<\placeholder{sub-second duration}>}% -\begin{itemdecl} -constexpr chrono::minutes minutes() const noexcept; -\end{itemdecl} +\rSec1[time.12]{12/24 hours functions} -\begin{itemdescr} \pnum -\returns -The stored minute of \tcode{*this}. -\end{itemdescr} +These functions aid in translating between a 12h format time of day +and a 24h format time of day. -\indexlibrarymember{seconds}{time_of_day<\placeholder{sub-second duration}>}% +\indexlibrary{\idxcode{is_am}}% \begin{itemdecl} -constexpr chrono::seconds seconds() const noexcept; +constexpr bool is_am(const hours& h) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -The stored second of \tcode{*this}. +\tcode{0h <= h \&\& h <= 11h}. \end{itemdescr} -\indexlibrarymember{subseconds}{time_of_day<\placeholder{sub-second duration}>}% +\indexlibrary{\idxcode{is_pm}}% \begin{itemdecl} -constexpr duration subseconds() const noexcept; +constexpr bool is_pm(const hours& h) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -The stored subsecond of \tcode{*this}. +\tcode{12h <= h \&\& h <= 23h}. \end{itemdescr} -\indexlibrarymember{operator precision}{time_of_day<\placeholder{sub-second duration}>}% +\indexlibrary{\idxcode{make12}}% \begin{itemdecl} -constexpr explicit operator precision() const noexcept; +constexpr hours make12(const hours& h) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -The number of subseconds since midnight. -\end{itemdescr} - -\indexlibrarymember{to_duration}{time_of_day<\placeholder{sub-second duration}>}% -\begin{itemdecl} -constexpr precision to_duration() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{precision\{*this\}}. -\end{itemdescr} - -\indexlibrarymember{make24}{time_of_day<\placeholder{sub-second duration}>}% -\begin{itemdecl} -constexpr void make24() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If \tcode{*this} is a 12-hour time, -converts to a 24-hour time. -Otherwise, no effects. -\end{itemdescr} - -\indexlibrarymember{make12}{time_of_day<\placeholder{sub-second duration}>}% -\begin{itemdecl} -constexpr void make12() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If \tcode{*this} is a 24-hour time, -converts to a 12-hour time. -Otherwise, no effects. -\end{itemdescr} - -\rSec2[time.tod.io]{Formatted output} - -\indexlibrarymember{operator<<}{time_of_day}% -\begin{itemdecl} -template - basic_ostream& - operator<<(basic_ostream& os, const time_of_day& t); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If \tcode{t} is a 24-hour time, -outputs to \tcode{os} according to the format -\tcode{"\%H00"}\iref{time.format}. -Otherwise -outputs to \tcode{os} according to the format -\tcode{"\%I\%p"}\iref{time.format}. - -\pnum -\returns \tcode{os}. - -\pnum -\begin{example} -\begin{codeblock} -for (hours h : {1h, 18h}) { - time_of_day tod(h); - os << tod << '\n'; - tod.make12(); - os << tod << '\n'; -} -\end{codeblock} - -Produces the output: - -\begin{outputblock} -0100 -1am -1800 -6pm -\end{outputblock} -\end{example} +The 12-hour equivalent of \tcode{h} in the range \crange{1h}{12h}. +If \tcode{h} is not in the range \crange{0h}{23h}, +the value returned is unspecified. \end{itemdescr} -\indexlibrarymember{operator<<}{time_of_day}% -\begin{itemdecl} -template - basic_ostream& - operator<<(basic_ostream& os, const time_of_day& t); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If \tcode{t} is a 24-hour time, -outputs to \tcode{os} according to the format -\tcode{"\%H:\%M"}\iref{time.format}. -Otherwise -outputs to \tcode{os} according to the format -\tcode{"\%I:\%M\%p"}\iref{time.format}. - -\pnum -\returns \tcode{os}. - -\begin{example} -\begin{codeblock} -for (minutes m : {68min, 1095min}) { - time_of_day tod(m); - os << tod << '\n'; - tod.make12(); - os << tod << '\n'; -} -\end{codeblock} - -Produces the output: - -\begin{outputblock} -01:08 -1:08am -18:15 -6:15pm -\end{outputblock} -\end{example} -\end{itemdescr} - -\indexlibrarymember{operator<<}{time_of_day}% -\begin{itemdecl} -template - basic_ostream& - operator<<(basic_ostream& os, const time_of_day& t); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If \tcode{t} is a 24-hour time, -outputs to \tcode{os} according to the format -\tcode{"\%T"}\iref{time.format}. -Otherwise -outputs to \tcode{os} according to the format -\tcode{"\%I:\%M:\%S\%p"}\iref{time.format}. - -\pnum -\returns \tcode{os}. - -\begin{example} -\begin{codeblock} -for (seconds s : {4083s, 65745s}) { - time_of_day tod(s); - os << tod << '\n'; - tod.make12(); - os << tod << '\n'; -} -\end{codeblock} - -Produces the output: - -\begin{outputblock} -01:08:03 -1:08:03am -18:15:45 -6:15:45pm -\end{outputblock} -\end{example} -\end{itemdescr} - -\indexlibrarymember{operator<<}{time_of_day<\placeholder{sub-second duration}>}% -\begin{itemdecl} -template - basic_ostream& - operator<<(basic_ostream& os, const time_of_day>& t); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -If \tcode{t} is a 24-hour time, -outputs to \tcode{os} according to the format -\tcode{"\%T"}\iref{time.format}. -Otherwise -outputs to \tcode{os} according to the format -\tcode{"\%I:\%M:\%S\%p"}\iref{time.format}. - -\pnum -\returns \tcode{os}. - -\begin{example} -\begin{codeblock} -for (milliseconds ms : {4083007ms, 65745123ms}) { - time_of_day tod(ms); - os << tod << '\n'; - tod.make12(); - os << tod << '\n'; -} -\end{codeblock} - -Produces the output: +\indexlibrary{\idxcode{make24}}% +\begin{itemdecl} +constexpr hours make24(const hours& h, bool is_pm) noexcept; +\end{itemdecl} -\begin{outputblock} -01:08:03.007 -1:08:03.007am -18:15:45.123 -6:15:45.123pm -\end{outputblock} -\end{example} +\begin{itemdescr} +\pnum +\returns +If \tcode{is_pm} is \tcode{false}, +returns the 24-hour equivalent of \tcode{h} +in the range \crange{0h}{11h}, +assuming \tcode{h} represents an ante meridiem hour. +Otherwise, +returns the 24-hour equivalent of \tcode{h} +in the range \crange{12h}{23h}, +assuming \tcode{h} represents a post meridiem hour. +If \tcode{h} is not in the range \crange{1h}{12h}, +the value returned is unspecified. \end{itemdescr} \rSec1[time.zone]{Time zones} @@ -9565,14 +8890,14 @@ \returns \tcode{x.name() == y.name()}. \end{itemdescr} -\indexlibrarymember{operator<}{time_zone}% +\indexlibrarymember{operator<=>}{time_zone}% \begin{itemdecl} -bool operator<(const time_zone& x, const time_zone& y) noexcept; +strong_ordering operator<=>(const time_zone& x, const time_zone& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{x.name() < y.name()}. +\returns \tcode{x.name() <=> y.name()}. \end{itemdescr} \rSec2[time.zone.zonedtraits]{Class template \tcode{zoned_traits}} @@ -10099,18 +9424,6 @@ \returns \tcode{x.zone_ == y.zone_ \&\& x.tp_ == y.tp_}. \end{itemdescr} -\indexlibrarymember{operator"!=}{zoned_time}% -\begin{itemdecl} -template - bool operator!=(const zoned_time& x, - const zoned_time& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{!(x == y)}. -\end{itemdescr} - \indexlibrarymember{operator<<}{zoned_time}% \begin{itemdecl} template @@ -10131,25 +9444,6 @@ \returns \tcode{os}. \end{itemdescr} -\indexlibrarymember{to_stream}{zoned_time}% -\begin{itemdecl} -template - basic_ostream& - to_stream(basic_ostream& os, const charT* fmt, - const zoned_time& tp); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -First obtains a \tcode{sys_info} via \tcode{tp.get_info()} -which for exposition purposes will be referred to as \tcode{info}. -Then calls \tcode{to_stream(os, fmt, tp.get_local_time(), \&info.abbrev, \&info.offset)}. - -\pnum -\returns \tcode{os}. -\end{itemdescr} - \rSec2[time.zone.leap]{Class \tcode{leap}} \rSec3[time.zone.leap.overview]{Overview} @@ -10239,14 +9533,14 @@ \returns \tcode{x.date() == y.date()}. \end{itemdescr} -\indexlibrarymember{operator<}{leap}% +\indexlibrarymember{operator<=>}{leap}% \begin{itemdecl} -constexpr bool operator<(const leap& x, const leap& y) noexcept; +constexpr strong_ordering operator<=>(const leap& x, const leap& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{x.date() < y.date()}. +\returns \tcode{x.date() <=> y.date()}. \end{itemdescr} \indexlibrarymember{operator==}{leap}% @@ -10261,42 +9555,6 @@ \returns \tcode{x.date() == y}. \end{itemdescr} -\indexlibrarymember{operator==}{leap}% -\indexlibrarymember{operator==}{sys_time}% -\begin{itemdecl} -template - constexpr bool operator==(const sys_time& x, const leap& y) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{y == x}. -\end{itemdescr} - -\indexlibrarymember{operator"!=}{leap}% -\indexlibrarymember{operator"!=}{sys_time}% -\begin{itemdecl} -template - constexpr bool operator!=(const leap& x, const sys_time& y) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{!(x == y)}. -\end{itemdescr} - -\indexlibrarymember{operator"!=}{leap}% -\indexlibrarymember{operator"!=}{sys_time}% -\begin{itemdecl} -template - constexpr bool operator!=(const sys_time& x, const leap& y) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{!(x == y)}. -\end{itemdescr} - \indexlibrarymember{operator<}{leap}% \indexlibrarymember{operator<}{sys_time}% \begin{itemdecl} @@ -10393,6 +9651,18 @@ \returns \tcode{!(x < y)}. \end{itemdescr} +\indexlibrarymember{operator<=>}{leap}% +\indexlibrarymember{operator<=>}{sys_time}% +\begin{itemdecl} +template Duration> + constexpr auto operator<=>(const leap& x, const sys_time& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns \tcode{x.date() <=> y}. +\end{itemdescr} + \rSec2[time.zone.link]{Class \tcode{link}} \rSec3[time.zone.link.overview]{Overview} @@ -10454,175 +9724,109 @@ \returns \tcode{x.name() == y.name()}. \end{itemdescr} -\indexlibrarymember{operator<}{link}% +\indexlibrarymember{operator<=>}{link}% \begin{itemdecl} -bool operator<(const link& x, const link& y) noexcept; +strong_ordering operator<=>(const link& x, const link& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{x.name() < y.name()}. +\returns \tcode{x.name() <=> y.name()}. \end{itemdescr} \rSec1[time.format]{Formatting} \pnum -Each \tcode{format} overload specified in this subclause -calls \tcode{to_stream} unqualified, -so as to enable argument dependent lookup\iref{basic.lookup.argdep}. - -\indexlibrary{\idxcode{format}|(}% -\begin{itemdecl} -template - basic_string - format(const charT* fmt, const Streamable& s); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\remarks -This function shall not participate in overload resolution unless -\begin{codeblock} -to_stream(declval&>(), fmt, s) -\end{codeblock} -is a valid expression. - -\pnum -\effects -Constructs a local variable of type -\tcode{basic_ostringstream} -(named \tcode{os} for exposition purposes). -Executes \tcode{os.exceptions(ios::failbit | ios::badbit)}. -Then calls \tcode{to_stream(os, fmt, s)}. - -\pnum -\returns \tcode{os.str()}. -\end{itemdescr} - -\begin{itemdecl} -template - basic_string - format(const locale& loc, const charT* fmt, const Streamable& s); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\remarks -This function shall not participate in overload resolution unless -\begin{codeblock} -to_stream(declval&>(), fmt, s) -\end{codeblock} -is a valid expression. - -\pnum -\effects -Constructs a local variable of type -\tcode{basic_ostringstream} -(named \tcode{os} for exposition purposes). -Executes \tcode{os.exceptions(ios::failbit | ios::badbit)}. -Then calls \tcode{os.imbue(loc)}. -Then calls \tcode{to_stream(os, fmt, s)}. - -\pnum -\returns \tcode{os.str()}. -\end{itemdescr} - -\begin{itemdecl} -template - basic_string - format(const basic_string& fmt, const Streamable& s); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\remarks -This function shall not participate in overload resolution unless -\begin{codeblock} -to_stream(declval&>(), fmt.c_str(), s) -\end{codeblock} -is a valid expression. - -\pnum -\effects -Constructs a local variable of type -\tcode{basic_ostringstream} -(named \tcode{os} for exposition purposes). -Executes \tcode{os.exceptions(ios::failbit | ios::badbit)}. -Then calls \tcode{to_stream(os, fmt.c_str(), s)}. - -\pnum -\returns \tcode{os.str()}. -\end{itemdescr} - -\begin{itemdecl} -template - basic_string - format(const locale& loc, const basic_string& fmt, const Streamable& s); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\remarks -This function shall not participate in overload resolution unless -\begin{codeblock} -to_stream(declval&>(), fmt.c_str(), s) -\end{codeblock} -is a valid expression. - -\pnum -\effects -Constructs a local variable of type -\tcode{basic_ostringstream} -(named \tcode{os} for exposition purposes). -Then calls \tcode{os.imbue(loc)}. -Executes \tcode{os.exceptions(ios::failbit | ios::badbit)}. -Then calls \tcode{to_stream(os, fmt.c_str(), s)}. - -\pnum -\returns \tcode{os.str()}. -\end{itemdescr} - -\pnum -The \tcode{format} functions call a \tcode{to_stream} function with -a \tcode{basic_ostream}, -a formatting string specifier, -and a \tcode{Streamable} argument. -Each \tcode{to_stream} overload is customized for each \tcode{Streamable} type. -However all \tcode{to_stream} overloads -treat the formatting string specifier -according to the following specification: - -\pnum -The \tcode{fmt} string consists of zero or more conversion specifiers -and ordinary multibyte characters. -A conversion specifier consists of -a \tcode{\%} character, -possibly followed by an \tcode{E} or \tcode{O} modifier character (described below), -followed by a character that determines the behavior of the conversion specifier. -All ordinary multibyte characters (excluding the terminating null character) -are streamed unchanged into the \tcode{basic_ostream}. - -\pnum -Each conversion specifier is replaced by appropriate characters +Each \tcode{formatter}\iref{format.formatter} specialization +in the chrono library\iref{time.syn} +meets the \newoldconcept{Formatter} requirements\iref{formatter.requirements}. +The \tcode{parse} member functions of these formatters +interpret the format specification +as a \fmtgrammarterm{chrono-format-spec} +according to the following syntax: + +\begin{ncbnf} +\fmtnontermdef{chrono-format-spec}\br + \opt{fill-and-align} \opt{width} \opt{precision} \opt{chrono-specs} +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{chrono-specs}\br + conversion-spec\br + chrono-specs conversion-spec\br + chrono-specs literal-char +\end{ncbnf} + +% FIXME: This should obviously also exclude \tcode{\%}. +\begin{ncbnf} +\fmtnontermdef{literal-char}\br + \textnormal{any character other than \tcode{\{} or \tcode{\}}} +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{conversion-spec}\br + \terminal{\%} \opt{modifier} type +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{modifier} \textnormal{one of}\br + \terminal{E O} +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{type} \textnormal{one of}\br + \terminal{a A b B c C d D e F g G h H I j m M n}\br + \terminal{p r R S t T u U V w W x X y Y z Z \%} +\end{ncbnf} + +The productions +\fmtgrammarterm{fill-and-align}, +\fmtgrammarterm{width}, and +\fmtgrammarterm{precision} +are described in \ref{format.string}. +Giving a \fmtgrammarterm{precision} specification +in the \fmtgrammarterm{chrono-format-spec} +is valid only for \tcode{std::chrono::duration} types +where the representation type \tcode{Rep} +is a floating-point type. +For all other \tcode{Rep} types, +an exception of type \tcode{format_error} is thrown +if the \fmtgrammarterm{chrono-format-spec} +contains a \fmtgrammarterm{precision} specification. +All ordinary multibyte characters +represented by \fmtgrammarterm{literal-char} +are copied unchanged to the output. + +\pnum +Each conversion specifier \fmtgrammarterm{conversion-spec} +is replaced by appropriate characters as described in \tref{time.format.spec}. Some of the conversion specifiers -depend on the locale which is imbued to the \tcode{basic_ostream}. -If the \tcode{Streamable} object does not contain -the information the conversion specifier refers to, -the value streamed to the \tcode{basic_ostream} is unspecified. +depend on the locale that is passed to the formatting function +if the latter takes one, +or the global locale otherwise. +If the formatted object does not contain the information +the conversion specifier refers to, +an exception of type \tcode{format_error} is thrown. \pnum -Unless explicitly specified, -\tcode{Streamable} types will not contain time zone abbreviation +Unless explicitly requested, +the result of formatting a chrono type +does not contain time zone abbreviation and time zone offset information. -If available, +If the information is available, the conversion specifiers \tcode{\%Z} and \tcode{\%z} will format this information (respectively). -If the information is not available, -and \tcode{\%Z} or \tcode{\%z} are contained in \tcode{fmt}, -\tcode{os.setstate(ios_base::failbit)} shall be called. +\begin{note} +If the information is not available and +a \tcode{\%Z} or \tcode{\%z} +conversion specifier appears in +the \fmtgrammarterm{chrono-format-spec}, +an exception of type \tcode{format_error} is thrown, +as described above. +\end{note} -\begin{LongTable}{Meaning of \tcode{format} conversion specifiers}{time.format.spec}{lx{.8\hsize}} +\begin{LongTable}{Meaning of conversion specifiers}{time.format.spec}{lx{.8\hsize}} \\ \topline \lhdr{Specifier} & \rhdr{Replacement} \\ \capsep \endfirsthead @@ -10633,22 +9837,22 @@ \tcode{\%a} & The locale's abbreviated weekday name. If the value does not contain a valid weekday, -\tcode{setstate(ios::failbit)} is called. +an exception of type \tcode{format_error} is thrown. \\ \rowsep \tcode{\%A} & The locale's full weekday name. If the value does not contain a valid weekday, -\tcode{setstate(ios::failbit)} is called. +an exception of type \tcode{format_error} is thrown. \\ \rowsep \tcode{\%b} & The locale's abbreviated month name. If the value does not contain a valid month, -\tcode{setstate(ios::failbit)} is called. +an exception of type \tcode{format_error} is thrown. \\ \rowsep \tcode{\%B} & The locale's full month name. If the value does not contain a valid month, -\tcode{setstate(ios::failbit)} is called. +an exception of type \tcode{format_error} is thrown. \\ \rowsep \tcode{\%c} & The locale's date and time representation. @@ -10733,6 +9937,12 @@ \tcode{\%p} & The locale's equivalent of the AM/PM designations associated with a 12-hour clock. \\ \rowsep +\tcode{\%q} & +The duration's unit suffix as specified in \ref{time.duration.io}. +\\ \rowsep +\tcode{\%Q} & +The duration's numeric value (as if extracted via \tcode{.count()}). +\\ \rowsep \tcode{\%r} & The locale's 12-hour clock time. \\ \rowsep @@ -10816,18 +10026,218 @@ The modified commands \tcode{\%Ez} and \tcode{\%Oz} insert a \tcode{:} between the hours and minutes: \tcode{-04:30}. If the offset information is not available, -\tcode{setstate(ios_base::failbit)} shall be called. +an exception of type \tcode{format_error} is thrown. \\ \rowsep \tcode{\%Z} & The time zone abbreviation. If the time zone abbreviation is not available, -\tcode{setstate(ios_base::failbit)} shall be called. +an exception of type \tcode{format_error} is thrown. \\ \rowsep \tcode{\%\%} & A \tcode{\%} character. \\ \end{LongTable} +\pnum +If the \fmtgrammarterm{chrono-specs} is omitted, +the chrono object is formatted +as if by streaming it to \tcode{std::ostringstream os} +and copying \tcode{os.str()} through the output iterator of the context +with additional padding and adjustments as specified by the format specifiers. +\begin{example} +\begin{codeblock} +string s = format("{:=>8}", 42ms); // value of \tcode{s} is \tcode{"====42ms"} +\end{codeblock} +\end{example} + +\indexlibrary{\idxcode{formatter}!specializations!\idxcode{chrono::sys_time}}% +\begin{itemdecl} +template + struct formatter, charT>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\remarks +If \tcode{\%Z} is used, +it is replaced with \tcode{\exposid{STATICALLY-WIDEN}("UTC")}. +If \tcode{\%z} (or a modified variant of \tcode{\%z}) is used, +an offset of \tcode{0min} is formatted. +\end{itemdescr} + +\indexlibrary{\idxcode{formatter}!specializations!\idxcode{chrono::utc_time}}% +\begin{itemdecl} +template + struct formatter, charT>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\remarks +If \tcode{\%Z} is used, +it is replaced with \tcode{\exposid{STATICALLY-WIDEN}("UTC")}. +If \tcode{\%z} (or a modified variant of \tcode{\%z}) is used, +an offset of \tcode{0min} is formatted. +If the argument represents a time during a leap second insertion, +and if a seconds field is formatted, +the integral portion of that format is +\tcode{\exposid{STATICALLY-WIDEN}("60")}. +\end{itemdescr} + +\indexlibrary{\idxcode{formatter}!specializations!\idxcode{chrono::tai_time}}% +\begin{itemdecl} +template + struct formatter, charT>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\remarks +If \tcode{\%Z} is used, +it is replaced with \tcode{\exposid{STATICALLY-WIDEN}("TAI")}. +If \tcode{\%z} (or a modified variant of \tcode{\%z}) is used, +an offset of \tcode{0min} is formatted. +The date and time formatted are equivalent to +those formatted by a \tcode{sys_time} initialized with +\begin{codeblock} +sys_time{tp.time_since_epoch()} - + (sys_days{1970y/January/1} - sys_days{1958y/January/1}) +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{formatter}!specializations!\idxcode{chrono::gps_time}}% +\begin{itemdecl} +template + struct formatter, charT>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\remarks +If \tcode{\%Z} is used, +it is replaced with \tcode{\exposid{STATICALLY-WIDEN}("GPS")}. +If \tcode{\%z} (or a modified variant of \tcode{\%z}) is used, +an offset of \tcode{0min} is formatted. +The date and time formatted are equivalent to +those formatted by a \tcode{sys_time} initialized with +\begin{codeblock} +sys_time{tp.time_since_epoch()} + + (sys_days{1980y/January/Sunday[1]} - sys_days{1970y/January/1}) +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{formatter}!specializations!\idxcode{chrono::file_time}}% +\begin{itemdecl} +template + struct formatter, charT>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\remarks +If \tcode{\%Z} is used, +it is replaced with \tcode{\exposid{STATICALLY-WIDEN}("UTC")}. +If \tcode{\%z} (or a modified variant of \tcode{\%z}) is used, +an offset of \tcode{0min} is formatted. +The date and time formatted are equivalent to +those formatted +by a \tcode{sys_time} initialized with \tcode{clock_cast(t)}, or +by a \tcode{utc_time} initialized with \tcode{clock_cast(t)}, +where \tcode{t} is the first argument to \tcode{format}. +\end{itemdescr} + +\indexlibrary{\idxcode{formatter}!specializations!\idxcode{chrono::local_time}}% +\begin{itemdecl} +template + struct formatter, charT>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\remarks +If \tcode{\%Z}, \tcode{\%z}, or a modified version of \tcode{\%z} is used, +an exception of type \tcode{format_error} is thrown. +\end{itemdescr} + +\indexlibrary{local-time-format-t@\exposid{local-time-format-it}}% +\begin{codeblock} +template struct @\placeholder{local-time-format-t}@ { // \expos + local_time time; // \expos + const string* abbrev; // \expos + const seconds* offset_sec; // \expos +}; +\end{codeblock} + +\indexlibrary{\idxcode{local_time_format}}% +\begin{itemdecl} +template + @\placeholder{local-time-format-t}@ + local_time_format(local_time time, const string* abbrev = nullptr, + const seconds* offset_sec = nullptr); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns \tcode{\{time, abbrev, offset_sec\}}. +\end{itemdescr} + +\indexlibrary{\idxcode{formatter}!specializations!chrono::local-time-format-t@\tcode{chrono::\exposid{local-time-format-t}}}% +\begin{itemdecl} +template + struct formatter, charT>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{f} be a \tcode{\exposid{local-time-format-t}} object +passed to \tcode{formatter::format}. + +\pnum +\remarks +If \tcode{\%Z} is used, +it is replaced with \tcode{*f.abbrev} +if \tcode{f.abbrev} is not a null pointer value. +If \tcode{\%Z} is used +and \tcode{f.abbrev} is a null pointer value, +an exception of type \tcode{format_error} is thrown. +If \tcode{\%z} (or a modified variant of \tcode{\%z}) is used, +it is formatted with the value of \tcode{*f.offset_sec} +if \tcode{f.offset_sec} is not a null pointer value. +If \tcode{\%z} (or a modified variant of \tcode{\%z}) is used +and \tcode{f.offset_sec} is a null pointer value, +then an exception of type \tcode{format_error} is thrown. +\end{itemdescr} + +\indexlibrary{\idxcode{formatter}!specializations!\idxcode{chrono::zoned_time}}% +\begin{codeblock} +template +struct formatter, charT> + : formatter, charT> { + template + typename FormatContext::iterator + format(const chrono::zoned_time& tp, FormatContext& ctx); +}; +\end{codeblock} + +% FIXME: Decide how to index this. This template-id is a lie. +\indexlibrary{\idxcode{format}!\idxcode{formatter}}% +\begin{itemdecl} +template + typename FormatContext::iterator + format(const chrono::zoned_time& tp, FormatContext& ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +sys_info info = tp.get_info(); +return formatter, charT>:: + format({tp.get_local_time(), &info.abbrev, &info.offset}, ctx); +\end{codeblock} +\end{itemdescr} + \indexlibrary{\idxcode{format}|)}% \rSec1[time.parse]{Parsing} @@ -10940,11 +10350,11 @@ Each flag begins with a \tcode{\%}. Some flags can be modified by \tcode{E} or \tcode{O}. During parsing each flag interprets characters as parts of date and time types -according to the table below. +according to~\tref{time.parse.spec}. Some flags can be modified by a width parameter given as a positive decimal integer called out as \tcode{\placeholder{N}} below which governs how many characters are parsed from the stream in interpreting the flag. -All characters in the format string that are not represented in the table below, +All characters in the format string that are not represented in~\tref{time.parse.spec}, except for white space, are parsed unchanged from the stream. A white space character matches zero or more white space characters in the input stream. @@ -11155,11 +10565,11 @@ \\ \rowsep \tcode{\%x} & The locale's date representation. -The modified command \tcode{\%Ex} produces the locale's alternate date representation. +The modified command \tcode{\%Ex} interprets the locale's alternate date representation. \\ \rowsep \tcode{\%X} & The locale's time representation. -The modified command \tcode{\%EX} produces the locale's alternate time representation. +The modified command \tcode{\%EX} interprets the locale's alternate time representation. \\ \rowsep \tcode{\%y} & The last two decimal digits of the year. diff --git a/source/utilities.tex b/source/utilities.tex index 749006ed1f..b80f3f3dc3 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -27,7 +27,8 @@ \ref{ratio} & Compile-time rational arithmetic & \tcode{} \\ \rowsep \ref{type.index} & Type indexes & \tcode{} \\ \rowsep \ref{execpol} & Execution policies & \tcode{} \\ \rowsep -\ref{charconv} & Primitive numeric conversions & \tcode{} \\ +\ref{charconv} & Primitive numeric conversions & \tcode{} \\ \rowsep +\ref{format} & Formatting & \tcode{} \\ \end{libsumtab} \rSec1[utility]{Utility components} @@ -100,19 +101,6 @@ struct pair; // \ref{pairs.spec}, pair specialized algorithms - template - constexpr bool operator==(const pair&, const pair&); - template - constexpr bool operator!=(const pair&, const pair&); - template - constexpr bool operator< (const pair&, const pair&); - template - constexpr bool operator> (const pair&, const pair&); - template - constexpr bool operator<=(const pair&, const pair&); - template - constexpr bool operator>=(const pair&, const pair&); - template constexpr void swap(pair& x, pair& y) noexcept(noexcept(x.swap(y))); @@ -499,6 +487,15 @@ constexpr pair& operator=(pair&& p); constexpr void swap(pair& p) noexcept(@\seebelow@); + + // \ref{pairs.spec}, pair specialized algorithms + friend constexpr bool operator==(const pair&, const pair&) = default; + friend constexpr bool operator==(const pair& x, const pair& y) + requires (is_reference_v || is_reference_v) + { return x.first == y.first && x.second == y.second; } + friend constexpr common_comparison_category_t<@\placeholder{synth-three-way-result}@, + @\placeholder{synth-three-way-result}@> + operator<=>(const pair& x, const pair& y) { @\seebelow@ } }; template @@ -763,75 +760,23 @@ \rSec2[pairs.spec]{Specialized algorithms} -\indexlibrarymember{operator==}{pair}% -\begin{itemdecl} -template - constexpr bool operator==(const pair& x, const pair& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x.first == y.first \&\& x.second == y.second}. -\end{itemdescr} - -\indexlibrarymember{operator"!=}{pair}% -\begin{itemdecl} -template - constexpr bool operator!=(const pair& x, const pair& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{!(x == y)}. -\end{itemdescr} - -\indexlibrarymember{operator<}{pair}% -\begin{itemdecl} -template - constexpr bool operator<(const pair& x, const pair& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x.first < y.first || (!(y.first < x.first) \&\& x.second < y.second)}. -\end{itemdescr} - -\indexlibrarymember{operator>}{pair}% -\begin{itemdecl} -template - constexpr bool operator>(const pair& x, const pair& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{y < x}. -\end{itemdescr} - -\indexlibrarymember{operator<=}{pair}% -\begin{itemdecl} -template - constexpr bool operator<=(const pair& x, const pair& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{!(y < x)}. -\end{itemdescr} - -\indexlibrarymember{operator>=}{pair}% +\indexlibrarymember{operator<=>}{pair}% \begin{itemdecl} -template - constexpr bool operator>=(const pair& x, const pair& y); +friend constexpr + common_comparison_category_t<@\placeholder{synth-three-way-result}@, @\placeholder{synth-three-way-result}@> + operator<=>(const pair& x, const pair& y); \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{!(x < y)}. +\effects +Equivalent to: +\begin{codeblock} +if (auto c = @\placeholdernc{synth-three-way}@(x.first, y.first); c != 0) return c; +return @\placeholdernc{synth-three-way}@(x.second, y.second); +\end{codeblock} \end{itemdescr} - \indexlibrary{\idxcode{swap}!\idxcode{pair}}% \begin{itemdecl} template @@ -1061,15 +1006,8 @@ template constexpr bool operator==(const tuple&, const tuple&); template - constexpr bool operator!=(const tuple&, const tuple&); - template - constexpr bool operator<(const tuple&, const tuple&); - template - constexpr bool operator>(const tuple&, const tuple&); - template - constexpr bool operator<=(const tuple&, const tuple&); - template - constexpr bool operator>=(const tuple&, const tuple&); + constexpr common_comparison_category_t<@\placeholder{synth-three-way-result}@...> + operator<=>(const tuple&, const tuple&); // \ref{tuple.traits}, allocator-related traits template @@ -1114,7 +1052,8 @@ // allocator-extended constructors template - constexpr tuple(allocator_arg_t, const Alloc& a); + constexpr explicit(@\seebelow@) + tuple(allocator_arg_t, const Alloc& a); template constexpr explicit(@\seebelow@) tuple(allocator_arg_t, const Alloc& a, const Types&...); @@ -1210,8 +1149,9 @@ \begin{note} This behavior can be implemented by a constructor template with default template arguments. \end{note} The expression inside \tcode{explicit} evaluates to \tcode{true} -if and only if $\tcode{T}_i$ is not implicitly -default-constructible for at least one $i$. +if and only if $\tcode{T}_i$ is not +copy-list-initializable from an empty list +for at least one $i$. \begin{note} This behavior can be implemented with a trait that checks whether a \tcode{const $\tcode{T}_i$\&} can be initialized with \tcode{\{\}}. \end{note} \end{itemdescr} @@ -1278,7 +1218,7 @@ \begin{itemdescr} \pnum -\requires \tcode{is_move_constructible_v<$\tcode{T}_i$>} is \tcode{true} for all $i$. +\constraints \tcode{is_move_constructible_v<$\tcode{T}_i$>} is \tcode{true} for all $i$. \pnum \effects For all $i$, initializes the $i^\text{th}$ element of \tcode{*this} with @@ -1398,7 +1338,8 @@ \indexlibrary{\idxcode{tuple}!constructor}% \begin{itemdecl} template - constexpr tuple(allocator_arg_t, const Alloc& a); + constexpr explicit(@\seebelow@) + tuple(allocator_arg_t, const Alloc& a); template constexpr explicit(@\seebelow@) tuple(allocator_arg_t, const Alloc& a, const Types&...); @@ -1641,7 +1582,7 @@ \pnum \effects Constructs a tuple of references to the arguments in \tcode{t} suitable for forwarding as arguments to a function. Because the result may contain references -to temporary variables, a program shall ensure that the return value of this +to temporary objects, a program shall ensure that the return value of this function does not outlive any of its arguments (e.g., the program should typically not store the result in a named variable). @@ -1764,7 +1705,7 @@ Given the exposition-only function: \begin{codeblock} template -constexpr T @\placeholdernc{make-from-tuple-impl}@(Tuple&& t, index_sequence) { // exposition only +constexpr T @\placeholdernc{make-from-tuple-impl}@(Tuple&& t, index_sequence) { // \expos return T(get(std::forward(t))...); } \end{codeblock} @@ -2003,77 +1944,37 @@ \tcode{false}. \end{itemdescr} -\indexlibrarymember{operator"!=}{tuple}% -\begin{itemdecl} -template - constexpr bool operator!=(const tuple& t, const tuple& u); -\end{itemdecl} -\begin{itemdescr} -\pnum\returns \tcode{!(t == u)}. -\end{itemdescr} - -\indexlibrarymember{operator<}{tuple}% +\indexlibrarymember{operator<=>}{tuple}% \begin{itemdecl} template - constexpr bool operator<(const tuple& t, const tuple& u); + constexpr common_comparison_category_t<@\placeholder{synth-three-way-result}@...> + operator<=>(const tuple& t, const tuple& u); \end{itemdecl} \begin{itemdescr} \pnum -\requires For all \tcode{i}, -where \tcode{0 <= i} and -\tcode{i < sizeof...(TTypes)}, both \tcode{get(t) < get(u)} -and \tcode{get(u) < get(t)} -are valid expressions returning types that are -convertible to \tcode{bool}. -\tcode{sizeof...(TTypes)} \tcode{==} -\tcode{sizeof...(UTypes)}. - -\pnum\returns The result of a lexicographical comparison -between \tcode{t} and \tcode{u}. The result is defined -as: \tcode{(bool)(get<0>(t) < get<0>(u)) || -(!(bool)(get<0>(u) < get<0>(t)) \&\& t$_{\mathrm{tail}}$ < -u$_{\mathrm{tail}}$)}, where \tcode{r$_{\mathrm{tail}}$} for some -tuple \tcode{r} is a tuple containing all but the first element -of \tcode{r}. For any two zero-length tuples \tcode{e} -and \tcode{f}, \tcode{e < f} returns \tcode{false}. -\end{itemdescr} - -\indexlibrarymember{operator>}{tuple}% -\begin{itemdecl} -template - constexpr bool operator>(const tuple& t, const tuple& u); -\end{itemdecl} -\begin{itemdescr} -\pnum\returns \tcode{u < t}. -\end{itemdescr} - -\indexlibrarymember{operator<=}{tuple}% -\begin{itemdecl} -template - constexpr bool operator<=(const tuple& t, const tuple& u); -\end{itemdecl} -\begin{itemdescr} -\pnum\returns \tcode{!(u < t)}. -\end{itemdescr} - -\indexlibrarymember{operator>=}{tuple}% -\begin{itemdecl} -template - constexpr bool operator>=(const tuple& t, const tuple& u); -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{!(t < u)}. +\effects +Performs a lexicographical comparison between \tcode{t} and \tcode{u}. +For any two zero-length tuples \tcode{t} and \tcode{u}, +\tcode{t <=> u} returns \tcode{strong_ordering::equal}. +Otherwise, equivalent to: +\begin{codeblock} +if (auto c = @\placeholder{synth-three-way}@(get<0>(t), get<0>(u)); c != 0) return c; +return @$\tcode{t}_\mathrm{tail}$@ <=> @$\tcode{u}_\mathrm{tail}$@; +\end{codeblock} +where $\tcode{r}_\mathrm{tail}$ for some tuple \tcode{r} +is a tuple containing all but the first element of \tcode{r}. \end{itemdescr} -\pnum \begin{note} The above definitions for comparison functions -do not require \tcode{t$_{\mathrm{tail}}$} +\pnum +\begin{note} +The above definition does not require \tcode{t$_{\mathrm{tail}}$} (or \tcode{u$_{\mathrm{tail}}$}) to be constructed. It may not even be possible, as \tcode{t} and \tcode{u} are not required to be copy constructible. Also, all comparison functions are short circuited; they do not perform element accesses beyond what is required to determine the -result of the comparison. \end{note} +result of the comparison. +\end{note} \rSec3[tuple.traits]{Tuple traits} @@ -2160,20 +2061,14 @@ constexpr bool operator<=(const optional&, const optional&); template constexpr bool operator>=(const optional&, const optional&); + template U> + constexpr compare_three_way_result_t + operator<=>(const optional&, const optional&); // \ref{optional.nullops}, comparison with \tcode{nullopt} template constexpr bool operator==(const optional&, nullopt_t) noexcept; - template constexpr bool operator==(nullopt_t, const optional&) noexcept; - template constexpr bool operator!=(const optional&, nullopt_t) noexcept; - template constexpr bool operator!=(nullopt_t, const optional&) noexcept; - template constexpr bool operator<(const optional&, nullopt_t) noexcept; - template constexpr bool operator<(nullopt_t, const optional&) noexcept; - template constexpr bool operator>(const optional&, nullopt_t) noexcept; - template constexpr bool operator>(nullopt_t, const optional&) noexcept; - template constexpr bool operator<=(const optional&, nullopt_t) noexcept; - template constexpr bool operator<=(nullopt_t, const optional&) noexcept; - template constexpr bool operator>=(const optional&, nullopt_t) noexcept; - template constexpr bool operator>=(nullopt_t, const optional&) noexcept; + template + constexpr strong_ordering operator<=>(const optional&, nullopt_t) noexcept; // \ref{optional.comp.with.t}, comparison with \tcode{T} template constexpr bool operator==(const optional&, const U&); @@ -2188,6 +2083,9 @@ template constexpr bool operator<=(const T&, const optional&); template constexpr bool operator>=(const optional&, const U&); template constexpr bool operator>=(const T&, const optional&); + template U> + constexpr compare_three_way_result_t + operator<=>(const optional&, const U&); // \ref{optional.specalg}, specialized algorithms template @@ -2292,9 +2190,9 @@ Member \tcode{val} is provided for exposition only. When an \tcode{optional} object contains a value, \tcode{val} points to the contained value. \pnum -\tcode{T} shall be an object type +\tcode{T} shall be a type other than \cv{} \tcode{in_place_t} or \cv{} \tcode{nullopt_t} -and shall meet the \oldconcept{Destructible} requirements (\tref{cpp17.destructible}). +that meets the \oldconcept{Destructible} requirements (\tref{cpp17.destructible}). \rSec3[optional.ctor]{Constructors} @@ -3306,79 +3204,30 @@ shall be constexpr functions. \end{itemdescr} -\rSec2[optional.nullops]{Comparison with \tcode{nullopt}} - -\indexlibrarymember{operator==}{optional}% -\begin{itemdecl} -template constexpr bool operator==(const optional& x, nullopt_t) noexcept; -template constexpr bool operator==(nullopt_t, const optional& x) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{!x}. -\end{itemdescr} - -\indexlibrarymember{operator"!=}{optional}% -\begin{itemdecl} -template constexpr bool operator!=(const optional& x, nullopt_t) noexcept; -template constexpr bool operator!=(nullopt_t, const optional& x) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{bool(x)}. -\end{itemdescr} - -\indexlibrarymember{operator<}{optional}% -\begin{itemdecl} -template constexpr bool operator<(const optional& x, nullopt_t) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{false}. -\end{itemdescr} - -\indexlibrarymember{operator<}{optional}% +\indexlibrarymember{operator<=>}{optional}% \begin{itemdecl} -template constexpr bool operator<(nullopt_t, const optional& x) noexcept; +template U> + constexpr compare_three_way_result_t + operator<=>(const optional& x, const optional& y); \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{bool(x)}. -\end{itemdescr} - -\indexlibrarymember{operator>}{optional}% -\begin{itemdecl} -template constexpr bool operator>(const optional& x, nullopt_t) noexcept; -\end{itemdecl} +If \tcode{x \&\& y}, \tcode{*x <=> *y}; otherwise \tcode{bool(x) <=> bool(y)}. -\begin{itemdescr} \pnum -\returns -\tcode{bool(x)}. +\remarks +Specializations of this function template +for which \tcode{*x <=> *y} is a core constant expression +shall be constexpr functions. \end{itemdescr} -\indexlibrarymember{operator>}{optional}% -\begin{itemdecl} -template constexpr bool operator>(nullopt_t, const optional& x) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{false}. -\end{itemdescr} +\rSec2[optional.nullops]{Comparison with \tcode{nullopt}} -\indexlibrarymember{operator<=}{optional}% +\indexlibrarymember{operator==}{optional}% \begin{itemdecl} -template constexpr bool operator<=(const optional& x, nullopt_t) noexcept; +template constexpr bool operator==(const optional& x, nullopt_t) noexcept; \end{itemdecl} \begin{itemdescr} @@ -3387,37 +3236,15 @@ \tcode{!x}. \end{itemdescr} -\indexlibrarymember{operator<=}{optional}% -\begin{itemdecl} -template constexpr bool operator<=(nullopt_t, const optional& x) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{true}. -\end{itemdescr} - -\indexlibrarymember{operator>=}{optional}% -\begin{itemdecl} -template constexpr bool operator>=(const optional& x, nullopt_t) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{true}. -\end{itemdescr} - -\indexlibrarymember{operator>=}{optional}% +\indexlibrarymember{operator<=>}{optional}% \begin{itemdecl} -template constexpr bool operator>=(nullopt_t, const optional& x) noexcept; +template constexpr strong_ordering operator<=>(const optional& x, nullopt_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{!x}. +\tcode{bool(x) <=> false}. \end{itemdescr} \rSec2[optional.comp.with.t]{Comparison with \tcode{T}} @@ -3617,6 +3444,18 @@ Equivalent to: \tcode{return bool(x) ?\ v >= *x :\ true;} \end{itemdescr} +\indexlibrarymember{operator<=>}{optional}% +\begin{itemdecl} +template U> + constexpr compare_three_way_result_t + operator<=>(const optional& x, const U& v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return bool(x) ?\ *x <=> v :\ strong_ordering::less;} +\end{itemdescr} \rSec2[optional.specalg]{Specialized algorithms} @@ -3779,6 +3618,9 @@ constexpr bool operator<=(const variant&, const variant&); template constexpr bool operator>=(const variant&, const variant&); + template requires (three_way_comparable && ...) + constexpr common_comparison_category_t...> + operator<=>(const variant&, const variant&); // \ref{variant.visit}, visitation template @@ -3791,11 +3633,7 @@ // \ref{variant.monostate.relops}, \tcode{monostate} relational operators constexpr bool operator==(monostate, monostate) noexcept; - constexpr bool operator!=(monostate, monostate) noexcept; - constexpr bool operator<(monostate, monostate) noexcept; - constexpr bool operator>(monostate, monostate) noexcept; - constexpr bool operator<=(monostate, monostate) noexcept; - constexpr bool operator>=(monostate, monostate) noexcept; + constexpr strong_ordering operator<=>(monostate, monostate) noexcept; // \ref{variant.specalg}, specialized algorithms template @@ -3879,8 +3717,8 @@ storage suitably aligned for all types in \tcode{Types}. \pnum -All types in \tcode{Types} shall be (possibly cv-qualified) -object types that are not arrays. +All types in \tcode{Types} shall meet +the \oldconcept{Destructible} requirements (\tref{cpp17.destructible}). \pnum A program that instantiates the definition of \tcode{variant} with @@ -4872,6 +4710,28 @@ otherwise \tcode{get<$i$>(v) >= get<$i$>(w)} with $i$ being \tcode{v.index()}. \end{itemdescr} +\indexlibrarymember{operator<=>}{variant}% +\begin{itemdecl} +template requires (three_way_comparable && ...) + constexpr common_comparison_category_t...> + operator<=>(const variant& v, const variant& w); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +if (v.valueless_by_exception() && w.valueless_by_exception()) + return strong_ordering::equal; +if (v.valueless_by_exception()) return strong_ordering::less; +if (w.valueless_by_exception()) return strong_ordering::greater; +if (auto c = v.index() <=> w.index(); c != 0) return c; +return get<@$i$@>(v) <=> get<@$i$@>(w); +\end{codeblock} +with $i$ being \tcode{v.index()}. +\end{itemdescr} + \rSec2[variant.visit]{Visitation} \indexlibrary{\idxcode{visit}}% @@ -4941,26 +4801,20 @@ \rSec2[variant.monostate.relops]{\tcode{monostate} relational operators} \indexlibrary{\idxcode{operator==}!\idxcode{monostate}}% -\indexlibrary{\idxcode{operator"!=}!\idxcode{monostate}}% -\indexlibrary{\idxcode{operator<}!\idxcode{monostate}}% -\indexlibrary{\idxcode{operator>}!\idxcode{monostate}}% -\indexlibrary{\idxcode{operator<=}!\idxcode{monostate}}% -\indexlibrary{\idxcode{operator>=}!\idxcode{monostate}}% +\indexlibrary{\idxcode{operator<=>}!\idxcode{monostate}}% \begin{itemdecl} constexpr bool operator==(monostate, monostate) noexcept { return true; } -constexpr bool operator!=(monostate, monostate) noexcept { return false; } -constexpr bool operator<(monostate, monostate) noexcept { return false; } -constexpr bool operator>(monostate, monostate) noexcept { return false; } -constexpr bool operator<=(monostate, monostate) noexcept { return true; } -constexpr bool operator>=(monostate, monostate) noexcept { return true; } +constexpr strong_ordering operator<=>(monostate, monostate) noexcept +{ return strong_ordering::equal; } \end{itemdecl} \begin{itemdescr} \pnum -\begin{note} \tcode{monostate} objects have only a single state; they thus always compare equal.\end{note} +\begin{note} +\tcode{monostate} objects have only a single state; they thus always compare equal. +\end{note} \end{itemdescr} - \rSec2[variant.specalg]{Specialized algorithms} \indexlibrary{\idxcode{swap}!\idxcode{variant}}% @@ -5751,7 +5605,6 @@ size_t count() const noexcept; constexpr size_t size() const noexcept; bool operator==(const bitset& rhs) const noexcept; - bool operator!=(const bitset& rhs) const noexcept; bool test(size_t pos) const; bool all() const noexcept; bool any() const noexcept; @@ -6266,18 +6119,6 @@ equals the value of the corresponding bit in \tcode{rhs}. \end{itemdescr} -\indexlibrarymember{operator"!=}{bitset}% -\begin{itemdecl} -bool operator!=(const bitset& rhs) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{true} if -\tcode{!(*this == rhs)}. -\end{itemdescr} - \indexlibrarymember{test}{bitset}% \begin{itemdecl} bool test(size_t pos) const; @@ -6484,7 +6325,7 @@ \end{itemize} \pnum -If no characters are stored in \tcode{str}, calls +If \tcode{N > 0} and no characters are stored in \tcode{str}, calls \tcode{is.setstate(ios_base::failbit)} (which may throw \tcode{ios_base::failure}\iref{iostate.flags}). @@ -6574,22 +6415,28 @@ // \ref{allocator.uses.construction}, uses-allocator construction template - auto uses_allocator_construction_args(const Alloc& alloc, Args&&... args) -> @\seebelow@; + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + Args&&... args) noexcept -> @\seebelow@; template - auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t, - Tuple1&& x, Tuple2&& y) -> @\seebelow@; + constexpr auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t, + Tuple1&& x, Tuple2&& y) + noexcept -> @\seebelow@; template - auto uses_allocator_construction_args(const Alloc& alloc) -> @\seebelow@; + constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept -> @\seebelow@; template - auto uses_allocator_construction_args(const Alloc& alloc, U&& u, V&& v) -> @\seebelow@; + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + U&& u, V&& v) noexcept -> @\seebelow@; template - auto uses_allocator_construction_args(const Alloc& alloc, const pair& pr) -> @\seebelow@; + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + const pair& pr) noexcept -> @\seebelow@; template - auto uses_allocator_construction_args(const Alloc& alloc, pair&& pr) -> @\seebelow@; + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + pair&& pr) noexcept -> @\seebelow@; template - T make_obj_using_allocator(const Alloc& alloc, Args&&... args); + constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args); template - T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc, Args&&... args); + constexpr T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc, + Args&&... args); // \ref{allocator.traits}, allocator traits template struct allocator_traits; @@ -6597,9 +6444,7 @@ // \ref{default.allocator}, the default allocator template class allocator; template - bool operator==(const allocator&, const allocator&) noexcept; - template - bool operator!=(const allocator&, const allocator&) noexcept; + constexpr bool operator==(const allocator&, const allocator&) noexcept; // \ref{specialized.algorithms}, specialized algorithms // \ref{special.mem.concepts}, special memory concepts @@ -6631,14 +6476,14 @@ namespace ranges { template<@\placeholdernc{no-throw-forward-iterator}@ I, @\placeholdernc{no-throw-sentinel}@ S> - requires DefaultConstructible> + requires default_constructible> I uninitialized_default_construct(I first, S last); template<@\placeholdernc{no-throw-forward-range}@ R> - requires DefaultConstructible>> + requires default_constructible> safe_iterator_t uninitialized_default_construct(R&& r); template<@\placeholdernc{no-throw-forward-iterator}@ I> - requires DefaultConstructible> + requires default_constructible> I uninitialized_default_construct_n(I first, iter_difference_t n); } @@ -6655,14 +6500,14 @@ namespace ranges { template<@\placeholdernc{no-throw-forward-iterator}@ I, @\placeholdernc{no-throw-sentinel}@ S> - requires DefaultConstructible> + requires default_constructible> I uninitialized_value_construct(I first, S last); template<@\placeholdernc{no-throw-forward-range}@ R> - requires DefaultConstructible>> + requires default_constructible> safe_iterator_t uninitialized_value_construct(R&& r); template<@\placeholdernc{no-throw-forward-iterator}@ I> - requires DefaultConstructible> + requires default_constructible> I uninitialized_value_construct_n(I first, iter_difference_t n); } @@ -6684,20 +6529,20 @@ namespace ranges { template using uninitialized_copy_result = copy_result; - template S1, + template S1, @\placeholdernc{no-throw-forward-iterator}@ O, @\placeholdernc{no-throw-sentinel}@ S2> - requires Constructible, iter_reference_t> + requires constructible_from, iter_reference_t> uninitialized_copy_result uninitialized_copy(I ifirst, S1 ilast, O ofirst, S2 olast); - template - requires Constructible>, iter_reference_t>> + template + requires constructible_from, range_reference_t> uninitialized_copy_result, safe_iterator_t> - uninitialized_copy(IR&& input_range, OR&& output_range); + uninitialized_copy(IR&& in_range, OR&& out_range); template using uninitialized_copy_n_result = uninitialized_copy_result; - template S> - requires Constructible, iter_reference_t> + template S> + requires constructible_from, iter_reference_t> uninitialized_copy_n_result uninitialized_copy_n(I ifirst, iter_difference_t n, O ofirst, S olast); } @@ -6720,22 +6565,21 @@ namespace ranges { template using uninitialized_move_result = uninitialized_copy_result; - template S1, + template S1, @\placeholdernc{no-throw-forward-iterator}@ O, @\placeholdernc{no-throw-sentinel}@ S2> - requires Constructible, iter_rvalue_reference_t> + requires constructible_from, iter_rvalue_reference_t> uninitialized_move_result uninitialized_move(I ifirst, S1 ilast, O ofirst, S2 olast); - template - requires Constructible>, - iter_rvalue_reference_t>> + template + requires constructible_from, range_rvalue_reference_t> uninitialized_move_result, safe_iterator_t> - uninitialized_move(IR&& input_range, OR&& output_range); + uninitialized_move(IR&& in_range, OR&& out_range); template using uninitialized_move_n_result = uninitialized_copy_result; - template S> - requires Constructible, iter_rvalue_reference_t> + requires constructible_from, iter_rvalue_reference_t> uninitialized_move_n_result uninitialized_move_n(I ifirst, iter_difference_t n, O ofirst, S olast); } @@ -6753,44 +6597,54 @@ namespace ranges { template<@\placeholdernc{no-throw-forward-iterator}@ I, @\placeholdernc{no-throw-sentinel}@ S, class T> - requires Constructible, const T&> + requires constructible_from, const T&> I uninitialized_fill(I first, S last, const T& x); template<@\placeholdernc{no-throw-forward-range}@ R, class T> - requires Constructible>, const T&> + requires constructible_from, const T&> safe_iterator_t uninitialized_fill(R&& r, const T& x); template<@\placeholdernc{no-throw-forward-iterator}@ I, class T> - requires Constructible, const T&> + requires constructible_from, const T&> I uninitialized_fill_n(I first, iter_difference_t n, const T& x); } + // \ref{specialized.construct}, \tcode{construct_at} + template + constexpr T* construct_at(T* location, Args&&... args); + + namespace ranges { + template + constexpr T* construct_at(T* location, Args&&... args); + } + + // \ref{specialized.destroy}, \tcode{destroy} template - void destroy_at(T* location); + constexpr void destroy_at(T* location); template - void destroy(ForwardIterator first, ForwardIterator last); + constexpr void destroy(ForwardIterator first, ForwardIterator last); template - void destroy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - ForwardIterator first, ForwardIterator last); + constexpr void destroy(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator first, ForwardIterator last); template - ForwardIterator destroy_n(ForwardIterator first, Size n); + constexpr ForwardIterator destroy_n(ForwardIterator first, Size n); template - ForwardIterator destroy_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} - ForwardIterator first, Size n); + constexpr ForwardIterator destroy_n(ExecutionPolicy&& exec, // see \ref{algorithms.parallel.overloads} + ForwardIterator first, Size n); namespace ranges { - template - void destroy_at(T* location) noexcept; + template + constexpr void destroy_at(T* location) noexcept; template<@\placeholdernc{no-throw-input-iterator}@ I, @\placeholdernc{no-throw-sentinel}@ S> - requires Destructible> - I destroy(I first, S last) noexcept; + requires destructible> + constexpr I destroy(I first, S last) noexcept; template<@\placeholdernc{no-throw-input-range}@ R> - requires Destructible> - safe_iterator_t destroy(R&& r) noexcept; + requires destructible> + constexpr safe_iterator_t destroy(R&& r) noexcept; template<@\placeholdernc{no-throw-input-iterator}@ I> - requires Destructible> - I destroy_n(I first, iter_difference_t n) noexcept; + requires destructible> + constexpr I destroy_n(I first, iter_difference_t n) noexcept; } // \ref{unique.ptr}, class template \tcode{unique_ptr} @@ -6818,8 +6672,6 @@ template bool operator==(const unique_ptr& x, const unique_ptr& y); - template - bool operator!=(const unique_ptr& x, const unique_ptr& y); template bool operator<(const unique_ptr& x, const unique_ptr& y); template @@ -6828,15 +6680,15 @@ bool operator<=(const unique_ptr& x, const unique_ptr& y); template bool operator>=(const unique_ptr& x, const unique_ptr& y); + template + requires three_way_comparable_with::pointer, + typename unique_ptr::pointer> + compare_three_way_result_t::pointer, + typename unique_ptr::pointer> + operator<=>(const unique_ptr& x, const unique_ptr& y); template bool operator==(const unique_ptr& x, nullptr_t) noexcept; - template - bool operator==(nullptr_t, const unique_ptr& y) noexcept; - template - bool operator!=(const unique_ptr& x, nullptr_t) noexcept; - template - bool operator!=(nullptr_t, const unique_ptr& y) noexcept; template bool operator<(const unique_ptr& x, nullptr_t); template @@ -6853,6 +6705,10 @@ bool operator>=(const unique_ptr& x, nullptr_t); template bool operator>=(nullptr_t, const unique_ptr& y); + template + requires three_way_comparable_with::pointer, nullptr_t> + compare_three_way_result_t::pointer, nullptr_t> + operator<=>(const unique_ptr& x, nullptr_t); template basic_ostream& operator<<(basic_ostream& os, const unique_ptr& p); @@ -6904,40 +6760,12 @@ template bool operator==(const shared_ptr& a, const shared_ptr& b) noexcept; template - bool operator!=(const shared_ptr& a, const shared_ptr& b) noexcept; - template - bool operator<(const shared_ptr& a, const shared_ptr& b) noexcept; - template - bool operator>(const shared_ptr& a, const shared_ptr& b) noexcept; - template - bool operator<=(const shared_ptr& a, const shared_ptr& b) noexcept; - template - bool operator>=(const shared_ptr& a, const shared_ptr& b) noexcept; + strong_ordering operator<=>(const shared_ptr& a, const shared_ptr& b) noexcept; template bool operator==(const shared_ptr& x, nullptr_t) noexcept; template - bool operator==(nullptr_t, const shared_ptr& y) noexcept; - template - bool operator!=(const shared_ptr& x, nullptr_t) noexcept; - template - bool operator!=(nullptr_t, const shared_ptr& y) noexcept; - template - bool operator<(const shared_ptr& x, nullptr_t) noexcept; - template - bool operator<(nullptr_t, const shared_ptr& y) noexcept; - template - bool operator>(const shared_ptr& x, nullptr_t) noexcept; - template - bool operator>(nullptr_t, const shared_ptr& y) noexcept; - template - bool operator<=(const shared_ptr& x, nullptr_t) noexcept; - template - bool operator<=(nullptr_t, const shared_ptr& y) noexcept; - template - bool operator>=(const shared_ptr& x, nullptr_t) noexcept; - template - bool operator>=(nullptr_t, const shared_ptr& y) noexcept; + strong_ordering operator<=>(const shared_ptr& x, nullptr_t) noexcept; // \ref{util.smartptr.shared.spec}, \tcode{shared_ptr} specialized algorithms template @@ -7442,7 +7270,8 @@ \indexlibrary{\idxcode{uses_allocator_construction_args}}% \begin{itemdecl} template - auto uses_allocator_construction_args(const Alloc& alloc, Args&&... args) -> @\seebelow@; + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + Args&&... args) noexcept -> @\seebelow@; \end{itemdecl} \begin{itemdescr} @@ -7460,7 +7289,7 @@ return \tcode{forward_as_tuple(std::forward(args)...)}. \item Otherwise, if \tcode{uses_allocator_v} is \tcode{true} and - \tcode{is_constructible_v} + \tcode{is_constructible_v} is \tcode{true}, return \begin{codeblock} @@ -7469,7 +7298,7 @@ \end{codeblock} \item Otherwise, if \tcode{uses_allocator_v} is \tcode{true} and - \tcode{is_constructible_v} is \tcode{true}, + \tcode{is_constructible_v} is \tcode{true}, return \tcode{forward_as_tuple(std::forward(args)..., alloc)}. \item Otherwise, the program is ill-formed. @@ -7484,8 +7313,9 @@ \indexlibrary{\idxcode{uses_allocator_construction_args}}% \begin{itemdecl} template - auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t, - Tuple1&& x, Tuple2&& y) -> @\seebelow@; + constexpr auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t, + Tuple1&& x, Tuple2&& y) + noexcept -> @\seebelow@; \end{itemdecl} \begin{itemdescr} @@ -7513,7 +7343,7 @@ \indexlibrary{\idxcode{uses_allocator_construction_args}}% \begin{itemdecl} template - auto uses_allocator_construction_args(const Alloc& alloc) -> @\seebelow@; + constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept -> @\seebelow@; \end{itemdecl} \begin{itemdescr} @@ -7533,7 +7363,8 @@ \indexlibrary{\idxcode{uses_allocator_construction_args}}% \begin{itemdecl} template - auto uses_allocator_construction_args(const Alloc& alloc, U&& u, V&& v) -> @\seebelow@; + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + U&& u, V&& v) noexcept -> @\seebelow@; \end{itemdecl} \begin{itemdescr} @@ -7554,7 +7385,8 @@ \indexlibrary{\idxcode{uses_allocator_construction_args}}% \begin{itemdecl} template - auto uses_allocator_construction_args(const Alloc& alloc, const pair& pr) -> @\seebelow@; + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + const pair& pr) noexcept -> @\seebelow@; \end{itemdecl} \begin{itemdescr} @@ -7575,7 +7407,8 @@ \indexlibrary{\idxcode{uses_allocator_construction_args}}% \begin{itemdecl} template - auto uses_allocator_construction_args(const Alloc& alloc, pair&& pr) -> @\seebelow@; + constexpr auto uses_allocator_construction_args(const Alloc& alloc, + pair&& pr) noexcept -> @\seebelow@; \end{itemdecl} \begin{itemdescr} @@ -7596,7 +7429,7 @@ \indexlibrary{\idxcode{make_obj_using_allocator}}% \begin{itemdecl} template - T make_obj_using_allocator(const Alloc& alloc, Args&&... args); + constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -7612,7 +7445,7 @@ \indexlibrary{\idxcode{uninitialized_construct_using_allocator}}% \begin{itemdecl} template - T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc, Args&&... args); + constexpr T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -7658,20 +7491,21 @@ template using rebind_alloc = @\seebelow@; template using rebind_traits = allocator_traits>; - [[nodiscard]] static pointer allocate(Alloc& a, size_type n); - [[nodiscard]] static pointer allocate(Alloc& a, size_type n, const_void_pointer hint); + [[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n); + [[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n, + const_void_pointer hint); - static void deallocate(Alloc& a, pointer p, size_type n); + static constexpr void deallocate(Alloc& a, pointer p, size_type n); template - static void construct(Alloc& a, T* p, Args&&... args); + static constexpr void construct(Alloc& a, T* p, Args&&... args); template - static void destroy(Alloc& a, T* p); + static constexpr void destroy(Alloc& a, T* p); - static size_type max_size(const Alloc& a) noexcept; + static constexpr size_type max_size(const Alloc& a) noexcept; - static Alloc select_on_container_copy_construction(const Alloc& rhs); + static constexpr Alloc select_on_container_copy_construction(const Alloc& rhs); }; } \end{codeblock} @@ -7826,7 +7660,7 @@ \indexlibrarymember{allocate}{allocator_traits}% \begin{itemdecl} -[[nodiscard]] static pointer allocate(Alloc& a, size_type n); +[[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n); \end{itemdecl} \begin{itemdescr} @@ -7836,7 +7670,7 @@ \indexlibrarymember{allocate}{allocator_traits}% \begin{itemdecl} -[[nodiscard]] static pointer allocate(Alloc& a, size_type n, const_void_pointer hint); +[[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n, const_void_pointer hint); \end{itemdecl} \begin{itemdescr} @@ -7846,7 +7680,7 @@ \indexlibrarymember{deallocate}{allocator_traits}% \begin{itemdecl} -static void deallocate(Alloc& a, pointer p, size_type n); +static constexpr void deallocate(Alloc& a, pointer p, size_type n); \end{itemdecl} \begin{itemdescr} @@ -7860,31 +7694,31 @@ \indexlibrarymember{construct}{allocator_traits}% \begin{itemdecl} template - static void construct(Alloc& a, T* p, Args&&... args); + static constexpr void construct(Alloc& a, T* p, Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum \effects Calls \tcode{a.construct(p, std::forward(args)...)} if that call is well-formed; -otherwise, invokes \tcode{::new (static_cast(p)) T(std::forward(args)...)}. +otherwise, invokes \tcode{construct_at(p, std::forward(args)...)}. \end{itemdescr} \indexlibrarymember{destroy}{allocator_traits}% \begin{itemdecl} template - static void destroy(Alloc& a, T* p); + static constexpr void destroy(Alloc& a, T* p); \end{itemdecl} \begin{itemdescr} \pnum \effects Calls \tcode{a.destroy(p)} if that call is well-formed; otherwise, invokes -\tcode{p->\~{}T()}. +\tcode{destroy_at(p)}. \end{itemdescr} \indexlibrarymember{max_size}{allocator_traits}% \begin{itemdecl} -static size_type max_size(const Alloc& a) noexcept; +static constexpr size_type max_size(const Alloc& a) noexcept; \end{itemdecl} \begin{itemdescr} @@ -7895,7 +7729,7 @@ \indexlibrarymember{select_on_container_copy_construction}{allocator_traits}% \begin{itemdecl} -static Alloc select_on_container_copy_construction(const Alloc& rhs); +static constexpr Alloc select_on_container_copy_construction(const Alloc& rhs); \end{itemdecl} \begin{itemdescr} @@ -7930,11 +7764,11 @@ constexpr allocator() noexcept; constexpr allocator(const allocator&) noexcept; template constexpr allocator(const allocator&) noexcept; - ~allocator(); - allocator& operator=(const allocator&) = default; + constexpr ~allocator(); + constexpr allocator& operator=(const allocator&) = default; - [[nodiscard]] T* allocate(size_t n); - void deallocate(T* p, size_t n); + [[nodiscard]] constexpr T* allocate(size_t n); + constexpr void deallocate(T* p, size_t n); }; } \end{codeblock} @@ -7950,7 +7784,7 @@ \indexlibrarymember{allocate}{allocator}% \begin{itemdecl} -[[nodiscard]] T* allocate(size_t n); +[[nodiscard]] constexpr T* allocate(size_t n); \end{itemdecl} \begin{itemdescr} @@ -7972,7 +7806,7 @@ \indexlibrarymember{deallocate}{allocator}% \begin{itemdecl} -void deallocate(T* p, size_t n); +constexpr void deallocate(T* p, size_t n); \end{itemdecl} \begin{itemdescr} @@ -7999,7 +7833,7 @@ \indexlibrarymember{operator==}{allocator}% \begin{itemdecl} template - bool operator==(const allocator&, const allocator&) noexcept; + constexpr bool operator==(const allocator&, const allocator&) noexcept; \end{itemdecl} \begin{itemdescr} @@ -8008,18 +7842,6 @@ \tcode{true}. \end{itemdescr} -\indexlibrarymember{operator"!=}{allocator}% -\begin{itemdecl} -template - bool operator!=(const allocator&, const allocator&) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{false}. -\end{itemdescr} - \rSec2[specialized.algorithms]{Specialized algorithms} \pnum @@ -8064,9 +7886,9 @@ unqualified\iref{basic.lookup.unqual} name lookup for the \grammarterm{postfix-expression} in a function call\iref{expr.call}, they inhibit argument-dependent name lookup. -\item Overloads of algorithms that take \libconcept{Range} arguments\iref{range.range} +\item Overloads of algorithms that take \libconcept{range} arguments\iref{range.range} behave as if they are implemented by calling \tcode{ranges::begin} - and \tcode{ranges::end} on the \libconcept{Range}(s) and dispatching to the + and \tcode{ranges::end} on the \libconcept{range}(s) and dispatching to the overload that takes separate iterator and sentinel arguments. \item The number and order of deducible template parameters for algorithm declarations is unspecified, except where explicitly stated otherwise. @@ -8089,7 +7911,7 @@ \tcode{\placeholdernc{voidify}}: \begin{codeblock} template - void* @\placeholdernc{voidify}@(T& obj) noexcept { + constexpr void* @\placeholdernc{voidify}@(T& obj) noexcept { return const_cast(static_cast(addressof(obj))); } \end{codeblock} @@ -8102,10 +7924,10 @@ \begin{itemdecl} template -concept @\placeholdernc{no-throw-input-iterator}@ = // exposition only - InputIterator && +concept @\placeholdernc{no-throw-input-iterator}@ = // \expos + input_iterator && is_lvalue_reference_v> && - Same>, iter_value_t>; + same_as>, iter_value_t>; \end{itemdecl} \begin{itemdescr} @@ -8118,14 +7940,14 @@ \pnum \begin{note} -This concept allows some \tcode{InputIterator}\iref{iterator.concept.input} +This concept allows some \libconcept{input_iterator}\iref{iterator.concept.input} operations to throw exceptions. \end{note} \end{itemdescr} \begin{itemdecl} template -concept @\placeholdernc{no-throw-sentinel}@ = Sentinel; // exposition only +concept @\placeholdernc{no-throw-sentinel}@ = sentinel_for; // \expos \end{itemdecl} \begin{itemdescr} @@ -8137,15 +7959,15 @@ \pnum \begin{note} -This concept allows some \tcode{Sentinel}\iref{iterator.concept.sentinel} +This concept allows some \libconcept{sentinel_for}\iref{iterator.concept.sentinel} operations to throw exceptions. \end{note} \end{itemdescr} \begin{itemdecl} template -concept @\placeholdernc{no-throw-input-range}@ = // exposition only - Range && +concept @\placeholdernc{no-throw-input-range}@ = // \expos + range && @\placeholder{no-throw-input-iterator}@> && @\placeholdernc{no-throw-sentinel}@, iterator_t>; \end{itemdecl} @@ -8159,23 +7981,23 @@ \begin{itemdecl} template -concept @\placeholdernc{no-throw-forward-iterator}@ = // exposition only +concept @\placeholdernc{no-throw-forward-iterator}@ = // \expos @\placeholder{no-throw-input-iterator}@ && - ForwardIterator && + forward_iterator && @\placeholdernc{no-throw-sentinel}@; \end{itemdecl} \begin{itemdescr} \pnum \begin{note} -This concept allows some \tcode{ForwardIterator}\iref{iterator.concept.forward} +This concept allows some \libconcept{forward_iterator}\iref{iterator.concept.forward} operations to throw exceptions. \end{note} \end{itemdescr} \begin{itemdecl} template -concept @\placeholdernc{no-throw-forward-range}@ = // exposition only +concept @\placeholdernc{no-throw-forward-range}@ = // \expos @\placeholder{no-throw-input-range}@ && @\placeholder{no-throw-forward-iterator}@>; \end{itemdecl} @@ -8221,10 +8043,10 @@ \begin{itemdecl} namespace ranges { template<@\placeholdernc{no-throw-forward-iterator}@ I, @\placeholdernc{no-throw-sentinel}@ S> - requires DefaultConstructible> + requires default_constructible> I uninitialized_default_construct(I first, S last); template<@\placeholdernc{no-throw-forward-range}@ R> - requires DefaultConstructible>> + requires default_constructible> safe_iterator_t uninitialized_default_construct(R&& r); } \end{itemdecl} @@ -8261,7 +8083,7 @@ \begin{itemdecl} namespace ranges { template<@\placeholdernc{no-throw-forward-iterator}@ I> - requires DefaultConstructible> + requires default_constructible> I uninitialized_default_construct_n(I first, iter_difference_t n); } \end{itemdecl} @@ -8298,10 +8120,10 @@ \begin{itemdecl} namespace ranges { template<@\placeholdernc{no-throw-forward-iterator}@ I, @\placeholdernc{no-throw-sentinel}@ S> - requires DefaultConstructible> + requires default_constructible> I uninitialized_value_construct(I first, S last); template<@\placeholdernc{no-throw-forward-range}@ R> - requires DefaultConstructible>> + requires default_constructible> safe_iterator_t uninitialized_value_construct(R&& r); } \end{itemdecl} @@ -8338,7 +8160,7 @@ \begin{itemdecl} namespace ranges { template<@\placeholdernc{no-throw-forward-iterator}@ I> - requires DefaultConstructible> + requires default_constructible> I uninitialized_value_construct_n(I first, iter_difference_t n); } \end{itemdecl} @@ -8383,15 +8205,15 @@ \indexlibrary{\idxcode{uninitialized_copy}}% \begin{itemdecl} namespace ranges { - template S1, + template S1, @\placeholdernc{no-throw-forward-iterator}@ O, @\placeholdernc{no-throw-sentinel}@ S2> - requires Constructible, iter_reference_t> + requires constructible_from, iter_reference_t> uninitialized_copy_result uninitialized_copy(I ifirst, S1 ilast, O ofirst, S2 olast); - template - requires Constructible>, iter_reference_t>> + template + requires constructible_from, range_reference_t> uninitialized_copy_result, safe_iterator_t> - uninitialized_copy(IR&& input_range, OR&& output_range); + uninitialized_copy(IR&& in_range, OR&& out_range); } \end{itemdecl} @@ -8438,8 +8260,8 @@ \indexlibrary{\idxcode{uninitialized_copy_n}}% \begin{itemdecl} namespace ranges { - template S> - requires Constructible, iter_reference_t> + template S> + requires constructible_from, iter_reference_t> uninitialized_copy_n_result uninitialized_copy_n(I ifirst, iter_difference_t n, O ofirst, S olast); } @@ -8488,15 +8310,15 @@ \indexlibrary{\idxcode{uninitialized_move}}% \begin{itemdecl} namespace ranges { - template S1, + template S1, @\placeholdernc{no-throw-forward-iterator}@ O, @\placeholdernc{no-throw-sentinel}@ S2> - requires Constructible, iter_rvalue_reference_t> + requires constructible_from, iter_rvalue_reference_t> uninitialized_move_result uninitialized_move(I ifirst, S1 ilast, O ofirst, S2 olast); - template - requires Constructible>, iter_rvalue_reference_t>> + template + requires constructible_from, range_rvalue_reference_t> uninitialized_move_result, safe_iterator_t> - uninitialized_move(IR&& input_range, OR&& output_range); + uninitialized_move(IR&& in_range, OR&& out_range); } \end{itemdecl} @@ -8548,8 +8370,8 @@ \indexlibrary{\idxcode{uninitialized_move_n}}% \begin{itemdecl} namespace ranges { - template S> - requires Constructible, iter_rvalue_reference_t> + template S> + requires constructible_from, iter_rvalue_reference_t> uninitialized_move_n_result uninitialized_move_n(I ifirst, iter_difference_t n, O ofirst, S olast); } @@ -8600,10 +8422,10 @@ \begin{itemdecl} namespace ranges { template<@\placeholdernc{no-throw-forward-iterator}@ I, @\placeholdernc{no-throw-sentinel}@ S, class T> - requires Constructible, const T&> + requires constructible_from, const T&> I uninitialized_fill(I first, S last, const T& x); template<@\placeholdernc{no-throw-forward-range}@ R, class T> - requires Constructible>, const T&> + requires constructible_from, const T&> safe_iterator_t uninitialized_fill(R&& r, const T& x); } \end{itemdecl} @@ -8640,7 +8462,7 @@ \begin{itemdecl} namespace ranges { template<@\placeholdernc{no-throw-forward-iterator}@ I, class T> - requires Constructible, const T&> + requires constructible_from, const T&> I uninitialized_fill_n(I first, iter_difference_t n, const T& x); } \end{itemdecl} @@ -8653,22 +8475,49 @@ \end{codeblock} \end{itemdescr} -\rSec3[specialized.destroy]{\tcode{destroy}} +\rSec3[specialized.construct]{\tcode{construct_at}} -\indexlibrary{\idxcode{destroy_at}}% +\indexlibrary{\idxcode{construct_at}} \begin{itemdecl} -template - void destroy_at(T* location); +template + constexpr T* construct_at(T* location, Args&&... args); + namespace ranges { - template - void destroy_at(T* location) noexcept; + template + constexpr T* construct_at(T* location, Args&&... args); } \end{itemdecl} \begin{itemdescr} \pnum -\effects -\begin{itemize} +\constraints +The expression \tcode{::new (declval()) T(declval()...)} +is well-formed when treated as an unevaluated operand. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +return ::new (@\placeholdernc{voidify}@(*location)) T(std::forward(args)...); +\end{codeblock} +\end{itemdescr} + +\rSec3[specialized.destroy]{\tcode{destroy}} + +\indexlibrary{\idxcode{destroy_at}}% +\begin{itemdecl} +template + constexpr void destroy_at(T* location); +namespace ranges { + template + constexpr void destroy_at(T* location) noexcept; +} +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +\begin{itemize} \item If \tcode{T} is an array type, equivalent to \tcode{destroy(begin(*location), end(*location))}. \item Otherwise, equivalent to @@ -8679,7 +8528,7 @@ \indexlibrary{\idxcode{destroy}}% \begin{itemdecl} template - void destroy(ForwardIterator first, ForwardIterator last); + constexpr void destroy(ForwardIterator first, ForwardIterator last); \end{itemdecl} \begin{itemdescr} @@ -8696,11 +8545,11 @@ \begin{itemdecl} namespace ranges { template<@\placeholdernc{no-throw-input-iterator}@ I, @\placeholdernc{no-throw-sentinel}@ S> - requires Destructible> - I destroy(I first, S last) noexcept; + requires destructible> + constexpr I destroy(I first, S last) noexcept; template<@\placeholdernc{no-throw-input-range}@ R> - requires Destructible>> - safe_iterator_t destroy(R&& r) noexcept; + requires destructible> + constexpr safe_iterator_t destroy(R&& r) noexcept; } \end{itemdecl} @@ -8717,7 +8566,7 @@ \indexlibrary{\idxcode{destroy_n}}% \begin{itemdecl} template - ForwardIterator destroy_n(ForwardIterator first, Size n); + constexpr ForwardIterator destroy_n(ForwardIterator first, Size n); \end{itemdecl} \begin{itemdescr} @@ -8735,8 +8584,8 @@ \begin{itemdecl} namespace ranges { template<@\placeholdernc{no-throw-input-iterator}@ I> - requires Destructible> - I destroy_n(I first, iter_difference_t n) noexcept; + requires destructible> + constexpr I destroy_n(I first, iter_difference_t n) noexcept; } \end{itemdecl} @@ -9143,6 +8992,9 @@ \end{itemdecl} \begin{itemdescr} +\pnum +\constraints \tcode{is_move_constructible_v} is \tcode{true}. + \pnum \requires If \tcode{D} is not a reference type, \tcode{D} shall meet the \oldconcept{MoveConstructible} @@ -9233,6 +9085,9 @@ \end{itemdecl} \begin{itemdescr} +\pnum +\constraints \tcode{is_move_assignable_v} is \tcode{true}. + \pnum \requires If \tcode{D} is not a reference type, \tcode{D} shall meet the \oldconcept{MoveAssignable} requirements (\tref{cpp17.moveassignable}) and assignment @@ -9758,17 +9613,6 @@ \returns \tcode{x.get() == y.get()}. \end{itemdescr} -\indexlibrarymember{operator"!=}{unique_ptr}% -\begin{itemdecl} -template - bool operator!=(const unique_ptr& x, const unique_ptr& y); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{x.get() != y.get()}. -\end{itemdescr} - \indexlibrarymember{operator<}{unique_ptr}% \begin{itemdecl} template @@ -9828,30 +9672,31 @@ \returns \tcode{!(x < y)}. \end{itemdescr} -\indexlibrarymember{operator==}{unique_ptr}% +\indexlibrarymember{operator<=>}{unique_ptr}% \begin{itemdecl} -template - bool operator==(const unique_ptr& x, nullptr_t) noexcept; -template - bool operator==(nullptr_t, const unique_ptr& x) noexcept; +template + requires three_way_comparable_with::pointer, + typename unique_ptr::pointer> + compare_three_way_result_t::pointer, + typename unique_ptr::pointer> + operator<=>(const unique_ptr& x, const unique_ptr& y); \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{!x}. +\returns +\tcode{compare_three_way()(x.get(), y.get())}. \end{itemdescr} -\indexlibrarymember{operator"!=}{unique_ptr}% +\indexlibrarymember{operator==}{unique_ptr}% \begin{itemdecl} template - bool operator!=(const unique_ptr& x, nullptr_t) noexcept; -template - bool operator!=(nullptr_t, const unique_ptr& x) noexcept; + bool operator==(const unique_ptr& x, nullptr_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -\returns \tcode{(bool)x}. +\returns \tcode{!x}. \end{itemdescr} \indexlibrarymember{operator<}{unique_ptr}% @@ -9925,6 +9770,20 @@ The second function template returns \tcode{!(nullptr < x)}. \end{itemdescr} +\indexlibrarymember{operator<=>}{unique_ptr}% +\begin{itemdecl} +template + requires three_way_comparable_with::pointer, nullptr_t> + compare_three_way_result_t::pointer, nullptr_t> + operator<=>(const unique_ptr& x, nullptr_t); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{compare_three_way()(x.get(), nullptr)}. +\end{itemdescr} + \rSec3[unique.ptr.io]{I/O} \indexlibrarymember{operator<<}{unique_ptr}% @@ -10933,29 +10792,10 @@ \returns \tcode{a.get() == b.get()}. \end{itemdescr} -\indexlibrarymember{operator<}{shared_ptr}% -\begin{itemdecl} -template - bool operator<(const shared_ptr& a, const shared_ptr& b) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{less<>()(a.get(), b.get())}. - -\pnum -\begin{note} -Defining a comparison function allows \tcode{shared_ptr} objects to be -used as keys in associative containers. -\end{note} -\end{itemdescr} - \indexlibrarymember{operator==}{shared_ptr}% \begin{itemdecl} template bool operator==(const shared_ptr& a, nullptr_t) noexcept; -template - bool operator==(nullptr_t, const shared_ptr& a) noexcept; \end{itemdecl} \begin{itemdescr} @@ -10963,83 +10803,34 @@ \returns \tcode{!a}. \end{itemdescr} -\indexlibrarymember{operator"!=}{shared_ptr}% -\begin{itemdecl} -template - bool operator!=(const shared_ptr& a, nullptr_t) noexcept; -template - bool operator!=(nullptr_t, const shared_ptr& a) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{(bool)a}. -\end{itemdescr} - -\indexlibrarymember{operator<}{shared_ptr}% -\begin{itemdecl} -template - bool operator<(const shared_ptr& a, nullptr_t) noexcept; -template - bool operator<(nullptr_t, const shared_ptr& a) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The first function template returns -\begin{codeblock} -less::element_type*>()(a.get(), nullptr) -\end{codeblock} -The second function template returns -\begin{codeblock} -less::element_type*>()(nullptr, a.get()) -\end{codeblock} -\end{itemdescr} - -\indexlibrarymember{operator>}{shared_ptr}% +\indexlibrarymember{operator<=>}{shared_ptr}% \begin{itemdecl} -template - bool operator>(const shared_ptr& a, nullptr_t) noexcept; -template - bool operator>(nullptr_t, const shared_ptr& a) noexcept; +template + strong_ordering operator<=>(const shared_ptr& a, const shared_ptr& b) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -The first function template returns \tcode{nullptr < a}. -The second function template returns \tcode{a < nullptr}. -\end{itemdescr} +\tcode{compare_three_way()(a.get(), b.get())}. -\indexlibrarymember{operator<=}{shared_ptr}% -\begin{itemdecl} -template - bool operator<=(const shared_ptr& a, nullptr_t) noexcept; -template - bool operator<=(nullptr_t, const shared_ptr& a) noexcept; -\end{itemdecl} - -\begin{itemdescr} \pnum -\returns -The first function template returns \tcode{!(nullptr < a)}. -The second function template returns \tcode{!(a < nullptr)}. +\begin{note} +Defining a comparison function allows \tcode{shared_ptr} objects +to be used as keys in associative containers. +\end{note} \end{itemdescr} -\indexlibrarymember{operator>=}{shared_ptr}% +\indexlibrarymember{operator<=>}{shared_ptr}% \begin{itemdecl} template - bool operator>=(const shared_ptr& a, nullptr_t) noexcept; -template - bool operator>=(nullptr_t, const shared_ptr& a) noexcept; + strong_ordering operator<=>(const shared_ptr& a, nullptr_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns -The first function template returns \tcode{!(a < nullptr)}. -The second function template returns \tcode{!(nullptr < a)}. +\tcode{compare_three_way()(a.get(), nullptr)}. \end{itemdescr} \rSec3[util.smartptr.shared.spec]{Specialized algorithms} @@ -11678,6 +11469,10 @@ bool compare_exchange_strong(shared_ptr& expected, shared_ptr desired, memory_order order = memory_order::seq_cst) noexcept; + void wait(shared_ptr old, memory_order order = memory_order::seq_cst) const noexcept; + void notify_one() noexcept; + void notify_all() noexcept; + constexpr atomic() noexcept = default; atomic(shared_ptr desired) noexcept; atomic(const atomic&) = delete; @@ -11892,6 +11687,70 @@ shall be replaced by the value \tcode{memory_order::relaxed}. \end{itemdescr} +\indexlibrarymember{wait}{atomic>}% +\begin{itemdecl} +void wait(shared_ptr old, memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{order} is +neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Repeatedly performs the following steps, in order: +\begin{itemize} +\item + Evaluates \tcode{load(order)} and compares it to \tcode{old}. +\item + If the two are not equivalent, returns. +\item + Blocks until it + is unblocked by an atomic notifying operation or is unblocked spuriously. +\end{itemize} + +\pnum +\remarks +Two \tcode{shared_ptr} objects are equivalent +if they store the same pointer and either share ownership or are both empty. +This function is an atomic waiting operation\iref{atomics.wait}. +\end{itemdescr} + +\indexlibrarymember{notify_one}{atomic>}% +\begin{itemdecl} +void notify_one() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Unblocks the execution of at least one atomic waiting operation +that is eligible to be unblocked\iref{atomics.wait} by this call, +if any such atomic waiting operations exist. + +\pnum +\remarks +This function is an atomic notifying operation\iref{atomics.wait}. +\end{itemdescr} + +\indexlibrarymember{notify_all}{atomic>}% +\begin{itemdecl} +void notify_all() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Unblocks the execution of all atomic waiting operations +that are eligible to be unblocked\iref{atomics.wait} by this call. + +\pnum +\remarks +This function is an atomic notifying operation\iref{atomics.wait}. +\end{itemdescr} + \rSec3[util.smartptr.atomic.weak]{Atomic specialization for \tcode{weak_ptr}} \indexlibrary{\idxcode{atomic>}}% \begin{codeblock} @@ -11918,6 +11777,10 @@ bool compare_exchange_strong(weak_ptr& expected, weak_ptr desired, memory_order order = memory_order::seq_cst) noexcept; + void wait(weak_ptr old, memory_order order = memory_order::seq_cst) const noexcept; + void notify_one() noexcept; + void notify_all() noexcept; + constexpr atomic() noexcept = default; atomic(weak_ptr desired) noexcept; atomic(const atomic&) = delete; @@ -12130,6 +11993,71 @@ a value of \tcode{memory_order::release} shall be replaced by the value \tcode{memory_order::relaxed}. \end{itemdescr} + +\indexlibrarymember{wait}{atomic>}% +\begin{itemdecl} +void wait(weak_ptr old, memory_order order = memory_order::seq_cst) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{order} is +neither \tcode{memory_order::release} nor \tcode{memory_order::acq_rel}. + +\pnum +\effects +Repeatedly performs the following steps, in order: +\begin{itemize} +\item + Evaluates \tcode{load(order)} and compares it to \tcode{old}. +\item + If the two are not equivalent, returns. +\item + Blocks until it + is unblocked by an atomic notifying operation or is unblocked spuriously. +\end{itemize} + +\pnum +\remarks +Two \tcode{weak_ptr} objects are equivalent +if they store the same pointer and either share ownership or are both empty. +This function is an atomic waiting operation\iref{atomics.wait}. +\end{itemdescr} + + +\indexlibrarymember{notify_one}{atomic>}% +\begin{itemdecl} +void notify_one() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Unblocks the execution of at least one atomic waiting operation +that is eligible to be unblocked\iref{atomics.wait} by this call, +if any such atomic waiting operations exist. + +\pnum +\remarks +This function is an atomic notifying operation\iref{atomics.wait}. +\end{itemdescr} + +\indexlibrarymember{notify_all}{atomic>}% +\begin{itemdecl} +void notify_all() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Unblocks the execution of all atomic waiting operations +that are eligible to be unblocked\iref{atomics.wait} by this call. + +\pnum +\remarks +This function is an atomic notifying operation\iref{atomics.wait}. +\end{itemdescr} \indextext{atomic smart pointers|)} \rSec1[mem.res]{Memory resources} @@ -12143,7 +12071,6 @@ class memory_resource; bool operator==(const memory_resource& a, const memory_resource& b) noexcept; - bool operator!=(const memory_resource& a, const memory_resource& b) noexcept; // \ref{mem.poly.allocator.class}, class template \tcode{polymorphic_allocator} template class polymorphic_allocator; @@ -12151,9 +12078,6 @@ template bool operator==(const polymorphic_allocator& a, const polymorphic_allocator& b) noexcept; - template - bool operator!=(const polymorphic_allocator& a, - const polymorphic_allocator& b) noexcept; // \ref{mem.res.global}, global memory resources memory_resource* new_delete_resource() noexcept; @@ -12324,17 +12248,6 @@ \tcode{\&a == \&b || a.is_equal(b)}. \end{itemdescr} -\indexlibrarymember{operator"!=}{memory_resource}% -\begin{itemdecl} -bool operator!=(const memory_resource& a, const memory_resource& b) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{!(a == b)}. -\end{itemdescr} - \rSec2[mem.poly.allocator.class]{Class template \tcode{polymorphic_allocator}} \pnum @@ -12675,20 +12588,6 @@ \tcode{*a.resource() == *b.resource()}. \end{itemdescr} -\indexlibrarymember{operator"!=}{polymorphic_allocator}% -\begin{itemdecl} -template - bool operator!=(const polymorphic_allocator& a, - const polymorphic_allocator& b) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{!(a == b)}. -\end{itemdescr} - - \rSec2[mem.res.global]{Access to program-wide \tcode{memory_resource} objects} \indexlibrary{\idxcode{new_delete_resource}}% @@ -13308,9 +13207,6 @@ template bool operator==(const scoped_allocator_adaptor& a, const scoped_allocator_adaptor& b) noexcept; - template - bool operator!=(const scoped_allocator_adaptor& a, - const scoped_allocator_adaptor& b) noexcept; } \end{codeblock} @@ -13724,18 +13620,6 @@ \end{codeblock} \end{itemdescr} -\indexlibrarymember{operator"!=}{scoped_allocator_adaptor}% -\begin{itemdecl} -template - bool operator!=(const scoped_allocator_adaptor& a, - const scoped_allocator_adaptor& b) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{!(a == b)}. -\end{itemdescr} - \rSec1[function.objects]{Function objects} \pnum @@ -13760,22 +13644,23 @@ namespace std { // \ref{func.invoke}, invoke template - invoke_result_t invoke(F&& f, Args&&... args) + constexpr invoke_result_t invoke(F&& f, Args&&... args) noexcept(is_nothrow_invocable_v); // \ref{refwrap}, \tcode{reference_wrapper} template class reference_wrapper; - template reference_wrapper ref(T&) noexcept; - template reference_wrapper cref(const T&) noexcept; + template constexpr reference_wrapper ref(T&) noexcept; + template constexpr reference_wrapper cref(const T&) noexcept; template void ref(const T&&) = delete; template void cref(const T&&) = delete; - template reference_wrapper ref(reference_wrapper) noexcept; - template reference_wrapper cref(reference_wrapper) noexcept; + template constexpr reference_wrapper ref(reference_wrapper) noexcept; + template constexpr reference_wrapper cref(reference_wrapper) noexcept; template struct unwrap_reference; - template struct unwrap_ref_decay : unwrap_reference> {}; + template using unwrap_reference_t = typename unwrap_reference::type; + template struct unwrap_ref_decay; template using unwrap_ref_decay_t = typename unwrap_ref_decay::type; // \ref{arithmetic.operations}, arithmetic operations @@ -13828,19 +13713,19 @@ struct identity; // \ref{func.not.fn}, function template \tcode{not_fn} - template @\unspec@ not_fn(F&& f); + template constexpr @\unspec@ not_fn(F&& f); // \ref{func.bind.front}, function template \tcode{bind_front} - template @\unspec@ bind_front(F&&, Args&&...); + template constexpr @\unspec@ bind_front(F&&, Args&&...); // \ref{func.bind}, bind template struct is_bind_expression; template struct is_placeholder; template - @\unspec@ bind(F&&, BoundArgs&&...); + constexpr @\unspec@ bind(F&&, BoundArgs&&...); template - @\unspec@ bind(F&&, BoundArgs&&...); + constexpr @\unspec@ bind(F&&, BoundArgs&&...); namespace placeholders { // \tcode{\placeholder{M}} is the \impldef{number of placeholders for bind expressions} number of placeholders @@ -13854,7 +13739,7 @@ // \ref{func.memfn}, member function adaptors template - @\unspec@ mem_fn(R T::*) noexcept; + constexpr @\unspec@ mem_fn(R T::*) noexcept; // \ref{func.wrap}, polymorphic function wrappers class bad_function_call; @@ -13867,12 +13752,6 @@ template bool operator==(const function&, nullptr_t) noexcept; - template - bool operator==(nullptr_t, const function&) noexcept; - template - bool operator!=(const function&, nullptr_t) noexcept; - template - bool operator!=(nullptr_t, const function&) noexcept; // \ref{func.search}, searchers template> @@ -14013,22 +13892,19 @@ \indextext{call wrapper}% \indextext{call wrapper!simple}% \indextext{call wrapper!forwarding}% -Every call wrapper\iref{func.def} is \oldconcept{MoveConstructible}. -A \defn{argument forwarding call wrapper} is a +Every call wrapper\iref{func.def} meets the \oldconcept{MoveConstructible} +and \oldconcept{Destructible} requirements. +An \defn{argument forwarding call wrapper} is a call wrapper that can be called with an arbitrary argument list and delivers the arguments to the wrapped callable object as references. This forwarding step delivers rvalue arguments as rvalue references and lvalue arguments as lvalue references. -A \defn{simple call wrapper} is an argument forwarding call wrapper that is -\oldconcept{CopyConstructible} and \oldconcept{CopyAssignable} and -whose copy constructor, move constructor, copy assignment operator, -and move assignment operator do not throw exceptions. \begin{note} In a typical implementation, argument forwarding call wrappers have an overloaded function call operator of the form \begin{codeblock} template - R operator()(UnBoundArgs&&... unbound_args) @\textit{cv-qual}@; + constexpr R operator()(UnBoundArgs&&... unbound_args) @\textit{cv-qual}@; \end{codeblock} \end{note} @@ -14055,7 +13931,13 @@ with references as described in the corresponding forwarding steps. \pnum -The copy/move constructor of a perfect forwarding call wrapper has +A \defn{simple call wrapper} is a perfect forwarding call wrapper that meets +the \oldconcept{CopyConstructible} and \oldconcept{CopyAssignable} requirements +and whose copy constructor, move constructor, and assignment operators +are constexpr functions that do not throw exceptions. + +\pnum +The copy/move constructor of an argument forwarding call wrapper has the same apparent semantics as if memberwise copy/move of its state entities were performed\iref{class.copy.ctor}. @@ -14067,7 +13949,7 @@ \end{note} \pnum -Perfect forwarding call wrappers returned by +Argument forwarding call wrappers returned by a given standard library function template have the same type if the types of their corresponding state entities are the same. @@ -14076,7 +13958,7 @@ \indexlibrary{invoke@\tcode{\placeholder{INVOKE}}}% \begin{itemdecl} template - invoke_result_t invoke(F&& f, Args&&... args) + constexpr invoke_result_t invoke(F&& f, Args&&... args) noexcept(is_nothrow_invocable_v); \end{itemdecl} @@ -14099,19 +13981,19 @@ // construct/copy/destroy template - reference_wrapper(U&&) noexcept(@\seebelow@); - reference_wrapper(const reference_wrapper& x) noexcept; + constexpr reference_wrapper(U&&) noexcept(@\seebelow@); + constexpr reference_wrapper(const reference_wrapper& x) noexcept; // assignment - reference_wrapper& operator=(const reference_wrapper& x) noexcept; + constexpr reference_wrapper& operator=(const reference_wrapper& x) noexcept; // access - operator T& () const noexcept; - T& get() const noexcept; + constexpr operator T& () const noexcept; + constexpr T& get() const noexcept; // invocation template - invoke_result_t operator()(ArgTypes&&...) const; + constexpr invoke_result_t operator()(ArgTypes&&...) const; }; template reference_wrapper(T&) -> reference_wrapper; @@ -14134,7 +14016,7 @@ \indexlibrary{\idxcode{reference_wrapper}!constructor}% \begin{itemdecl} template - reference_wrapper(U&& u) noexcept(@\seebelow@); + constexpr reference_wrapper(U&& u) noexcept(@\seebelow@); \end{itemdecl} \begin{itemdescr} @@ -14159,7 +14041,7 @@ \indexlibrary{\idxcode{reference_wrapper}!constructor}% \begin{itemdecl} -reference_wrapper(const reference_wrapper& x) noexcept; +constexpr reference_wrapper(const reference_wrapper& x) noexcept; \end{itemdecl} \begin{itemdescr} @@ -14171,7 +14053,7 @@ \indexlibrarymember{operator=}{reference_wrapper}% \begin{itemdecl} -reference_wrapper& operator=(const reference_wrapper& x) noexcept; +constexpr reference_wrapper& operator=(const reference_wrapper& x) noexcept; \end{itemdecl} \begin{itemdescr} @@ -14182,7 +14064,7 @@ \indexlibrarymember{operator T\&}{reference_wrapper}% \begin{itemdecl} -operator T& () const noexcept; +constexpr operator T& () const noexcept; \end{itemdecl} \begin{itemdescr} @@ -14191,7 +14073,7 @@ \indexlibrarymember{get}{reference_wrapper}% \begin{itemdecl} -T& get() const noexcept; +constexpr T& get() const noexcept; \end{itemdecl} \begin{itemdescr} @@ -14203,7 +14085,7 @@ \indexlibrarymember{operator()}{reference_wrapper}% \begin{itemdecl} template - invoke_result_t + constexpr invoke_result_t operator()(ArgTypes&&... args) const; \end{itemdecl} @@ -14225,7 +14107,7 @@ \indexlibrarymember{ref}{reference_wrapper}% \begin{itemdecl} -template reference_wrapper ref(T& t) noexcept; +template constexpr reference_wrapper ref(T& t) noexcept; \end{itemdecl} \begin{itemdescr} @@ -14234,7 +14116,7 @@ \indexlibrarymember{ref}{reference_wrapper}% \begin{itemdecl} -template reference_wrapper ref(reference_wrapper t) noexcept; +template constexpr reference_wrapper ref(reference_wrapper t) noexcept; \end{itemdecl} \begin{itemdescr} @@ -14243,7 +14125,7 @@ \indexlibrarymember{cref}{reference_wrapper}% \begin{itemdecl} -template reference_wrapper cref(const T& t) noexcept; +template constexpr reference_wrapper cref(const T& t) noexcept; \end{itemdecl} \begin{itemdescr} @@ -14252,7 +14134,7 @@ \indexlibrarymember{cref}{reference_wrapper}% \begin{itemdecl} -template reference_wrapper cref(reference_wrapper t) noexcept; +template constexpr reference_wrapper cref(reference_wrapper t) noexcept; \end{itemdecl} \begin{itemdescr} @@ -14267,11 +14149,25 @@ struct unwrap_reference; \end{itemdecl} +\begin{itemdescr} \pnum If \tcode{T} is a specialization \tcode{reference_wrapper} for some type \tcode{X}, the member typedef \tcode{type} of \tcode{unwrap_reference} is \tcode{X\&}, otherwise it is \tcode{T}. +\end{itemdescr} + +\indexlibrary{\idxcode{unwrap_ref_decay}}% +\begin{itemdecl} +template + struct unwrap_ref_decay; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The member typedef \tcode{type} of \tcode{unwrap_ref_decay} +denotes the type \tcode{unwrap_reference_t>}. +\end{itemdescr} \rSec2[arithmetic.operations]{Arithmetic operations} @@ -14762,23 +14658,24 @@ \rSec2[range.cmp]{Concept-constrained comparisons} \pnum -In this subclause, \tcode{\placeholdernc{BUILTIN_PTR_CMP}(T, $op$, U)} for types \tcode{T} +In this subclause, \tcode{\placeholdernc{BUILTIN-PTR-CMP}(T, $op$, U)} for types \tcode{T} and \tcode{U} and where $op$ is an equality\iref{expr.eq} or relational operator\iref{expr.rel} is a boolean constant expression. -\tcode{\placeholdernc{BUILTIN_PTR_CMP}(T, $op$, U)} is \tcode{true} if and only if $op$ +\tcode{\placeholdernc{BUILTIN-PTR-CMP}(T, $op$, U)} is \tcode{true} if and only if $op$ in the expression \tcode{declval() $op$ declval()} resolves to a built-in operator comparing pointers. \pnum There is an implementation-defined strict total ordering over all pointer values of a given type. This total ordering is consistent with the partial order imposed -by the builtin operators \tcode{<}, \tcode{>}, \tcode{<=}, and \tcode{>=}. +by the builtin operators \tcode{<}, \tcode{>}, \tcode{<=}, \tcode{>=}, and +\tcode{<=>}. \indexlibrary{\idxcode{equal_to}}% \begin{itemdecl} struct ranges::equal_to { template - requires EqualityComparableWith || @\placeholdernc{BUILTIN_PTR_CMP}@(T, ==, U) + requires equality_comparable_with || @\placeholdernc{BUILTIN-PTR-CMP}@(T, ==, U) constexpr bool operator()(T&& t, U&& u) const; using is_transparent = @\unspecnc@; @@ -14813,7 +14710,7 @@ \begin{itemdecl} struct ranges::not_equal_to { template - requires EqualityComparableWith || @\placeholdernc{BUILTIN_PTR_CMP}@(T, ==, U) + requires equality_comparable_with || @\placeholdernc{BUILTIN-PTR-CMP}@(T, ==, U) constexpr bool operator()(T&& t, U&& u) const; using is_transparent = @\unspecnc@; @@ -14832,7 +14729,7 @@ \begin{itemdecl} struct ranges::greater { template - requires StrictTotallyOrderedWith || @\placeholdernc{BUILTIN_PTR_CMP}@(U, <, T) + requires totally_ordered_with || @\placeholdernc{BUILTIN-PTR-CMP}@(U, <, T) constexpr bool operator()(T&& t, U&& u) const; using is_transparent = @\unspecnc@; @@ -14851,7 +14748,7 @@ \begin{itemdecl} struct ranges::less { template - requires StrictTotallyOrderedWith || @\placeholdernc{BUILTIN_PTR_CMP}@(T, <, U) + requires totally_ordered_with || @\placeholdernc{BUILTIN-PTR-CMP}@(T, <, U) constexpr bool operator()(T&& t, U&& u) const; using is_transparent = @\unspecnc@; @@ -14892,7 +14789,7 @@ \begin{itemdecl} struct ranges::greater_equal { template - requires StrictTotallyOrderedWith || @\placeholdernc{BUILTIN_PTR_CMP}@(T, <, U) + requires totally_ordered_with || @\placeholdernc{BUILTIN-PTR-CMP}@(T, <, U) constexpr bool operator()(T&& t, U&& u) const; using is_transparent = @\unspecnc@; @@ -14911,7 +14808,7 @@ \begin{itemdecl} struct ranges::less_equal { template - requires StrictTotallyOrderedWith || @\placeholdernc{BUILTIN_PTR_CMP}@(U, <, T) + requires totally_ordered_with || @\placeholdernc{BUILTIN-PTR-CMP}@(U, <, T) constexpr bool operator()(T&& t, U&& u) const; using is_transparent = @\unspecnc@; @@ -15232,7 +15129,7 @@ \indexlibrary{\idxcode{not_fn}}% \begin{itemdecl} -template @\unspec@ not_fn(F&& f); +template constexpr @\unspec@ not_fn(F&& f); \end{itemdecl} \begin{itemdescr} @@ -15243,8 +15140,7 @@ \item \tcode{FD} is the type \tcode{decay_t}, \item \tcode{fd} is the target object of \tcode{g}\iref{func.def} of type \tcode{FD}, - initialized with - the \grammarterm{initializer} \tcode{(std::forward(f\brk{}))}\iref{dcl.init}, + direct-non-list-initialized with \tcode{std::forward(f)}, \item \tcode{call_args} is an argument pack used in a function call expression\iref{expr.call} of \tcode{g}. \end{itemize} @@ -15273,7 +15169,7 @@ \indexlibrary{\idxcode{bind_front}}% \begin{itemdecl} template - @\unspec@ bind_front(F&& f, Args&&... args); + constexpr @\unspec@ bind_front(F&& f, Args&&... args); \end{itemdecl} \begin{itemdescr} @@ -15283,15 +15179,14 @@ \item \tcode{g} is a value of the result of a \tcode{bind_front} invocation, \item \tcode{FD} is the type \tcode{decay_t}, \item \tcode{fd} is the target object of \tcode{g}\iref{func.def} - of type \tcode{FD} initialized with - the \grammarterm{initializer} \tcode{(std::forward(\brk{}f))}\iref{dcl.init}, + of type \tcode{FD}, + direct-non-list-initialized with \tcode{std::forward(f)}, \item \tcode{BoundArgs} is a pack - that denotes \tcode{std::unwrap_ref_decay_t...}, + that denotes \tcode{decay_t...}, \item \tcode{bound_args} is a pack of bound argument entities of \tcode{g}\iref{func.def} of types \tcode{BoundArgs...}, - initialized with - \grammarterm{initializer}{s} \tcode{(std::forward(args))...}, + direct-non-list-initialized with \tcode{std::forward(args)...}, respectively, and \item \tcode{call_args} is an argument pack used in a function call expression\iref{expr.call} of \tcode{g}. @@ -15300,8 +15195,10 @@ \pnum \mandates \begin{codeblock} -conjunction_v, is_move_constructible, - is_constructible..., is_move_constructible...> +is_constructible_v && +is_move_constructible_v && +(is_constructible_v && ...) && +(is_move_constructible_v && ...) \end{codeblock} is true. @@ -15345,11 +15242,11 @@ uses \tcode{is_bind_expression} to detect subexpressions. \pnum -Instantiations of the \tcode{is_bind_expression} template shall meet +Specializations of the \tcode{is_bind_expression} template shall meet the \oldconcept{UnaryTypeTrait} requirements\iref{meta.rqmts}. The implementation -shall provide a definition that has a base characteristic of +provides a definition that has a base characteristic of \tcode{true_type} if \tcode{T} is a type returned from \tcode{bind}, -otherwise it shall have a base characteristic of \tcode{false_type}. +otherwise it has a base characteristic of \tcode{false_type}. A program may specialize this template for a program-defined type \tcode{T} to have a base characteristic of \tcode{true_type} to indicate that \tcode{T} should be treated as a subexpression in a \tcode{bind} call. @@ -15369,11 +15266,11 @@ \tcode{is_placeholder} to detect placeholders. \pnum -Instantiations of the \tcode{is_placeholder} template shall meet +Specializations of the \tcode{is_placeholder} template shall meet the \oldconcept{UnaryTypeTrait} requirements\iref{meta.rqmts}. The implementation -shall provide a definition that has the base characteristic of +provides a definition that has the base characteristic of \tcode{integral_constant} if \tcode{T} is the type of -\tcode{std::placeholders::_\placeholder{J}}, otherwise it shall have a +\tcode{std::placeholders::_\placeholder{J}}, otherwise it has a base characteristic of \tcode{integral_constant}. A program may specialize this template for a program-defined type \tcode{T} to have a base characteristic of \tcode{integral_constant} @@ -15387,12 +15284,18 @@ In the text that follows: \begin{itemize} +\item \tcode{g} is a value of the result of a \tcode{bind} invocation, \item \tcode{FD} is the type \tcode{decay_t}, -\item \tcode{fd} is an lvalue of type \tcode{FD} constructed from \tcode{std::forward(f)}, +\item \tcode{fd} is an lvalue that + is a target object of \tcode{g}\iref{func.def} of type \tcode{FD} + direct-non-list-initialized with \tcode{std::forward(f)}, \item $\tcode{T}_i$ is the $i^\text{th}$ type in the template parameter pack \tcode{BoundArgs}, \item $\tcode{TD}_i$ is the type \tcode{decay_t<$\tcode{T}_i$>}, \item $\tcode{t}_i$ is the $i^\text{th}$ argument in the function parameter pack \tcode{bound_args}, -\item $\tcode{td}_i$ is an lvalue of type $\tcode{TD}_i$ constructed from \tcode{std::forward<$\tcode{T}_i$>($\tcode{t}_i$)}, +\item $\tcode{td}_i$ is a bound argument entity + of \tcode{g}\iref{func.def} of type $\tcode{TD}_i$ + direct-non-list-initialized with + \tcode{std::forward<\brk{}$\tcode{T}_i$>($\tcode{t}_i$)}, \item $\tcode{U}_j$ is the $j^\text{th}$ deduced type of the \tcode{UnBoundArgs\&\&...} parameter of the argument forwarding call wrapper, and \item $\tcode{u}_j$ is the $j^\text{th}$ argument associated with $\tcode{U}_j$. @@ -15401,86 +15304,57 @@ \indexlibrary{\idxcode{bind}}% \begin{itemdecl} template - @\unspec@ bind(F&& f, BoundArgs&&... bound_args); + constexpr @\unspec@ bind(F&& f, BoundArgs&&... bound_args); +template + constexpr @\unspec@ bind(F&& f, BoundArgs&&... bound_args); \end{itemdecl} \begin{itemdescr} \pnum -\requires -\tcode{is_constructible_v} shall be \tcode{true}. For each $\tcode{T}_i$ -in \tcode{BoundArgs}, \tcode{is_cons\-tructible_v<$\tcode{TD}_i$, $\tcode{T}_i$>} shall be \tcode{true}. +\mandates +\tcode{is_constructible_v} is \tcode{true}. For each $\tcode{T}_i$ +in \tcode{BoundArgs}, \tcode{is_cons\-tructible_v<$\tcode{TD}_i$, $\tcode{T}_i$>} is \tcode{true}. + +\pnum +\expects +\tcode{FD} and each $\tcode{TD}_i$ meet +the \oldconcept{MoveConstructible} and \oldconcept{Destructible} requirements. \tcode{\placeholdernc{INVOKE}(fd, $\tcode{w}_1$, $\tcode{w}_2$, $\dotsc$, -$\tcode{w}_N$)}\iref{func.require} shall be a valid expression for some +$\tcode{w}_N$)}\iref{func.require} is a valid expression for some values $\tcode{w}_1$, $\tcode{w}_2$, $\dotsc{}$, $\tcode{w}_N$, where $N$ has the value \tcode{sizeof...(bound_args)}. -The cv-qualifiers \cv{} of the call wrapper \tcode{g}, -as specified below, shall be neither \tcode{volatile} nor \tcode{const volatile}. \pnum\returns An argument forwarding call wrapper \tcode{g}\iref{func.require}. -The effect of \tcode{g($\tcode{u}_1$, $\tcode{u}_2$, $\dotsc$, $\tcode{u}_M$)} shall -be +A program that attempts to invoke a volatile-qualified \tcode{g} +is ill-formed. +When \tcode{g} is not volatile-qualified, invocation of +\tcode{g($\tcode{u}_1$, $\tcode{u}_2$, $\dotsc$, $\tcode{u}_M$)} +is expression-equivalent\iref{defns.expression-equivalent} to +\begin{codeblock} +@\placeholdernc{INVOKE}@(static_cast<@$\tcode{V}_\tcode{fd}$@>(@$\tcode{v}_\tcode{fd}$@), + static_cast<@$\tcode{V}_1$@>(@$\tcode{v}_1$@), static_cast<@$\tcode{V}_2$@>(@$\tcode{v}_2$@), @$\dotsc$@, static_cast<@$\tcode{V}_N$@>(@$\tcode{v}_N$@)) +\end{codeblock} +for the first overload, and \begin{codeblock} -@\placeholdernc{INVOKE}@(fd, std::forward<@$\tcode{V}_1$@>(@$\tcode{v}_1$@), std::forward<@$\tcode{V}_2$@>(@$\tcode{v}_2$@), @$\dotsc$@, std::forward<@$\tcode{V}_N$@>(@$\tcode{v}_N$@)) +@\placeholdernc{INVOKE}@(static_cast<@$\tcode{V}_\tcode{fd}$@>(@$\tcode{v}_\tcode{fd}$@), + static_cast<@$\tcode{V}_1$@>(@$\tcode{v}_1$@), static_cast<@$\tcode{V}_2$@>(@$\tcode{v}_2$@), @$\dotsc$@, static_cast<@$\tcode{V}_N$@>(@$\tcode{v}_N$@)) \end{codeblock} -where the values and types of the bound -arguments $\tcode{v}_1$, $\tcode{v}_2$, $\dotsc$, $\tcode{v}_N$ are determined as specified below. -The copy constructor and move constructor of the argument forwarding call wrapper shall throw an -exception if and only if the corresponding constructor of \tcode{FD} or of any of the types -$\tcode{TD}_i$ throws an exception. +for the second overload, +where the values and types of the target argument $\tcode{v}_\tcode{fd}$ and +of the bound arguments +$\tcode{v}_1$, $\tcode{v}_2$, $\dotsc$, $\tcode{v}_N$ are determined as specified below. \pnum -\throws Nothing unless the construction of -\tcode{fd} or of one of the values $\tcode{td}_i$ throws an exception. +\throws Any exception thrown by the initialization of +the state entities of \tcode{g}. \pnum -\remarks The return type shall meet the \oldconcept{MoveConstructible} requirements. If all -of \tcode{FD} and $\tcode{TD}_i$ meet the \oldconcept{CopyConstructible} requirements, then the -return type shall meet the \oldconcept{CopyConstructible} requirements. \begin{note} This implies -that all of \tcode{FD} and $\tcode{TD}_i$ are \oldconcept{MoveConst\-ruct\-ible}. \end{note} -\end{itemdescr} - -\indexlibrary{\idxcode{bind}}% -\begin{itemdecl} -template - @\unspec@ bind(F&& f, BoundArgs&&... bound_args); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\requires -\tcode{is_constructible_v} shall be \tcode{true}. For each $\tcode{T}_i$ -in \tcode{BoundArgs}, \tcode{is_con\-structible_v<$\tcode{TD}_i$, $\tcode{T}_i$>} shall be \tcode{true}. -\tcode{\placeholdernc{INVOKE}(fd, $\tcode{w}_1$, $\tcode{w}_2$, $\dotsc$, $\tcode{w}_N$)} shall be a valid -expression for some -values $\tcode{w}_1$, $\tcode{w}_2$, $\dotsc$, $\tcode{w}_N$, where -$N$ has the value \tcode{sizeof...(bound_args)}. -The cv-qualifiers \cv{} of the call wrapper \tcode{g}, -as specified below, shall be neither \tcode{volatile} nor \tcode{const volatile}. - -\pnum -\returns -An argument forwarding call wrapper \tcode{g}\iref{func.require}. -The effect of -\tcode{g($\tcode{u}_1$, $\tcode{u}_2$, $\dotsc$, $\tcode{u}_M$)} shall be -\begin{codeblock} -@\placeholdernc{INVOKE}@(fd, std::forward<@$\tcode{V}_1$@>(@$\tcode{v}_1$@), std::forward<@$\tcode{V}_2$@>(@$\tcode{v}_2$@), @$\dotsc$@, std::forward<@$\tcode{V}_N$@>(@$\tcode{v}_N$@)) -\end{codeblock} -where the values and types of the bound -arguments $\tcode{v}_1$, $\tcode{v}_2$, $\dotsc$, $\tcode{v}_N$ are determined as specified below. -The copy constructor and move constructor of the argument forwarding call wrapper shall throw an -exception if and only if the corresponding constructor of \tcode{FD} or of any of the types -$\tcode{TD}_i$ throws an exception. - -\pnum -\throws Nothing unless the construction of -\tcode{fd} or of one of the values $\tcode{td}_i$ throws an exception. - -\pnum -\remarks The return type shall meet the \oldconcept{MoveConstructible} requirements. If all -of \tcode{FD} and $\tcode{TD}_i$ meet the \oldconcept{CopyConstructible} requirements, then the -return type shall meet the \oldconcept{CopyConstructible} requirements. \begin{note} This implies -that all of \tcode{FD} and $\tcode{TD}_i$ are \oldconcept{MoveConst\-ruct\-ible}. \end{note} +\begin{note} +If all of \tcode{FD} and $\tcode{TD}_i$ meet +the requirements of \oldconcept{CopyConstructible}, then +the return type meets the requirements of \oldconcept{CopyConstructible}. +\end{note} \end{itemdescr} \pnum @@ -15496,9 +15370,12 @@ argument is \tcode{$\tcode{td}_i$.get()} and its type $\tcode{V}_i$ is \tcode{T\&}; \item if the value of \tcode{is_bind_expression_v<$\tcode{TD}_i$>} -is \tcode{true}, the argument is \tcode{$\tcode{td}_i$(std::forward<$\tcode{U}_j$>($\tcode{u}_j$)...)} and its -type $\tcode{V}_i$ is -\tcode{invoke_result_t<$\tcode{TD}_i$ \cv{} \&, $\tcode{U}_j$...>\&\&}; +is \tcode{true}, the argument is +\begin{codeblock} +static_cast<@\cv{} $\tcode{TD}_i$@&>(@$\tcode{td}_i$@)(std::forward<@$\tcode{U}_j$@>(@$\tcode{u}_j$@)...) +\end{codeblock} +and its type $\tcode{V}_i$ is +\tcode{invoke_result_t<\cv{} $\tcode{TD}_i$\&, $\tcode{U}_j$...>\&\&}; \item if the value \tcode{j} of \tcode{is_placeholder_v<$\tcode{TD}_i$>} is not zero, the argument is \tcode{std::forward<$\tcode{U}_j$>($\tcode{u}_j$)} @@ -15506,8 +15383,12 @@ is \tcode{$\tcode{U}_j$\&\&}; \item otherwise, the value is $\tcode{td}_i$ and its type $\tcode{V}_i$ -is \tcode{$\tcode{TD}_i$ \cv{} \&}. +is \tcode{\cv{} $\tcode{TD}_i$\&}. \end{itemize} + +\pnum +The value of the target argument $\tcode{v}_\tcode{fd}$ is \tcode{fd} and +its corresponding type $\tcode{V}_\tcode{fd}$ is \tcode{\cv{} FD\&}. \indexlibrary{\idxcode{bind}|)}% \rSec3[func.bind.place]{Placeholders} @@ -15527,12 +15408,15 @@ \end{codeblock} \pnum -All placeholder types shall be \oldconcept{DefaultConstructible} and -\oldconcept{CopyConstructible}, and their default constructors and copy/move -constructors shall not throw exceptions. It is \impldef{assignability of placeholder +All placeholder types meet the \oldconcept{DefaultConstructible} and +\oldconcept{CopyConstructible} requirements, and +their default constructors and copy/move +constructors are constexpr functions that +do not throw exceptions. It is \impldef{assignability of placeholder objects} whether -placeholder types are \oldconcept{CopyAssignable}. \oldconcept{CopyAssignable} placeholders' copy -assignment operators shall not throw exceptions. +placeholder types meet the \oldconcept{CopyAssignable} requirements, +but if so, their copy assignment operators are +constexpr functions that do not throw exceptions. \pnum Placeholders should be defined as: @@ -15550,14 +15434,17 @@ \indexlibrary{\idxcode{mem_fn}}% \begin{itemdecl} -template @\unspec@ mem_fn(R T::* pm) noexcept; +template constexpr @\unspec@ mem_fn(R T::* pm) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns A simple call wrapper\iref{func.def} \tcode{fn} -such that the expression \tcode{fn(t, a$_2$, $\dotsc$, a$_N$)} is equivalent -to \tcode{\placeholdernc{INVOKE}(pm, t, a$_2$, $\dotsc$, a$_N$)}\iref{func.require}. +with call pattern \tcode{invoke(pmd, call_args...)}, where +\tcode{pmd} is the target object of \tcode{fn} of type \tcode{R T::*} +direct-non-list-initialized with \tcode{pm}, and +\tcode{call_args} is an argument pack +used in a function call expression\iref{expr.call} of \tcode{pm}. \end{itemdescr} \indextext{function object!\idxcode{mem_fn}|)} @@ -15640,19 +15527,10 @@ template function(F) -> function<@\seebelow@>; - // \ref{func.wrap.func.nullptr}, Null pointer comparisons + // \ref{func.wrap.func.nullptr}, null pointer comparison functions template bool operator==(const function&, nullptr_t) noexcept; - template - bool operator==(nullptr_t, const function&) noexcept; - - template - bool operator!=(const function&, nullptr_t) noexcept; - - template - bool operator!=(nullptr_t, const function&) noexcept; - // \ref{func.wrap.func.alg}, specialized algorithms template void swap(function&, function&) noexcept; @@ -15957,26 +15835,12 @@ \begin{itemdecl} template bool operator==(const function& f, nullptr_t) noexcept; -template - bool operator==(nullptr_t, const function& f) noexcept; \end{itemdecl} \begin{itemdescr} \pnum\returns \tcode{!f}. \end{itemdescr} -\indexlibrarymember{operator"!=}{function}% -\begin{itemdecl} -template - bool operator!=(const function& f, nullptr_t) noexcept; -template - bool operator!=(nullptr_t, const function& f) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum\returns \tcode{(bool)f}. -\end{itemdescr} - \rSec4[func.wrap.func.alg]{Specialized algorithms} \indexlibrarymember{swap}{function}% @@ -16411,7 +16275,9 @@ \rSec2[meta.type.synop]{Header \tcode{} synopsis} \indexhdr{type_traits}% +\indexlibrary{\idxcode{is_layout_compatible_v}}% \indexlibrary{\idxcode{is_nothrow_convertible_v}}% +\indexlibrary{\idxcode{is_pointer_interconvertible_base_of_v}}% \indexlibrary{\idxcode{type_identity_t}}% \indexlibrary{\idxcode{common_reference_t}}% % FIXME: Many index entries missing. @@ -16509,6 +16375,8 @@ template struct has_unique_object_representations; + template struct has_strong_structural_equality; + // \ref{meta.unary.prop.query}, type property queries template struct alignment_of; template struct rank; @@ -16519,6 +16387,8 @@ template struct is_base_of; template struct is_convertible; template struct is_nothrow_convertible; + template struct is_layout_compatible; + template struct is_pointer_interconvertible_base_of; template struct is_invocable; template struct is_invocable_r; @@ -16632,13 +16502,6 @@ template struct disjunction; template struct negation; - // \ref{meta.endian}, endian - enum class endian { - little = @\seebelow@, - big = @\seebelow@, - native = @\seebelow@ - }; - // \ref{meta.unary.cat}, primary type categories template inline constexpr bool is_void_v = is_void::value; @@ -16786,6 +16649,10 @@ inline constexpr bool has_unique_object_representations_v = has_unique_object_representations::value; + template + inline constexpr bool has_strong_structural_equality_v + = has_strong_structural_equality::value; + // \ref{meta.unary.prop.query}, type property queries template inline constexpr size_t alignment_of_v = alignment_of::value; @@ -16803,6 +16670,11 @@ inline constexpr bool is_convertible_v = is_convertible::value; template inline constexpr bool is_nothrow_convertible_v = is_nothrow_convertible::value; + template + inline constexpr bool is_layout_compatible_v = is_layout_compatible::value; + template + inline constexpr bool is_pointer_interconvertible_base_of_v + = is_pointer_interconvertible_base_of::value; template inline constexpr bool is_invocable_v = is_invocable::value; template @@ -16821,6 +16693,12 @@ template inline constexpr bool negation_v = negation::value; + // \ref{meta.member}, member relationships + template + constexpr bool is_pointer_interconvertible_with_class(M S::*m) noexcept; + template + constexpr bool is_corresponding_member(M1 S1::*m1, M2 S2::*m2) noexcept; + // \ref{meta.const.eval}, constant evaluation context constexpr bool is_constant_evaluated() noexcept; } @@ -17423,6 +17301,14 @@ \tcode{T} shall be a complete type, \cv{}~\tcode{void}, or an array of unknown bound. \\ \rowsep +\indexlibrary{\idxcode{has_strong_structural_equality}}% +\tcode{template}\br + \tcode{struct has_strong_structural_equality;} & + The type \tcode{T} has + strong structural equality\iref{class.compare.default}. & + \tcode{T} shall be a complete type, \cv{} \tcode{void}, or + an array of unknown bound. \\ \rowsep + \end{libreqtab3b} \pnum @@ -17627,6 +17513,29 @@ types, arrays of unknown bound, or \cv{}~\tcode{void} types. \\ \rowsep +\indexlibrary{\idxcode{is_layout_compatible}}% +\tcode{template}\br + \tcode{struct is_layout_compatible;} & + \tcode{T} and \tcode{U} are layout-compatible\iref{basic.types} & + \tcode{T} and \tcode{U} shall be complete types, + \cv{}~\tcode{void}, + or arrays of unknown bound. \\ \rowsep + +\indexlibrary{\idxcode{is_pointer_interconvertible_base_of}}% +\tcode{template}\br + \tcode{struct is_pointer_interconvertible_base_of;} & + \tcode{Derived} is unambiguously derived from \tcode{Base} + without regard to cv-qualifiers, + and each object of type \tcode{Derived} + is pointer-interconvertible\iref{basic.compound} with + its \tcode{Base} subobject, + or \tcode{Base} and \tcode{Derived} are not unions + and name the same class type + without regard to cv-qualifiers. & + If \tcode{Base} and \tcode{Derived} are non-union class types + and are not (possibly cv-qualified versions of) the same type, + \tcode{Derived} shall be a complete type. \\ \rowsep + \indexlibrary{\idxcode{is_invocable}}% \tcode{template}\br \tcode{struct is_invocable;} & @@ -18121,38 +18030,38 @@ \tcode{\placeholdernc{COPYCV}(const int, volatile short)} is an alias for \tcode{const volatile short}. \end{example} -\item \tcode{\placeholdernc{COND_RES}(X, Y)} be +\item \tcode{\placeholdernc{COND-RES}(X, Y)} be \tcode{decltype(false ?\ declval()() :\ declval()())}. \end{itemize} Given types \tcode{A} and \tcode{B}, let \tcode{X} be \tcode{remove_reference_t}, let \tcode{Y} be \tcode{remove_reference_t}, and -let \tcode{\placeholdernc{COMMON_REF}(A, B)} be: +let \tcode{\placeholdernc{COMMON-\brk{}REF}(A, B)} be: \begin{itemize} \item If \tcode{A} and \tcode{B} are both lvalue reference types, - \tcode{\placeholdernc{COMMON_REF}(A, B)} is - \tcode{\placeholdernc{COND_RES}(\placeholdernc{COPYCV}(X, Y) \&, + \tcode{\placeholdernc{COMMON-REF}(A, B)} is + \tcode{\placeholdernc{COND-RES}(\placeholdernc{COPYCV}(X, Y) \&, \placeholdernc{COPYCV}(\brk{}Y, X) \&)} if that type exists and is a reference type. \item Otherwise, let \tcode{C} be - \tcode{remove_reference_t<\placeholdernc{COMMON_REF}(X\&, Y\&)>\&\&}. + \tcode{remove_reference_t<\placeholdernc{COMMON-REF}(X\&, Y\&)>\&\&}. If \tcode{A} and \tcode{B} are both rvalue reference types, \tcode{C} is well-formed, and \tcode{is_convertible_v \&\& is_convertible_v} is \tcode{true}, - then \tcode{\placeholdernc{COMMON_REF}(A, B)} is \tcode{C}. + then \tcode{\placeholdernc{COMMON-REF}(A, B)} is \tcode{C}. \item Otherwise, let \tcode{D} be - \tcode{\placeholdernc{COMMON_REF}(const X\&, Y\&)}. If \tcode{A} is an rvalue + \tcode{\placeholdernc{COMMON-REF}(const X\&, Y\&)}. If \tcode{A} is an rvalue reference and \tcode{B} is an lvalue reference and \tcode{D} is well-formed and \tcode{is_convertible_v} is - \tcode{true}, then \tcode{\placeholdernc{COMMON_REF}(A, B)} is \tcode{D}. + \tcode{true}, then \tcode{\placeholdernc{COMMON-REF}(A, B)} is \tcode{D}. \item Otherwise, if \tcode{A} is an lvalue reference and \tcode{B} - is an rvalue reference, then \tcode{\placeholdernc{COMMON_REF}(A, B)} is - \tcode{\placeholdernc{COMMON_REF}(B, A)}. -\item Otherwise, \tcode{\placeholdernc{COMMON_REF}(A, B)} is ill-formed. + is an rvalue reference, then \tcode{\placeholdernc{COMMON-REF}(A, B)} is + \tcode{\placeholdernc{COMMON-REF}(B, A)}. +\item Otherwise, \tcode{\placeholdernc{COMMON-REF}(A, B)} is ill-formed. \end{itemize} If any of the types computed above is ill-formed, then -\tcode{\placeholdernc{COMMON_REF}(A, B)} is ill-formed. +\tcode{\placeholdernc{COMMON-REF}(A, B)} is ill-formed. \pnum Note A: @@ -18183,16 +18092,20 @@ None of the following will apply if there is a specialization \tcode{common_type}. \end{note} + \item Otherwise, if both \tcode{D1} and \tcode{D2} denote + comparison category types\iref{cmp.categories.pre}, + let \tcode{C} denote the common comparison type\iref{class.spaceship} + of \tcode{D1} and \tcode{D2}. \item Otherwise, if \begin{codeblock} decay_t() : declval())> \end{codeblock} denotes a valid type, let \tcode{C} denote that type. \item Otherwise, if - \tcode{\placeholdernc{COND_RES}(\placeholdernc{CREF}(D1), + \tcode{\placeholdernc{COND-RES}(\placeholdernc{CREF}(D1), \placeholdernc{CREF}(D2))} denotes a type, let \tcode{C} denote the type - \tcode{decay_t<\placeholdernc{COND_RES}(\placeholdernc{CREF}(D1), + \tcode{decay_t<\placeholdernc{COND-RES}(\placeholdernc{CREF}(D1), \placeholdernc{CREF}(D2))>}. \end{itemize} In either case, the member \grammarterm{typedef-name} \tcode{type} shall denote @@ -18242,7 +18155,7 @@ denote the two types in the pack \tcode{T}. Then \begin{itemize} \item If \tcode{T1} and \tcode{T2} are reference types and - \tcode{\placeholdernc{COMMON_REF}(T1, T2)} is well-formed, then the member + \tcode{\placeholdernc{COMMON-REF}(T1, T2)} is well-formed, then the member typedef \tcode{type} denotes that type. \item Otherwise, if @@ -18250,7 +18163,7 @@ \brk{}\placeholdernc{XREF}(\brk{}T1), \placeholdernc{XREF}(T2)>::type} is well-formed, then the member typedef \tcode{type} denotes that type. - \item Otherwise, if \tcode{\placeholdernc{COND_RES}(T1, T2)} is well-formed, + \item Otherwise, if \tcode{\placeholdernc{COND-RES}(T1, T2)} is well-formed, then the member typedef \tcode{type} denotes that type. \item Otherwise, if \tcode{common_type_t} is well-formed, then the @@ -18440,42 +18353,75 @@ is a \oldconcept{UnaryTypeTrait} with a base characteristic of \tcode{bool_constant}. \end{itemdescr} -\rSec2[meta.endian]{Endian} +\rSec2[meta.member]{Member relationships} + +\indexlibrary{\idxcode{is_pointer_interconvertible_with_class}} +\begin{itemdecl} +template + constexpr bool is_pointer_interconvertible_with_class(M S::*m) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates \tcode{S} is a complete type. \pnum -Two common methods of byte ordering in multibyte scalar types are big-endian -and little-endian in the execution environment. Big-endian is a format for -storage of binary data in which the most significant byte is placed first, -with the rest in descending order. Little-endian is a format for storage of -binary data in which the least significant byte is placed first, with the rest -in ascending order. This subclause describes the endianness of the scalar types -of the execution environment. +\returns \tcode{true} if and only if + \tcode{S} is a standard-layout type, + \tcode{M} is an object type, + \tcode{m} is not null, + and each object \tcode{s} of type \tcode{S} + is pointer-interconvertible\iref{basic.compound} + with its subobject \tcode{s.*m}. +\end{itemdescr} -\indexlibrary{\idxcode{endian}}% -\indexlibrarymember{little}{endian}% -\indexlibrarymember{big}{endian}% -\indexlibrarymember{native}{endian}% +\indexlibrary{\idxcode{is_corresponding_member}} \begin{itemdecl} -enum class endian { - little = @\seebelow@, - big = @\seebelow@, - native = @\seebelow@ -}; +template + constexpr bool is_corresponding_member(M1 S1::*m1, M2 S2::*m2) noexcept; \end{itemdecl} \begin{itemdescr} \pnum -If all scalar types have size 1 byte, then all of \tcode{endian::little}, -\tcode{endian::big}, and \tcode{endian::native} have the same value. -Otherwise, \tcode{endian::little} is not equal to \tcode{endian::big}. -If all scalar types are big-endian, \tcode{endian::native} is -equal to \tcode{endian::big}. -If all scalar types are little-endian, \tcode{endian::native} is -equal to \tcode{endian::little}. -Otherwise, \tcode{endian::native} is not equal -to either \tcode{endian::big} or \tcode{endian::little}. +\mandates \tcode{S1} and \tcode{S2} are complete types. + +\pnum +\returns \tcode{true} if and only if + \tcode{S1} and \tcode{S2} are standard-layout types, + \tcode{M1} and \tcode{M2} are object types, + \tcode{m1} and \tcode{m2} are not null, + and \tcode{m1} and \tcode{m2} point to corresponding members of + the common initial sequence\iref{class.mem} of \tcode{S1} and \tcode{S2}. \end{itemdescr} +\pnum +\begin{note} +The type of a pointer-to-member expression \tcode{\&C::b} +is not always a pointer to member of \tcode{C}, +leading to potentially surprising results +when using these functions in conjunction with inheritance. +\begin{example} +\begin{codeblock} +struct A { int a; }; // a standard-layout class +struct B { int b; }; // a standard-layout class +struct C: public A, public B { }; // not a standard-layout class + +static_assert( is_pointer_interconvertible_with_class( &C::b ) ); + // Succeeds because, despite its appearance, \tcode{\&C::b} has type + // ``pointer to member of \tcode{B} of type \tcode{int}''. +static_assert( is_pointer_interconvertible_with_class( &C::b ) ); + // Forces the use of class \tcode{C}, and fails. + +static_assert( is_corresponding_member( &C::a, &C::b ) ); + // Succeeds because, despite its appearance, \tcode{\&C::a} and \tcode{\&C::b} have types + // ``pointer to member of \tcode{A} of type \tcode{int}'' and + // ``pointer to member of \tcode{B} of type \tcode{int}'', respectively. +static_assert( is_corresponding_member( &C::a, &C::b ) ); + // Forces the use of class \tcode{C}, and fails. +\end{codeblock} +\end{example} +\end{note} + \rSec2[meta.const.eval]{Constant evaluation context} \begin{itemdecl} constexpr bool is_constant_evaluated() noexcept; @@ -18757,11 +18703,11 @@ public: type_index(const type_info& rhs) noexcept; bool operator==(const type_index& rhs) const noexcept; - bool operator!=(const type_index& rhs) const noexcept; bool operator< (const type_index& rhs) const noexcept; bool operator> (const type_index& rhs) const noexcept; bool operator<=(const type_index& rhs) const noexcept; bool operator>=(const type_index& rhs) const noexcept; + strong_ordering operator<=>(const type_index& rhs) const noexcept; size_t hash_code() const noexcept; const char* name() const noexcept; @@ -18802,16 +18748,6 @@ \returns \tcode{*target == *rhs.target}. \end{itemdescr} -\indexlibrarymember{operator"!=}{type_index}% -\begin{itemdecl} -bool operator!=(const type_index& rhs) const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns \tcode{*target != *rhs.target}. -\end{itemdescr} - \indexlibrarymember{operator<}{type_index}% \begin{itemdecl} bool operator<(const type_index& rhs) const noexcept; @@ -18852,6 +18788,22 @@ \returns \tcode{!target->before(*rhs.target)}. \end{itemdescr} +\indexlibrarymember{operator<=>}{type_index}% +\begin{itemdecl} +strong_ordering operator<=>(const type_index& rhs) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +if (*target == *rhs.target) return strong_ordering::equal; +if (target->before(*rhs.target)) return strong_ordering::less; +return strong_ordering::greater; +\end{codeblock} +\end{itemdescr} + \indexlibrarymember{hash_code}{type_index}% \begin{itemdecl} size_t hash_code() const noexcept; @@ -19108,6 +19060,7 @@ struct to_chars_result { char* ptr; errc ec; + friend bool operator==(const to_chars_result&, const to_chars_result&) = default; }; to_chars_result to_chars(char* first, char* last, @\seebelow@ value, int base = 10); @@ -19135,6 +19088,7 @@ struct from_chars_result { const char* ptr; errc ec; + friend bool operator==(const from_chars_result&, const from_chars_result&) = default; }; from_chars_result from_chars(const char* first, const char* last, @@ -19419,3 +19373,1910 @@ \end{itemdescr} \xrefc{7.22.1.3, 7.22.1.4} + +\rSec1[format]{Formatting} + +\rSec2[format.syn]{Header \tcode{} synopsis} + +\indexhdr{format}% +\indexlibrary{\idxcode{format_parse_context}}% +\indexlibrary{\idxcode{wformat_parse_context}}% +\indexlibrary{\idxcode{format_context}}% +\indexlibrary{\idxcode{wformat_context}}% +\indexlibrary{\idxcode{format_args}}% +\indexlibrary{\idxcode{wformat_args}}% +\indexlibrary{\idxcode{format_args_t}}% +\indexlibrary{\idxcode{format_to_n_result}}% +\indexlibrarymember{out}{format_to_n_result}% +\indexlibrarymember{size}{format_to_n_result}% +\begin{codeblock} +namespace std { + // \ref{format.functions}, formatting functions + template + string format(string_view fmt, const Args&... args); + template + wstring format(wstring_view fmt, const Args&... args); + template + string format(const locale& loc, string_view fmt, const Args&... args); + template + wstring format(const locale& loc, wstring_view fmt, const Args&... args); + + string vformat(string_view fmt, format_args args); + wstring vformat(wstring_view fmt, wformat_args args); + string vformat(const locale& loc, string_view fmt, format_args args); + wstring vformat(const locale& loc, wstring_view fmt, wformat_args args); + + template + Out format_to(Out out, string_view fmt, const Args&... args); + template + Out format_to(Out out, wstring_view fmt, const Args&... args); + template + Out format_to(Out out, const locale& loc, string_view fmt, const Args&... args); + template + Out format_to(Out out, const locale& loc, wstring_view fmt, const Args&... args); + + template + Out vformat_to(Out out, string_view fmt, format_args_t args); + template + Out vformat_to(Out out, wstring_view fmt, format_args_t args); + template + Out vformat_to(Out out, const locale& loc, string_view fmt, + format_args_t args); + template + Out vformat_to(Out out, const locale& loc, wstring_view fmt, + format_args_t args); + + template struct format_to_n_result { + Out out; + iter_difference_t size; + }; + template + format_to_n_result format_to_n(Out out, iter_difference_t n, + string_view fmt, const Args&... args); + template + format_to_n_result format_to_n(Out out, iter_difference_t n, + wstring_view fmt, const Args&... args); + template + format_to_n_result format_to_n(Out out, iter_difference_t n, + const locale& loc, string_view fmt, + const Args&... args); + template + format_to_n_result format_to_n(Out out, iter_difference_t n, + const locale& loc, wstring_view fmt, + const Args&... args); + + template + size_t formatted_size(string_view fmt, const Args&... args); + template + size_t formatted_size(wstring_view fmt, const Args&... args); + template + size_t formatted_size(const locale& loc, string_view fmt, const Args&... args); + template + size_t formatted_size(const locale& loc, wstring_view fmt, const Args&... args); + + // \ref{format.formatter}, formatter + template struct formatter; + + // \ref{format.parse.ctx}, class template \tcode{basic_format_parse_context} + template class basic_format_parse_context; + using format_parse_context = basic_format_parse_context; + using wformat_parse_context = basic_format_parse_context; + + template class basic_format_context; + using format_context = basic_format_context<@\unspec@, char>; + using wformat_context = basic_format_context<@\unspec@, wchar_t>; + + // \ref{format.arguments}, arguments + // \ref{format.arg}, class template \tcode{basic_format_arg} + template class basic_format_arg; + + template + @\seebelow@ visit_format_arg(Visitor&& vis, basic_format_arg arg); + + // \ref{format.arg.store}, class template \exposid{format-arg-store} + template struct @\placeholder{format-arg-store}@; // \expos + + template + @\placeholder{format-arg-store}@ + make_format_args(const Args&... args); + template + @\placeholder{format-arg-store}@ + make_wformat_args(const Args&... args); + + // \ref{format.args}, class template \tcode{basic_format_args} + template class basic_format_args; + using format_args = basic_format_args; + using wformat_args = basic_format_args; + + template + using format_args_t = basic_format_args>; + + // \ref{format.error}, class \tcode{format_error} + class format_error; +} +\end{codeblock} + +\rSec2[format.string]{Format string} + +\rSec3[format.string.general]{In general} + +% FIXME: For now, keep the format grammar productions out of the index, since +% they conflict with the main grammar. +% Consider renaming these en masse (to fmt-* ?) to avoid this problem. +\newcommand{\fmtnontermdef}[1]{{\BnfNontermshape#1\itcorr}\textnormal{:}} +\newcommand{\fmtgrammarterm}[1]{\gterm{#1}} + +\pnum +A \defn{format string} is a (possibly empty) sequence of +\defnx{replacement fields}{replacement field!format string}, +\defnx{escape sequences}{escape sequence!format string}, +and characters other than \tcode{\{} and \tcode{\}}. +Let \tcode{charT} be the character type of the format string. +Each character that is not part of +a replacement field or an escape sequence +is copied unchanged to the output. +An escape sequence is one of \tcode{\{\{} or \tcode{\}\}}. +It is replaced with \tcode{\{} or \tcode{\}}, respectively, in the output. +The syntax of replacement fields is as follows: + +\begin{ncbnf} +\fmtnontermdef{replacement-field}\br + \terminal{\{} \opt{arg-id} \opt{format-specifier} \terminal{\}} +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{arg-id}\br + \terminal{0}\br + positive-integer +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{positive-integer}\br + nonzero-digit\br + positive-integer digit +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{nonnegative-integer}\br + digit\br + nonnegative-integer digit +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{nonzero-digit} \textnormal{one of}\br + \terminal{1 2 3 4 5 6 7 8 9} +\end{ncbnf} + +% FIXME: This exactly duplicates the digit grammar term from [lex] +\begin{ncbnf} +\fmtnontermdef{digit} \textnormal{one of}\br + \terminal{0 1 2 3 4 5 6 7 8 9} +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{format-specifier}\br + \terminal{:} format-spec +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{format-spec}\br + \textnormal{as specified by the \tcode{formatter} specialization for the argument type} +\end{ncbnf} + +\pnum +The \fmtgrammarterm{arg-id} field specifies the index of +% FIXME: "args" hasn't been introduced yet! +the argument in \tcode{args} +whose value is to be formatted and inserted into the output +instead of the replacement field. +The optional \fmtgrammarterm{format-specifier} field +explicitly specifies a format for the replacement value. + +\pnum +\begin{example} +\begin{codeblock} +string s = format("{0}-{{", 8); // value of \tcode{s} is \tcode{"8-\{"} +\end{codeblock} +\end{example} + +\pnum +If all \fmtgrammarterm{arg-id}s in a format string are omitted +(including those in the \fmtgrammarterm{format-spec}, +as interpreted by the corresponding \tcode{formatter} specialization), +argument indices 0, 1, 2, \ldots{} will automatically be used in that order. +If some \fmtgrammarterm{arg-id}s are omitted and some are present, +the string is not a format string. +\begin{note} +A format string cannot contain a +mixture of automatic and manual indexing. +\end{note} +\begin{example} +\begin{codeblock} +string s0 = format("{} to {}", "a", "b"); // OK, automatic indexing +string s1 = format("{1} to {0}", "a", "b"); // OK, manual indexing +string s2 = format("{0} to {}", "a", "b"); // not a format string (mixing automatic and manual indexing), + // throws \tcode{format_error} +string s3 = format("{} to {1}", "a", "b"); // not a format string (mixing automatic and manual indexing), + // throws \tcode{format_error} +\end{codeblock} +\end{example} + +\pnum +The \fmtgrammarterm{format-spec} field contains +\defnx{format specifications}{format specification!format string} +that define how the value should be presented. +Each type can define its own +interpretation of the \fmtgrammarterm{format-spec} field. +\begin{example} +\begin{itemize} +\item +For arithmetic, pointer, and string types +the \fmtgrammarterm{format-spec} +is interpreted as a \fmtgrammarterm{std-format-spec} +as described in \iref{format.string.std}. +\item +For chrono types +the \fmtgrammarterm{format-spec} +is interpreted as a \fmtgrammarterm{chrono-format-spec} +as described in \iref{time.format}. +\item +For user-defined \tcode{formatter} specializations, +the behavior of the \tcode{parse} member function +determines how the \fmtgrammarterm{format-spec} +is interpreted. +\end{itemize} +\end{example} + +\rSec3[format.string.std]{Standard format specifiers} + +\pnum +Each \tcode{formatter} specializations +described in \ref{format.formatter.spec} +for fundamental and string types +interprets \fmtgrammarterm{format-spec} as a +\fmtgrammarterm{std-format-spec}. +\begin{note} +The format specification can be used to specify such details as +field width, alignment, padding, and decimal precision. +Some of the formatting options +are only supported for arithmetic types. +\end{note} +The syntax of format specifications is as follows: + +\begin{ncbnf} +\fmtnontermdef{std-format-spec}\br + \opt{fill-and-align} \opt{sign} \opt{\terminal{\#}} \opt{\terminal{0}} \opt{width} \opt{precision} \opt{type} +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{fill-and-align}\br + \opt{fill} align +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{fill}\br + \textnormal{any character other than \tcode{\{} or \tcode{\}}} +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{align} \textnormal{one of}\br + \terminal{< > \caret} +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{sign} \textnormal{one of}\br + \terminal{+ -} \textnormal{space} +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{width}\br + positive-integer\br + \terminal{\{} arg-id \terminal{\}} +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{precision}\br + \terminal{.} nonnegative-integer\br + \terminal{.} \terminal{\{} arg-id \terminal{\}} +\end{ncbnf} + +\begin{ncbnf} +\fmtnontermdef{type} \textnormal{one of}\br + \terminal{a A b B c d e E f F g G n o p s x X} +\end{ncbnf} + +\pnum +\begin{note} +The \fmtgrammarterm{fill} character can be any character +other than \tcode{\{} or \tcode{\}}. +The presence of a fill character is signaled by the +character following it, which must be one of the alignment options. +If the second character of \fmtgrammarterm{std-format-spec} +is not a valid alignment option, +then it is assumed that both the fill character and the alignment option are +absent. +\end{note} + +\pnum +The meaning of the various alignment options is as specified in \tref{format.align}. +\begin{example} +\begin{codeblock} +char c = 120; +string s0 = format("{:6}", 42); // value of \tcode{s0} is \tcode{"\ \ \ \ 42"} +string s1 = format("{:6}", 'x'); // value of \tcode{s1} is \tcode{"x\ \ \ \ \ "} +string s2 = format("{:*<6}", 'x'); // value of \tcode{s2} is \tcode{"x*****"} +string s3 = format("{:*>6}", 'x'); // value of \tcode{s3} is \tcode{"*****x"} +string s4 = format("{:*^6}", 'x'); // value of \tcode{s4} is \tcode{"**x***"} +string s5 = format("{:6d}", c); // value of \tcode{s5} is \tcode{"\ \ \ 120"} +string s6 = format("{:6}", true); // value of \tcode{s6} is \tcode{"true\ \ "} +\end{codeblock} +\end{example} +\begin{note} +Unless a minimum field width is defined, the field width is determined by +the size of the content and the alignment option has no effect. +\end{note} + +\begin{floattable}{Meaning of \fmtgrammarterm{align} options}{format.align}{lp{.8\hsize}} +\topline +\lhdr{Option} & \rhdr{Meaning} \\ \rowsep +\tcode{<} & +Forces the field to be left-aligned within the available space. +This is the default for +non-arithmetic types, \tcode{charT}, and \tcode{bool}, +unless an integer presentation type is specified. +\\ \rowsep +% +\tcode{>} & +Forces the field to be right-aligned within the available space. +This is the default for +arithmetic types other than \tcode{charT} and \tcode{bool} +or when an integer presentation type is specified. +\\ \rowsep +% +\tcode{\caret} & +Forces the field to be centered within the available space +by inserting +$\bigl\lfloor \frac{n}{2} \bigr\rfloor$ +characters before and +$\bigl\lceil \frac{n}{2} \bigr\rceil$ +characters after the value, where +$n$ is the total number of fill characters to insert. +\\ +\end{floattable} + +\pnum +The \fmtgrammarterm{sign} option is only valid +for arithmetic types other than \tcode{charT} and \tcode{bool} +or when an integer presentation type is specified. +The meaning of the various options is as specified in \tref{format.sign}. + +\begin{floattable}{Meaning of \fmtgrammarterm{sign} options}{format.sign}{lp{.8\hsize}} +\topline +\lhdr{Option} & \rhdr{Meaning} \\ \rowsep +\tcode{+} & +Indicates that a sign should be used for both non-negative and negative +numbers. +\\ \rowsep +% +\tcode{-} & +Indicates that a sign should be used only for negative numbers (this is +the default behavior). +\\ \rowsep +% +space & +Indicates that a leading space should be used for non-negative numbers, and +a minus sign for negative numbers. +\\ +\end{floattable} + +\pnum +The \fmtgrammarterm{sign} option applies to floating-point infinity and NaN. +\begin{example} +\begin{codeblock} +double inf = numeric_limits::infinity(); +double nan = numeric_limits::quiet_NaN(); +string s0 = format("{0:},{0:+},{0:-},{0: }", 1); // value of \tcode{s0} is \tcode{"1,+1,1, 1"} +string s1 = format("{0:},{0:+},{0:-},{0: }", -1); // value of \tcode{s1} is \tcode{"-1,-1,-1,-1"} +string s2 = format("{0:},{0:+},{0:-},{0: }", inf); // value of \tcode{s2} is \tcode{"inf,+inf,inf, inf"} +string s3 = format("{0:},{0:+},{0:-},{0: }", nan); // value of \tcode{s3} is \tcode{"nan,+nan,nan, nan"} +\end{codeblock} +\end{example} + +\pnum +The \tcode{\#} option causes the +% FIXME: This is not a definition. +\defnx{alternate form}{alternate form!format string} +to be used for the conversion. +This option is only valid for arithmetic types other than +\tcode{charT} and \tcode{bool} +or when an integer presentation type is specified. +For integral types, +the alternate form adds the +base prefix (if any) specified in \tref{format.type.int} +to the output value. +For floating-point types, +the alternate form causes the result of the conversion +to always contain a decimal-point character, +even if no digits follow it. +% FIXME: This is a weird place for this part of the spec to appear. +Normally, a decimal-point character appears in the result of these +conversions only if a digit follows it. +In addition, for \tcode{g} and \tcode{G} conversions, +% FIXME: Are they normally? What does this even mean? Reach into to_chars and +% alter its behavior? +trailing zeros are not removed from the result. + +\pnum +% FIXME: What if it's an arg-id? +The \fmtgrammarterm{positive-integer} in +\fmtgrammarterm{width} is a decimal integer defining the minimum field width. +If \fmtgrammarterm{width} is not specified, +there is no minimum field width, and +the field width is determined based on the content of the field. + +\pnum +A zero (\tcode{0}) character +preceding the \fmtgrammarterm{width} field +pads the field with leading zeros (following any indication of sign or base) +to the field width, +except when applied to an infinity or NaN. +This option is only valid for +arithmetic types other than \tcode{charT} and \tcode{bool} +or when an integer presentation type is specified. +If the \tcode{0} character and an \fmtgrammarterm{align} option both appear, +the \tcode{0} character is ignored. +\begin{example} +\begin{codeblock} +char c = 120; +string s1 = format("{:+06d}", c); // value of \tcode{s1} is \tcode{"+00120"} +string s2 = format("{:#06x}", 0xa); // value of \tcode{s2} is \tcode{"0x000a"} +string s3 = format("{:<06}", -42); // value of \tcode{s3} is \tcode{"-42\ \ \ "} (\tcode{0} is ignored because of \tcode{<} alignment) +\end{codeblock} +\end{example} + +\pnum +% FIXME: What if it's an arg-id? +The \fmtgrammarterm{nonnegative-integer} in +\fmtgrammarterm{precision} is a decimal integer defining +the precision or maximum field size. +It can only be used with floating-point and string types. +For floating-point types this field specifies the formatting precision. +For string types it specifies how many characters will be used from the string. + +\pnum +The \fmtgrammarterm{type} determines how the data should be presented. + +\pnum +% FIXME: What is a "string" here, exactly? +The available string presentation types are specified in \tref{format.type.string}. +% +\begin{floattable}{Meaning of \fmtgrammarterm{type} options for strings}{format.type.string}{ll} +\topline +\lhdr{Type} & \rhdr{Meaning} \\ \rowsep +none, \tcode{s} & +Copies the string to the output. +\\ +\end{floattable} + +\pnum +The meaning of some non-string presentation types +is defined in terms of a call to \tcode{to_chars}. +In such cases, +let \range{first}{last} be a range +large enough to hold the \tcode{to_chars} output +and \tcode{value} be the formatting argument value. +Formatting is done as if by calling \tcode{to_chars} as specified +and copying the output through the output iterator of the format context. +\begin{note} +Additional padding and adjustments are performed +prior to copying the output through the output iterator +as specified by the format specifiers. +\end{note} + +\pnum +The available integer presentation types +for integral types other than \tcode{bool} and \tcode{charT} +are specified in \tref{format.type.int}. +\begin{example} +\begin{codeblock} +string s0 = format("{}", 42); // value of \tcode{s0} is \tcode{"42"} +string s1 = format("{0:b} {0:d} {0:o} {0:x}", 42); // value of \tcode{s1} is \tcode{"101010 42 52 2a"} +string s2 = format("{0:#x} {0:#X}", 42); // value of \tcode{s2} is \tcode{"0x2a 0X2A"} +string s3 = format("{:n}", 1234); // value of \tcode{s3} might be \tcode{"1,234"} + // (depending on the locale) +\end{codeblock} +\end{example} +% +\begin{floattable}{Meaning of \fmtgrammarterm{type} options for integer types}{format.type.int}{lp{.8\hsize}} +\topline +\lhdr{Type} & \rhdr{Meaning} \\ \rowsep +\tcode{b} & +\tcode{to_chars(first, last, value, 2)}; +\indextext{base prefix}% +the base prefix is \tcode{0b}. +\\ \rowsep +% +\tcode{B} & +The same as \tcode{b}, except that +\indextext{base prefix}% +the base prefix is \tcode{0B}. +\\ \rowsep +% +\tcode{c} & +Copies the character \tcode{static_cast(value)} to the output. +Throws \tcode{format_error} if \tcode{value} is not +in the range of representable values for \tcode{charT}. +\\ \rowsep +% +\tcode{d} & +\tcode{to_chars(first, last, value)}. +\\ \rowsep +% +\tcode{o} & +\tcode{to_chars(first, last, value, 8)}; +\indextext{base prefix}% +the base prefix is \tcode{0} if \tcode{value} is nonzero and is empty otherwise. +\\ \rowsep +% +\tcode{x} & +\tcode{to_chars(first, last, value, 16)}; +\indextext{base prefix}% +the base prefix is \tcode{0x}. +\\ \rowsep +% +\tcode{X} & +The same as \tcode{x}, except that +it uses uppercase letters for digits above 9 and +\indextext{base prefix}% +the base prefix is \tcode{0X}. +\\ \rowsep +% +\tcode{n} & +The same as \tcode{d}, except that +it uses the context's locale +to insert the appropriate digit group separator characters. +\\ \rowsep +% +none & +The same as \tcode{d}. +\begin{note} +If the formatting argument type is \tcode{charT} or \tcode{bool}, +the default is instead \tcode{c} or \tcode{s}, respectively. +\end{note} +\\ +\end{floattable} + +\pnum +The available \tcode{charT} presentation types are specified in \tref{format.type.char}. +% +\begin{floattable}{Meaning of \fmtgrammarterm{type} options for \tcode{charT}}{format.type.char}{ll} +\topline +\lhdr{Type} & \rhdr{Meaning} \\ \rowsep +none, \tcode{c} & +Copies the character to the output. +\\ \rowsep +% +\tcode{b}, \tcode{B}, \tcode{d}, \tcode{o}, \tcode{x}, \tcode{X}, \tcode{n} & +As specified in \tref{format.type.int}. +\\ +\end{floattable} + +\pnum +The available \tcode{bool} presentation types are specified in \tref{format.type.bool}. +% +\begin{floattable}{Meaning of \fmtgrammarterm{type} options for \tcode{bool}}{format.type.bool}{ll} +\topline +\lhdr{Type} & \rhdr{Meaning} \\ \rowsep +none, +\tcode{s} & +Copies textual representation, either \tcode{true} or \tcode{false}, to the output. +\\ \rowsep +% +\tcode{b}, \tcode{B}, \tcode{c}, \tcode{d}, \tcode{o}, \tcode{x}, \tcode{X}, \tcode{n} & +As specified in \tref{format.type.int} +for the value +\tcode{static_cast(value)}. +\\ +\end{floattable} + +\pnum +The available floating-point presentation types and their meanings +for values other than infinity and NaN are +specified in \tref{format.type.float}. +For lower-case presentation types, infinity and NaN are formatted as +\tcode{inf} and \tcode{nan}, respectively. +For upper-case presentation types, infinity and NaN are formatted as +\tcode{INF} and \tcode{NAN}, respectively. +\begin{note} +In either case, a sign is included +if indicated by the \fmtgrammarterm{sign} option. +\end{note} +% +\begin{floattable}{Meaning of \fmtgrammarterm{type} options for floating-point types}{format.type.float}{lp{.8\hsize}} +\topline +\lhdr{Type} & \rhdr{Meaning} \\ \rowsep +\tcode{a} & +If \fmtgrammarterm{precision} is specified, equivalent to +\begin{codeblock} +to_chars(first, last, value, chars_format::hex, precision) +\end{codeblock} +where \tcode{precision} is the specified formatting precision; equivalent to +\begin{codeblock} +to_chars(first, last, value, chars_format::hex) +\end{codeblock} +otherwise. +\\ +\rowsep +% +\tcode{A} & +The same as \tcode{a}, except that +it uses uppercase letters for digits above 9 and +\tcode{P} to indicate the exponent. +\\ \rowsep +% +\tcode{e} & +Equivalent to +\begin{codeblock} +to_chars(first, last, value, chars_format::scientific, precision) +\end{codeblock} +where \tcode{precision} is the specified formatting precision, +or \tcode{6} if \fmtgrammarterm{precision} is not specified. +\\ \rowsep +% +\tcode{E} & +The same as \tcode{e}, except that it uses \tcode{E} to indicate exponent. +\\ \rowsep +% +\tcode{f}, \tcode{F} & +Equivalent to +\begin{codeblock} +to_chars(first, last, value, chars_format::fixed, precision) +\end{codeblock} +where \tcode{precision} is the specified formatting precision, +or \tcode{6} if \fmtgrammarterm{precision} is not specified. +\\ \rowsep +% +\tcode{g} & +Equivalent to +\begin{codeblock} +to_chars(first, last, value, chars_format::general, precision) +\end{codeblock} +where \tcode{precision} is the specified formatting precision, +or \tcode{6} if \fmtgrammarterm{precision} is not specified. +\\ \rowsep +% +\tcode{G} & +The same as \tcode{g}, except that +it uses \tcode{E} to indicate exponent. +\\ \rowsep +% +\tcode{n} & +The same as \tcode{g}, except that +it uses the context's locale to insert the appropriate +digit group and decimal radix separator characters. +\\ \rowsep +% +none & +If \fmtgrammarterm{precision} is specified, equivalent to +\begin{codeblock} +to_chars(first, last, value, chars_format::general, precision) +\end{codeblock} +where \tcode{precision} is the specified formatting precision; equivalent to +\begin{codeblock} +to_chars(first, last, value) +\end{codeblock} +otherwise. +\\ +\end{floattable} + +\pnum +The available pointer presentation types and their mapping to +\tcode{to_chars} are specified in \tref{format.type.ptr}. +\begin{note} +Pointer presentation types also apply to \tcode{nullptr_t}. +\end{note} +% +\begin{floattable}{Meaning of \fmtgrammarterm{type} options for pointer types}{format.type.ptr}{lp{.8\hsize}} +\topline +\lhdr{Type} & \rhdr{Meaning} \\ \rowsep +none, \tcode{p} & +If \tcode{uintptr_t} is defined, +\begin{codeblock} +to_chars(first, last, reinterpret_cast(value), 16) +\end{codeblock} +with the prefix \tcode{0x} added to the output; +otherwise, implementation-defined. +\\ +\end{floattable} + +\rSec2[format.functions]{Formatting functions} + +\pnum +In the description of the functions, operator \tcode{+} is used +for some of the iterator categories for which it does not have to be defined. +In these cases the semantics of \tcode{a + n} are +the same as in \ref{algorithms.requirements}. + +\indexlibrary{\idxcode{format}}% +\begin{itemdecl} +template + string format(string_view fmt, const Args&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\begin{codeblock} +return vformat(fmt, make_format_args(args...)); +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{format}}% +\begin{itemdecl} +template + wstring format(wstring_view fmt, const Args&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\begin{codeblock} +return vformat(fmt, make_wformat_args(args...)); +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{format}}% +\begin{itemdecl} +template + string format(const locale& loc, string_view fmt, const Args&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\begin{codeblock} +return vformat(loc, fmt, make_format_args(args...)); +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{format}}% +\begin{itemdecl} +template + wstring format(const locale& loc, wstring_view fmt, const Args&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\begin{codeblock} +return vformat(loc, fmt, make_wformat_args(args...)); +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{vformat}}% +\begin{itemdecl} +string vformat(string_view fmt, format_args args); +wstring vformat(wstring_view fmt, wformat_args args); +string vformat(const locale& loc, string_view fmt, format_args args); +wstring vformat(const locale& loc, wstring_view fmt, wformat_args args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A string object holding the character representation of +formatting arguments provided by \tcode{args} formatted according to +specifications given in \tcode{fmt}. +If present, \tcode{loc} is used for locale-specific formatting. + +\pnum +\throws +\tcode{format_error} if \tcode{fmt} is not a format string. +\end{itemdescr} + +\indexlibrary{\idxcode{format_to}}% +\begin{itemdecl} +template + Out format_to(Out out, string_view fmt, const Args&... args); +template + Out format_to(Out out, wstring_view fmt, const Args&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\begin{codeblock} +using context = basic_format_context; +return vformat_to(out, fmt, {make_format_args(args...)}); +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{format_to}}% +\begin{itemdecl} +template + Out format_to(Out out, const locale& loc, string_view fmt, const Args&... args); +template + Out format_to(Out out, const locale& loc, wstring_view fmt, const Args&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\begin{codeblock} +using context = basic_format_context; +return vformat_to(out, loc, fmt, {make_format_args(args...)}); +\end{codeblock} +\end{itemdescr} + +\indexlibrary{\idxcode{vformat_to}}% +\begin{itemdecl} +template + Out vformat_to(Out out, string_view fmt, format_args_t args); +template + Out vformat_to(Out out, wstring_view fmt, format_args_t args); +template + Out vformat_to(Out out, const locale& loc, string_view fmt, + format_args_t args); +template + Out vformat_to(Out out, const locale& loc, wstring_view fmt, + format_args_t args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{charT} be \tcode{decltype(fmt)::value_type}. + +\pnum +\constraints +\tcode{Out} satisfies \tcode{output_iterator}. + +\pnum +\expects +\tcode{Out} models \tcode{\libconcept{output_iterator}}. + +\pnum +\effects +Places the character representation of formatting +the arguments provided by \tcode{args}, +formatted according to the specifications given in \tcode{fmt}, +into the range \range{out}{out + N}, +where \tcode{N} is +\tcode{formatted_size(fmt, args...)} for the functions without a \tcode{loc} parameter and +\tcode{formatted_size(loc, fmt, args...)} for the functions with a \tcode{loc} parameter. +If present, \tcode{loc} is used for locale-specific formatting. + +\pnum +\returns +\tcode{out + N}. + +\pnum +\throws +\tcode{format_error} if \tcode{fmt} is not a format string. +\end{itemdescr} + +\indexlibrary{\idxcode{format_to_n}}% +\begin{itemdecl} +template + format_to_n_result format_to_n(Out out, iter_difference_t n, + string_view fmt, const Args&... args); +template + format_to_n_result format_to_n(Out out, iter_difference_t n, + wstring_view fmt, const Args&... args); +template + format_to_n_result format_to_n(Out out, iter_difference_t n, + const locale& loc, string_view fmt, + const Args&... args); +template + format_to_n_result format_to_n(Out out, iter_difference_t n, + const locale& loc, wstring_view fmt, + const Args&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let +\begin{itemize} +\item \tcode{charT} be \tcode{decltype(fmt)::value_type}, +\item \tcode{N} be +\tcode{formatted_size(fmt, args...)} for the functions without a \tcode{loc} parameter and +\tcode{formatted_size(loc, fmt, args...)} for the functions with a \tcode{loc} parameter, and +\item \tcode{M} be \tcode{clamp(n, 0, N)}. +\end{itemize} + +\pnum +\constraints +\tcode{Out} satisfies \tcode{\libconcept{output_iterator}}. + +\pnum +\expects +\tcode{Out} models \tcode{\libconcept{output_iterator}}, and +\tcode{formatter<}$\tcode{T}_i$\tcode{, charT>} +meets the \newoldconcept{Formatter} requirements\iref{formatter.requirements} +for each $\tcode{T}_i$ in \tcode{Args}. + +\pnum +\effects +Places the first \tcode{M} characters of the character representation of +formatting the arguments provided by \tcode{args}, +formatted according to the specifications given in \tcode{fmt}, +into the range \range{out}{out + M}. +If present, \tcode{loc} is used for locale-specific formatting. + +\pnum +\returns +\tcode{\{out + M, N\}}. + +\pnum +\throws +\tcode{format_error} if \tcode{fmt} is not a format string. +\end{itemdescr} + +\indexlibrary{\idxcode{formatted_size}}% +\begin{itemdecl} +template + size_t formatted_size(string_view fmt, const Args&... args); +template + size_t formatted_size(wstring_view fmt, const Args&... args); +template + size_t formatted_size(const locale& loc, string_view fmt, const Args&... args); +template + size_t formatted_size(const locale& loc, wstring_view fmt, const Args&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{charT} be \tcode{decltype(fmt)::value_type}. + +\pnum +\expects +\tcode{formatter<}$\tcode{T}_i$\tcode{, charT>} +meets the \newoldconcept{Formatter} requirements\iref{formatter.requirements} +for each $\tcode{T}_i$ in \tcode{Args}. + +\pnum +\returns +The number of characters in the character representation of +formatting arguments \tcode{args} +formatted according to specifications given in \tcode{fmt}. +If present, \tcode{loc} is used for locale-specific formatting. + +\pnum +\throws +\tcode{format_error} if \tcode{fmt} is not a format string. +\end{itemdescr} + +\rSec2[format.formatter]{Formatter} + +\rSec3[formatter.requirements]{Formatter requirements} + +\pnum +\indextext{requirements!\idxnewoldconcept{Formatter}}% +A type \tcode{F} meets the \newoldconceptdefn{Formatter} requirements if: + +\begin{itemize} +\item +it meets the +\begin{itemize} +\item \oldconcept{DefaultConstructible} (\tref{cpp17.defaultconstructible}), +\item \oldconcept{CopyConstructible} (\tref{cpp17.copyconstructible}), +\item \oldconcept{CopyAssignable} (\tref{cpp17.copyassignable}), and +\item \oldconcept{Destructible} (\tref{cpp17.destructible}) +\end{itemize} +requirements, + +\item +it is swappable\iref{swappable.requirements} for lvalues, and + +\item +the expressions shown in \tref{formatter} are valid and +have the indicated semantics. +\end{itemize} + +\pnum +Given character type \tcode{charT}, output iterator type +\tcode{Out}, and formatting argument type \tcode{T}, +in \tref{formatter}: +\begin{itemize} +\item \tcode{f} is a value of type \tcode{F}, +\item \tcode{u} is an lvalue of type \tcode{T}, +\item \tcode{t} is a value of a type convertible to (possibly const) \tcode{T}, +\item \tcode{PC} is \tcode{basic_format_parse_context}, +\item \tcode{FC} is \tcode{basic_format_context}, +\item \tcode{pc} is an lvalue of type \tcode{PC}, and +\item \tcode{fc} is an lvalue of type \tcode{FC}. +\end{itemize} +\tcode{pc.begin()} points to the beginning of the +\fmtgrammarterm{format-spec}\iref{format.string} +of the replacement field being formatted +in the format string. +If \fmtgrammarterm{format-spec} is empty then either +\tcode{pc.begin() == pc.end()} or +\tcode{*pc.begin() == '\}'}. + +\begin{concepttable}{\newoldconcept{Formatter} requirements}{formatter} +{p{1.2in}p{1in}p{2.9in}} +\topline +\hdstyle{Expression} & \hdstyle{Return type} & \hdstyle{Requirement} \\ \capsep +\tcode{f.parse(pc)} & +\tcode{PC::iterator} & +Parses \fmtgrammarterm{format-spec}\iref{format.string} +for type \tcode{T} +in the range \range{pc.begin()}{pc.end()} +until the first unmatched character. +Throws \tcode{format_error} unless the whole range is parsed +or the unmatched character is \tcode{\}}. +\begin{note} +This allows formatters to emit meaningful error messages. +\end{note} +Stores the parsed format specifiers in \tcode{*this} and +returns an iterator past the end of the parsed range. +\\ \rowsep +\tcode{f.format(t, fc)} & +\tcode{FC::iterator} & +Formats \tcode{t} according to the specifiers stored in \tcode{*this}, +writes the output to \tcode{fc.out()} and +returns an iterator past the end of the output range. +The output shall only depend on +\tcode{t}, +\tcode{fc.locale()}, +and the range \range{pc.begin()}{pc.end()} +from the last call to \tcode{f.parse(pc)}. +\\ \rowsep +\tcode{f.format(u, fc)} & +\tcode{FC::iterator} & +As above, but does not modify \tcode{u}. +\\ +\end{concepttable} + +\rSec3[format.formatter.spec]{Formatter specializations} +\indexlibrary{\idxcode{formatter}}% + +\pnum +% FIXME: Specify this in [format.functions], not here! +The functions defined in \ref{format.functions} use +specializations of the class template \tcode{formatter} to format +individual arguments. + +\pnum +Let \tcode{charT} be either \tcode{char} or \tcode{wchar_t}. +Each specialization of \tcode{formatter} is either enabled or disabled, +as described below. +\begin{note} +Enabled specializations meet the \newoldconcept{Formatter} requirements, +and disabled specializations do not. +\end{note} +Each header that declares the template \tcode{formatter} +provides the following enabled specializations: +\begin{itemize} +\item +\indexlibrary{\idxcode{formatter}!specializations!character types}% +The specializations +\begin{codeblock} +template<> struct formatter; +template<> struct formatter; +template<> struct formatter; +\end{codeblock} + +\item +\indexlibrary{\idxcode{formatter}!specializations!string types}% +For each \tcode{charT}, +the string type specializations +\begin{codeblock} +template<> struct formatter; +template<> struct formatter; +template struct formatter; +template + struct formatter, charT>; +template + struct formatter, charT>; +\end{codeblock} + +\item +\indexlibrary{\idxcode{formatter}!specializations!arithmetic types}% +For each \tcode{charT}, +for each cv-unqualified arithmetic type \tcode{ArithmeticT} +other than +\tcode{char}, +\tcode{wchar_t}, +\tcode{char8_t}, +\tcode{char16_t}, or +\tcode{char32_t}, +a specialization +\begin{codeblock} +template<> struct formatter; +\end{codeblock} + +\item +\indexlibrary{\idxcode{formatter}!specializations!pointer types}% +\indexlibrary{\idxcode{formatter}!specializations!\idxcode{nullptr_t}}% +For each \tcode{charT}, +the pointer type specializations +\begin{codeblock} +template<> struct formatter; +template<> struct formatter; +template<> struct formatter; +\end{codeblock} +\end{itemize} +The \tcode{parse} member functions of these formatters +interpret the format specification +as a \fmtgrammarterm{std-format-spec} +as described in \ref{format.string.std}. +\begin{note} +Specializations such as \tcode{formatter} +and \tcode{formatter} +that would require implicit +multibyte / wide string or character conversion are disabled. +\end{note} + +\pnum +For any types \tcode{T} and \tcode{charT} for which +neither the library nor the user provides +an explicit or partial specialization of +the class template \tcode{formatter}, +\tcode{formatter} is disabled. + +\pnum +If the library provides an explicit or partial specialization of +\tcode{formatter}, that specialization is enabled +except as noted otherwise. + +\pnum +If \tcode{F} is a disabled specialization of \tcode{formatter}, these +values are \tcode{false}: +\begin{itemize} +\item \tcode{is_default_constructible_v}, +\item \tcode{is_copy_constructible_v}, +\item \tcode{is_move_constructible_v}, +\item \tcode{is_copy_assignable_v}, and +\item \tcode{is_move_assignable_v}. +\end{itemize} + +\pnum +An enabled specialization \tcode{formatter} meets the +\newoldconcept{Formatter} requirements\iref{formatter.requirements}. +\begin{example} +\begin{codeblock} +#include + +enum color { red, green, blue }; +const char* color_names[] = { "red", "green", "blue" }; + +template<> struct std::formatter : std::formatter { + auto format(color c, format_context& ctx) { + return formatter::format(color_names[c], ctx); + } +}; + +struct err {}; + +std::string s0 = std::format("{}", 42); // OK, library-provided formatter +std::string s1 = std::format("{}", L"foo"); // ill-formed: disabled formatter +std::string s2 = std::format("{}", red); // OK, user-provided formatter +std::string s3 = std::format("{}", err{}); // ill-formed: disabled formatter +\end{codeblock} +\end{example} + +\rSec3[format.parse.ctx]{Class template \tcode{basic_format_parse_context}} + +\indexlibrary{\idxcode{basic_format_parse_context}}% +\indexlibrarymember{char_type}{basic_format_parse_context}% +\indexlibrarymember{const_iterator}{basic_format_parse_context}% +\indexlibrarymember{iterator}{basic_format_parse_context}% +\begin{codeblock} +namespace std { + template + class basic_format_parse_context { + public: + using char_type = charT; + using const_iterator = typename basic_string_view::const_iterator; + using iterator = const_iterator; + + private: + iterator begin_; // \expos + iterator end_; // \expos + enum indexing { unknown, manual, automatic }; // \expos + indexing indexing_; // \expos + size_t next_arg_id_; // \expos + size_t num_args_; // \expos + + public: + constexpr explicit basic_format_parse_context(basic_string_view fmt, + size_t num_args = 0) noexcept; + basic_format_parse_context(const basic_format_parse_context&) = delete; + basic_format_parse_context& operator=(const basic_format_parse_context&) = delete; + + constexpr const_iterator begin() const noexcept; + constexpr const_iterator end() const noexcept; + constexpr void advance_to(const_iterator it); + + constexpr size_t next_arg_id(); + constexpr void check_arg_id(size_t id); + }; +} +\end{codeblock} + +\pnum +An instance of \tcode{basic_format_parse_context} holds +the format string parsing state consisting of +the format string range being parsed and +the argument counter for automatic indexing. + +\indexlibrary{\idxcode{basic_format_parse_context}!constructor}% +\begin{itemdecl} +constexpr explicit basic_format_parse_context(basic_string_view fmt, + size_t num_args = 0) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes +\tcode{begin_} with \tcode{fmt.begin()}, +\tcode{end_} with \tcode{fmt.end()}, +\tcode{indexing_} with \tcode{unknown}, +\tcode{next_arg_id_} with \tcode{0}, and +\tcode{num_args_} with \tcode{num_args}. +\end{itemdescr} + +\indexlibrarymember{begin}{basic_format_parse_context}% +\begin{itemdecl} +constexpr const_iterator begin() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{begin_}. +\end{itemdescr} + +\indexlibrarymember{end}{basic_format_parse_context}% +\begin{itemdecl} +constexpr const_iterator end() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{end_}. +\end{itemdescr} + +\indexlibrarymember{advance_to}{basic_format_parse_context}% +\begin{itemdecl} +constexpr void advance_to(const_iterator it); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{end()} is reachable from \tcode{it}. + +\pnum +\effects Equivalent to: \tcode{begin_ = it;} +\end{itemdescr} + +\indexlibrarymember{next_arg_id}{basic_format_parse_context}% +\begin{itemdecl} +constexpr size_t next_arg_id(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +If \tcode{indexing_ != manual}, equivalent to: +\begin{codeblock} +if (indexing_ == unknown) + indexing_ = automatic; +return next_arg_id_++; +\end{codeblock} + +\pnum +\throws +\tcode{format_error} if \tcode{indexing_ == manual} +which indicates mixing of automatic and manual argument indexing. +\end{itemdescr} + +\indexlibrarymember{check_arg_id}{basic_format_parse_context}% +\begin{itemdecl} +constexpr void check_arg_id(size_t id); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +If \tcode{indexing_ != automatic}, equivalent to: +\begin{codeblock} +if (indexing_ == unknown) + indexing_ = manual; +\end{codeblock} + +\pnum +\throws +\tcode{format_error} if +\tcode{indexing_ == automatic} which indicates mixing of automatic and +manual argument indexing. + +\pnum +\remarks +Call expressions where \tcode{id >= num_args_} are not +core constant expressions\iref{expr.const}. +\end{itemdescr} + +\rSec3[format.context]{Class template \tcode{basic_format_context}} + +\indexlibrary{\idxcode{basic_format_context}}% +\indexlibrarymember{iterator}{basic_format_context}% +\indexlibrarymember{char_type}{basic_format_context}% +\indexlibrarymember{formatter_type}{basic_format_context}% +\begin{codeblock} +namespace std { + template + class basic_format_context { + basic_format_args args_; // \expos + Out out_; // \expos + + public: + using iterator = Out; + using char_type = charT; + template using formatter_type = formatter; + + basic_format_arg arg(size_t id) const; + std::locale locale(); + + iterator out(); + void advance_to(iterator it); + }; +} +\end{codeblock} + +\pnum +An instance of \tcode{basic_format_context} holds formatting state +consisting of the formatting arguments and the output iterator. + +\pnum +\tcode{Out} shall model \tcode{\libconcept{output_iterator}}. + +\pnum +\indexlibrary{\idxcode{format_context}}% +\tcode{format_context} is an alias for +a specialization of \tcode{basic_format_context} +with an output iterator +that appends to \tcode{string}, +such as \tcode{back_insert_iterator}. +\indexlibrary{\idxcode{wformat_context}}% +Similarly, \tcode{wformat_context} is an alias for +a specialization of \tcode{basic_format_context} +with an output iterator +that appends to \tcode{wstring}. + +\pnum +\begin{note} +For a given type \tcode{charT}, +implementations are encouraged to provide +a single instantiation of \tcode{basic_format_context} +for appending to +\tcode{basic_string}, +\tcode{vector}, +or any other container with contiguous storage +by wrapping those in temporary objects with a uniform interface +(such as a \tcode{span}) and polymorphic reallocation. +\end{note} + +\indexlibrarymember{arg}{basic_format_context}% +\begin{itemdecl} +basic_format_arg arg(size_t id) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{args_.get(id)}. +\end{itemdescr} + +\indexlibrarymember{locale}{basic_format_context}% +\begin{itemdecl} +std::locale locale(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The locale passed to the formatting function +if the latter takes one, +and \tcode{std::locale()} otherwise. +\end{itemdescr} + +\indexlibrarymember{out}{basic_format_context}% +\begin{itemdecl} +iterator out(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{out_}. +\end{itemdescr} + +\indexlibrarymember{advance_to}{basic_format_context}% +\begin{itemdecl} +void advance_to(iterator it); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: \tcode{out_ = it;} +\end{itemdescr} + +\index{left-pad}% +\begin{example} +\begin{codeblock} +struct S { int value; }; + +template<> struct std::formatter { + size_t width_arg_id = 0; + + // Parses a width argument id in the format \tcode{\{} \fmtgrammarterm{digit} \tcode{\}}. + constexpr auto parse(format_parse_context& ctx) { + auto iter = ctx.begin(); + auto get_char = [&]() { return iter != ctx.end() ? *iter : 0; }; + if (get_char() != '{') + return iter; + ++iter; + char c = get_char(); + if (!isdigit(c) || (++iter, get_char()) != '}') + throw format_error("invalid format"); + width_arg_id = c - '0'; + ctx.check_arg_id(width_arg_id); + return ++iter; + } + + // Formats an \tcode{S} with width given by the argument \tcode{width_arg_id}. + auto format(S s, format_context& ctx) { + int width = visit_format_arg([](auto value) -> int { + if constexpr (!is_integral_v) + throw format_error("width is not integral"); + else if (value < 0 || value > numeric_limits::max()) + throw format_error("invalid width"); + else + return value; + }, ctx.arg(width_arg_id)); + return format_to(ctx.out(), "{0:x<{1}}", s.value, width); + } +}; + +std::string s = std::format("{0:{1}}", S{42}, 10); // value of \tcode{s} is \tcode{"xxxxxxxx42"} +\end{codeblock} +\end{example} + +\rSec2[format.arguments]{Arguments} + +\rSec3[format.arg]{Class template \tcode{basic_format_arg}} + +\indexlibrary{\idxcode{basic_format_arg}}% +\begin{codeblock} +namespace std { + template + class basic_format_arg { + public: + class handle; + + private: + using char_type = typename Context::char_type; // \expos + + variant, + const void*, handle> value; // \expos + + template explicit basic_format_arg(const T& v) noexcept; // \expos + explicit basic_format_arg(float n) noexcept; // \expos + explicit basic_format_arg(double n) noexcept; // \expos + explicit basic_format_arg(long double n) noexcept; // \expos + explicit basic_format_arg(const char_type* s); // \expos + + template + explicit basic_format_arg( + basic_string_view s) noexcept; // \expos + + template + explicit basic_format_arg( + const basic_string& s) noexcept; // \expos + + explicit basic_format_arg(nullptr_t) noexcept; // \expos + + template + explicit basic_format_arg(const T* p) noexcept; // \expos + + template + friend auto visit_format_arg(Visitor&& vis, + basic_format_arg arg); // \expos + + template + friend @\placeholder{format-arg-store}@ + make_format_args(const Args&... args); // \expos + + public: + basic_format_arg() noexcept; + + explicit operator bool() const noexcept; + }; +} +\end{codeblock} + +\pnum +An instance of \tcode{basic_format_arg} provides access to +a formatting argument for user-defined formatters. + +\pnum +The behavior of a program that adds specializations of +\tcode{basic_format_arg} is undefined. + +\indexlibrary{\idxcode{basic_format_arg}!constructor|(}% +\begin{itemdecl} +basic_format_arg() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ensures \tcode{!(*this)}. +\end{itemdescr} + +\begin{itemdecl} +template explicit basic_format_arg(const T& v) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +The template specialization +\begin{codeblock} +typename Context::template formatter_type +\end{codeblock} +is an enabled specialization of \tcode{formatter}\iref{format.formatter}. +The extent to which an implementation determines that +the specialization is enabled is unspecified, +except that as a minimum the expression +\begin{codeblock} +typename Context::template formatter_type() + .format(declval(), declval()) +\end{codeblock} +shall be well-formed when treated as an unevaluated operand. + +\pnum +\effects +\begin{itemize} +\item +if \tcode{T} is \tcode{bool} or \tcode{char_type}, +initializes \tcode{value} with \tcode{v}; otherwise, +\item +if \tcode{T} is \tcode{char} and \tcode{char_type} is +\tcode{wchar_t}, initializes \tcode{value} with +\tcode{static_cast(v)}; otherwise, +\item +if \tcode{T} is a signed integer type\iref{basic.fundamental} +and \tcode{sizeof(T) <= sizeof(int)}, +initializes \tcode{value} with \tcode{static_cast(v)}; +otherwise, +\item +if \tcode{T} is an unsigned integer type and +\tcode{sizeof(T) <= sizeof(unsigned int)}, initializes +\tcode{value} with \tcode{static_cast(v)}; +otherwise, +\item +if \tcode{T} is a signed integer type and +\tcode{sizeof(T) <= sizeof(long long int)}, initializes +\tcode{value} with \tcode{static_cast(v)}; +otherwise, +\item +if \tcode{T} is an unsigned integer type and +\tcode{sizeof(T) <= sizeof(unsigned long long int)}, initializes +\tcode{value} with +\tcode{static_cast(v)}; otherwise, +\item +initializes \tcode{value} with \tcode{handle(v)}. +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +explicit basic_format_arg(float n) noexcept; +explicit basic_format_arg(double n) noexcept; +explicit basic_format_arg(long double n) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Initializes \tcode{value} with \tcode{n}. +\end{itemdescr} + +\begin{itemdecl} +explicit basic_format_arg(const char_type* s); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{s} points to a NTCTS\iref{defns.ntcts}. + +\pnum +\effects Initializes \tcode{value} with \tcode{s}. +\end{itemdescr} + +\begin{itemdecl} +template + explicit basic_format_arg(basic_string_view s) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Initializes \tcode{value} with \tcode{s}. +\end{itemdescr} + +\begin{itemdecl} +template + explicit basic_format_arg( + const basic_string& s) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Initializes \tcode{value} with +\tcode{basic_string_view(s.data(), s.size())}. +\end{itemdescr} + +\begin{itemdecl} +explicit basic_format_arg(nullptr_t) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Initializes \tcode{value} with + \tcode{static_cast(nullptr)}. +\end{itemdescr} + +\begin{itemdecl} +template explicit basic_format_arg(T* p) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constraints +\tcode{is_void_v} is \tcode{true}. + +\pnum +\effects Initializes \tcode{value} with \tcode{p}. + +\pnum +\begin{note} +Constructing \tcode{basic_format_arg} from +a pointer to a member is ill-formed unless +the user provides an enabled specialization of +\tcode{formatter} for that pointer to member type. +\end{note} +\end{itemdescr} +\indexlibrary{\idxcode{basic_format_arg}!constructor|)}% + +\indexlibrarymember{operator bool}{basic_format_arg}% +\begin{itemdecl} +explicit operator bool() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{!holds_alternative(value)}. +\end{itemdescr} + +\pnum +The class \tcode{handle} allows formatting an object of a user-defined type. + +\indexlibrary{basic_format_arg::handle}% +\indexlibrarymember{handle}{basic_format_arg}% +\begin{codeblock} +namespace std { + template + class basic_format_arg::handle { + const void* ptr_; // \expos + void (*format_)(basic_format_parse_context&, + Context&, const void*); // \expos + + template explicit handle(const T& val) noexcept; // \expos + + friend class basic_format_arg; // \expos + + public: + void format(basic_format_parse_context&, Context& ctx) const; + }; +} +\end{codeblock} + +\indexlibrary{\idxcode{basic_format_arg::handle}!constructor}% +\begin{itemdecl} +template explicit handle(const T& val) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes +\tcode{ptr_} with \tcode{addressof(val)} and +\tcode{format_} with +\begin{codeblock} +[](basic_format_parse_context& parse_ctx, + Context& format_ctx, const void* ptr) { + typename Context::template formatter_type f; + parse_ctx.advance_to(f.parse(parse_ctx)); + format_ctx.advance_to(f.format(*static_cast(ptr), format_ctx)); +} +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{format}{basic_format_arg::handle}% +\begin{itemdecl} +void format(basic_format_parse_context& parse_ctx, Context& format_ctx) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: \tcode{format_(parse_ctx, format_ctx, ptr_);} +\end{itemdescr} + +\indexlibrary{\idxcode{visit_format_arg}}% +\begin{itemdecl} +template + @\seebelow@ visit_format_arg(Visitor&& vis, basic_format_arg arg); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: \tcode{return visit(forward(vis), arg.value);} +\end{itemdescr} + +\rSec3[format.arg.store]{Class template \exposid{format-arg-store}} + +\begin{codeblock} +namespace std { + template + struct @\placeholder{format-arg-store}@ { // \expos + array, sizeof...(Args)> args; + }; +} +\end{codeblock} + +\pnum +An instance of \exposid{format-arg-store} stores formatting arguments. + +\indexlibrary{\idxcode{make_format_args}}% +\begin{itemdecl} +template + @\placeholder{format-arg-store}@ make_format_args(const Args&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +The type +\tcode{typename Context::template formatter_type<}$\tcode{T}_i$\tcode{>} +meets the \newoldconcept{Formatter} requirements\iref{formatter.requirements} +for each $\tcode{T}_i$ in \tcode{Args}. + +\pnum +\returns +\tcode{\{basic_format_arg(args)...\}}. +\end{itemdescr} + +\indexlibrary{\idxcode{make_wformat_args}}% +\begin{itemdecl} +template + @\placeholder{format-arg-store}@ make_wformat_args(const Args&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Equivalent to: +\tcode{return make_format_args(args...);} +\end{itemdescr} + +\rSec3[format.args]{Class template \tcode{basic_format_args}} + +\begin{codeblock} +namespace std { + template + class basic_format_args { + size_t size_; // \expos + const basic_format_arg* data_; // \expos + + public: + basic_format_args() noexcept; + + template + basic_format_args(const @\placeholder{format-arg-store}@& store) noexcept; + + basic_format_arg get(size_t i) const noexcept; + }; +} +\end{codeblock} + +\pnum +An instance of \tcode{basic_format_args} provides access to formatting +arguments. + +\indexlibrary{\idxcode{basic_format_args}!constructor}% +\begin{itemdecl} +basic_format_args() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Initializes \tcode{size_} with \tcode{0}. +\end{itemdescr} + +\indexlibrary{\idxcode{basic_format_args}!constructor}% +\begin{itemdecl} +template + basic_format_args(const @\placeholder{format-arg-store}@& store) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects Initializes +\tcode{size_} with \tcode{sizeof...(Args)} and +\tcode{data_} with \tcode{store.args.data()}. +\end{itemdescr} + +\indexlibrarymember{get}{basic_format_args}% +\begin{itemdecl} +basic_format_arg get(size_t i) const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{i < size_ ?\ data_[i] :\ basic_format_arg()}. +\end{itemdescr} + +\begin{note} +Implementations are encouraged +to optimize the representation of \tcode{basic_format_args} +for small number of formatting arguments +by storing indices of type alternatives separately from values +and packing the former. +\end{note} + +\rSec2[format.error]{Class \tcode{format_error}} + +\indexlibrary{\idxcode{format_error}}% +\begin{codeblock} +namespace std { + class format_error : public runtime_error { + public: + explicit format_error(const string& what_arg); + explicit format_error(const char* what_arg); + }; +} +\end{codeblock} + +\pnum +The class \tcode{format_error} defines the type of objects thrown as +exceptions to report errors from the formatting library. + +\indexlibrary{\idxcode{format_error}!constructor}% +\begin{itemdecl} +format_error(const string& what_arg); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ensures +\tcode{strcmp(what(), what_arg.c_str()) == 0}. + +\indexlibrary{\idxcode{format_error}!constructor}% +\end{itemdescr} +\begin{itemdecl} +format_error(const char* what_arg); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ensures +\tcode{strcmp(what(), what_arg) == 0}. +\end{itemdescr}